Skip to content

Instantly share code, notes, and snippets.

@churchofthought
Created June 10, 2013 23:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save churchofthought/5753292 to your computer and use it in GitHub Desktop.
Save churchofthought/5753292 to your computer and use it in GitHub Desktop.
x86 hooking/detours macros and procedures written in MASM
comment *==========================================
jagHook
Note that:
macros are like win32 api; they may modify all registers but ebx, edi, esi
your .text section needs to be writable if using the non-procedural hooking
if using radasm, add /SECTION:.text|RWE the LINK box under Project -> Project Options]
otherwise, just add /SECTION:.text,RWE to linking arguments
Usage Below
BeginHook & EndHook
--------------------
This pair of macros creates a hook procedure.
HookName is a unique identifier you choose for your hook
PatchLength is the number of bytes (must be >= 5) that will be emulated
>= 5 because the hook jmp is 5 bytes long so need at least 5 bytes to fit it
if PatchLength is left out, it will default to 5
DoPushPop - if this optional argument is TRUE, push ebx,edi,esi and pop ebx,edi,esi are placed in the beginning
and end of your hook, respectively. Use it to make code cleaner or type less when needed.
Most of the time you will need to use push ebx,edi,esi and pop ebx,edi,esi since you shouldn't have any crucial registers
changed when handing control back to the hooked procedure.
BeginHook HookName[, PatchLength][, DoPushPop]
...code...
EndHook
-------------------------------------------
InstallHook
------------
This macro hooks a target function.
HookName is the unique identifier of the hook you previously created
TargetProcedure is the procedure to hook onto
InstallHook HookName, TargetProcedure
-------------------------------------------
ReinstallHook
--------------
This macro hooks the target function previously hooked by HookName
HookName is the unique identifier of the hook you previously created
ReinstallHook HookName
-------------------------------------------
UninstallHook
--------------
This macro clears the hook from the procedure it is attached to.
HookName is the unique identifier of the hook you previously created
UninstallHook HookName
-------------------------------------------
StubLen
------------
This macro returns the # of bytes needed to create a stub, given the patch length.
PatchLength is how many bytes will be emulated
StubLen PatchLength
-------------------------------------------
ProcInstallHook
-----------------------
This procedure hooks the target function and returns a pointer to an allocated stub
which can be used to call the original function.
HookProcedure is the procedure which the target will be redirected to
TargetProcedure is the target procedure to hook into
DetourStub is a pointer to a buffer of length StubLen(PatchLength)
PatchLength is how many bytes will be emulated
invoke ProcInstallHook, HookProcedure, TargetProcedure, DetourStub, PatchLength
-------------------------------------------
ProcReinstallHook
-------------------------
This procedure reinstalls a hook on a target function without allocating another stub
HookProcedure is the procedure which the target will be redirected to
DetourStub is a pointer to the stub previously used by a call to ProcInstallHook
PatchLength is the amount of bytes that were emulated
Note: HookProcedure does not need to be the same one that was used to create the stub
Note: TargetProc is not needed since the stub pointer will be used to calculate it
invoke ProcReinstallHook, HookProcedure, DetourStub, PatchLength
-------------------------------------------
ProcUninstallHook
-----------------------
This procedure uninstalls a hook that was previously installed.
DetourStub is a pointer to the stub previously used by a call to ProcInstallHook
PatchLength is the amount of bytes that were emulated
Note: TargetProc is not needed since the stub pointer will be used to calculate it.
invoke ProcUninstallHook, DetourStub, PatchLength
-------------------------------------------
Examples
Example 1
; This example hijacks the text of messageboxes using non-procedural hooking (faster performance-wise)
.data
module db "user32.dll", 0
procname db "MessageBoxA", 0
normaltext db "woooot my text!!!", 0
newtext db "Stole your messagebox!", 0
.code
; 5 bytes need to be replaced for MessageBoxA
; 77D804EA > 8BFF MOV EDI,EDI
; 77D804EC 55 PUSH EBP
; 77D804ED 8BEC MOV EBP,ESP
; we want to change the text (3nd parameter = 8 byte offset)
; return address is on stack (4 bytes)
; push ebp will be executed (ebp on stack <--- esp)
; so the text address is stored in esp + 12
BeginHook MyMsgBoxHook, 5
mov [esp + 12], OFFSET newtext
EndHook
start:
; get address of MessageBoxA
invoke GetModuleHandle, OFFSET module
invoke GetProcAddress, eax, OFFSET procname
; do some hook demonstrations
InstallHook MyMsgBoxHook, eax
invoke MessageBox, NULL, OFFSET normaltext, NULL, MB_OK ; we should see modified title
UninstallHook MyMsgBoxHook
invoke MessageBox, NULL, OFFSET normaltext, NULL, MB_OK ; we should see normal title
ReinstallHook MyMsgBoxHook
invoke MessageBox, NULL, OFFSET normaltext, NULL, MB_OK ; we should see modified title
ret
end start
Example 2
; This example hijacks the text of messageboxes using procedural hooking (easier - less headaches)
.data
module db "user32.dll", 0
procname db "MessageBoxA", 0
normaltext db "woooot my text!!!", 0
newtext db "Stole your messagebox!", 0
.data?
pMBoxDetour db StubLen(5) dup (?)
.code
; 5 bytes need to be replaced for MessageBoxA
; 77D804EA > 8BFF MOV EDI,EDI
; 77D804EC 55 PUSH EBP
; 77D804ED 8BEC MOV EBP,ESP
MyMsgBoxHook proc hWnd:HWND, lpText:LPCTSTR, lpCaption:LPCTSTR, uType:UINT
invoke pr4 PTR pMBoxDetour, hWnd, OFFSET newtext, lpCaption, uType
ret
MyMsgBoxHook endp
start:
; get address of MessageBoxA
invoke GetModuleHandle, OFFSET module
invoke GetProcAddress, eax, OFFSET procname
; do some hook demonstrations
invoke ProcInstallHook, MyMsgBoxHook, eax, OFFSET pMBoxDetour, 5
invoke MessageBox, NULL, OFFSET normaltext, NULL, MB_OK ; we should see modified title
invoke ProcUninstallHook, OFFSET pMBoxDetour, 5
invoke MessageBox, NULL, OFFSET normaltext, NULL, MB_OK ; we should see normal title
invoke ProcReinstallHook, MyMsgBoxHook, OFFSET pMBoxDetour, 5
invoke MessageBox, NULL, OFFSET normaltext, NULL, MB_OK ; we should see modified title
ret
end start
*========================================================
InstallHook macro hookName:REQ, targetProc:REQ
invoke pInstallHook, OFFSET jagHookBegin_&hookName, jagHookEnd_&hookName, targetProc, SIZEOF jagHookBegin_&hookName
endm
ReinstallHook macro hookName:REQ
invoke pReinstallHook, OFFSET jagHookBegin_&hookName, jagHookEnd_&hookName, SIZEOF jagHookBegin_&hookName
endm
UninstallHook macro hookName:REQ
invoke pUninstallHook, OFFSET jagHookBegin_&hookName, jagHookEnd_&hookName, SIZEOF jagHookBegin_&hookName
endm
BeginHook macro hookName:REQ, patchLen:=<5>, doPushPop
jagHookName TEXTEQU <hookName>
jagHookDoPushPop TEXTEQU <doPushPop>
jagHookBegin_&hookName db patchLen dup (?)
if doPushPop
push ebx
push edi
push esi
push ebp
endif
endm
EndHook macro
if jagHookDoPushPop
pop ebp
pop esi
pop edi
pop ebx
endif
db 0E9h
dd ?
% jagHookEnd_&jagHookName:
endm
StubLen macro patchLen:REQ
exitm <patchLen + 5>
endm
.code
pInstallHook proc uses ebx edi esi hookBegin:DWORD, hookEnd:DWORD, targetProc:DWORD, patchLen:DWORD
mov edi, targetProc
mov esi, patchLen
mov ebx, hookBegin
; make the target writable
invoke VirtualProtect, edi, 5, PAGE_EXECUTE_READWRITE, ADDR hookBegin
; copy the to-be-emulated bytes from targetProc to hook's beginning
invoke RtlMoveMemory, ebx, edi, esi
; replace the bytes with a jmp to the hook
sub ebx, 5
sub ebx, edi
mov BYTE PTR [edi], 0E9h
mov [edi + 1], ebx
; put a jmp to the targetProc at the end of hook
mov ebx, hookEnd
; set protections back to old ones to avoid complications
invoke VirtualProtect, edi, 5, hookBegin, ADDR hookBegin
sub edi, ebx
add edi, esi
mov [ebx - 4], edi
ret
pInstallHook endp
pReinstallHook proc uses ebx hookBegin:DWORD, hookEnd:DWORD, patchLen:DWORD
; get address of targetProc
mov eax, hookEnd
mov ebx, [eax - 4]
add ebx, eax
sub ebx, patchLen
; make the target writable
invoke VirtualProtect, ebx, 5, PAGE_EXECUTE_READWRITE, ADDR hookEnd
; replace the starting bytes with a jmp to the hook
mov eax, hookBegin
sub eax, 5
sub eax, ebx
mov BYTE PTR [ebx], 0E9h
mov [ebx + 1], eax
; set protections back to old ones to avoid complications
invoke VirtualProtect, ebx, 5, hookEnd, ADDR hookEnd
ret
pReinstallHook endp
pUninstallHook proc uses ebx hookBegin:DWORD, hookEnd:DWORD, patchLen:DWORD
; get address of targetProc
mov eax, hookEnd
mov ebx, [eax - 4]
add ebx, eax
sub ebx, patchLen
; make the target writable
invoke VirtualProtect, ebx, 5, PAGE_EXECUTE_READWRITE, ADDR hookEnd
; copy the emulated bytes from hook back to targetProc, replacing the jmp
mov eax, hookBegin
mov ecx, [eax]
mov dl, BYTE PTR [eax + 4]
mov [ebx], ecx
mov BYTE PTR [ebx + 4], dl
; set protections back to old ones to avoid complications
invoke VirtualProtect, ebx, 5, hookEnd, ADDR hookEnd
ret
pUninstallHook endp
ProcInstallHook proc uses ebx edi esi hookProc:DWORD, targetProc:DWORD, pDetour:DWORD, patchLen:DWORD
mov edi, targetProc
mov esi, patchLen
mov ebx, pDetour
; make the target writable
invoke VirtualProtect, edi, 5, PAGE_EXECUTE_READWRITE, ADDR targetProc
; copy the to-be-emulated bytes from targetProc to detour's beginning
invoke RtlMoveMemory, ebx, edi, esi
; replace the bytes with a jmp to the hook
mov eax, hookProc
sub eax, edi
sub eax, 5
mov BYTE PTR [edi], 0E9h
mov [edi + 1], eax
; put a jmp to the targetProc at the end of detour
add esi, ebx
; set protections back to old ones to avoid complications
invoke VirtualProtect, edi, 5, targetProc, ADDR targetProc
sub edi, ebx
sub edi, 5
mov BYTE PTR [esi], 0E9h
mov [esi + 1], edi
ret
ProcInstallHook endp
ProcReinstallHook proc uses ebx hookProc:DWORD, pDetour:DWORD, patchLen:DWORD
; get address of targetProc
mov eax, pDetour
mov ecx, patchLen
mov ebx, [eax + ecx + 1]
add ebx, eax
add ebx, 5
; make the target writable
invoke VirtualProtect, ebx, 5, PAGE_EXECUTE_READWRITE, ADDR pDetour
; replace the starting bytes with a jmp to the hook
mov eax, hookProc
sub eax, 5
sub eax, ebx
mov BYTE PTR [ebx], 0E9h
mov [ebx + 1], eax
; set protections back to old ones to avoid complications
invoke VirtualProtect, ebx, 5, pDetour, ADDR pDetour
ret
ProcReinstallHook endp
ProcUninstallHook proc uses ebx edi pDetour:DWORD, patchLen:DWORD
; get address of targetProc
mov ebx, pDetour
mov eax, patchLen
mov edi, [ebx + eax + 1]
add edi, ebx
add edi, 5
; make the target writable
invoke VirtualProtect, edi, 5, PAGE_EXECUTE_READWRITE, ADDR pDetour
; copy the emulated bytes from hook back to targetProc, replacing the jmp
mov eax, [ebx]
mov cl, BYTE PTR [ebx + 4]
mov [edi], eax
mov BYTE PTR [edi + 4], cl
; set protections back to old ones to avoid complications
invoke VirtualProtect, edi, 5, pDetour, ADDR pDetour
ret
ProcUninstallHook endp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment