Skip to content

Commit

Permalink
Merge pull request #1 from buzzer-re/dev
Browse files Browse the repository at this point in the history
ADD: HookChain feature
  • Loading branch information
buzzer-re authored Apr 22, 2023
2 parents f239ff6 + 61242df commit dc66554
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 33 deletions.
96 changes: 70 additions & 26 deletions Gancho/HookManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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
//
Expand All @@ -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
//
Expand All @@ -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;
Expand All @@ -161,6 +194,7 @@ HookManager::Hook32(
DWORD dwOldProtection;
DWORD overlap = 0;
BYTE* pSrc = Src;
Hook* HookStructure;

ZydisDecodedInstruction inst;

Expand Down Expand Up @@ -192,6 +226,7 @@ HookManager::Hook32(
VirtualProtect(Src, X86_TRAMPOLINE_SIZE, dwOldProtection, &dwOldProtection);
return nullptr;
}

//
// Copy the old code before overwrite
//
Expand Down Expand Up @@ -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;
}
19 changes: 12 additions & 7 deletions Gancho/HookManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<LPVOID, Hook> hooks;
std::unordered_map<LPVOID, std::vector<Hook*>> HookChain;
};


0 comments on commit dc66554

Please sign in to comment.