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.
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.
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.
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.
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.
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.
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.
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.