Zender Malware

Grok time ~9 minutes

Intro

I’ve been working through Practical Malware Analysis and taking diversions into the some fantastic chapters Dr. Fu’s Malware Analysis Tutorial. Dr. Fu also links to some great resources, including: - A 2011 UCSB class (CS290G): Host-based Security and Malicious Code

Another great reference is Malware Analyst’s Cookbook. It’s actually built cookbook-style with recipes for different types of processes you need to do.

The Lab

My setup is based on a few VMs. The host is a Win8.1 MSI GE70 running VirtualBox. The guests are:

OS Purpose
Windows 7 x64 Primarily used for acquiring malicious files. The files are then compressed and encrypted with 7-zip before being dropped into a shared folder with the host.
Windows XP SP2 The analysis VM. I pull the 7z archive from the shared folder and get to work with various tools. The network is VirtualBox’s “Internal Network” with the default gateway and DNS set to my Debian box.
Debian (Wheezy) Runs Inetsim. All DNS resolves back to Inetsim, fake files are served for any requests and redirection is turned on as well.

The Malware

Name Zender
File Name zender1.exe
File Size 1,063,572 bytes (1.01MB)
Family Win32/Kelihos (?)
Type Trojan & Spambot
Source 89.144.xxx.xxx (UK-based server for a small tech services company)
Hashes MD5: F3BBC6C7E45D0503A6F9E397798EC09D1
SHA1: 1C81A258640142DA0740C8ADDAD8341138958DB7
SHA256: F83E964E7FCF5EABA7889F62630685DBD298F88519D0DF9B1385FB981B9043BC
Callback IPs 94.76.78.20, 37.229.235.67, 46.118.54.70, 176.8.157.75, 176.101.197.10, 190.254.65.114, 92.113.60.116, 86.124.225.116, 78.84.123.145, 46.118.80.240, 5.105.56.87
The IP ISPs are primarily in Ukraine but also Russia, Romania, Latvia & Colombia
Ports &
Protocols
From: Sequential ephemeral ports
To: TCP/80
Detection Windows Defender recognizes it as part of the Win32/Kelihos trojan/botnet. The MD5 and SHA1 hashes didn’t return anything on VirusTotal. I hadn’t tried SHA-256. Once I uploaded it, only 8/57 antivirus programs recognized it as malicious.

Prior Art

If this thing is actually part of Kelihos, I’m not seeing the similarities just yet. That classification was based solely on Windows Defender so I’m actually not sure just yet.

Kyle Yang of Fortinet gave a great presentation at BlackHat 2012:Google Docs PDF or Original PDF. Ditto for a group of researchers at BotConf 2012: Google Docs PDF or Original PDF


Static Analysis

Strings

Most strings are just garbage, plus a couple DLL names. Most of the ASCII characters it finds are actually part of the toolbar bitmap in the .rsrc section (Location: 0x00406180, Length: 1064 bytes). I found no IPs or domain names.

Imports

Library Notes
advapi32 For opening the registry and checking security permissions.
gdi32 Presumably for drawing an interface, or appearing to be a legitimate piece of software.
kernel32 All the good stuff.
mfc42 Wraps the Windows API in an easier-to-use API. Version 4.2 is from the days of Windows 98.
msvcrt The C runtime libraries (which were removed from MFC in v4.2).

I’m guessing this file was originally a normal document editor that’s since been infected (and broken), or the authors just used a Visual Studio project template, considering an embedded bitmap toolbar that looks like it came out of Notepad and other imports like DoPreparePrinter, SaveAllModified, LoadToolbar, etc.

Functions

Half the functions are just stubs or appear to wrap some part of the Windows API. This may be the MFC stuff or intentional obfuscation; IDA failed to analyze some of them but there aren’t so few that it appears packed. In fact, multiple tools failed to recognize any packing.


Dynamic Analysis

First, Zender changes its own file attributes to Hidden and Archive. It does not hide itself from the Task Manager; even after a reboot, it remains in the process listing. With Process Monitor, I can see it iterates through hundreds of directories to see what’s on my box. It does the same with the registry but I’m not sure yet which are a “normal”.

For this variant at least, just renaming the EXE before rebooting appears to stop it in its tracks. I’d renamed the file and then noticed it wasn’t in Task Manager. Even if it was hiding itself from the listing, I saw none of the previous network activity through WireShark.

