[LEARN] IAT Hooking

On martes, 7 de septiembre de 2010 0 comentarios

[LEARN] IAT Hooking

Just before we start, let me mention that this tutorial teaches you how to do IAT hooking on your own module. Each module in a portable executable has its own IAT. In fact, it is not that hard to hook the IAT of another module if you have a good knowledge of the PE format. I may post a tutorial on how to do that sometime..

Straight into it :

Code:
.486
.model flat,stdcall
option casemap:none
option epilogue:none
option prologue:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

myfunc proto :DWORD, :DWORD, :DWORD, :DWORD

.DATA

   Caption         db "Success !",0
   Text             db "Called successfully via trampoline",0

.DATA?

   fxn_addr    dword   ?

.CODE

   start:

   xor ebx,ebx
   mov eax,[MessageBox]
   add eax,2
   mov eax,[eax]
   mov eax,[eax]
   add eax,5
   mov fxn_addr, eax

       invoke myfunc, ebx, addr Text, addr Caption, ebx
       invoke ExitProcess, ebx

myfunc proc w:DWORD,x:DWORD,y:DWORD,z:DWORD

   push ebp
   mov ebp,esp
   jmp fxn_addr

myfunc endp

   end start
Here I show you a way to trampoline over first 5 bytes of MessageBox without ever calling GetModuleHandle/LoadLibrary and GetProcAddress
Instead I use my understanding of the MASM32 linker to read the current address of the IAT via the thunk table Read on !

Code:
.486
.model flat,stdcall
option casemap:none
option epilogue:none
option prologue:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
Making declarations, etc. etc. Important things to note are these two lines:

Code:
option epilogue:none
option prologue:none
Usually when you are making a call to your own defined function, it will add some code at the start that sets up stack frame and some code that pops EBP back off. That is, your function will automatically set up its own stack frame:

Code:
push ebp
mov ebp, esp
Saving stack base then changing new stack base as old top of stack.
So we want to turn this function off and you will see why later.

Code:
myfunc proto :DWORD, :DWORD, :DWORD, :DWORD

.DATA

   Caption         db "Success !",0
   Text             db "Called successfully via trampoline",0

.DATA?

   fxn_addr    dword   ?
Declaring my own function prototype that takes 4 dwords as arguments. Defining 2 null terminated strings for later. Defining an uninitialised dword that will hold the function address that we want to trampoline.

Code:
.CODE

   start:

   xor ebx,ebx
   mov eax,[MessageBox]
   add eax,2
   mov eax,[eax]
   mov eax,[eax]
   add eax,5
   mov fxn_addr, eax
