[Asm] IAT Hooking

On domingo, 12 de septiembre de 2010 0 comentarios

IAT Hooking

This tutorial teaches you how to do IAT hooking on your own module. Each module in a portable executable has its own IAT.
wiki wrote:
Import Table

One section of note is the import address table (IAT), which is used as a lookup table when the application is calling a function in a different module. It can be in form of both import by ordinal and import by name. Because a compiled program cannot know the memory location of the libraries it depends upon, an indirect jump is required whenever an API call is made. As the dynamic linker loads modules and joins them together, it writes jump instructions into the IAT slots, so that they point to the memory locations of the corresponding library functions. Though this adds an extra jump over the cost of an intra-module call resulting in a performance penalty, it provides a key benefit: dynamic libraries are much more flexible and reduce code redundancy (which would occur if common libraries had to be linked statically to each program). If the compiler knows ahead of time that a call will be inter-module (via a dllimport attribute) it can produce more optimized code that simply results in an indirect call opcode.

Texe and LordPE are tools that can be used to view the Import and Export tables of PE Files.
In fact, it is not that hard to hook the IAT of another module if you have a good knowledge of the PE format.
wiki wrote:
The Portable Executable (PE) format is a file format for executables, object code and DLLs, used in 32-bit and 64-bit versions of Windows operating systems. The term "portable" refers to the format's versatility in numerous environments of operating system software architecture. The PE format is a data structure that encapsulates the information necessary for the Windows OS loader to manage the wrapped executable code. This includes dynamic library references for linking, API export and import tables, resource management data and thread-local storage (TLS) data. On NT operating systems, the PE format is used for EXE, DLL, OBJ, SYS (device driver), and other file types. The Extensible Firmware Interface (EFI) specification states that PE is the standard executable format in EFI environments.


Straight into it :
Syntax « asm » : [ Download ] [ Hide ] [ Expand ]
 .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 !
Syntax « asm » : [ Download ] [ Hide ] [ Expand ]
 .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:

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:

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.
Syntax « asm » : [ Download ] [ Hide ] [ Expand ]
 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.
Syntax « asm » : [ Download ] [ Hide ] [ Expand ]
 .CODE

   start:

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

Some note 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:

Image

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:

Image

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]

Image

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

Image

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:

Image

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:
Syntax « asm » : [ Download ] [ Hide ] [ Expand ]
 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:

Image

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:

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:

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 !
Syntax « asm » : [ Download ] [ Hide ] [ Expand ]
 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:

Image

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:
Syntax « asm » : [ Download ] [ Hide ] [ Expand ]
 myfunc proc w:DWORD,x:DWORD,y:DWORD,z:DWORD
   push ebp
   mov ebp,esp
   jmp fxn_addr

myfunc endp

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
Syntax « asm » : [ Download ] [ Hide ] [ Expand ]
 .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
Author: c0lo

0 comentarios:

Publicar un comentario