Without connection redirection turned on in Inetsim, the only outbound connections I captured were SYN requests to TCP/80. The IPs have to be hardcoded as no internet connection was available for it to get that data. However, they are not in the assembly as plaintext so it must be decrypting them on-the-fly. With connection redirection turned on, the handshake completes and Zender sends a TCP PSH with a bunch of, apparently encrypted, data.

I spent a bit of time searching for data cross-references. I found one long jumble of data at 0x405090 referencing 0x4021DD.

.data:00405090 byte_405090   db 0CDh  ; DATA XREF: .t:crypto_4021DD
.data:00405091               db  37h  ; 7
.data:00405092               db 0E4h  ; S
.data:00405093               db  0Ah
.data:00405094               db  7Eh  ; ~
.data:00405095               db 0D5h  ; +
.data:00405096               db 0CAh  ; -
.data:00405097               db    3
[ ... ]
.t:004021DD crypto_4021DD:               ; CODE XREF: .t:00402233
.t:004021DD                 mov     dl, ds:byte_405090
.t:004021E3                 lea     eax, [ecx+esi]
.t:004021E6                 mov     bl, [ebp+eax-0BA8h]
.t:004021ED                 mov     eax, 7D8C42B3h
.t:004021F2                 xor     bl, dl
.t:004021F4                 imul    edi
.t:004021F6                 sar     edx, 8
.t:004021F9                 mov     eax, edx
.t:004021FB                 shr     eax, 1Fh
.t:004021FE                 add     edx, eax
.t:00402200                 mov     [ebp+edx-0BA8h], bl
.t:00402207                 mov     al, [ebp+esi-0BA8h]
.t:0040220E                 cmp     al, 44h
.t:00402210                 ja      short loc_40221B
.t:00402212                 dec     al
.t:00402214                 mov     [ebp+esi-0BA8h], al
.t:0040221B
.t:0040221B loc_40221B:                 ; CODE XREF: .t:00402210
.t:0040221B                 inc     esi
.t:0040221C                 add     edi, 20Ah
.t:00402222                 mov     [ebp+8], esi
.t:00402225                 fild    dword ptr [ebp+8]
.t:00402228                 fcomp   ds:dbl_403AD0
.t:0040222E                 fnstsw  ax
.t:00402230                 test    ah, 44h
.t:00402233                 jnz     short crypto_4021DD
.t:00402235                 jmp     loc_4021A0

This contains an xor with two different operands (so it’s not just zeroing out a register). I followed the code in OllyDbg and noticed a segment just above it that it jumped to, then it skipped a couple lines based on a floating-point register. I set a breakpoint on that (0x4021B0) and let it run. It stopped on the breakpoint and I followed it to the decrypted code at 0x12E874. That was a call to 0x12EA86.

mov eax, 4120
call 0012EE04
push ecx

Eventually, I find myself at 0x12EA93. It just moves text to memory: “kernel32.dll” is written to 0x12CCB0, “GetModuleFileNameW” to 0x12CC5C, “CreateFile” to 0x12CC80, “VirtualAlloc” to 0x12CC70, “GetFileSize[NULL]ReadFile” to 0x12CC98.

It messes with EAX to push a couple addresses in this range onto the stack and continues writing more function names to the area. Then it calls 0x12E8A4, pushes more addresses (0x2D680, 0x2D680, 0x00, 0x92A, 0x12AFA4, 0xD5786, 0xD4E88) on the stack and calls 0x12E8D5.

Pushes more stuff, gets the name of the file from ECX+30 (0x241F10), pushes more stuff and calls 0x12E956.

At 0x12E956, it iterated through the EXE’s name (and then several WinAPI DLLs) and appeared to encrypted the file names. If I watched it right, the key for the OR operation is ` $ $ $ $ $` $ (without the spaces… markdown syntax stuff).

Following a bit more, at 0x12E906, it pushes 0x7C800000 into EAX. That address contains a PE image. The PE signature is at 0x7C8000F0 so the size is at offset+0x50. The hex, 0x0060, is little endian so the image size is 0x6000. The memory doesn’t actually go that far; 0x42 is the last non-zero byte at 0x7C800287.

CPU Dump
Address   Hex dump                                         ASCII
7C800000  4D 5A 90 00|03 00 00 00|04 00 00 00|FF FF 00 00| MZ.......ÿÿ..
7C800010  B8 00 00 00|00 00 00 00|40 00 00 00|00 00 00 00| ¸.......@.......
7C800020  00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
7C800030  00 00 00 00|00 00 00 00|00 00 00 00|F0 00 00 00| ............ð...
7C800040  0E 1F BA 0E|00 B4 09 CD|21 B8 01 4C|CD 21 54 68| º.´.Í!¸LÍ!Th
7C800050  69 73 20 70|72 6F 67 72|61 6D 20 63|61 6E 6E 6F| is program canno
7C800060  74 20 62 65|20 72 75 6E|20 69 6E 20|44 4F 53 20| t be run in DOS
7C800070  6D 6F 64 65|2E 0D 0D 0A|24 00 00 00|00 00 00 00| mode....$.......
7C800080  17 86 20 AA|53 E7 4E F9|53 E7 4E F9|53 E7 4E F9| † ªSçNùSçNùSçNù
7C800090  53 E7 4F F9|D9 E6 4E F9|90 E8 13 F9|50 E7 4E F9| SçOùÙæNùèùPçNù
7C8000A0  90 E8 12 F9|52 E7 4E F9|90 E8 10 F9|52 E7 4E F9| èùRçNùèùRçNù
7C8000B0  90 E8 41 F9|56 E7 4E F9|90 E8 11 F9|8E E7 4E F9| èAùVçNùèùŽçNù
7C8000C0  90 E8 2E F9|57 E7 4E F9|90 E8 14 F9|52 E7 4E F9| è.ùWçNùèùRçNù
7C8000D0  52 69 63 68|53 E7 4E F9|00 00 00 00|00 00 00 00| RichSçNù........
7C8000E0  00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
7C8000F0  50 45 00 00|4C 01 04 00|92 3B 20 53|00 00 00 00| PE..L.’; S....
7C800100  00 00 00 00|E0 00 0E 21|0B 01 07 0A|00 40 08 00| ....à.!..@.
7C800110  00 04 07 00|00 00 00 00|4E B6 00 00|00 10 00 00| ......N¶.....
7C800120  00 10 08 00|00 00 80 7C|00 10 00 00|00 02 00 00| ....€|......
7C800130  05 00 01 00|05 00 01 00|04 00 00 00|00 00 00 00| ...........
7C800140  00 60 0F 00|00 04 00 00|D5 63 0F 00|03 00 00 00| .`....Õc....
7C800150  00 00 04 00|00 10 00 00|00 00 10 00|00 10 00 00| ............
7C800160  00 00 00 00|10 00 00 00|2C 26 00 00|19 6D 00 00| .......,&..m..
7C800170  00 26 08 00|28 00 00 00|00 A0 08 00|E8 5E 06 00| .&.(.... .è^.
7C800180  00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
7C800190  00 00 0F 00|D8 5C 00 00|F0 4E 08 00|38 00 00 00| ...Ø\..ðN.8...
7C8001A0  00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
7C8001B0  00 00 00 00|00 00 00 00|B8 EB 04 00|40 00 00 00| ........¸ë.@...
7C8001C0  00 00 00 00|00 00 00 00|00 10 00 00|24 06 00 00| ...........$..
7C8001D0  00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00| ................
7C8001E0  00 00 00 00|00 00 00 00|2E 74 65 78|74 00 00 00| .........text...
7C8001F0  51 3F 08 00|00 10 00 00|00 40 08 00|00 04 00 00| Q?.....@....
7C800200  00 00 00 00|00 00 00 00|00 00 00 00|20 00 00 60| ............ ..`
7C800210  2E 64 61 74|61 00 00 00|40 44 00 00|00 50 08 00| .data...@D...P.
7C800220  00 26 00 00|00 44 08 00|00 00 00 00|00 00 00 00| .&...D.........
7C800230  00 00 00 00|40 00 00 C0|2E 72 73 72|63 00 00 00| ....@..À.rsrc...
7C800240  E8 5E 06 00|00 A0 08 00|00 60 06 00|00 6A 08 00| è^.. ..`..j.
7C800250  00 00 00 00|00 00 00 00|00 00 00 00|40 00 00 40| ............@..@
7C800260  2E 72 65 6C|6F 63 00 00|D8 5C 00 00|00 00 0F 00| .reloc..Ø\.....
7C800270  00 5E 00 00|00 CA 0E 00|00 00 00 00|00 00 00 00| .^...Ê.........
7C800280  00 00 00 00|40 00 00 42|00 00 00 00|00 00 00 00| ....@..B........

Update: I had the second post partially written for this but had a bit of a catastrophic failure after moving. I may get around to continuing but I’ve mostly moved on.