Websense Security Labs Blog

Websense Security Labs discovers, investigates and reports on advanced Internet threats that traditional security
research methods miss.

Extracting Malicious Codes from the Process Memory: ZeuS Case

View all posts > 

Extracting Malicious Codes from the Process Memory: ZeuS Case

Posted: 04 May 2010 06:53 PM | Matt Oh | no comments


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:

 

ws2_32.dll:
send, WSASend, closesocket

wininet.dll:
InternetCloseHandle, HttpSendRequestA, HttpQueryInfoA, InternetReadFile, InternetQueryDataAvailable, HttpSendRequestExW, InternetReadFileExA, HttpSendRequestW, HttpSendRequestExA

crypt32.dll:
PFXImportCertStore

user32.dll:
TranslateMessage, DefWindowProcW, NtUserBeginPaint, NtUserEndPaint, DefWindowProcA, GetClipboardData

ntdll.dll:
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

ws2_32!send:

71ab428a e911990c8f jmp 00b7dba0

0:000> u ws2_32!WSASend L1

ws2_32!WSASend:

71ab6233 e985790c8f jmp 00b7dbbd

0:000> u crypt32!PFXImportCertStore L1

crypt32!PFXImportCertStore:

77aef748 e9f7e50889 jmp 00b7dd44

0:000> u ntdll!ZwCreateThread L1

ntdll!ZwCreateThread:

7c90d7d2 e955962784 jmp 00b86e2c

0:000> u ntdll!NtQueryDirectoryFile L1

ntdll!NtQueryDirectoryFile:

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

Protect 00000040 PAGE_EXECUTE_READWRITE

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:

 

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

 

pe.write(out_filename)

 

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



Conclusion

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!

 



Leave a Comment

(required)  

Email address: (required)