Created
June 10, 2013 23:01
-
-
Save churchofthought/5753207 to your computer and use it in GitHub Desktop.
x86 Hooking Library written in MASM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
comment *========================================== | |
jagHook by jAgx | |
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