Pages

Monday, April 1, 2013

Analysis of an APT1 binary

In middle of February, Mandiant has released a huge report about cyber threat from Chinese government. Some of the technical details has been disclosed in Appendix C ("The Malware Arsenal") of their report.

Because of this APT buzz, I decided to take a look on one of the binary mentioned in APT1 report in order to know the level of this cyber threat.

After running a script on around 200 samples from APT1, I decided to analyse the binary which look the most strange. Report on VT can be found here.


According to PeID, this binary is not packed but it has 4 ".upx" sections and the OEP is pointing to the
last ".upx" section which is not a normal behavior. The few functions in the import table, the few strings in the binary and a high entropy in all sections confirm that point, the binary is packed! I thought interesting to take a look on this binary in order to understand and maybe discover the packer used as PeID failed to identify it.

Unpacking

Beginning of the packed code (in last .upx section : 0x8000) contains a lot of junk code. After these useless instructions, a loop is used to modify the code which follow the loop. The code after this loop is used to get addresses of LoadLibrary and GetProcAddress thanks to the ImportTableAddress field of the loaded PE file.

LoadLibrary is then used to load "kernel32.dll" and GetProcAddress to get addresses of the following functions :
GetModuleHandleA, VirtualProtect, GetModuleFileNameA, CreateFileA, GlobalAlloc, GlobalFree, ReadFile, GetFileSize, CloseHandle, CreateSemaphoreA, ReleaseSemaphore, Sleep, WaitForSingleObject, CreateThread

After the resolution of these functions, SizeOfImage in PEB->PEB_LDR_DATA->InLoadOrderModuleList is set to 1000 (previous value was 9000). Then, VirtualProtect is called in order to change access to ImageBase of the binary to PAGE_READWRITE.

Then some strings will be decoded from memory before being used for example to load library "kernel32.dll" again and then resolve addresses of VirtualProtect, VirtualAlloc,VirtualFree. As soon as the string has been used by LoadLibraryA or GetProcAddress, the string is replaced by several 0 in memory. With this kind of protection, the process contains few information in memory, so a dump of the actual process memory will be not really interesting for an analyst.

Then, code jumps to the third section (.upx 0x7000) which do similar stuff. Idem for the second .upx section.

The first .upx at RVA 0x5000 (but the last called, as order is reversed) will do similar stuff than previous sections but as this is the last packed section, these actions should be more interested for the unpacked binary.

In fact, this last .upx section will load all DLL used by the final (unpacked) binary and will resolve addresses of all functions :

kernel32.dll : CreateProcess, GetLongPathNameA, GetTempPathA, Sleep, CloseHandle, GetModuleHandleA, GetCommandLineA, GetModuleFileNameA, GetProcAddress, LoadLibraryA, ExitProcess

LZ32.dll : LZCopy, LZOpenFileA, LZClose

MSVCRT.dll : strstr, strncmp, atoi ...

ADVAPI32.dll : RegSetValueExA, RegCreateKeyExA, RegCloseKey

Then code jump in .text section, and OEP is then correct.

This packer uses several tricks to annoy the disassembler/analyst like some jumps in middle of an instruction, "push eax; retn", always true comparison ... but nothing to detect the presence of a debugger or a VM.


Malware features

After unpacking, this binary is in fact a simple downloader. The binary try to confuse IDA with lots of "JZ/JNZ" jumps. In fact, nearly all jumps are using this trick.

IDA confused

Disassembly fixed
The first function called by the unpacked code is used to resolve addresses of network functions. "wininet.dll" library is loaded at runtime with LoadLibrary and then InternetOpenUrlA, InternetOpenA, InternetCloseHandle and InternetReadFile functions addresses are resolved thanks to GetProcAddress. Address of UrlDownloadToFileA from "urlmon.dll" is also resolved with the same method.

The second function used is to assure reboot persistence to the malware. In order to run after a reboot, this malware add an entry to the registry :

[HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"McUpdate"="path_to_this_binary"

Key and subkey values are not stored in clear text in the file but are encoded with a xor algorithm. The following python script decodes all encoded strings used in this binary :



Then malware contacts its C&C to get an order. URL is encoded with the aforementioned algorithm. After decoding, URL is : http://216.15.210.68/197.1.16.3_7.html. After decoding, User-Agent used to connect to the C&C is "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)". If it can't contact the C&C, it will wait 10 minutes before retry. After 3 fails to get a command from the C&C, the binary ends its execution.

Commands on the C&C server are between "<!-- DOCHTML" and "-->" HTML tags. These two tags like the following commands are also encoded in the binary. Command can be one of the following :
- Ausov : Exit the program
- Author X : Wait X * 10 minutes
- http://url : url used to download and execute an other binary.

When the last command is obtained from C&C, the file pointed by the url is downloaded to the temporary folder thanks to UrlDownloadToFile function. As the downloaded file can be compressed by Lempel-Ziv algorithm, the malware opens the downloaded file with LZOpenFile. An other file is created with nearly the same path than the first file opened : ".exe" extension is added at the end. Then, content from the first file (the downloaded one) is copied (and decompressed if necessary) to the second thanks to LZCopy function.

After that, the copied (and uncompressed) file is executed with CreateProcessA.


After analysis, the aim of this malware is simple : download and execute (more advanced?) binaries on the victim computer. This malware seems to be one of the WEBC2-AUSOV family defined by Mandiant as "Ausov" is a command of this sample.

I have not being able to identify the packer used. So if you recognized it, feedback will be welcome ;-)