May 4, 2010

Extracting Malicious Codes from the Process Memory: ZeuS Case


In my last article, Analyzing Malwares Using Microsoft Tools, we collected a process dump image with an infected ZeuS variant inside it. In this article, we will go through the procedure for separating the ZeuS part from the other parts. With the extracted binary data, we can apply a disassembling process using IDA. You may wonder if it's possible to disassemble the image taken out from the process dump. In this case, the ZeuS variant was injecting a valid DLL file into the process, and somehow managed to hide the existence of the DLL so that it would not appear in the loaded modules list. We can locate that image and can take it out using some tricks.

In the previous article, we found that the following APIs were hooked:

send, WSASend, closesocket

InternetCloseHandle, HttpSendRequestA, HttpQueryInfoA, InternetReadFile, InternetQueryDataAvailable, HttpSendRequestExW, InternetReadFileExA, HttpSendRequestW, HttpSendRequestExA


TranslateMessage, DefWindowProcW, NtUserBeginPaint, NtUserEndPaint, DefWindowProcA, GetClipboardData

ZwCreateThread, NtQueryDirectoryFile

With the list of hooked APIs in mind, open the process dump file using Windbg. Then use the "u"(disassemble) command to check the first instructions they have. Below are some of the examples:

0:000> u ws2_32!send L1


71ab428a e911990c8f jmp 00b7dba0

0:000> u ws2_32!WSASend L1


71ab6233 e985790c8f jmp 00b7dbbd

0:000> u crypt32!PFXImportCertStore L1


77aef748 e9f7e50889 jmp 00b7dd44

0:000> u ntdll!ZwCreateThread L1


7c90d7d2 e955962784 jmp 00b86e2c

0:000> u ntdll!NtQueryDirectoryFile L1


7c90df5e e927902784 jmp 00b86f8a


From the installed inline hooks, we can get the memory region where the hooking function is installed. Here is one of the "!address" results from the hooking function's addresses:


0:000> !address 00b7dd44

00b70000 : 00b70000 - 00026000

Type 00020000 MEM_PRIVATE


State 00001000 MEM_COMMIT

Usage RegionUsageIsVAD


The memory region starts from 0xb70000 and the size is 0x26000 bytes. Let's just dump the start of the memory region using the "db" command, which dumps memory by bytes.

Yes, we got the start of the PE file. We can see the 'MZ' signature and some part of DOS header of the PE file. What we have to do now is simply dump the memory region to a file. Windbg provides a command called ".writemem" to write memory regions to a file.

The following command dumps the region of memory to the file " C:\Malwares\00b70000.bin".


0:000> .writemem C:\Malwares\00b70000.bin b70000 L26000

Writing 26000 bytes............................................................................


We open the file using IDA. It seems to be successful, until we find that there is something wrong with the disassembly listing.

First we get some error message dialog boxes:


Figure 1: Virtual Address Translation Error

We see that the imports table is empty:

Empty Table

Figure 2: Empty Imports Table

Even call instructions are referencing some invalid addresses:


Figure 3: Call Referencing Invalid Region

We notice broken data referencing:


This is happening because the base address for image loading is different from what is set in the PE header. We can check the value of the image base defined in the PE header by looking at the top of the IDA disassembly listing. In this case, the image base is set as 0x400000 as you can see from the following picture, but the image base when we dumped the image was actually 0xb70000.


Figure 4: Image Base is 0x400000

Will only fixing the image base solve the issues? No. We need to take care of the section relocations. When the PE file is loaded into the process address space, it is not just copied exactly. The sections inside are located according to their virtual address. Each section has their position and size in the physical file, and also has a virtual address region to be mapped. All the information is inside the PE file header.

We used the pefile Python module from Ero Carrera to achieve the PE file manipulation. Here's the source code for the script that we used:

import pefile

import sys


filename = sys.argv[1]

out_filename = sys.argv[2]

rebase_address = int(sys.argv[3],16)


pe = pefile.PE(filename)

print "Rebasing from ",hex(pe.OPTIONAL_HEADER.ImageBase),"to",hex(rebase_address)

pe.OPTIONAL_HEADER.ImageBase = rebase_address


for section in pe.sections:

    section.PointerToRawData = section.VirtualAddress




Save the python script as "Rebase.py" file. Here's how you can use the script:


c:\python26\python Rebase.py 00b70000.bin 00b70000_rebased.bin 0xb70000


This command will re-base the image base to 0xb70000 and will also correct section location information by setting PointerToRawData to be same as the VirtualAddress value. PointerToRawData is the offset in the file where the section starts. We dumped it from the memory and it should be same as VirtualAddress.

After running the script, open up the re-based image "00b70000_rebased.bin" using IDA.

Now we have a valid and good imports table:


Figure 5: Valid Imports Table

Call instructions are referencing valid APIs:


Figure 6: Call Instruction Referencing Valid APIs

Also, the string referencing is corrected and shows good values:


Figure 7: Valid String Data


Retrieving injected modules and making it valid for disassembling is possible with a few Windbg tricks and python scripts. Tracing malicious code inside a debugger doesn't compare to having it inside a full-blown disassembler. The script presented in this article can be applied to any injected modules in the Windows environment.

Next time we are going to talk about automated scripts that will do all the jobs that we have done with a single command.

Thanks and have a great reversing!


Forcepoint-authored blog posts are based on discussions with customers and additional research by our content teams.

Read more articles by Forcepoint

About Forcepoint

Forcepoint is the leading user and data protection cybersecurity company, entrusted to safeguard organizations while driving digital transformation and growth. Our solutions adapt in real-time to how people interact with data, providing secure access while enabling employees to create value.