diff --git a/Gancho/HookManager.cpp b/Gancho/HookManager.cpp index 293a18b..90e9d0a 100644 --- a/Gancho/HookManager.cpp +++ b/Gancho/HookManager.cpp @@ -11,34 +11,52 @@ HookManager::HookManager() #endif } + LPVOID HookManager::AddHook( _In_ BYTE* Src, - _In_ BYTE* Dst + _In_ BYTE* Dst, + _In_ BOOL IgnoreProt ) { - auto it = hooks.find(Src); - if (it != hooks.end()) return nullptr; - LPVOID pGatewayAddr; + Hook* NewHook; + auto it = HookChain.find(Src); + if (it != HookChain.end()) + { + Hook* LastHook = it->second.back(); + // + // Add new hook in the hook chain, so that way all the hooks are called recursively + // +#if defined(_WIN64) + NewHook = Hook64((BYTE*)LastHook->GatewayAddr, Dst, IgnoreProt); +#else + NewHook = Hook32((BYTE*)LastHook->GatewayAddr, Dst, IgnoreProt); +#endif + } + else + { #if defined(_WIN64) - pGatewayAddr = Hook64(Src, Dst); + NewHook = Hook64(Src, Dst, IgnoreProt); #else - pGatewayAddr = Hook32(Src, Dst); + NewHook = Hook32(Src, Dst, IgnoreProt); #endif + } + // + // Sad, we failed ;-; + // + if (NewHook == nullptr) + return nullptr; + // // Insert new hook on the manager map // - Hook hk; - hk.OriginalAddr = Src; - hk.HookAddr = Dst; - hk.GatewayAddr = pGatewayAddr; + HookChain[Src].push_back(NewHook); - hooks[Src] = hk; - - return pGatewayAddr; + return NewHook->GatewayAddr; } + VOID HookManager::DisassambleAt(_In_ ULONG_PTR* Address, _In_ SIZE_T NumberOfInstructions) { ZydisFormatter formatter; @@ -60,8 +78,8 @@ VOID HookManager::DisassambleAt(_In_ ULONG_PTR* Address, _In_ SIZE_T NumberOfIns } } -LPVOID -HookManager::Hook64(_In_ BYTE* Src, _In_ BYTE* Dst) +Hook* +HookManager::Hook64(_In_ BYTE* Src, _In_ BYTE* Dst, _In_ BOOL IgnoreProt) { // // This is the base template trampoline code that will be used in future operations. @@ -98,6 +116,11 @@ HookManager::Hook64(_In_ BYTE* Src, _In_ BYTE* Dst) // ZydisDecodedInstruction inst; + // + // Hook structure to store core information about this hook + // + Hook* HookStructure; + // // Disassemble to pick the instructions length // @@ -119,14 +142,15 @@ HookManager::Hook64(_In_ BYTE* Src, _In_ BYTE* Dst) // Store the original code, nop everything and build the trampoline code to jump back // VirtualProtect(Src, overlap, PAGE_EXECUTE_READWRITE, &dwOldProtect); + + // + // Add a NOP slide to give a good space to the HookChain structure + // + memset(pOldCode, NOP, NOP_SLIDE); // // Copy the exactly instructions that should be executed, extracted by Zydis // - memcpy_s(pOldCode, overlap + X64_TRAMPOLINE_SIZE + NOP_SLIDE, Src, overlap); - // - // Add a NOP slide to avoid that the trampoline code mess up with some opcode - // - memset(pOldCode + overlap, NOP, NOP_SLIDE); + memcpy_s(pOldCode + NOP_SLIDE, overlap + X64_TRAMPOLINE_SIZE, Src, overlap); // // Nop Src to avoid execute invalid instructions // @@ -144,15 +168,24 @@ HookManager::Hook64(_In_ BYTE* Src, _In_ BYTE* Dst) *(ULONG_PTR*)(JumpToHookCode + 2) = (ULONG_PTR)Dst; memcpy_s(Src, X64_TRAMPOLINE_SIZE, JumpToHookCode, X64_TRAMPOLINE_SIZE); - VirtualProtect(Src, X64_TRAMPOLINE_SIZE, dwOldProtect, &dwOldProtect); - return pOldCode; + if (!IgnoreProt) + VirtualProtect(Src, X64_TRAMPOLINE_SIZE, dwOldProtect, &dwOldProtect); + + HookStructure = new Hook; + HookStructure->HookAddr = Dst; + HookStructure->OriginalAddr = Src; + HookStructure->GatewayAddr = pOldCode; + HookStructure->NumInstLeftToExec = overlap; + + return HookStructure; } -LPVOID +Hook* HookManager::Hook32( _In_ BYTE* Src, - _In_ BYTE* Dst + _In_ BYTE* Dst, + _In_ BOOL IgnoreProt ) { ULONG_PTR dwOldCodeDelta; @@ -161,6 +194,7 @@ HookManager::Hook32( DWORD dwOldProtection; DWORD overlap = 0; BYTE* pSrc = Src; + Hook* HookStructure; ZydisDecodedInstruction inst; @@ -192,6 +226,7 @@ HookManager::Hook32( VirtualProtect(Src, X86_TRAMPOLINE_SIZE, dwOldProtection, &dwOldProtection); return nullptr; } + // // Copy the old code before overwrite // @@ -231,12 +266,21 @@ HookManager::Hook32( // // Recover old protections // - if (!VirtualProtect(Src, X86_TRAMPOLINE_SIZE, dwOldProtection, &dwOldProtection)) + if (!IgnoreProt && !VirtualProtect(Src, X86_TRAMPOLINE_SIZE, dwOldProtection, &dwOldProtection)) { std::printf("Error on replacing protection!\n"); VirtualFree(pOldCode, NULL, MEM_RELEASE); return nullptr; } - return (LPVOID)pOldCode; + HookStructure = new Hook; + HookStructure->Gateway32Delta = dwRelativeAddrDstDelta; + HookStructure->Trampoline32Delta = dwOldCodeDelta; + HookStructure->HookAddr = Dst; + HookStructure->OriginalAddr = Src; + HookStructure->GatewayAddr = pOldCode; + HookStructure->NumInstLeftToExec = overlap; + + + return HookStructure; } diff --git a/Gancho/HookManager.h b/Gancho/HookManager.h index e2729f9..9477664 100644 --- a/Gancho/HookManager.h +++ b/Gancho/HookManager.h @@ -9,7 +9,7 @@ #define X64_JUMP_BACK_SIZE X64_TRAMPOLINE_SIZE #define HOOK_MAX_SIZE 2*5 -#define NOP_SLIDE 16 +#define NOP_SLIDE 32 // Nop slide helps with the HookChain structure #define TRAMPOLINE_SIZE 5 #define NOP 0x90 @@ -25,22 +25,27 @@ struct Hook { LPVOID OriginalAddr; LPVOID HookAddr; LPVOID GatewayAddr; + + DWORD NumInstLeftToExec; + // Only used for 32 bit hooks + DWORD Trampoline32Delta; + DWORD Gateway32Delta; }; + class __declspec(dllexport) HookManager { public: HookManager(); - LPVOID AddHook(_In_ BYTE* Src, _In_ BYTE* Dst); + LPVOID AddHook(_In_ BYTE* Src, _In_ BYTE* Dst, _In_ BOOL IgnoreProt); VOID DisassambleAt(_In_ ULONG_PTR* Address, _In_ SIZE_T NumberOfInstructions); private: - LPVOID Hook64(_In_ BYTE* Src, _In_ BYTE* Dst); - LPVOID Hook32(_In_ BYTE* Src, _In_ BYTE* Dst); - + Hook* Hook64(_In_ BYTE* Src, _In_ BYTE* Dst, _In_ BOOL IgnoreProt); + Hook* Hook32(_In_ BYTE* Src, _In_ BYTE* Dst, _In_ BOOL IgnoreProt); private: ZydisDecoder ZDecoder; - - std::unordered_map hooks; + std::unordered_map> HookChain; }; +