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:

ESI - Function Pointer
EDI - Buffer
00C816F9 803E E9 CMP BYTE PTR DS:[ESI],0E9 ; check if the first instruction of API is a jump instruction
00C816FC 75 09 JNZ SHORT 00C81707
00C816FE 8B46 01 MOV EAX,DWORD PTR DS:[ESI+1]
00C81701 8D4430 05 LEA EAX,DWORD PTR DS:[EAX+ESI+5]
00C81705 EB 12 JMP SHORT 00C81719
00C81707 8D46 05 LEA EAX,DWORD PTR DS:[ESI+5] ; point eax to the 5th byte of the function
00C8170A A5 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ; store 5 bytes from the function into the buffer
00C8170B A4 MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00C8170C 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C] ; edi = buffer
00C8170F 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] ; esi = function pointer
00C81712 C745 F8 05000000 MOV DWORD PTR SS:[EBP-8],5
00C81719 8B55 F8 MOV EDX,DWORD PTR SS:[EBP-8]
00C8171C 2BC2 SUB EAX,EDX
00C8171E 2BC7 SUB EAX,EDI
00C81720 83E8 05 SUB EAX,5 ; eax = function pointer - buffer - 0x5
00C81723 8D0C3A LEA ECX,DWORD PTR DS:[EDX+EDI] ; buffer = buffer + 0x5
00C81726 8941 01 MOV DWORD PTR DS:[ECX+1],EAX ; write above calculated value of eax in the buffer
00C81729 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10] ; malicious subroutine
00C8172C 2BC6 SUB EAX,ESI
00C8172E 83E8 05 SUB EAX,5 ; hooked api = hooked api - function pointer - 0x5
00C81731 C601 E9 MOV BYTE PTR DS:[ECX],0E9 ; write jump opcode to buffer
00C81734 8946 01 MOV DWORD PTR DS:[ESI+1],EAX ; write the above calculated hooked api value to the function pointer + 1
00C81737 8D45 F4 LEA EAX,DWORD PTR SS:[EBP-C]
00C8173A 50 PUSH EAX
00C8173B FF75 F4 PUSH DWORD PTR SS:[EBP-C]
00C8173E C606 E9 MOV BYTE PTR DS:[ESI],0E9 ; write jump opcode to function pointer
view raw hookapi.asm hosted with ❤ by GitHub


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:

/*
Pintool to detect API hooks in a process
c0d3inj3cT
*/
#include <stdio.h>
#include <iostream>
#include "pin.H"
int i=0;
void VirtualProtectHandler(void *address, int newProtect)
{
if(newProtect == 0x40)
{
PIN_LockClient();
RTN lrtn = RTN_FindByAddress((ADDRINT) address);
if(RTN_Valid(lrtn))
{
i++;
string symbolName = RTN_Name(lrtn);
symbolName = PIN_UndecorateSymbolName(symbolName, UNDECORATION_COMPLETE);
printf("VirtualProtect(%p) ==> %s\n", address, symbolName.c_str());
}
PIN_UnlockClient();
}
}
void Image(IMG img, void *v)
{
RTN rtn = RTN_FindByName(img, "VirtualProtect");
if(RTN_Valid(rtn))
{
RTN_Open(rtn);
RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR) VirtualProtectHandler, IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_FUNCARG_ENTRYPOINT_VALUE, 2, IARG_END);
RTN_Close(rtn);
}
}
void Fini(INT32 code, void *v)
{
printf("There are %d functions hooked\n", i);
}
INT32 Usage()
{
printf("There was an error\n");
return -1;
}
int main(int argc, char *argv[])
{
PIN_InitSymbols();
if( PIN_Init(argc,argv) )
{
return Usage();
}
IMG_AddInstrumentFunction(Image, 0);
PIN_AddFiniFunction(Fini, 0);
PIN_StartProgram();
return 0;
}
view raw hookdetect.c hosted with ❤ by GitHub


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


