Hot Patching is a mechanism introduced in Windows XP if I remember correctly. It was created to solve the problems with hooking system library functions. For example to bugfix compatibility issues with older software running on a newer Windows version or applying security patches on the running machines.
Normally hooking a function in DLL libraries or EXE files is about getting the memory address of the function and putting a so-called trampoline (a jump) to the hook handling routine in place of its first instructions. Sounds simple, right?
Let's take a look.
Sample function prologue (beginning) before setting the hook:
_function_x: push ebp mov ebp,esp mov eax,ecx mov edx,0400h ...
Function after the hook is set:
_function_x: ; transfer execution to the hooking handler ; the original instructions were removed from ; the function prolog to put the JMP instruction ; that needs 5 bytes for encoding E9 xx xx xx xx jmp _hook_handler _after_the_trampoline: mov edx,0400h ... _hook_handler: ; save original registers & CPU flags states pushad pushfd ... ; execute hooking code, manipulate original parameters etc. ... popfd popad ; execute the code that's been cut off ; from the original function prologue ... push ebp mov ebp,esp mov eax,ecx ; return to the code after the trampoline jump jmp _after_the_trampoline
This involves using a disassembler to get the correct size of the first instructions (different x86/x64 instructions have different sizes) and make sure to replace enough bytes (five to be exact) to fit the assembly
jmp rel32 instruction (encoded as
E9 xx xx xx xx bytes).
But what if the first instructions are something else, like a
call instruction? That would require rewriting the original
call instruction or emulating it in the hooking handler code (we need to execute it after all!). But it's just troublesome to rewrite or emulate all the possible x86 instructions.
Microsoft has met such a demand for hooking and created a hot patching mechanism. The system library functions have a special prologue that makes it easy to quickly set up and remove hooks without having to bother to rewrite random instructions.
System library USER32.dll in HIEW hex editor and a sample function with hot patching code structure:
Notice the difference. It looks like this:
; 5 nop instructions db 90h, 90h, 90h, 90h, 90h _function_x: ; mov edi,edi takes 2 bytes mov edi,edi push ebp mov ebp,esp mov eax,ecx mov edx,0400h ...
In hot patching enabled binaries (you need to build it with appropriate compiler flags!) the first bytes of the functions are always the
mov edi,edi instruction (which does nothing by itself, it's like C++ version of
Before it, there is also a window (byte array) with five
nop instructions encoded as
0x90, 0x90, 0x90, 0x90 bytes.
First step. Putting a hook trampoline into such a constructed function consists of inserting the
jmp short (encoded as two bytes
EB xx opcode) instruction into this
mov edi,edi instruction place.
Second step. It jumps to the above 5x
nop window, where the
call rel32 or
jmp rel32 instructions are placed that jumps or calls the hook handler code.
So this time you don't have to worry about overwriting random function prologue instructions, because there is a standard construct that can be easily restored to the default value (unhooked).
The whole thing is trivially simple and allows you to quickly insert hooks without the need to use a library like Microsoft Detours.
Below I present the code for MASM compiler, showing an example of setting a hook on
SetWindowTextA function within our own process using hot patching code characteristics.
.data ; library to set a hook szLibUser db 'USER32.dll',0 ; hooked function name szSetWindowTextA db 'SetWindowTextA',0 ; original function address (after mov edi,edi prologue) lpOrgSetWindowTextA dd 0 ; default short jump instruction into 5 bytes NOP window ; it's encoded as a relative short jump instruction cHotPatchJmps db 0EBh,0F9h ; call _hook (E9 xx xx xx xx) instruction encoding cHotPatchCall db 0E9h dwHotPatchRel dd 0 szHookTest db 'https://www.pelock.com',0 .code ; sample hook handler code ; it replaced every call to: ; SetWindowTextA(hWindow, lpString); ; with ; SetWindowsTextA(hWindow, "https://www.pelock.com"); align 4 _hook_SetWindowTextA proc uses esi edi ebx, hWnd:dword, lpString:dword ; ignore the original lpString parameter ; and call the function with our bogus parameter ; push lpString <-- original parameter push offset szHookTest push hWnd call lpOrgSetWindowTextA ret _hook_SetWindowTextA endp align 4 _make_hook proc uses esi edi ebx, hProcess:dword, lpszLib:dword, lpszProc:dword, lpOrgPtr:dword, lpHookHandlerProc:dword ; check if the DLL is already loaded push lpszLib call GetModuleHandleA test eax,eax je _make_hook_exit ; get the function pointer push lpszProc push eax call GetProcAddress test eax,eax je _make_hook_exit ; save the function pointer to the EDI register mov edi,eax ; check if the first bytes of the function ; matches the bytes of the mov edi,edi instruction cmp word ptr[eax],0FF8Bh jne _make_hook_exit ; store the pointer to the code after the mov edi,edi ; instruction (where the real function starts) add eax,2 mov edx,lpOrgPtr mov dword ptr[edx],eax ; overwrite mov edi,edi instruction ; with a jump to the 5x NOP window push offset dwWritten push 2 push offset cHotPatchJmps push edi push hProcess call WriteProcessMemory ; hook handler routine address mov edx,lpHookHandlerProc ; let's build a call _hook_handler_proc instruction ; 5x NOP window memory address lea eax,[edi-5] ; call instruction is built like this: ; ; E9 xx xx xx xx ; ; where xx xx xx xx is 4 bytes of the relative ; address of the destination call address, relative ; to the position of the call instruction itself ; ; if we were to call the instruction right after ; any call instruction, for example like this: ; ; call _next_instruction_label ; _next_instruction_label: ; nop ; ; it would have been encoded as: ; ; E9 00 00 00 00 ; 90 ; ; to calculate the relative destination address ; take the destination pointer, subtract the call ; instruction pointer and its size (5 bytes) ; ; rel32 = dst - src - 5 ; sub edx,eax sub edx,5 mov dwHotPatchRel,edx ; patch library function memory, by overwriting ; the 5x NOP window with a call to the hooking ; handler routine push offset dwWritten push 5 push offset cHotPatchCall push eax push hProcess call WriteProcessMemory _make_hook_exit: ret _make_hook endp align 4 _test_hooks proc uses esi edi ebx ; our process ID call GetCurrentProcessId ; open our own process push eax push 1 push PROCESS_ALL_ACCESS call OpenProcess test eax,eax je _exit mov ebx,eax ; setup a hook mov edi,offset _make_hook push offset _hook_SetWindowTextA ; hook proc push offset lpOrgSetWindowTextA ; &lpOrgProc push offset szSetWindowTextA ; szApiName push offset szLibUser ; szLibName push ebx ; hProcess call edi ;_make_hook _exit: ret _test_hooks endp
As you can see, hot patching can be used not only by Windows, but we can use it too to our advantage.
If you are interested in similar security and low-level topics, I invite you to read my articles about reverse engineering, malware analysis & assembler.