API Hooking in Assembly
Sunday, November 24, 2013 | Author: Deep Flash
I wanted to write an article which discusses in depth the method used for hooking the entry point of an API. This method is often used in malwares to alter the behavior of some APIs. Usually the Networking APIs imported from ws2_32.dll, wininet.dll are hooked in this way.

As an example I have taken the Win32/Gepys virus family. The code examples are in assembly. This will help in understanding clearly the method used for hooking.

In order to hook the entry point of the API we need the following:

1. API Address. This can be retrieved by calling GetProcAddress() on the API.
2. Buffer: This buffer will be used to store the first few opcodes of the API along with the jump trampoline. You can get this buffer by calling VirtualAlloc().
3. Malicious Subroutine: This is the subroutine which we want to execute before executing the main API. It will be invoked each time the main API is called from the program.

Now, let's call the API hooking routine:

We need to call VirtualProtect() on both the API and the buffer to mark these regions of memory as PAGE_EXECUTE_READWRITE. We will be executing the code from the buffer as well.

VirtualProtect(buffer, 0x10, 0x40, &oldProtect);
VirtualProtect(api, 0x10, 0x40, &oldProtect);

Now comes the main code for hooking the API. I have explained it with comments:



Once we are done with it, we again mark these regions of memory as: PAGE_EXECUTE_READ.

VirtualProtect(api, 0x10, 0x20, &oldProtect)
VirtualProtect(buffer, 0x10, 0x20, &newProtect)

So, the buffer format is:

[first 5 bytes of the API][E9 - opcode for jump][function pointer - buffer - 0x5]

and the first 5 bytes of the API are calculated as:

E9 - jump opcode
Address = malicious subroutine address - function pointer - 0x5

As an example, if we are hooking the API, ws2_32.gethostbyname with the following details:

buffer = 00D90010
api = 71AB5355 (gethostbyname)
malicious subroutine: 00C8159B

This is how the first 3 instructions of the API look before hooking:

71AB5355 > 8BFF                 MOV EDI,EDI
71AB5357   55                      PUSH EBP
71AB5358   8BEC                  MOV EBP,ESP

Using the above format of the buffer, we know the buffer should look like this for hooking:

buffer = 8b ff 55 8b ec e9 45 53 d2 70

The opcodes in the above buffer correspond to:

00D90010   8BFF                  MOV EDI,EDI
00D90012   55                       PUSH EBP
00D90013   8BEC                 MOV EBP,ESP
00D90015  -E9 4053D270    JMP WS2_32.71AB535A

This jump instruction will redirect the execution to the 4th instruction of the API, ws2_32.gethostbyname.

Also, the first 5 bytes of the function pointer can be calculated using the above method as:

jump opcode: e9
address: 8F1CC241

API after hooking:

71AB5355 >-E9 41C21C8F      JMP 00C8159B    ; malicious subroutine
71AB535A   81EC 14020000        SUB ESP,214

malicious subroutine:

00C8159B   6A 00                    PUSH 0
00C8159D   FF7424 08            PUSH DWORD PTR SS:[ESP+8]
00C815A1   E8 23FDFFFF        CALL 00C812C9
00C815A6   59                         POP ECX
00C815A7   59                         POP ECX
00C815A8   50                         PUSH EAX
00C815A9   FF15 0030C900     CALL DWORD PTR DS:[C93000]
00C815AF   C2 0400               RETN 4

at address, 0xC93000 we have the address of the buffer.

So, the instruction, call dword ptr ds:[buffer] will redirect the execution to the buffer which has the opcodes for the first 3 instructions of the API and then redirects execution to the 4th instruction of the API.

Now, that we have understood this method of API hooking. Let us see how we can detect it.

In the case of Win32/Gepys virus family, it will add the full path of the malicious DLL to the Registry Entry: AppInit_DLL. This will allow the DLL to be loaded into the address space of any new process on the system (it should be linked with user32.dll).

Also, it performs the API hooking only when it is loaded in the address space of a Browser like firefox.exe, chrome.exe, iexplore.exe, opera.exe and so on.

So, to detect this method of API hooking, we will check the calls to VirtualProtect(). Since in API hooking we are writing our jump trampolines to the API, we will check specifically for calls to VirtualProtect() that mark the regions of memory as: PAGE_EXECUTE_READWRITE.

Also, we are interested in those VirtualProtect() calls which are invoked on the API addresses.

I wrote the following Pintool which can help automate this:



Below screenshot shows it detecting the API hooks in firefox.exe:


|
This entry was posted on Sunday, November 24, 2013 and is filed under . You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

0 comments: