C++ 20, x86/x64 Hooking Libary v2.0
Article 1: https://www.codeproject.com/articles/1100579/polyhook-the-cplusplus-x-x-hooking-library
Article 2: https://www.codeproject.com/Articles/1252212/PolyHook-2-Cplusplus17-x86-x64-Hooking-Library
Dynamic Re-Writing: https://twitter.com/stevemk14ebr/status/1518621861692817409
Ask for help, chat with others, talk to me here
PolyHook2 is available on vcpkg. Consider trying that installation method if you prefer. Just install vcpkg from microsofts directions:
Commands:
λ git clone https://github.com/Microsoft/vcpkg.git
λ cd vcpkg
λ .\bootstrap-vcpkg.bat -disableMetrics
λ (as admin) .\vcpkg integrate install
For x86:
λ vcpkg.exe install polyhook2:x86-windows-static polyhook2:x86-windows
For x64:
λ vcpkg.exe install polyhook2:x64-windows-static polyhook2:x64-windows
You then simply include the polyhook headers, be sure to link the generated .lib.
See: #59 (comment)
λ git clone --recursive https://github.com/stevemk14ebr/PolyHook_2_0.git
λ cd PolyHook_2_0
λ git submodule update --init --recursive
λ (dynamic build) cmake -B"./_build" -DCMAKE_INSTALL_PREFIX="./_install/" -DPOLYHOOK_BUILD_SHARED_LIB=ON
λ (static build) cmake -B"./_build" -DCMAKE_INSTALL_PREFIX="./_install/" -DPOLYHOOK_BUILD_SHARED_LIB=OFF
λ cmake --build "./_build" --config Release --target install
I provide directions below for how to setup the visual studio cmake environment only. If you don't want to use visual studio that's fine, this is a standard cmake project and will build from command line just fine.
An up to date visual studio is required. First clone the project and perform submodule init as above. Do not run the cmake commands, instead:
Open VS 2022, go to file->open->cmake.. this will load the project and start cmake generation. Next goto cmake->build all or cmake->build, you can also set a startup item and release mode to use the play button (do not use the install target). Capstone, Zydis, and asmjit are set to automatically build and link, you DO NOT need to build them seperately.
https://stevemk14ebr.github.io/PolyHook_2_0/ & Read the Tests!
I've setup an example project to show how to use this as a static library. You should clear your cmake cache between changing these options. The dll is built with the cmake option to export all symbols. This is different from the typical windows DLL where things are manually exported via declspec(dllexport), instead it behaves how linux dlls do with all symbols exported by default. This style should make it easier to maintain the code, the downside is there are many exports but i don't care.
-
Both capstone and zydis are supported as disassembly backends and are fully abstracted.
-
Inline hook (x86/x64 Detour)
- Places a jmp to a callback at the prologue, and then allocates a trampoline to continue execution of the original function
- Operates entirely on an intermediate instruction object, disassembler engine is swappable, capstone included by default
- Can JIT callback for when calling conv is unknown at compile time (see ILCallback.cpp)
- Follows already hooked functions
- Resolves indirect calls such as through the iat and hooks underlying function
- Relocates prologue and resolves all position dependent code
- Branches into overwritten section are resolved to the new moved location
- Jmps from moved prologue back to original section are resolved through a jmp table
- Relocations inside the moved section are resolved (not using relocation table, disassembles using engine)
- Non relocatable instructions are re-written by dynamic binary re-writing and replaced with semantically equivalent instructions
- x64 trampoline is not restricted to +- 2GB, can be anywhere, avoids shadow space + no registers spoiled (depending on detour scheme).
- Overwriting code caves and padding bytes may be set as a primary strategy instead, or as a fallback scheme
- If inline hook fails at an intermediate step the original function will not be malformed. All writes are batched until after we know later steps succeed.
- Cross-Architecture hooking is fully supported. Including the overriding of memory acccess routines to allow read/write of 64bit memory from 32bit process. You can hook 64bit from 32bit process if you're clever enough to write the shellcode required for the callbacks.
- Effecient reHook-ing logic is implemented. This can be used to combat third parties overwriting prologues back to original bytes. This is optimized into a few simple memcpy's rather than re-executing the entire logic in hook().
-
Runtime Inline Hook
- All the goodness of normal inline hooks, but JIT's a translation stub compatible with the given typedef and ABI. The translation stub will move arguments into a small struct, which is passed as pointer to a callback and allow the spoofing of return value. This allows tools to generate hook translation stubs at runtime, allowing for the full inline hooking of functions where the typedef is not known until runtime.
-
Virtual Function Swap (VFuncSwap)
- Swaps the pointers at given indexs in a C++ VTable to point to a callbacks
-
Virtual Table Swap (VTableSwap)
- Performs a deep copy on a c++ VTable and replaces the pointer to the table with the newly allocated copy. Then swaps the pointer entries in the copy to point to callbacks
-
Software Breakpoint Hook (BreakpointHook)
- Overwrites the first byte of a function with 0xCC and calls the callback in the exception handler. Provides the user with an automatic method to restore the original overwritten byte
-
Hardware Breakpoint Hook (HWBreakpointHook)
- Sets the debug registers of the CPU to add a HW execution BP for the calling thread. The callback is called in the exception handler. Remember HW BP's are per thread, the thread calling hook() must be the same as the one that is being hooked. You may find a quick detour, then setting up the HWBP in the detour callback, then unhooking to be a useful construct.
-
Import Address Table Hook (IatHook)
- Resolves loaded modules through PEB, finds IAT, then swaps the thunk pointer to the callback.
-
Export Address Table Hook (EatHook)
- Resolves loaded modules through PEB, finds EAT, then swaps pointer to export to the callback. Since this is a 32bit offset we optionally allocate a trampoline stub to do the full transfer to callback if it's beyond 32bits.
- THOROUGHLY unit tested, hundreds of tests, using the fantastic library Catch
- Unix compatible
- Breakpoint tests must not be run under a debugger. They are commented out by default now.
Linux support. There is a partial unix implementation, but it is not well tested. Please contribute or report bugs.
MIT - Please consider donating
evolution536, DarthTon, IChooseYou on Unknowncheats.me
@Ochii & https://www.unknowncheats.me/forum/c-and-c/50426-eat-hooking-dlls.html for EAT implementation
https://github.com/DarthTon/Blackbone
https://www.codeproject.com/Articles/44326/MinHook-The-Minimalistic-x-x-API-Hooking-Libra
https://wiki.osdev.org/CPU_Registers_x86#Debug_Registers
https://reverseengineering.stackexchange.com/questions/14992/what-are-the-vectored-continue-handlers
https://github.com/odzhan/shellcode/blob/master/os/win/getapi/dynamic/getapi.c