Whether it's to circumvent an anti-analysis check, or simply a bug that needs to be fixed, patching a binary is a useful technique to have in the reverse engineer's toolbox. Normally patching refers to a process where a patch file is generated and then applied to a binary. IDA Pro actually contains functionality to do this and there is an excellent tutorial on the subject here. But today we will be patching by simply editing a few bytes in the binary with a hex editor. It's quick, it's dirty, and it works.
Patching a binary will almost guarantee that it will not execute as intended. Quick patching should only be used when the focus of your analysis is limited to certain functionality that won’t be affected (ex. C2 communication, or encryption routines).
A while back a friend asked me to look at a malware sample that wasn't running in his sandbox. It turns out the malware contained two threads; one with some juicy indicators, and one that did some "other stuff" (official revers engineering terminology). Unfortunately the "other stuff" thread was killing the process before the "juicy indicator" thread had a chance to reveal itself to the sandbox. All I needed to do was patch the binary so the "other stuff" thread was never created. The following article outlines the steps I took to patch the binary.
Before we proceed we need to make sure we have the following tools:
- IDA disassembler
- Hex editor
Identify The Code
The first step in patching the binary is to identify the code that we want to patch. For this we need to load the malware in IDA look at the disassembly view. The image below shows the main function of the malware. Here we can see where the the two threads are created.
<img alt="Figure 1 - Two threads created" src="/content/images/2017/10/Screen-Shot-2017-10-22-at-5.26.15-PM.png" style="width: 600px;>
Next we need to see the opcodes for the disassembled instructions. The opcodes will match the hex bytes in the binary file that we intend to edit. To show the the opcodes in IDA you need to set the number of opcodes to be shown in the following menu:
Options -> General -> Number of opcode bytes
We will choose to show 15 bytes as this is maximum length of an Intel 64 and IA-32 instruction.
<img alt="Figure 2 - IDA opcode display" src="/content/images/2017/10/Screen-Shot-2017-10-22-at-5.54.47-PM.png" style="width: 600px;>
Now that we can see the opcode we are able to determine which bytes we want to edit in the binary.
<img alt="Figure 3 - Opcodes for the instructions we want to remove" src="/content/images/2017/10/Screen-Shot-2017-10-22-at-5.26.15-PM-1.png" style="width: 600px;>
In our example we want to remove the second call to
CreateThread as well as the arguments that were pushed onto the stack for the call. This means removing the bytes
6A 00 6A 00 6A 00 68 90 24 00 10 6A 00 6A 00 E8 8F 12 00 00. We want to keep the instruction that moves the returned thread handle
eax from the original call to
esi as this is later passed to
WaitForSingleObject in order to wait for the thread to terminate before the process exits.
Edit The Binary
Now that we know which bytes we need to change we can open the binary in a hex editor and start editing. Your choice of hex editor doesn't matter much using an editor that has a built in binary search function will make the process a lot quicker. My preferred hex editor is Synalyze It! for OSX.
With the binary search feature we can search for the opcode bytes
6A 00 6A 00 6A 00 68 90 24 00 10 6A 00 6A 00 E8 8F 12 00 00 that we identified in the previous step. This way we don't have to mess around with calculating the RAV from the IDA address.
<img alt="Figure 4 - Hex editor opcodes located" src="/content/images/2017/10/Screen-Shot-2017-10-22-at-6.36.14-PM.png" style="width: 600px;>
Now that we have found the opcode bytes in the binary we can simply edit them. But, we can't just delete them! Remember these are bytes in a PE file and if we start removing bytes we could corrupt the PE by changing the size of the sections. Instead we need to replace the bytes with an instruction the does nothing - the
NOP instruction. The hex value for a
0x90, so we can use this to replace the opcode bytes we want to remove.
<img alt="Figure 5 - Opcodes replaced by NOP" src="/content/images/2017/10/Screen-Shot-2017-10-22-at-6.49.15-PM.png" style="width: 600px;>
Remember we need to preserve the bytes
8B F0 which we are now using to copy the handle to the thread we are interested in to the
WaitForSingleObject function. Once the binary is edited we can save it and open it again in IDA to verify we patched the right bytes.
<img alt="Figure 6 - Verify the patch in IDA" src="/content/images/2017/10/Screen-Shot-2017-10-22-at-6.53.30-PM.png" style="width: 600px;>
In IDA we can see that the all of the code used to create the second thread has been removed. Our patch is a success!