First let me tell you a bit about the MASM linker. It tells the PE loader where addresses are via its own thunk table which is usually located at the end of the executable. It is a pointer to the import address table (which updates off the corresponding dynamic link library's export address table I believe).

So first off, I set ebx to 0 as above. This means later when I am going to use "push 0" instructions, I can "push ebx" instead which results in a smaller, faster executing program. ebx is chosen because it is a register that stdcall convention does not fiddle around with, unlike eax, ecx and edx.

Let me just show you a screenshot of the thunk table generated by MASM's linker:



You can see several things here.

- The "CALL 0040102D" is the call to my function. It directly calls the address of my function.
- There is a little table at the end with 3 entries

The table is the JMP thunk table. If you look at what code is the call to ExitProcess:



It does not call the virtual address of ExitProcess. This is because the address changes and so you can not just hardcode an address, unlike for my own function. What it calls instead is the entry of ExitProcess in the thunk table which is:

JMP DWORD PTR DS:[<&kernel32.ExitProcess>]

If you try to see what instruction that actually is, it is:

JMP DWORD PTR DS:[402000]



0x402000 is the entry in the import address table for the ExitProcess function. So if you look in the hex dump..



Bearing in mind the little endianness that the 80x86 uses, this means the current address of ExitProcess on my system is 0x76793B54. Sure enough, if I go there:



You can already recognise that procedure as ExitProcess because of the native API it calls : RtlExitUserProcess.

So now we know how to manually find the address of a function, look at how I have done it in MASM:

Code:
mov eax,[MessageBox]
   add eax,2
   mov eax,[eax]
   mov eax,[eax]
   add eax,5
   mov fxn_addr, eax
The first instruction will move the virtual address of the entry in the thunk table of MessageBox into eax. Then we add 2 to that address. Maybe you are thinking "wtf is this kid smoking ?". Look at this:



The bytes for "JMP DWORD PTR DS:[402008]" is "FF25 08204000". So the first 2 bytes "FF 25" must be for the opcode saying JMP DWORD PTR DS:[]. Then the pointer itself are the next 4 bytes (note the little endianness), 08204000 >> 402008

So "mov eax, [MessageBox]" would lead us to the virtual address that the above instruction is on. So to get to the actual pointer to the IAT entry for this API, we need to add 2 bytes. Next we have:

Code:
mov eax,[eax]
   mov eax,[eax]
We move the dword that is pointed to by eax into eax. So before this instruction executes, eax is the address of the thunk entry for that address + 2 which is the pointer to the IAT entry. So the first "mov eax, [eax]" moves the address of the IAT entry into eax. Then we do it again and this time the dword held at the IAT entry is moved into eax. You already saw from before that IAT holds a pointer to the function address.
Now we set up our address ready for trampolining:

Code:
add eax,5
   mov fxn_addr, eax
We add 5 to eax and then move that into our buffer named fxn_addr. All will be explained later if you have not come across this 5 byte trampoline method before !

Code:
invoke myfunc, ebx, addr Text, addr Caption, ebx
       invoke ExitProcess, ebx

myfunc proc w:DWORD,x:DWORD,y:DWORD,z:DWORD

   push ebp
   mov ebp,esp
   jmp fxn_addr

myfunc endp
  end start
So directly after this, I invoke my prototype function. The 4 dword parameters it is taking is ebx, address of text, address of caption and ebx again. These are the arguments for a normal call to MessageBox:



So the hWnd and type is null, which is fine if you look at the exact description of those arguments. Then address of text and caption as defined earlier, fine also. Now let's look at what my function is comprised of:

Code:
myfunc proc w:DWORD,x:DWORD,y:DWORD,z:DWORD
   push ebp
   mov ebp,esp
   jmp fxn_addr

myfunc endp
All it does is set up stack frame then jmp to the fxn_addr which is address of MessageBoxA + 5. So when I call my procedure, what happens is:
- Return address is pushed onto stack (virtual address of instruction directly after the call)

- Execution goes to the address that is called
- My procedure sets up stack frame (which is what the first 5 bytes of MessageBoxA does)
- We jmp to MessageBoxA + 5

What this has achieved is that it means we can now execute any function without ever touching its first 5 bytes. This is where GameGuard places its usermode hooks, as a far jump at the first 5 bytes of the function. So we can use this method to trampoline over GG's hook.

There are a few tricks that you will have to learn before you are able to do this to bypass a usermode hook but I'll let you figure that out yourself, it'd be no fun if I told you everything !

Later to come if I get bored enough.. How to do IAT hooking and intercept arguments of a function call and replace it with your own

(Now is later..)

MOAR CODE !!!

This code shows how to dynamically fetch the first 5 bytes (before I hardcoded bytes to set up stack frame). It also shows how to hook your own program's IAT and notice I have intercepted and modified the arguments of a call to MessageBox. If you need anything explained, please shout

Code:
.486
.model flat, stdcall
option casemap:none
option epilogue:none
option prologue:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

WriteMem proto
My_Proc  proto

.DATA

   Caption             db      "Title",0
   Text                db      "Text",0
   API_Fxn             dd      MessageBox
   Mod_Caption   db  "Modified Title",0
   Mod_Text   db  "Modified Text",0

.DATA?

   IAT_Entry_Addr      dword   ?
   Fxn_Addr            dword   ?
   Proc_Addr           dword   ?
   Ret_Addr   dword ?

   Arg1    dword ?
   Arg2    dword ?
   Arg3    dword ?
   Arg4    dword ?

   StackFrameCheck  dword ?

.CODE

start:

xor ebx, ebx
mov eax, [API_Fxn]
add eax, 2
mov eax, [eax]
mov IAT_Entry_Addr, eax
mov eax, [eax]
mov Fxn_Addr, eax
mov eax, offset My_Proc
mov Proc_Addr, eax

    invoke WriteMem

   push ebx
   push offset Caption
   push offset Text
   push ebx
   call API_Fxn

    invoke ExitProcess, ebx

WriteMem proc

   LOCAL OldProt:DWORD
   LOCAL OldProcProt:DWORD

       invoke VirtualProtect, IAT_Entry_Addr, 4, PAGE_EXECUTE_READWRITE, addr OldProt

   mov ecx, Proc_Addr
   mov edx, IAT_Entry_Addr
   mov [edx], ecx

       invoke VirtualProtect, IAT_Entry_Addr, 4, OldProt, addr OldProt
 invoke VirtualProtect, Proc_Addr, 5, PAGE_EXECUTE_READWRITE, addr OldProcProt

   mov eax, Fxn_Addr
   mov eax, [eax]
   mov ecx, [Proc_Addr]
   mov [ecx], eax
   mov eax, Fxn_Addr
   add eax, 4
   mov al, byte ptr ds:[eax]
   mov ecx, [Proc_Addr]
   add ecx, 4
   mov byte ptr ds:[ecx], al

       invoke VirtualProtect, Proc_Addr, 5, OldProcProt, addr OldProcProt
   ret

WriteMem endp

My_Proc proc
   nop
   nop
   nop
   nop
   nop
   pop StackFrameCheck
   pop Ret_Addr
   pop Arg4
   pop Arg3
   pop Arg2
   pop Arg1
   push ebx
   push offset Mod_Caption
   push offset Mod_Text
   push ebx
   push Ret_Addr
   push StackFrameCheck
   mov eax, [Fxn_Addr]
   add eax, 5
   jmp eax
My_Proc endp

   end start
Dynamically reads first 5 bytes of a given function and writes it to our own function prototype which then executes those 5 bytes, intercepts the arguments, modifies them and then trampolines over the real first 5 bytes (possible place where hook would go) to execute the rest of the real function

Features I intend to add soon:

- Allow user to choose what function to intercept and trampoline
- Allow user to choose what arguments to replace
- Dynamically push and pop only as many arguments as there are for that function. eg. had that function been say ExitProcess instead, it only has 1 argument and wastes clock cycles/space to hardcode it to push and pop 5 items off the stack including EBP. Not actually sure how to do this yet without setting up a big-ass array of all WinAPIs with the number of arguments they take. Even then some APIs have optional functions AARRGGHHHH !!!

- Check whether the first 5 bytes includes pushing of EBP. If not, then it doesn't have to be popped
- Convert to a DLL to allow any usermode hooked API in a target process to be trampolined over/bypassed and all arguments for that intercepted
- Not very likely but I might create a GUI for the DLL
Btw, yes I know the code for copying of the first 5 bytes is very ugly at the moment but I'm a newby, go easy

0 comentarios:

Publicar un comentario