Virus delays execution using Window Messages
Friday, November 22, 2013 | Author: Deep Flash
Recently while analyzing a virus family, I found an interesting way to introduce delay before invoking the malicious code. It also helps in not making evident the location of the malicious code. This can be obfuscated further though.

After unpacking the malware, the first thing it does is to register a Window Class with the name, "Runtime Check" with the Window Procedure subroutine at address, 00402680. It then creates the Window. During the creation of the Window, the Window Procedure is invoked which handles the initial window messages like WM_CREATE.

After the Window is created, it retrieves the message from the Thread's queue using GetMessage() and dispatches it to the Window Procedure using DispatchMessage().

Inside the Window Procedure, it reads the code of the Window Message from the stack and stores it in the EAX register. It then checks whether the window message code is greater than 0xF. If it is equal to 0x113, then it sets up a Timer that elapses after 1 second. Since the last parameter to the SetTimer() function is NULL, the system will post a WM_TIMER message to the queue every time the timer elapses. Each time a WM_TIMER message is retrieved from the application thread's message queue using GetMessage(), it increments a counter. Once the counter is equal to 5, it calls the malicious subroutine. Since the timer is set to elapse after 1 second, so overall delay introduced is approximately, 5 seconds.

Below are the corresponding sections of code:

; Below are the first few lines of code of the Window Procedure:
00402680 55 PUSH EBP
00402681 8BEC MOV EBP,ESP
00402683 83E4 F8 AND ESP,FFFFFFF8
00402686 83EC 4C SUB ESP,4C
00402689 A1 04A04000 MOV EAX,DWORD PTR DS:[40A004]
0040268E 33C4 XOR EAX,ESP
00402690 894424 48 MOV DWORD PTR SS:[ESP+48],EAX
00402694 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C] ; window message code
00402697 56 PUSH ESI
00402698 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8]
0040269B 83F8 0F CMP EAX,0F
0040269E 77 75 JA SHORT 249be839.00402715 ; if wind_code > 0xF
004026A0 74 47 JE SHORT 249be839.004026E9 ; WM_PAINT
004026A2 8BC8 MOV ECX,EAX
004026A4 49 DEC ECX
004026A5 74 1E JE SHORT 249be839.004026C5 ; if wind_code == 0x1 (WM_CREATE)
; The below code will setup the timer when the WM_CREATE window message is received by the Window Procedure:
004026C5 6A 00 PUSH 0
004026C7 68 E8030000 PUSH 3E8
004026CC 6A 01 PUSH 1
004026CE 56 PUSH ESI
004026CF FF15 5C714000 CALL DWORD PTR DS:[40715C] ; USER32.SetTimer
; The below code will check if the window message code is 0x113 (WM_TIMER) and call the corresponding code to handle this window message:
00402715 8BC8 MOV ECX,EAX
00402717 81E9 11010000 SUB ECX,111
0040271D 74 57 JE SHORT 249be839.00402776
0040271F 83E9 02 SUB ECX,2
00402722 74 22 JE SHORT 249be839.00402746 ; if wind_code == 0x113 (WM_TIMER)
00402746 A1 C4C64400 MOV EAX,DWORD PTR DS:[44C6C4]
0040274B 40 INC EAX ; increment the counter
0040274C A3 C4C64400 MOV DWORD PTR DS:[44C6C4],EAX
00402751 83F8 05 CMP EAX,5 ; check if counter == 0x5
00402754 75 67 JNZ SHORT 249be839.004027BD
00402756 E8 75FBFFFF CALL 249be839.004022D0 ; call malicious subroutine.
view raw wmtimer.asm hosted with ❤ by GitHub

and here is the code rewritten in C:

if(wind_code > 0xF)
{
    if(wind_code == 0x113)
    {
        counter++;
        if(counter == 0x5)
        {
            call malicious_code;
        }
    }
}
else if(wind_code == 0xF)
{
    // code for handling the WM_PAINT message
}
else if(wind_code == 0x1)
{
    SetTimer(hWnd, 1, 0x3e8, 0)
}
Some notes about Zeus
Friday, November 15, 2013 | Author: Deep Flash
Zeus bot uses some techniques which make it difficult to debug. Few of these techniques are common and used by other malwares as well. I will mention the techniques which I found interesting and worth mentioning. It will help in analyzing malwares which use similar techniques:

1. Code Injection: Like most malwares today, they inject the malicious code into the process address space of a benign system process like explorer.exe, winlogon.exe, svchost.exe and others, Zeus does the same thing. It injects the malicious code into winlogon.exe

At first, it needs to find the PID (process id) of winlogon.exe. To do this, it uses following sequence:

CreateToolHelp32Snapshot() to get the snapshot of all the running processes in the system.
Then it walks through the list of the running processes using, Process32First() and Process32Next() till it finds winlogon.exe.
Once it finds, winlogon.exe, it gets the PID from the PROCESSENTRY32 structure.

This same technique is also used to find svchost.exe PID. It makes sure that the process is running under SYSTEM account by using the following APIs:

OpenProcessToken (with Token_Query access)
GetTokenInformation (Token_User)
LookupPrivilegeValue

If in case the svchost.exe process is not running under SYSTEM account, then it continues to enumerate the processes further till it satisfies this condition.

Now, it needs to open the process with the desired access (CREATE_THREAD|VM_OPERATION|VM_READ|VM_WRITE|QUERY_INFORMATION) using OpenProcess API.

It is important to open the process with this access since we will be injecting our code into it and also creating a remote thread in it.

Once the process has been opened, we receive a handle for it. Now, we proceed to inject the code in phases.

It allocates memory into the remote process using VirtualAllocEx().

It finds the size of the sections, .text, .data, .reloc and .data1 of the malicious executable embedded within itself,  in sequence and then uses WriteProcessMemory to write it into the process address space of winlogon.exe

Now it calls RtlCreateUserThread() to create the thread in remote process.

Most malwares resume execution in the remote process using CreateRemoteThread, ResumeThread and so on. This was one of the features where Zeus differs from the rest by using the not so commonly used API.

One of the key differences between RtlCreateUserThread and CreateRemoteThread is in the way they initialize the context structures (value of the registers, eax and eip). It has been documented in detail here:

http://waleedassar.blogspot.in/2012/06/createremotethread-vs.html

The stack parameters for the call to RtlCreateUserThread look like this:


Since we know the StartAddress of the remote thread (0x00A766F8) in winlogon.exe, we can attach our debugger to winlogon.exe and set a breakpoint at it to debug further.

2.  Remote Thread Execution: The entry point of the remote thread looks like this:


In the remote thread it has a callback function (0x0A766E9) which is invoked using the CreateTimerQueueTimer() function. We get the address of the callback function from the arguments of above API, so we set a breakpoint at it.


This will create a new thread with the start address, 0x0A764E4 which is one of the parameters passed to the callback function.

After creating the necessary files on the filesystem like sdra64.exe, user.ds, local.ds and so on, it proceeds to create another thread with the following parameters:

If we look at the parameter passed to the thread start function above, it is a structure that looks like this:

 
In this structure, we have the address of a subroutine, 0x00A76361 which is the main controller routine. We will discuss more about this routine later.

We also have the handle of the NamedPipe (\Device\NamedPipe\_AVIRA_2109), two events and a pointer to the string, "_AVIRA_2109"

Let us take a look at the thread function at 0xA7A1D2 now:


It will create a mutex with the name, _AVIRA_2109 and then connect to the NamedPipe. This is the server end of the named pipe. Data is read from the NamedPipe using ReadFile and written to it using WriteFile. This is used for inter process communication.

It reads 4 bytes from the NamedPipe (which is the code of the command) that is passed to the controller function mentioned above (0x00A76361).

Here is the call to the controller function:


 And the controller function:


The command code is passed in the ecx register which is checked in the controller function.

The use of Named Pipes is another feature in Zeus that is not used in many malwares. It makes the process of debugging its code more difficult.

Similar to NamedPipes, there is another way for interprocess communication using CreateMailSlot which can be used by malwares.