Hotpatching enabled executable images are prepared by the compiler and linker to allow replacing the image while in use. The following two changes are applied (x86):
- The function entry point is set to a 2-byte no-op
mov edi, edi
(/hotpatch). - Five consecutive nop's are prepended to each function entry point (/FUNCTIONPADMIN).
To illustrate this, here is a typical disassembly listing of a hotpaching enabled function:
(2) 768C8D66 90 nop
768C8D67 90 nop
768C8D68 90 nop
768C8D69 90 nop
768C8D6A 90 nop
(1) 768C8D6B 8B FF mov edi,edi
(3) 768C8D6D 55 push ebp
768C8D6E 8B EC mov ebp,esp
(1)
designates the function entry point with the 2-byte no-op. (2)
is the padding provided by the linker, and (3)
is where the non-trivial function implementation starts.
To hook into a function you have to overwrite (2)
with a jump to your hook function jmp myHook
, and make this code reachable by replacing (1)
with a relative jump jmp $-5
.
The hook function must leave the stack in a consistent state. It should be declared as __declspec(naked)
to prevent the compiler from generating function prolog and epilog code. The final instruction must either perform stack cleanup in line with the calling convention of the hooked function, or jump back to the hooked function at the address designated by (3)
.