Hot Patching

Hot Patching to mechanizm wprowadzony już nie pamiętam, chyba w Windows XP, skorygujcie mnie jeśli błędnie strzeliłem, w każdym razie powstał on to po, aby uprościć stawianie hooków w funkcjach bibliotek systemowych.

Normalnie hookowanie funkcji w bibliotekach DLL polega na tym, aby pobrać adres funkcji i w miejscu pierwszych instrukcji wstawić trampolinę do kodu hooka, wiąże się to z użyciem deasemblera, przepisywaniem instrukcji i jest mówiąc krótko problematyczne.

Microsoft wyszedł naprzeciw takiemu zapotrzebowaniu na hookowanie i stworzył mechanizm hotpatching, funkcje bibliotek systemowych posiadają specjalny prolog, który ułatwia szybkie ustawianie i usuwanie hooków bez potrzeby grzebania się w przepisywanie instrukcji.

Zauważcie, że pierwsze bajty funkcji stanowi instrukcja mov edi,edi (która sama w sobie nic nie robi), a przed nią znajduje się okno z 5 instrukcjami nop.

Wstawienia hooka do takiej funkcji polega na tym, aby w miejscu instrukcji mov edi,edi wstawić krótki skok jmp short (zakodowany jako EB xx) do tego okna nop-ów, a w miejscu nop-ów ustawić instrukcję call (E8 xx xx xx xx), która wywoła właściwy kod hooka.

Całość jest banalnie prosta i pozwala w szybkim tempie wstawiać hooki bez potrzeby korzystania z bibliotek typu Detours.

Poniżej prezentuję kod dla MASM-a, przedstawiający przykładowe ustawienie hooka na funkcję SetWindowTextA z wykorzystaniem mechanizmu hotpatching.

.data

; biblioteka, ktora hookujemy
szLibUser               db 'USER32.dll',0

; nazwa hookowanej funkcji
szSetWindowTextA        db 'SetWindowTextA',0

; adres oryginalnej funkcji (po prologu mov edi,edi)
lpOrgSetWindowTextA     dd 0

; domyslny skok do okna NOP-ow
cHotPatchJmps           db 0EBh,0F9h

; instrukcja call _hook (E9 xx xx xx xx)
cHotPatchCall           db 0E9h
dwHotPatchRel           dd 0

szHookTest              db 'secnews.pl',0

.code

align 4
_hook_SetWindowTextA proc uses esi edi ebx, hWnd:dword, lpString:dword

; podmien parametr lpString na szHookTest i wykonaj
; oryginalna funkcje

;       push    lpString
        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, lpNewProc:dword

; sprawdz czy podana biblioteka jest dostepna
        push    lpszLib
        call    GetModuleHandleA
        test    eax,eax
        je      _make_hook_exit

; pobierz adres procedury, na ktora chcemy zalozyc hooka
        push    lpszProc
        push    eax
        call    GetProcAddress
        test    eax,eax
        je      _make_hook_exit

; czy pierwsze 2 bajty odpowiadaja instrukcji mov edi,edi
        cmp     word ptr[eax],0FF8Bh
        jne     _make_hook_exit

; zapisz wskaznik do kodu procedury (po prologu hotpatcha)
        add     eax,2
        mov     edx,lpOrgPtr
        mov     dword ptr[edx],eax

; wstaw krotki skok do serii nop-ow
        push    offset dwWritten
        push    2
        push    offset cHotPatchJmps
        push    edi
        push    hProcess
        call    WriteProcessMemory

; procka docelowa
        mov     edx,lpNewProc

; budujemy instrukcje call _hook
; zrodlo, gdzie bedzie instrukcja call = okno nopow
        lea     eax,[edi-5]

; relatywny adres calla
; = cel - zrodlo - 5 (rozmiar instrukcji call)
        sub     edx,eax
        sub     edx,5
        mov     dwHotPatchRel,edx

; zapisz instrukcje call wskazujaca na naszego hooka
        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

; id naszego procesu
        call    GetCurrentProcessId

; otworz nasz wlasny proces
        push    eax
        push    1
        push    PROCESS_ALL_ACCESS
        call    OpenProcess
        test    eax,eax
        je      _exit

        mov     ebx,eax

; ustaw hooki
        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

Update
Raymond Chen rzucił nieco informacji na temat hot patchingu:

http://blogs.msdn.com/b/oldnewthing/archive/2013/01/02/10381672.aspx