Blog

MOTW: VMProtect Analysis

09.01.2006 - 1:50 PM
Starting today, Websense Security Labs presents the analysis of the "Malicious Website / Malicious Code of the Week" which will be posted at the end of each week. These weekly postings will provide highly detailed, in-depth analysis of a piece of malicious code that the Labs has captured and classified.

General Description:

This malware is a simple Trojan downloader.Today's analysis will not focus on the actual payload, but on how the file is being protected against Reverse Engineering. The file has been protected by a PE protector called : VM Protect (Virtual Machine Protect). This protection converts Assembly instructions to pseudo code. There is a Virtual Machine embedded in the binary that will interpret this newly created code. Disassemblers are then useless because they don't support the Virtual CPU instructions. VMProtect uses a rather complex Virtual Machine, and analyzing it would take a long time. The VM are most likely different in each protected binaries, which makes the analysis useless on any other protected binary. Rather, I choose a different approach to analyze the code since the Imports were not scrambled. You will find an ollydebugger script that will sets breakpoints on every API functions that are imported by the binary. Simply parsing the Import Address Table. Then it is very easy to trace the application flow and guess what is going on in this binary.

Technical Details:

If we look at our file with a PE Editor, we notice section named ".vmp". This is a good hint that our file is VMProtected. Using IDA Pro to disassemble it, we see that our application starts with Assembly code, and it doesn't look like clean assembly. It is obviously obfuscated on purpose. Also important information, the ImageBase of our executable is: 0x13140000

Here is the disassembly of the Entry Point:

Anyone a bit familiar with Assembly will notice that this code isn't clean. As I said in the introduction, I am going to use another technique in order to follow the code flow and understand the logic behind this sample. Having a look at the Import Table, we see that it imports a few interesting API functions. They already give us a good amount of information on what the application might be doing:

CreateRemoteThread, WriteProcessMemory etc.. We don't know which process might be injected, nor if a dll is injected, or if it uses delta based assembly, or just any other techniques to inject code inside a remote process. In order to find out, I made an ollydbg script that will browse the Import Address Table and put breakpoints on every imported API function. The IAT starts at 13142000:

////////////////////////////////////////////////////
var IATstart
var IATslots

mov IATstart, 13142000 // IAT start address
mov IATslots, 15 // how many apis to handle.

breakpoint_loop:
 cmp [IATstart],0 // don't set breakpoint at nulls between IID.
 je skip_breakpoint
 bp [IATstart]
skip_breakpoint:
 add IATstart, 4
 dec IATslots
 cmp IATslots, 0
 jne breakpoint_loop
/////////////////////////////////////////////////////

Now, we just need to run the application in OllyDBG and when we are on the entry point, we run this little script. it will put the breakpoints for us.

We could have added a few more breakpoints on GetProcAddress and LoadLibraryA as well. (A malware could emulate both API functions though, so make sure to always debug malicious applications in a Virtual Machine, or even better, on a spare machine.)

By Pressing F9 and looking how the application stops on our breakpoints, we get this information:

0012FFBC   13145D45  /CALL to GetModuleHandleA
0012FFC0   00000000  \pModule = NULL
0012FFC4   7C816D4F  RETURN to kernel32.7C816D4F

The application does a few GetModuleHandleA, nothing of interest.

0012FFB8   13145DB7   /CALL to FindWindowA
0012FFBC   13141152  |Class = "shell_traywnd"
0012FFC0   00000000  \Title = NULL
0012FFC4   7C816D4F  RETURN to kernel32.7C816D4F
0012FFC8   7C920738  ntdll.7C920738

Then it does a FindWindow on the class "Shell_traywnd", which belongs to the explorer.exe application.
It gives us a good hint: This file might inject explorer.exe

0012FFB8   13145F29  /CALL to GetWindowThreadProcessId
0012FFBC   00050054  |hWnd = 00050054 (class='Shell_TrayWnd')
0012FFC0   13141350  \pProcessID = show.13141350
0012FFC4   7C816D4F  RETURN to kernel32.7C816D4F

It then gets some process information using GetWindowThreadProcessID.
It uses the handle found before with FindWindowA

0012FFB4   1314610B  /CALL to OpenProcess
0012FFB8   001F0FFF  |Access = PROCESS_ALL_ACCESS
0012FFBC   00000000  |Inheritable = FALSE
0012FFC0   000001CC  \ProcessId = 1CC

It Opens the Process with PROCESS_ALL_ACCESS.
After that, you will find a VirtualAllocEx allocating memory at address: 13140000

0012FFAC   13145E23  call to VirtualAllocEx
0012FFB0   00000048
0012FFB4   13140000  show.13140000 // Address of allocation.
0012FFB8   00008000
0012FFBC   00003000
0012FFC0   00000040

Notes:
It is important to notice that our application tries to allocate memory in explorer.exe using its own imagebase as a parameter of VirtualAllocEx.
Our application has a non standard imagebase and this is made on purpose. The idea behind this imagebase is that, the injector can copy itself directly in the remote process if it can allocate some memory at the same memory address. What does that mean? It simply mean that the injected code won't need to use delta based code, no relocations will be needed. The imports are already resolved into the injector IAT, thus when they are injected in the remote process, the imports will still be correct. Eventually, after the allocation we have a WriteProcessMemory which will write 8000h bytes in explorer.exe starting from 13140000.

0012FFAC   13145EB6  /CALL to WriteProcessMemory
0012FFB0   00000048  |hProcess = 00000048 (window)
0012FFB4   13140000  |Address = 13140000
0012FFB8   13140000  |Buffer = show.13140000
0012FFBC   00008000  |BytesToWrite = 8000 (32768.) ; writes 8000 bytes
0012FFC0   13141354  \pBytesWritten = show.13141354
0012FFC4   7C816D4F  RETURN to kernel32.7C816D4F

Finally, we have a call to CreateRemoteThread to execute the injected Code.
CreateRemoteThread at address 13141168.

0012FFA4   13145D39  show.13145D39
0012FFA8   00000048
0012FFAC   00000000
0012FFB0   00000000
0012FFB4   13141168  show.13141168 // Start address of the remote
                                      thread==> the interesting code.
0012FFB8   13140000  show.13140000
0012FFBC   00000000
0012FFC0   13141358  show.13141358

Having a look at this memory location, we see:

We can see that the payload is very simple. The injected code starts by deleting the application that did the injection in order to remove any evidence.
After that, it will try to download another executable from a website, and will place it inside the Windows Directory. This newly created Application is then executed.

Outro:
I hope this little article gave the readers some ideas on how you can analyze applications using some complex obfuscation techniques. This was an easy example, but this kind of technique can be adapted and applied on different situations.

Researcher: Nicolas Brulez, Websense Security Labs

Bookmark This Post:

Post a Comment: