In the previous post, we talked about using tcpdump on a VM to monitor network traffic produced by another VM infected with Necurs. We noticed that some “weird” UDP packets were being generated after infection, and used this observation to verify that the malware sample would run in a virtual environment, as well as in a debugger. In this blog post, we’re going to try to figure out the location of the instructions that are responsible for generating the UDP packets. We’re not going to succeed (at least not yet), but we will see some interesting things.
Pausing at the Malware’s Entry Point
In the previous post, we located the entry point of the Necurs malware sample in WinDbg so we that we could use a debugger to analyze the sample. While in WinDbg, I like to have several windows opened and docked so I can see the disassembled code, view memory, and issue commands to the debugger. So I usually use the icons in the toolbar to open a memory window and disassembler window. The command windows opens automatically when you open the executable. An image of my layout is shown below. After I setup this layout, I took a snapshot of the VM, so I could quickly return to the WinDbg session paused at the malware’s entry point.
Some things to note about the layout: a breakpoint was set at the entry point of the program, and the program has paused execution at the breakpoint. This instruction is highlighted in purple in the disassembler window. The display format in the memory window is “byte”, and the entry in the “virtual” text box is “@$scopeip”. As long as these settings are used, the memory window will display the hex values currently in memory starting from the offset of the paused instruction in the disassembler.
Analyzing the Start Subroutine
We’re going to begin by analyzing the Start subroutine in IDA Pro. A snapshot of the routine is shown below. There are two instructions in the subroutine: a call instruction to sub_406E5D and a jmp to loc_403474. Remember that our goal is to find the code that generates the UDP traffic we observed in tcpdump. One would think that either the call to sub_406E5D will eventually execute the instructions that generate the UDP packets or the jmp instruction will do so. In WinDbg, we are going to step over the call to sub_406E5D and then monitor the output of tcpdump on the Ubuntu VM. If we start seeing the “weird” UDP packets that we saw when we ran the malware sample in the previous blog, we’ll know that if we further analyze sub_406E5D (and all the subroutines it may call), we should find the code that generates the UDP traffic. If not, the jmp to loc_403474 should eventually lead us to the code that generates the UDP packets.
To step over the call to sub_406E5D, enter p into the WinDbg command window. If you wait a few seconds, you should see the “weird” UDP packets in the tcpdump output. This means that we need to analyze sub_406E5D. Next, we want to restore the snapshot so that we are in WinDbg at the malware’s entry point. Instead of stepping over sub_406E5D, enter t into the command window to step into the subroutine.
If we look at sub_406E5D in IDA Pro, we’ll notice that there are no call instructions. Instead, there is a jmp instruction to an address that’s stored in the ecx register. A few lines above the jmp instruction, you will see the address of sub_402C4B being loaded into the ecx register. It’s pretty strange to use this set of instructions to jump to a subroutine instead of simply using a call instruction. When a call instruction is executed, the address of the instruction after the call instruction is pushed onto the stack before code execution is transferred to the subroutine. Once the subroutine ends, execution can be transferred to the address that was stored on the stack. We’ll see later in this post what happens when jmp is used instead of call in this subroutine.
Next, I used the p command in the WinDbg command window to step over instructions until I arrived at the first instruction in sub_402C4B.
If we analyze sub_402C4B, we will see that it is a pretty long subroutine with a number of call instructions. Many of the call instructions have text strings next to them (for example, the call to LCMapStringA at 0x402D38). These are calls to Windows API functions. If you are interested in learning more about the API calls, documentation for most of the API functions can be found on the Microsoft Developer Network website (msdn.com). There are also calls to sub_xxx subroutines, where xxx is a location within the malware sample. These subroutines have been disassembled by IDA Pro. Since none of the Windows API functions in this subroutine appear to be network related, they probably do not generate the UDP packets we are seeing in tcpdump.
So, we are going to focus on the calls to the sub_xxx subroutines. These are the subroutines that are called in sub_402C4B:
- sub_402BE2 (at 0x40308E and 0x4030AA)
- sub_401000 (at 0x403188)
- bp 0x40308E
- bp 0x4030AA
- bp 0x403188
Next, we type p in the command window to step over the subroutine. When program execution pauses, the instruction at 0x403093 is highlighted in blue. This means that this is the next instruction that will be executed, but its not purple because no breakpoint is set on that line. If you look at the tcpdump output on the Ubuntu VM, there should be no “weird” UDP packets generated by the infected VM. Since we did not see any UDP packets, the call to this subroutine is not responsible for the UDP traffic.
Next, after typing g into the command window, program execution paused at 0x4030aa. Once again we can type p to step over the subroutine and check the tcpdump output for UDP packets. Once again, no UDP packets are displayed in the tcpdump output, so the call to this subroutine is not responsible for the UDP traffic. Next, we type g to continue executing the program. However, this time, we do not hit another breakpoint. Instead, the program exits. If we look at the tcpdump output, we will see UDP traffic being generated by the infected VM.
Why Didn’t We Hit Another BreakPoint
Based on the static analysis, it looked like either sub_402BE2 or sub_401000 was responsible for generating the UDP traffic. But, we found that even though sub_402BE2 was called twice, it was not responsible for generating the UDP traffic, and that sub_401000 was never called. What happened?
There’s a couple of reasons this may have happened. First, we may have hit a jump statement within sub_402C4B that took us someplace unexpected. The second is that we hit a retn instruction, and were returned to an unexpected place. We will focus on finding a retn statement. First, restore the snapshot of the infected VM where the malware was paused at the entry point. Then, set a breakpoint at 0x4030AA, the last breakpoint that was hit in the previous paragraph. Type p into the WinDbg command window to step over the subroutine, then type pt. This command will continue execution until the next retn instruction, and then pause the program. The program should pause at 0x403180. Then type p to execute the retn instruction. The program will then pause execution at instruction 0x402296.
Remember when we were analyzing sub_406E5D, and execution was transferred to sub_402C4B with a jmp instead of a call instruction? The malware placed the address of sub_402296 on the stack so that when sub_402C4B completed execution, code execution would be transferred to sub_402296. This is an example of a technique used to hinder static analysis in IDA Pro. However, stepping through the program allowed us to determine where code execution resumes, and we now have a new subroutine to analyze.
Once again, we will start by looking at IDA Pro, and identify the possible subroutines that we want to step over and monitor. The following subroutines are called within sub_402296:
- sub_40200A (0x4023A1)
- sub_402241 (0x402449)
- sub_40320F (0x4024A6)
- sub_402AE8 (0x40298D)
- sub_4031D4 (0x4029F3)
Once again, we will restore our snapshot at the program entry point. This time, we need to set a breakpoint at 0x4024A6, the last breakpoint that we successfully hit. Enter g in the WinDbg command window and the malware should pause at the breakpoint.
Next, we’ll take a closer look at the IDA Pro disassembly. We know that we’re not running into an unexpected retn instruction, so we’ll look at the jmp instructions instead. Most of the jmp instructions will jump to a known location in the malware sample. For example, the jmp instruction at 0x4025DB jumps to loc_4025EA. However, the instruction at 0x40290C is a little more interesting. It’s a location determined at runtime, as shown below.
If we set a breakpoint on this location, and then type g in the command window, the malware will pause execution at this point. Next, type p to execute the jump instruction. The next instruction that will be executed is at 0x40614c. If you look in IDA Pro, this portion of the malware was not disassembled, as shown below.
There’s something else that is odd about this code. If you switch to the hex view in IDA Pro, and jump to address 0x40614C (by selecting “Jump to address” from the “Jump” menu item), you will be able to view a hex dump of the code at that offset. If you look at the hex output in the WinDbg memory window, you will see that the hex outputs do not match.
Some of the previous subroutines that we stepped over probably unpacked this portion of the executable. Once unpacked, code execution was transferred to this portion of the malware. So, even if we tried to manually disassemble this portion of code with IDA Pro, since the values at this offset were changed, the disassembly would not match the code being executed in WinDbg.
In the next blog post, I’ll talk about some techniques for patching the malware sample and the data in IDA Pro. After doing so, we’ll be able to use IDA Pro to disassemble the unpacked code so we can continue with our static analysis.