// Pointer for calling original MessageBoxW. MESSAGEBOXW fpMessageBoxW = NULL;
// Detour function which overrides MessageBoxW. int WINAPI DetourMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) { return fpMessageBoxW(hWnd, L"Hooked!", lpCaption, uType); }
intmain() { // Initialize MinHook. if (MH_Initialize() != MH_OK) { return1; } // Create a hook for MessageBoxW, in disabled state. if (MH_CreateHook(&MessageBoxW, &DetourMessageBoxW, reinterpret_cast<LPVOID*>(&fpMessageBoxW)) != MH_OK) { return1; } // or you can use the new helper function like this. //if (MH_CreateHookApiEx( // L"user32", "MessageBoxW", &DetourMessageBoxW, &fpMessageBoxW) != MH_OK) //{ // return 1; //} // Enable the hook for MessageBoxW. if (MH_EnableHook(&MessageBoxW) != MH_OK) { return1; }
typedefstruct _HOOK_ENTRY { LPVOID pTarget; // Address of the target function. LPVOID pDetour; // Address of the detour or relay function. LPVOID pTrampoline; // Address of the trampoline function. UINT8 backup[8]; // Original prologue of the target function.
UINT8 patchAbove : 1; // Uses the hot patch area. UINT8 isEnabled : 1; // Enabled. UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
UINT nIP : 4; // Count of the instruction boundaries. UINT8 oldIPs[8]; // Instruction boundaries of the target function. UINT8 newIPs[8]; // Instruction boundaries of the trampoline function. } HOOK_ENTRY, *PHOOK_ENTRY;
typedefstruct _TRAMPOLINE { LPVOID pTarget; // [In] Address of the target function. LPVOID pDetour; // [In] Address of the detour function. LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
#if defined(_M_X64) || defined(__x86_64__) LPVOID pRelay; // [Out] Address of the relay function. #endif BOOL patchAbove; // [Out] Should use the hot patch area? UINT nIP; // [Out] Number of the instruction boundaries. UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function. UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function. } TRAMPOLINE, *PTRAMPOLINE;
// Alloc a new block below if not found. if (pBlock == NULL) { LPVOID pAlloc = pOrigin; while ((ULONG_PTR)pAlloc <= maxAddr) { pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity); if (pAlloc == NULL) break;
pCopySrc = (LPVOID)pOldInst; if (oldPos >= sizeof(JMP_REL)) { // The trampoline function is long enough. // Complete the function with the jump to the target function. #if defined(_M_X64) || defined(__x86_64__) jmp.address = pOldInst; // x64模式写, 0xFF25 disp64进行jmp #else jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp))); #endif pCopySrc = &jmp; copySize = sizeof(jmp);
// Avoid using memcpy to reduce the footprint. #ifndef _MSC_VER memcpy(instBuf, (LPBYTE)pOldInst, copySize); #else __movsb(instBuf, (LPBYTE)pOldInst, copySize); #endif pCopySrc = instBuf; // Relative address is stored at (instruction length - immediate value length - 4). pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4); *pRelAddr = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len)); // 写入相对跳转地址 // Complete the function if JMP (FF /4). if (hs.opcode == 0xFF && hs.modrm_reg == 4) finished = TRUE; } #endif elseif (hs.opcode == 0xE8) // 如果是call指令 { // Direct relative CALL ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32; //call 指令的目的跳转地址 #if defined(_M_X64) || defined(__x86_64__) call.address = dest; #else call.operand = (UINT32)(dest - (pNewInst + sizeof(call))); // 修改call指令的目的跳转地址 #endif pCopySrc = &call; copySize = sizeof(call); } elseif ((hs.opcode & 0xFD) == 0xE9) // 如果是jmp { // Direct relative JMP (EB or E9) ULONG_PTR dest = pOldInst + hs.len;
if (hs.opcode == 0xEB) // isShort jmp dest += (INT8)hs.imm.imm8; else dest += (INT32)hs.imm.imm32;
// Simply copy an internal jump. if ((ULONG_PTR)ct->pTarget <= dest && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) { if (jmpDest < dest) jmpDest = dest; } else { #if defined(_M_X64) || defined(__x86_64__) jmp.address = dest; #else jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp))); #endif pCopySrc = &jmp; copySize = sizeof(jmp);
// Exit the function If it is not in the branch finished = (pOldInst >= jmpDest); } } elseif ((hs.opcode & 0xF0) == 0x70 || (hs.opcode & 0xFC) == 0xE0 || (hs.opcode2 & 0xF0) == 0x80) { // Direct relative Jcc ULONG_PTR dest = pOldInst + hs.len;
if ((hs.opcode & 0xF0) == 0x70// Jcc || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ dest += (INT8)hs.imm.imm8; else dest += (INT32)hs.imm.imm32;
// Simply copy an internal jump. if ((ULONG_PTR)ct->pTarget <= dest && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL))) { if (jmpDest < dest) jmpDest = dest; } elseif ((hs.opcode & 0xFC) == 0xE0) { // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported. return FALSE; } else { UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F); #if defined(_M_X64) || defined(__x86_64__) // Invert the condition in x64 mode to simplify the conditional jump logic. jcc.opcode = 0x71 ^ cond; jcc.address = dest; #else jcc.opcode1 = 0x80 | cond; jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc))); #endif pCopySrc = &jcc; copySize = sizeof(jcc); } } elseif ((hs.opcode & 0xFE) == 0xC2) { // RET (C2 or C3)
// Complete the function if not in a branch. finished = (pOldInst >= jmpDest); }
// Can't alter the instruction length in a branch. if (pOldInst < jmpDest && copySize != hs.len) return FALSE;
// Trampoline function is too large. if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE) return FALSE;
// Trampoline function has too many instructions. if (ct->nIP >= ARRAYSIZE(ct->oldIPs)) return FALSE;
staticvoidProcessThreadIPs(HANDLE hThread, UINT pos, UINT action) { // If the thread suspended in the overwritten area, // move IP to the proper address.