Reverse Engineering Necurs (Part 3 – Patching)

Introduction

In the previous post, we started to step through the Necurs sample using WinDbg. We also used IDA Pro to perform static analysis of the malware sample so we could get an idea of where to set breakpoints. However, while stepping through the code, we jumped to a location in WinDbg that was not disassembled by IDA Pro. When we looked a little closer, the hex values in the memory window in WinDbg did not match up with the hex values displayed in IDA Pro. It looked like the malware sample had “unpacked” itself, and we had jumped to a location that’s called the “original entry point”, or OEP. This post is going to describe how to patch the original executable with the unpacked code so we can continue to use IDA Pro to perform static analysis.

I’m going spend some time talking about the information in the PE header. Since discussing the PE header in detail is outside of the scope of this blog post, I’d highly recommend taking a look at an article in CodeBreakers Magazine called Portable Executable File Format – A Reverse Engineer View. The article was written in 2006, but is applicable to this sample. It is pretty lengthy, but is well written and very interesting. It’s also a lot easier to understand than the formal specification of the PE file format.

Section Header Analysis

Before getting started, recall that we are paused at offset 0x40614C in WinDbg. Take a snapshot of the Windows VM and call the snapshot OEP. Then restore the snapshot of the VM that was paused at the entry point of the program. Enter !dh 0x400000 in the WinDbg command window. This was the command that was used to display the entry point of the executable. This command will also display information about the different sections in the malware sample.  The section we are interested in is section 1, the text section.

Section header for the "text" section

Section header for the “text” section

The first item of interested is the virtual address. It has a value of 0x1000. We can determine the location in memory of this section by adding the virtual address value to the module’s base address.  Since the start address of the module was 0x400000, this section was loaded in memory at address 0x401000. If we type this address into the Virtual textbox of WinDbg’s memory window, we can view the hex values that were loaded into memory at this location. If we jump to this location in IDA Pro, we will see that the values in IDA Pro match the values displayed in WinDbg.
WinDbg memory window. Hex values at offset 0x401000

WinDbg memory window. Hex values at offset 0x401000

IDA Pro Hex View tab. Hex values at offset 0x401000

IDA Pro Hex View tab. Hex values at offset 0x401000

The next item of interest in the section header data is the file pointer to raw data. This value is the offset of the section within the executable file itself.  It is located at offset 0x400. If we open the malware sample in a hex editor, and look at the values at this offset, we’ll see that they also match up with the values at offset 0x401000 in IDA Pro and WinDbg.
Hex dump of original exe at offset 0x400

Hex dump of original exe at offset 0x400

The final two items of interest are size of raw data and virtual size. The size of raw data is the number of bytes this section occupies in the executable (0xF200 bytes). The virtual size is the amount of space needed when loading this section into memory (0xF088 bytes). For performance reasons, sections are written to file in 512 byte increments. If a section does not end at a 512 byte increment, the remaining bytes are null padded. If we inspect the data at location 0x400 +  0xF088 = 0xF488 in the hex editor, we will see a series of null bytes used to pad the section to the 512 byte increment. The virtual size is smaller than the size of raw data because the null bytes do not need to be loaded into memory.
Null padding at end of section in executable file

Null padding at end of section in executable file

If we inspect the values at offset 0x401000 + 0xF088 = 0x410088 in IDA Pro and WinDbg, we will see the null padding as well. When an executable is loaded into memory, the memory is allocated in 4096 or 8192 byte chunks.  So, we should see null padding at the end of the text section because the section does not end at a 4096/8192 byte increment.
IDA Pro view of null padding at end of text section

IDA Pro view of null padding at end of text section

WinDbg view of null padding

WinDbg view of null padding

Patching Strategy

We know that the text section is loaded into memory at offset 0x401000. We also know that 0xF088 bytes of memory were allocated for this section.  Finally, we know that the executable has been unpacked in the OEP snapshot. So if we can dump the contents of memory at this offset into a file and replace the text section of the original executable with the memory dump, we should have an unpacked executable that can be disassembled by IDA Pro. We will also have to patch the entry point of the program so that IDA Pro knows where to start disassembling the new executable.

To dump the memory, restore the OEP snapshot. Then in the WinDbg command window, use the following command to dump the memory:

.writemem c:\necurs.bin 0x401000 0x410087.

The command window should display that F088 bytes were written. We will use the necurs.bin file to patch the text section of the malware sample.

The entry point of the malware sample is stored at offset 0x118 in the original executable. This offset shows a value of 0xd460. However, the actual value of the entry point was 0x60D4. The entry point is stored in little endian format, so when we patch this value, we will need to convert the new entry point into little endian format as well. Recall that we jumped to 0x40614C after the executable was unpacked, so we’ll change the bytes at offset 0x118 from 0x60D4 to 0x4C61.

Entry point value at offset 0x118 of malware sample

Entry point value at offset 0x118 of malware sample

The python script shown below was used to patch the malware sample. The original malware sample was named necurs-packed.exe. The memory dump was named necurs.bin, and the patched malware sample was called necurs-unpacked.exe.

python script used to patch packed malware sample

python script used to patch packed malware sample

If we use IDA Pro to disassemble the unpacked executable, and inspect the start subroutine (at offset 0x40614C), the disassembly in IDA Pro matches up with the disassembly in WinDbg. We’re now able to perform a static analysis of the unpacked code while stepping through the code with WinDbg.
IDA Pro disassembly at offset 0x40614C

IDA Pro disassembly at offset 0x40614C

 

WinDbg disassembly at offset 0x40614C

WinDbg disassembly at offset 0x40614C

Some Things To Keep In Mind

It was relatively easy to patch the Necurs malware sample so we could analyze it in IDA Pro. However, there are packing algorithms that also compress the executable code. If this happens, the size of the unpacked section may be larger than the size of raw data in the executable file. If this is the case, the memory dump will not “fit” into the text section of the original executable. If this happens, it’s still possible to patch the executable, but it gets a little bit more complicated. Specifically, the file pointer to raw data field of any other sections would need to be patched to make room for the contents of the memory dump.

Also, even though we patched the entry point of the unpacked executable, the unpacked executable may not run in a debugger in the same way as the unpacked code. Any subroutines that were executed before the jump to the OEP may have written data to memory, and the new start routine may need to access this data. Remember that the main purpose of unpacking the executable in this way was to allow IDA Pro to properly disassemble the malware sample.

Next Steps

In the next blog post, I’ll talk about using scripting in IDA Pro as an alternative to patching the executable.

Tagged with: , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

*