Virus Share: Random Sample #1 - Part Four: Extraction

Synopsis

Today we are picking up where we left off in part three. The goal here is to extract the PE file that's injected into iexplorer.exe's address space. Unlike the prior article, this post will be light on static analysis as its main goal is to help us transition to reversing the injected binary.

Follow along note: We'll be using the sample dumped after step 8 (part one) for IDA. When running the sample in x64dbg, the dumped sample is taken just prior to step 8.

Exercise caution (i.e. run in an isolated VM) as this is a live malware sample.
I'm not responsible for any damage.


Recap

Here is what we have covered so far:

Part One

  • Extracted executable from web page
  • Using the upx executable, unpacked the first packer
  • Using a debugger, unpacked the sample a second time
  • The final running instance of the dumped executable looked to have been wrapped with another packer that, when removed, caused the unpacked executable to throw an error during execution.
    • Had to leave the final packer in place for the debugger but removed for IDA.

Part Two

  • Inspected API hooking of ZwWriteVirtualMemory
  • Call to CreateProcessA to trigger it
  • Removal of the API hook

Part Three

  • Reviewed the code the API hook jumps to
  • Discovered that the code is writing another PE file into the address space of iexplorer.exe

Extraction

Here we will use two debuggers to control execution. The first one will pause execution of svchost.exe so that the second debugger can be attached to iexplorer.exe (before the injected code in iexplorer.exe executes).

Debugger One

Debugger 1 will control svchost.exe by setting a break point inside the function the API hook jumps to. To set the break point, highlight the instruction after final call to WriteProcessMemory @ 402AFD and hit F2. Or, assuming your base address is the same, run this script in x64Dbg.

run
bpc
bp 411513
run
step
bp 402B02
run

Code Snippet 1 - x64Dbg script to break execution for svchost.exe

The script also covers unpacking the packer at the beginning of the executable's process. This will leave the program paused at the correct location for the next phase.


Screenshot 1 - Debugger running svchost.exe paused after hooking iexplorer.exe's entry point

Calling Debugger Two

Open up another instance of x64Dbg and attach it to the running instance of iexplorer.exe.


Screenshot 2 - Attaching to iexplorer.exe

Go to iexplorer.exe's entry point by hitting Ctrl+g and entering this formula.

To find iexplorer.exe's base address go to the Memory Map tab in x64Dbg and look for iexplorer.exe.

AddressBase + [AddressBase + [AddressBase + 3c] + 28]

Code Snippet 2 - Entry Point Formula

The current running instance of iexplorer.exe is loaded into 1380000 so our formula looks like this.


Screenshot 3 - Find iexplorer.exe entry point

Which takes us to this location in the disassembler.


Screenshot 4 - iexplorer.exe entry point

Next, set a break point at the call edi instruction (@ RVA 1CA4) and now we are ready to let svchost.exe run its course. Go back to svchost.exe's x64Dbg instance and hit F9. The program will exit; however, in iexplorer.exe's x64Dbg instance the program will pause at the break point. Might need to hit F9 a single time in iexplorer.exe's debugger to let execution to get to the entry point and out of ntdll.dll.

So close! Now we need to extract the PE file at the opportune moment.

When to Extract

Before we can extract the binary we need to do a little bit of analysis. Remember the value pushed onto the stack just prior to the call to EDI (see part three)? This is an allocated memory region which holds variables the function called probably needs. Right click on the push instruction and select Follow in Dump and choose the address value.


Screenshot 5 - Follow in Dump

In x64Dbg's Dump window it should look something like this. Might need to set the view to Address.


Screenshot 6 - Memory Addresses

The ones in red resolve to ntdll functions. Notice when looking at the top 5 in x64Dbg's Memory Map tab, 4 correspond to places in memory with ERW permissions (also included the two memory segments which hold the variables and the function @ EDI).


Screenshot 7 - Allocated Memory (1)


Screenshot 8 - Allocated Memory (2)

Let's take this analysis a little bit further. Open up each of these memory segments in the Dump window.

  1. 20010000
  • Screenshot 9 - Start of address space 20010000

  • 20017C79

  • Screenshot 10 - Hex values @ 20017C79

  • 50000

  • Screenshot 11 - Start of address space 50000

  • 60000

  • Screenshot 12 - Start of address space 60000

Aha! Notice the MZ at the start of 20010000! This should be the injected binary file! Looking at the address of the second address entry in screenshot 6, the value points to an address inside the address space for 20010000. This is probably the entry point into the binary.

Let's search for a call to this entry point. Upon looking at the assembly code, we notice that call instructions are made using the base address in EDI; so, EDI probably holds the the value of the function's argument. We can confirm by looking near the beginning of the function where the argument passed into this function is loaded into EDI. Let's mimic the format for these calls in the find dialog box. Press Ctrl+f in x64Dbg and search for call dword ptr ds:[edi+4].


Screenshot 13 - Find call

Following the only result returned, we see the call instruction at 70083.


Screenshot 14 - Find Result

Notice the value of [edi+4] is 20017C79.


Screenshot 15 - Value of dword ptr[edi+4]

We could go all crazy and further confirm using the entry point formula we used earlier to see if the entry point address matches this value.


Screenshot 16 - Resolve Entry Point of injected binary

This corresponds directly with screenshot 6's second entry!

We probably could extract it now, but let's get EIP to point to the entry point first just to be safe.

Extracting

Set a break point at call dword ptr ds:[edi+4] and run to that point.


Screenshot 17 - Execution paused at jump to entry point

Single step using F7 and the EIP should now point to the injected binary's entry point.


Screenshot 18 - Execution at binary's entry point

Now time to dump the binary from memory. Open Scylla and click on Dump Memory under File.


Screenshot 19 - Scylla Dump Memory option

Select the used memory ranges inside of 20010000 and click Dump PE. Give the file a name (choose extension .dll as this turns out to be a dll according to Puppy[^n]) and save the file.


Screenshot 20 - Memory selection in Scylla

Before we can declare victory, let's perform two quick checks to help ensure the dumped file runs.

Check 1: Open the dumped PE file in your favorite PE viewer to see if it can be parsed.

Check 2: Launch the DLL in the debugger to see it if works

  1. Change the IMAGE_FILE_HEADER characteristics value from 210E to 010E to signal that it is an exe versus a dll.[^n]
  • Screenshot 21 - Change the DLL's characteristics
  • Use Save As to save the change in-order to not overwrite the original dumped file.
  • Start the exe in x64Dbg and confirm the RVA of the starting address is 7C79.

And, hopefully, Victory!


Conclusion

Overall nothing deep here as we successfully dump the injected DLL to disk for further inspection. In the next post of the series we will start to pick apart the DLL's functionality.


References

comments powered by Disqus