Reverse Engineering Necurs (Part 4 – IDA Pro’s Python API)

Introduction

In the previous post, we had paused execution of the malware sample at a point where the malware had “unpacked” itself. We then used the .writemem WinDbg command to output the unpacked data into a file. Finally, we used a Python script to “patch” the original malware sample so we could analyze the unpacked malware with IDA Pro. In this post, we’re going to take a look at using IDA Pro’s scripting capabilities to achieve the same thing.

Python scripts can be used to automate tasks in IDA Pro. This is a pretty nice thing because you can use standard Python functions for doing things like opening and reading files. You will only need to use IDA Pro’s Python API when you need to do something IDA Pro specific. This means the learning curve is not as bad as it could have been if IDA Pro had setup a scripting language from scratch.

Manually Patching Data in IDA Pro

A screenshot of the IDA Pro disassembly view of the malware sample at offset 0x40614C is shown below. Recall from the last blog post that this address is called the original entry point of the malware sample. When we used the Python script to patch the malware sample, we reset the entry point of the program to this address.

The data at this offset was not disassembled by IDA Pro when analyzing the original, packed malware sample. However, even if IDA Pro had disassembled the data, the disassembled instructions would not match the instructions being executed in WinDbg because the values starting at this location were changed when the malware unpacked itself.

IDA Pro disassembly view

IDA Pro disassembly view

To start to work with this data, we’re going to look at patching the information in IDA Pro manually. If you right-click on the first 4-byte value at offset 0x40614C (the value 9CCB38F8h), a context menu will be displayed.

 

IDA Pro context menu after right-clicking on data

IDA Pro context menu after right-clicking on data

If you click on “Undefine” and answer “yes” to the confirmation dialog, IDA Pro will display each byte of data on its own line. Its a little bit easier for me to work in IDA Pro if I start by reformatting the data in this way. The disassembly view should now look like this:

 

IDA Pro disassembly view after reformatting

IDA Pro disassembly view after reformatting

Next, click on the byte value (2Bh) at offset 0x40614C in the disassembly view. You should see the “2Bh” highlighted in yellow. From IDA Pro’s menu bar, select Edit -> Patch program -> Change byte…, and IDA Pro will display a dialog box where you can make changes. The dialog will allow you to change a number of bytes, not just a single one.

 

IDA Pro Patch Bytes dialog

IDA Pro Patch Bytes dialog

We’re going to replace the first nine bytes in the dialog box with the following bytes: 55 8B EC 81 EC D4 00 00 00. After clicking on “OK”, the patched bytes will be displayed. Next, right-click on the 55h at offset 0x40614C. From the context menu that is displayed, click on “Code”. IDA Pro will provide a disassembly of the data starting at that offset. Since we only patched 9 bytes, only the first three instructions will match the instructions in the WinDbg disassembly window. The fourth instruction does not match the instruction in WinDbg.

 

IDA Pro - patched instructions

IDA Pro – patched instructions

 

WinDbg disassembly at OEP

WinDbg disassembly at OEP

IDA Pro and Python

The next thing we’re going to do is experiment with entering Python commands in the IDA Pro console. Before doing so, right click on the text jns that is next to offset 0x406155 of the disassembly view, and select Undefine from the context menu that is displayed. The disassembly view should now look like:

 

IDA Pro disassembly view after undefining instructions

IDA Pro disassembly view after undefining instructions

The input for the console window will have the label “Python” next to it and is located toward the bottom of the IDA Pro display. This is where we will type our Python commands.

 

IDA Pro console

IDA Pro console

Documentation for the Python API can be found at IDA Pro Python API. The documentation is pretty lengthy, but, if you use the menu options in IDA Pro’s interface for search terms, you might have an easier time finding the functions you are interested in. In this example, we are using the Patch program… -> Change byte menu option, so I searched the web page for the text “patch”. One of the search results was a function called idaapi.patch_byte.

Even though there are a lot of API functions listed on the site, the documentation for each function does not seem very detailed to me. The only documentation I could find at this site is a function definition: bool patch_byte(ea, x). But, if you google “byte_patch”, you can find some additional help. The ea parameter refers to the address of the byte in the disassembly window, and x is the value that we want to use as the replacement value.

Suppose we want to change the byte value at offset 0x406155 from 79h to 53h. If you type patch_byte(0x406155, 0x53) into the console, and then hit the enter key, you should see the value change. So, we have verified which Python API function to use to patch a byte value at a specific location in the disassembly.

 

Patching a byte using patch_byte in the IDA Pro console

Patching a byte using patch_byte in the IDA Pro console

IDA Python Scripts

Now that we have found a IDA Pro Python function that will replace a byte in the disassembly with a byte of our choosing, we can write a script that will read the memory dump we produced in the previous post, and use the information in the file to patch the bytes in the disassembly. The script used to patch the disassembly is shown below:

 

Python script used to patch IDA Pro disassembly

Python script used to patch IDA Pro disassembly

A couple of things to note about the script. First, we are going to use the data starting at offset 0x514C to patch values at 0x40614C of the disassembly. Why? In the previous post, we used the command .writemem c:\necurs.bin 0x401000 0x410087 to dump the contents of the code section in memory to a file. Since we started dumping memory at 0x401000, the byte at offset 0x514C in the file will correspond to the byte at offset 0x401000 + 0x514C = 0x40614C in the disassembly. Second, the memory file necurs.bin must be in the same directory as the malware sample. If not, you may need to fully qualify the file path when making the open() call in the script. Third, there are a couple of print statements to show that the script started and finished. These are included because IDA Pro does not always display a message telling you if your script ran or not.

To run the script, select File -> Script file… from the IDA Pro menu bar. Select the script in the file dialog that is displayed, and click open. The script will run at this point and you should see some output that tells you the script ran in the console window. The bytes should also be patched once the script finishes.

After the script has finished, right-click on the address 0040614C in the IDA Pro disassembly view and click on Code in the context menu that is displayed. The disassembly should look like the screenshot shown below. Notice that the disassembled instructions match up with the disassembly in WinDbg.

 

Disassembly after running the patch script

Disassembly after running the patch script

Next Steps

Now that we have a disassembly of the unpacked malware, we will start to step through the code again using WinDbg.

 

 

Posted in Reverse Engineering Tagged with: , ,

Leave a Reply

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

*