Tuesday, March 13, 2012

I can't deny i was interested in Visual Basic Malware the last few days. So, i am going to share some of my experiences with this type of malware.

Since i don't feel comfortable with VB Decompiler and the likes (perhaps you do), i decided to take two VB Malware samples and see what special procedures could be taken to make the analysis process easier without use of these tools.

Before going into the details of VB malware, i will quickly give some basic information about VB executables.

1) VB executables come into two flavors, P-Code and Native. P-Code executables are compiled into bytecode which is interpreted by the Visual Basic virtual machine at runtime, while Native ones are compiled into native machine language. So, Native VB executables are easier to debug. On the other side, P-Code VB executables are easier to decompile.

2) At the entry point, there is always a non-returning call to the "ThunRTMain" function. This function has only one parameter, which is a pointer to a bulky structure holding everything the executable needs.

3) The code section contains a lot of interesting and non-interesting stuff. So, a quick and dirty way to spot functions (Native only) is to search for 0xE9E9E9E9 in disassembly. This dword denotes the real start of code. In P-Code executables, 0xE9E9E9E9 is followed by 0x9E9E9E9E as they have no x86 instructions.

4) Each function starts with a call to the "Zombie_AddRef" function and ends with a call to the "Zombie_Release" function. So, a simple executable might have hundreds of calls to these two functions.

5) Calling an API function is conducted either by calling the MSVBVM60.dll function that wraps up that API or by calling the "DllFunctionCall" stub. See the images below.

6) Any "Private/Public Declare Function ..." statement in a module is reflected in the executable as a "DllFunctionCall" stub.

The "DllFunctionCall" function receives one parameter. This parameter points a small structure whose first and second members point to the DLL and function names successively. The "DllFunctionCall" function is internally as simple as a call to the "LoadLibraryA" function followed by a call to the "GetProcAddress" function, see the image below. Actually, the function's name is not very accurate as the function only retrieves addresses.

Conclusion: Enumerating all calls to the "DllFunctionCall" stubs in a VB executable is very useful in analyzing VB malware.

Enumerating this kind of calls in disassembly is as easy as searching the PE sections for a specific byte pattern. The pattern is usually, if not always, like this:

I have created an OllyDbg plugin, OllyVB, to let you easily find all "DllFunctionCall" stubs by matching the byte pattern shown above.

Usage: ALT+E to enumerate modules in OllyDbg and then Right-Click and choose "View names".

Back to our main topic.

Sample 1)

Loading sample1.exe into OllyDbg v1.10 (with the "OllyVB" plugin), we will find that it imports many APIs. See the images below.

As you can see, all the "DllFunctionCall" stubs are encrypted except the "CallWindowProcW" one. Why "CallWindowProcW"? we will find this later, just keep reading.

The next step is to place breakpoints on all the "DllFunctionCall" stubs we have and then run (F9).

Once execution stops at the "CallWindowProc" stub, take a quick look at the stack to inspect parameters. You will see that the first and second parameters passed to the "CallWindowProcW" function are so fishy as the first parameter which is supposed to be a pointer to a window procedure points to a heap location and the second parameter which is supposed to be a window handle points to a string. To find the reason behind this weird function call, let's quickly dig into the "CallWindowProcW" function internals.

As you can see in the image above, the call to the "CallWindowProcW" function ends up with call dword ptr[ebp+0x8], which causes code at this heap location to be executed. we can now conclude that the "CallWindowProcW" function is only used to invoke its first parameter.

As many know, Visual Basic does not intrinsically support function pointers, this is why VB programmers (I bet not so many are still alive) are using this function (other functions can also be used) to implement something similar to the C function pointers, a quick and dirty way to execute shellcode or hide the "DllFunctionCall" stubs from disassembly. See the images below.

The sample in question does not call the "VirtualProtect" function to allow execution from heap (Perhaps, cuz it was written too long ago) and this is why Hardware Data Execution Prevention (DEP) kills this piece of malware.

Now, let's see the shellcode that the "CallWindowProcW" function executes using the call dword ptr[ebp+0x8] trick.

As you can see in the image above, the shellcode resolves a function address given its DLL name and hash. The address resolved will later be used to form another shellocde. We will see this later.

Repeating the same trick, we will see a call to the "CreateProcess" function by which the executable spawns itself in suspended state.

It will then unmap the image of the spawned executable from address space by calling the "ZwUnmapViewOfSection" function and re-allocate 0x4f000 bytes at 0x400000 by calling the "ZwAllocateVirtualMemory" function.

The "ZwWriteVirtualMemory" function will then be called several times to create the new executable. Finally, the "ZwResumeThread" function will be called to resume the suspended process.

After taking a memory dump of the new process and fixing its section table (by merging all sections into one big section), i got another Visual Basic piece of malware that is not encrypted at all. This piece of malware will be discussed in another post but here is a quick view of its "DllFunctionCall" stubs.

Notes:
1) The markers 0xE9E9E9E9 and 0x9E9E9E9E are not mandatory. They don't affect the executable if removed.
2) Everything that applies to the "CallWindowProcW" function also applies to its ANSI version.
3) Many other APIs can be used in the same way as the "CallWindowProcW" function.
4) I hate Visual Basic.

"VB executables come into two flavors, P-Code and Native. " Excuse my ignorance, but is this VB6 we are talking about? Surely everything has been VB.NET for many years, which can't produce native execs, or can it?? Great article anyway.