Tuesday, March 13, 2012

Visual Basic Malware - Part 1

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.

Here you can find sample 1. password : infectedtakecare

Any comments or ideas are more than welcome.

You can follow me on Twitter @waleedassar 

17 comments:

  1. Hi,

    Your post was great. Could you please to upload two VB Malwares ? Thanks

    Best Regards,
    VietWOW

    ReplyDelete
  2. I have just uploaded sample1. The archive password is "infectedtakecare".

    Have fun

    ReplyDelete
  3. Your post was great tutorial bro... :))

    ReplyDelete
  4. nice .................


    -zInx

    ReplyDelete
  5. thank u

    Your post was Good~

    But i can file download failed...

    please MD5 let me know ..

    ReplyDelete
    Replies
    1. MD5 Checksum: 3e7126c600eb3d73c9b470aa98f2a416

      Delete
  6. thank u so mach ^^

    ReplyDelete
  7. When is ur next post on VB coming up. Can you write on malwares like vbobfus or changeup

    ReplyDelete
  8. Nice Article....
    Waiting for Visual Basic Malware - Part 2

    ReplyDelete
  9. is that possible to get the "OllyVB.dll" source code? Also wait the Part 2 article

    ReplyDelete
  10. Many thanks for this article.
    Your blog is really interesting.

    We're waiting for Part 2.

    ReplyDelete
  11. wow i wonder how i've missed this post, it's a really nice introduction.

    ReplyDelete
  12. waiting for Part 2 !

    ReplyDelete
  13. "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.

    ReplyDelete
    Replies
    1. Of course, i am talking about pre-dotnet VB executables i.e. VB5 and VB6.

      Thanks for leaving me comments.

      Delete
  14. I have been trying to debug my own sample of VB malware using your tutorial. It was of great help except when I reach a point where the debugging is halted due to the exception:

    Inexact floating point error.

    Even after adding that exception to the ignore list, my sample does not continue its course of execution. Pressing Shift F7/F8/F9 does nothing.

    If you could help me out with this I would be ever so grateful! Thanks in advance and kudos to your tutorial!

    ReplyDelete
  15. Great tutorial.
    Thanks a lot.

    ReplyDelete