[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 :
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 !
Making declarations, etc. etc. Important things to note are these two lines:
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:
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.
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.
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:
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:
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:
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 !
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:
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
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
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
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
Code:
option epilogue:none option prologue:none
Code:
push ebp mov ebp, esp
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 ?
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
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 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]
Now we set up our address ready for trampolining:
Code:
add eax,5 mov fxn_addr, eax
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 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
- 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
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