Analyzing Malware with Anti Disassembly

This post will go over my analysis of the Lab15-03 binary from Practical Malware Analysis. The binary can be found here.

Running the Program

The program itself looks like a harmless tool that lists a bunch of information about all running processes and the dll’s they load. Since this binary is in a chapter about static analysis, it makes sense that most of the work here will be done in IDA.

Part of Lab15-03.exe output

Static Analysis

Modifying return address

Initially, the program looks to be a non-malicious binary that does exactly what we observed by running it. If we look towards the beginning of the _main function, we can see that IDA has highlighted part of the mov [ebp+4], eax instruction. This is highlighted because IDA does not expect a function to modify a value outside its own stack frame.

IDA highlighting suspicious mov instruction

The call instruction places the address of the next instruction on the stack so when the called function returns, execution can continue in the caller. The retn function will pop the value of the return address off the stack and move pc to that address. This piece of malware exploits this mechanic by overwriting the return address at ebp+4 to some malicious code hidden in the binary. After main is finished, the malicious payload beginning at address 0x40148C will execute.

Stack at mov instruction

Jumping Under Constant Condition

When we disassemble the code near 0x40148C, we quickly find that IDA generates some weird disassembly. IDA tells us that this disassembly is suspicious by highlighting the address of the jmp instruction at 0x401496. Looking up at the previous two instructions, we see a sequence that always results in a jump to 0x401497. IDA has already disassembled the byte at that address as part of a bad jump instruction.

Jumping with a constant condition

We can fix this by patching the 0xE9 byte to a nop so IDA can correctly disassemble the rest of the function.

Exception Handling

The next chunk of code disassembled looks like something that prints a message to the user. When we ran this binary we never saw this message. This code is a distraction to hide the interesting functionality of this software.

Exception handling

The three instructions starting at 0x401487 sets up an exception handler. Windows uses the fs segment to store information about the current thread. The first piece of data in this segment is a pointer to a linked list of exception handlers. When an exception occurs, the CPU will try to execute the first handler in the list. If that handler cannot recover from the exception, it will pass to the next handler. These three instructions create a handler with code at 0x4014C0 on the stack. It then stores the address of this handler at fs:0.

The next two instructions cause an exception to occur. The ecx register is set to zero used to divide. Once this exception occurs, control will go to the exception handler made previously. Since the following instructions never execute, we can simplify the code to an unconditional jump to 0x4014C0 so that stack analysis goes smoothly in the future. To continue with analysis, we need to examine 0x4014C0

Impossible Disassembly

IDA did not disassemble the data at 0x4014C0. This is fine because we can press c while highlighted over the raw bytes. IDA will disassemble from this address and we can make more sense of the is happening.

Jmp instruction reusing its own bytes

The disassembly produced by IDA reveals some code that cleans up after the weird exception handling stuff. Following that is an interesting jmp instruction. This instruction will jump to the second byte of the jmp instruction. Reusing bytes in instructions confuses IDA because it does not have a good way to display that there are more than one instructions at the same address. The disassembler continues but cannot disassemble the next byte because 0xC0 is not a valid opcode. We can fix this by turning the first byte of the jmp into a nop. It is important to note that this only helps us understand the functionality since we are creating functionally equivalent code. It may be confusing if we debugged this program because the jmp instruction actually does execute.

Jumps with the same target

The code revealed after patching the jmp decodes two strings from memory uses them to download a file from a remote server. After the download, we see a combination of a jz and a jnz that both go one byte into a call instruction. Functionally, this is the same thing as an unconditional jump to the fixed instruction. The benefit of this technique is that IDA will disassemble the code as if the branch was not taken first. When it tries to disassemble the code as if the branch was taken, it sees that that address is already part of an instruction so no further processing is needed.

Using two jumps to make a jump to constant condition

We can just treat this as a jump under a constant condition and nop out the byte not executed. Once this patch is complete, we can define go to 0x4014c0 and press p. IDA will define the this malicious portion of the code as a function and we can easily read it in graph mode or decompile it with Hexrays.