
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.
How function hooking works at a low-level?
Normally hooking a function in DLL libraries or EXE files is about getting the memory address of the function and putting a so-calledtrampoline (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:pushebpmovebp,espmoveax,ecxmovedx,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 xxjmp_hook_handler_after_the_trampoline:movedx,0400h..._hook_handler:; save original registers & CPU flags statespushadpushfd...; execute hooking code, manipulate original parameters etc....popfdpopad; execute the code that's been cut off; from the original function prologue...pushebpmovebp,espmoveax,ecx; return to the code after the trampoline jumpjmp_after_the_trampoline
This involves using adisassembler 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 assemblyjmp rel32
instruction (encoded asE9 xx xx xx xx
bytes).
Problems with hooking prologue code with random instructions
But what if the first instructions are something else, like acall
instruction? That would require rewriting the originalcall
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 aspecial prologue that makes it easy to quickly set up and remove hooks without having to bother to rewrite random instructions.
Function prologue with hot patching design
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 instructionsdb90h,90h,90h,90h,90h_function_x:; mov edi,edi takes 2 bytesmovedi,edipushebpmovebp,espmoveax,ecxmovedx,0400h...
In hot patching enabled binaries (you need to build it with appropriate compiler flags!) the first bytes of the functions are always themov edi,edi
instruction (which does nothing by itself, it's like C++ version of0=0;
statement).
Before it, there is also a window (byte array) with fivenop
instructions encoded as0x90, 0x90, 0x90, 0x90
bytes.
What's the deal here, huh?
First step. Putting a hook trampoline into such a constructed function consists of inserting thejmp short
(encoded as two bytesEB xx
opcode) instruction into thismov edi,edi
instruction place.
Second step. It jumps to the above 5xnop
window, where thecall rel32
orjmp 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 likeMicrosoft Detours.
Patching libraries using hot patching features
Below I present the code forMASM compiler, showing an example of setting a hook onSetWindowTextA
function within our own process using hot patching code characteristics.
.data; library to set a hookszLibUserdb'USER32.dll',0; hooked function nameszSetWindowTextAdb'SetWindowTextA',0; original function address (after mov edi,edi prologue)lpOrgSetWindowTextAdd0; default short jump instruction into 5 bytes NOP window; it's encoded as a relative short jump instructioncHotPatchJmpsdb0EBh,0F9h; call _hook (E9 xx xx xx xx) instruction encodingcHotPatchCalldb0E9hdwHotPatchReldd0szHookTestdb'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");align4_hook_SetWindowTextAprocusesesiediebx,hWnd:dword,lpString:dword; ignore the original lpString parameter; and call the function with our bogus parameter; push lpString <-- original parameterpushoffsetszHookTestpushhWndcalllpOrgSetWindowTextAret_hook_SetWindowTextAendpalign4_make_hookprocusesesiediebx,hProcess:dword,lpszLib:dword,lpszProc:dword,lpOrgPtr:dword,lpHookHandlerProc:dword; check if the DLL is already loadedpushlpszLibcallGetModuleHandleAtesteax,eaxje_make_hook_exit; get the function pointerpushlpszProcpusheaxcallGetProcAddresstesteax,eaxje_make_hook_exit; save the function pointer to the EDI registermovedi,eax; check if the first bytes of the function; matches the bytes of the mov edi,edi instructioncmpwordptr[eax],0FF8Bhjne_make_hook_exit; store the pointer to the code after the mov edi,edi; instruction (where the real function starts)addeax,2movedx,lpOrgPtrmovdwordptr[edx],eax; overwrite mov edi,edi instruction; with a jump to the 5x NOP windowpushoffsetdwWrittenpush2pushoffsetcHotPatchJmpspushedipushhProcesscallWriteProcessMemory; hook handler routine addressmovedx,lpHookHandlerProc; let's build a call _hook_handler_proc instruction; 5x NOP window memory addressleaeax,[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;subedx,eaxsubedx,5movdwHotPatchRel,edx; patch library function memory, by overwriting; the 5x NOP window with a call to the hooking; handler routinepushoffsetdwWrittenpush5pushoffsetcHotPatchCallpusheaxpushhProcesscallWriteProcessMemory_make_hook_exit:ret_make_hookendpalign4_test_hooksprocusesesiediebx; our process IDcallGetCurrentProcessId; open our own processpusheaxpush1pushPROCESS_ALL_ACCESScallOpenProcesstesteax,eaxje_exitmovebx,eax; setup a hookmovedi,offset_make_hookpushoffset_hook_SetWindowTextA; hook procpushoffsetlpOrgSetWindowTextA; &lpOrgProcpushoffsetszSetWindowTextA; szApiNamepushoffsetszLibUser; szLibNamepushebx; hProcesscalledi;_make_hook_exit:ret_test_hooksendp
As you can see, hot patching can be used not only by Windows, but we can use it too to our advantage.
More low-level and reverse engineering resources
If you are interested in similar security and low-level topics, I invite you to read my articles aboutreverse engineering, malware analysis & assembler.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse