Log in

View Full Version : API Hooking


bedrock
March 4th, 2008, 13:48
I've done quite a bit of reading about API hooks, I've taken a look at Detours and a couple of other hooking API's. And the basic procedure i see is:

Inject hooking dll into process (using CreateRemoteThread ?)
Get address of API to hook, store original bytes (5)
Overwrite with jump to hooked function
etc...

However, i basically want to hook all exported functions from a particular dll, also i want to do this in a thread safe way and on a per process basis (not system wide) i have also read about trampolining and suspending all threads whilst the hook is written, and i guess I'm going to have to do something along these lines

Can any of the experts here offer any advice and the best/most practical way to achieve this?

--
bedrock

Admiral
March 5th, 2008, 05:10
IAT hooking is a good option if you only need to target calls from a single module, especially if you aim to target an existing project. The other reasonable choice is to write a proxy DLL (which forwards each exported call to the real DLL) and put it in the application's directory - provided this suits your needs, it's clean easy and reliable.

bedrock
March 5th, 2008, 07:54
I may have got confused, but will IAT hooking allow me to hook calls in the whole process (or just a single module?)

A proxy dll sounds great, but i want to be able to hook 1 process while allowing another process which uses the same dll exports to run as normal. From what i know about proxy dlls, i would have to rename the real.dll to something like real_.dll and then insert my proxy dll as real.dll, so i'm not sure this is going to work.

--
bedrock

naides
March 5th, 2008, 08:23
Bedrock:
You need to put the proxy (lets call it) my.dll, with the same name as the "general" my.dll but in the process' working folder.

By default, the loader searches for my.dll first into the current working folder, loading your modified version. If not found, which would happen if any other process (starting from a different folder, of course) tries to load my.dll, the loader will look for modules called my.dll in the usual places, \windows\system32 etc.

dELTA
March 5th, 2008, 10:30
Quote:
[Originally Posted by naides;73111]Bedrock:
You need to put the proxy (lets call it) my.dll, with the same name as the "general" my.dll but in the process' working folder.

By default, the loader searches for my.dll first into the current working folder first, loading your modified version. If not found, which would happen if any other process (starting from a different folder, of course) tries to load my.dll, the loader will look for modules called my.dll in the usual places, \windows\system32 etc.
Actually, this is not true by default in later Windows versions (XP SP2 and upwards). Windows can be tweaked to work this way on your own machine though, see the following for more info:

http://msdn2.microsoft.com/en-us/library/ms682586.aspx

Admiral
March 5th, 2008, 14:33
Quote:
[Originally Posted by bedrock;73110]I may have got confused, but will IAT hooking allow me to hook calls in the whole process (or just a single module?)

Both, kind of. Each module has its own IAT, which it uses to resolve its own outgoing inter-modular calls. By patching an IAT entry you can redirect all calls from the owning module to wherever you choose, on a per-function basis. Calls from any other module to the same compile-time target will remain unaffected. Of course, there's nothing stopping you patching the IAT for each module in the process, which would then have the effect of re-routing all static calls, but this is usually unnecessary.

dELTA
March 5th, 2008, 17:37
The next level would be to hook the APIs by patching a single hook into the first code bytes of each DLL export, which would be guaranteed to be global for all modules in the entire process (still only for that single process though, due to the copy-on-write semantics of DLLs in NT based Windows versions).

Admiral
March 6th, 2008, 03:40
Quote:
[Originally Posted by dELTA;73126]The next level would be to hook the APIs by patching a single hook into the first code bytes of each DLL export, which would be guaranteed to be global for all modules in the entire process (still only for that single process though, due to the copy-on-write semantics of DLLs in NT based Windows versions).

We should probably mention Microsoft's Detours (http://research.microsoft.com/sn/detours/), which provides a slightly different but very powerful and reliable way of achieving the same thing.

dELTA
March 6th, 2008, 03:52
We should probably mention the entire following CRCETL category, while we're at it.

http://www.woodmann.com/collaborative/tools/Category:Code_Injection_Tools

bedrock
March 6th, 2008, 07:12
Guy's thanks for all the info.

I have read about Detours (and other hooking API's) I understand how to do the hooking, it was simply that i wanted to hook every export of a specific dll and i was just interested in the best way to achieve this.

@Delta, i know how much you love the CRCETL, so here's a few more hooking engines i came across

Code:

http://www.madshi.net/madCodeHookDescription.htm
http://codefromthe70s.org/mhook2.asp
http://www.x86coders.com/public/DetourXS.rar


--
bedrock

dELTA
March 7th, 2008, 05:35
Thanks for the tips.

I added all but the madCodeHook, since it was purely commercial, and in the cases/categories where there are enough equivalent free tools available, I usually don't add commercial-only ones at all.

disavowed
March 14th, 2008, 15:21
i wouldn't recommend doing hooking via iat patching, since as admiral said above, this will only allow you to hook static imports. i've had good luck with detours (which doesn't use CreateRemoteThread for dll injection, btw).

aionescu
March 16th, 2008, 17:05
Careful though, detours has a couple of bugs

disavowed
March 17th, 2008, 19:28
yes, it also has a bunch of unnecessary checks that can be removed. for example, it fails if it can't get a good crc, though you can change the code to tell it to ignore that. it also fails if the target doesn't have an import table, but you can modify detours to fix that as well so that it doesn't give up.

bedrock
April 1st, 2008, 09:15
I am progressing with this project a little and rather than writing lots of hook functions, it occurred to me that it would be nice to write a generic hook, that I could use to hook multiple functions inside the target.

I don't know if this is possible?

I am mostly a C/C++ coder, but i have dabbled with a little assembly and am comfortable inside olly for debugging purposes.

I'd like to create the following (I think):
Code:
__declspec(naked) HRESULT WINAPI hook_Generic()
{
__asm pushad;

// do some stuff

__asm popad;

// call original func
}


My problem is this, assuming this is a generic hook, when it executes, how can I figure out which original function I should call?

Thanks in advance

--
bedrock

dELTA
April 3rd, 2008, 07:24
Read the return address that was pushed by the original call on the stack. Disassemble/decode the call instruction preceding it, and resolve the function address from that one. Done.

bedrock
April 3rd, 2008, 10:48
Thanks delta,

Well I have now done the first two parts of this (I have the return address and have disassembled the call instruction proceeding it)

It seems this call has different levels of indirection depending upon whether the target is built in debug/release.

I am at a point where I have the function address, but I would really like to get it's name, and pointers on the best way to go about this?

Should I process the export table of the dll?
Should i call GetProcessAddress for all exports on the dll and compare the returned address with the one i have calculated?

Is there a better solution?

I feel at the moment my code is somewhat sledge hammer to a nut

I spent some time yesterday afternoon playing around with the dbghelp API and StackWalk64, before realising I could get the return address off the stack with a couple of lines of asm...

Thanks all

dELTA
April 4th, 2008, 02:48
If you are hooking only imports (contrary to arbitrary internal functions), I'd create a hash-table of all import addresses (or a plain sorted vector in which you can binary search) once at the start, and then resolve the function names from this one. Just remember to add all new addresses as soon as LoadLibrary() / GetProcAddress() is called (from your generic hook code, of course).

And yes, the different levels of indirection should be auto-detected and handled first of all.

Jakor
April 7th, 2008, 15:57
I would personally suggest Hooking both the Import table on the application you want to 'spy on' as well as the Export table for the dll which you want to 'spy on' as well. Someone got kinda close but mixed it up. I havn't ever needed to hook the export table (as the programs I hook don't use GetProcAddress to dynamically lookup the addresses of the functions.) but you can use my HookImport routine (masm source). The call shows how to hook the function "send" from "WSOCK32.DLL" Just make sure you take care of the parameters just as the function would (otherwise, you *must* jmp dword ptr [OriginalFunctionAddress] to return) aka define the parameters. You could modify this code slightly to lookup the export address which is returned from GetProcAddress calls inside the module(dll)

Code:

HookImport proto WORD,WORD,WORD
.data
szWsock32dll db "WSOCK32.DLL",0
szSend db "send",0

.code
...
invoke HookImport,addr szWsock32dll,addr szSend,addr Send_Hook
...
Send_Hook proc sWORD,bufWORD,llenWORD,flagsWORD
invoke send,s,buf,llen,flags
ret

Send_Hook endp
...
HookImport proc lpszDllNameWORD, lpszFunctionWORD, lpCallbackWORD
LOCAL hModuleWORD
LOCAL lOrigProtectWORD
LOCAL lOldAddrWORD

pushad
.if lpszDllName != 0
.if lpszFunction != 0
.if lpCallback != 0
invoke GetModuleHandle,lpszDllName
.if eax != 0
invoke GetProcAddress,eax,lpszFunction
.if eax != 0
mov lOldAddr, eax
invoke GetModuleHandle,NULL
.if eax != 0
mov hModule, eax
mov edi, hModule
assume editr IMAGE_DOS_HEADER
.if [edi].e_magic == IMAGE_DOS_SIGNATURE
mov eax, [edi].e_lfanew
add edi, eax
assume editr IMAGE_NT_HEADERS
.if [edi].Signature == IMAGE_NT_SIGNATURE
lea edx, [edi].OptionalHeader
assume edxtr IMAGE_OPTIONAL_HEADER
lea edx, [edx].DataDirectory
add edx, sizeof IMAGE_DATA_DIRECTORY
assume edxtr IMAGE_DATA_DIRECTORY
mov edx,[edx].VirtualAddress
.if edx != 0
mov edi, hModule
add edi, edx
assume editr IMAGE_IMPORT_DESCRIPTOR
.while [edi].Name1 != 0
mov ecx, hModule
add ecx, [edi].Name1
mov edx, lpszDllName
invoke lstrcmpi,ecx,edx
.if eax == 0
.break
.endif
add edi, sizeof IMAGE_IMPORT_DESCRIPTOR
.endw
mov edi, [edi].FirstThunk
add edi, hModule
assume editr IMAGE_THUNK_DATA
.while TRUE
.if [edi] != 0
mov edx, [edi]
.if edx == lOldAddr
lea ebx, [edi].u1.Function
invoke VirtualProtect,ebx,4,PAGE_WRITECOPY,addr lOrigProtect
mov eax, lpCallback
mov [ebx], eax
invoke VirtualProtect,ebx,4,addr lOrigProtect,NULL
mov eax, 1
popad
ret
.endif
.endif
add edi, 4
.endw
.endif
.endif
.endif
.endif
.endif
.endif
.endif
.endif
.endif
xor eax, eax
popad
ret

HookImport endp