Jump to content
Tuts 4 You

API Hooks Detours in MASM32


clip

Recommended Posts

Hi, I'm working on a socket debugger, I know there are plenty of this around, but I want to learn how to make my own in MASM32.

Initially I'm trying to hook the "send" function from wsock32.dll then open firefox. I would like to replace the information being sent by firefox with "Gotcha". I used jaghook for this. So far it's not working. Does anyone have a clue why?

replace.asm


.486
.model flat, stdcall
option casemap: noneinclude \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\wsock32.incincludelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\wsock32.libinclude jagHook.inc .data
module db "wsock32.dll", 0
procname db "send", 0 newtext db "Gotcha", 0
CMD db "c:\program files\mozilla firefox\firefox.exe",0
sinfo STARTUPINFO <>
pinfo PROCESS_INFORMATION <> .data?
pmsenddetour 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 MySendHook proc sock:SOCKET, Body:LPCTSTR, uType1:UINT, uType2:UINT
invoke pr4 PTR pmsenddetour, sock, OFFSET newtext, 6, uType2
ret
MySendHook endp start:
invoke GetModuleHandle, OFFSET module
invoke GetProcAddress, eax, OFFSET procname
; do some hook demonstrations
invoke ProcInstallHook, MySendHook, eax, OFFSET pmsenddetour, 5
invoke send, 0,0,0,0
invoke CreateProcess, ADDR CMD, NULL, NULL, NULL, NULL, 0, 0,0,addr sinfo,addr pinfo
invoke Sleep, 600000
invoke ProcUninstallHook, OFFSET pmsenddetour, 5
ret
end start

jaghook.inc:


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
endmReinstallHook macro hookName:REQ
invoke pReinstallHook, OFFSET jagHookBegin_&hookName, jagHookEnd_&hookName, SIZEOF jagHookBegin_&hookName
endmUninstallHook macro hookName:REQ
invoke pUninstallHook, OFFSET jagHookBegin_&hookName, jagHookEnd_&hookName, SIZEOF jagHookBegin_&hookName
endmBeginHook 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
endmEndHook macro
if jagHookDoPushPop
pop ebp
pop esi
pop edi
pop ebx
endif
db 0E9h
dd ?
% jagHookEnd_&jagHookName:
endmStubLen macro patchLen:REQ
exitm <patchLen + 5>
endm.codepInstallHook 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 retpInstallHook endppReinstallHook 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 retpReinstallHook 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 retpUninstallHook endpProcInstallHook 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 retProcInstallHook 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 retProcReinstallHook endpProcUninstallHook 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 retProcUninstallHook endp

Sample codes for MS' detour, IAT manipulation and API Hooking in MASM would be greately appreciated. (Does anyone have an asm example using ELiCZ's lib?)

Thank you.

Link to comment

if i remember correctly, once i did a hooker to log all api and wsock didnt work due it checks if its not hooked.

so you need to get around it.

and btw i see you hook send,use send and you said you want to hook send inside firefox, well hook is only local. will not work in another process when you start firefox with createprocess. you need to hook it inside firefox. well you dont if you use crap win9x that shares dll's:P

to create better hook, use dll injection. a lot easier to code,no need to take care of replacing code,adresses,load proper dll's for hook.

and another thing this hook engine is ****, code your own hooker,for this case you want gotcha to replace send api. so you dont need original api code.

but in other cases you need bytes that you replace to run after hook. so you need run lenght disasm to tell you how many bytes copy and where set return from hook to code due instructions that E9 jump will replace will not always be 5 bytes long.

Edited by human
Link to comment

if i remember correctly, once i did a hooker to log all api and wsock didnt work due it checks if its not hooked.

so you need to get around it.

and btw i see you hook send,use send and you said you want to hook send inside firefox, well hook is only local. will not work in another process when you start firefox with createprocess. you need to hook it inside firefox. well you dont if you use crap win9x that shares dll's:P

I am not much of a coder, but I'm working on it. Thanks for the reply.

there's not much resource i could find about this that is masm-specific. they red-flag and shoot this type of topic over at masm32.com. I hooked send then used send (invoke send, 0,0,0,0) because for some reason the program crashes if you don't use the function being hooked. How do I hook this inside firefox? Can you please point me to a masm-specific resource if you have any? I'm running this on NT-based OS (XP-VISTA).

to create better hook, use dll injection. a lot easier to code,no need to take care of replacing code,adresses,load proper dll's for hook.

and another thing this hook engine is ****, code your own hooker,for this case you want gotcha to replace send api. so you dont need original api code.

but in other cases you need bytes that you replace to run after hook. so you need run lenght disasm to tell you how many bytes copy and where set return from hook to code due instructions that E9 jump will replace will not always be 5 bytes long.

just to clear things up I do not intend to use this for malware, I just wanted to code my own "socket debugger" type of program. There are plenty of this type of program available online and I wanted to "reinvent the wheel" to see how it works and learn. I was thinking the "legal" way of doing this, like most debuggers do, is to launch the program to be debugged with it, or as you said, hook it inside the app. I just don't know how to do this. If DLL injection is the better way then I'll take it. I've read about injecting jumps (E9xxxx), IAT manipulation, but they are all theories, I don't know how to put it in code.

Thanks again.

Link to comment

there was app long time ago called sockscap,that was in delphi and asm,used dll injection. so you can use socks proxy tunnel in any app. it came with sourcecode. you can try to find it or other stuff on google.

Link to comment
  • 1 year later...

I'm sorry, but when i first read your post my immediate thought was: "Hmmm, why resurrect a dead thread? (Posted 26 November 2009)", but this was quickly followed by "Okay, the poster has included some sources that others can use when faced with this problem themselves.".

Now i've taken the time to download both sources and examine them, i have revised again my thoughts. Both sources have absolutely nothing to do with the original posters problem or with the solution, instead they are an open source r.a.t and an example http downloader from Iczelion's MASM Win32 tutorials.

Can i ask then, why on earth would these sources be relevant to API hooking using MASM code, aside from the obvious fact they share API names and one could get argument lists from the use of such API? The latter is something which MSDN could provide and the former is meaningless, maybe to share such code simply a fresh thread in the coding section would have sufficed?

HR,

Ghandi

Link to comment
<br />I'm sorry, but when i first read your post my immediate thought was: "Hmmm, why resurrect a dead thread? (Posted 26 November 2009)", but this was quickly followed by "Okay, the poster has included some sources that others can use when faced with this problem themselves.".<br /><br />Now i've taken the time to download both sources and examine them, i have revised again my thoughts. Both sources have absolutely nothing to do with the original posters problem or with the solution, instead they are an open source r.a.t and an example http downloader from Iczelion's MASM Win32 tutorials.<br /><br />Can i ask then, why on earth would these sources be relevant to API hooking using MASM code, aside from the obvious fact they share API names and one could get argument lists from the use of such API? The latter is something which MSDN could provide and the former is meaningless, maybe to share such code simply a fresh thread in the coding section would have sufficed?<br /><br />HR,<br />Ghandi<br />
<br /><br /><br />

My sincere apologies, from reading the posters .asm it seemed like what I posted could be another way of what he was trying to accomplish

very sorry about that...

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...