Here is a little story of how I approached the malware of the day, I hope to entertain you a little with this light post.
The malware is MFC based, and among all the sections there is one with a suspicious name: “.aspack”. It’s a good starting point, too bad the section is neither packed nor protected. The code is clear, but the strings are encoded using base64. It’s easy to recognize them due to their nature, some samples:
All these encoded strings refer to API functions, and they are used by the executable following this precise scheme:
405818 DecodeExecCreateDirectoryA proc near 405818 push esi 405819 push edi 40581A push Str_dll ; Encoded DLL name 405820 xor edi, edi 405822 call Base64DecodeString ; Decode DLL name: "kernel32.dll" 405827 pop ecx 405828 push eax 405829 call ds:LoadLibraryA ; Load the DLL 40582F push offset _CreateDirectoryA_String ; Base64 encoded string: "Q3JlYXRlRGlyZWN0b3J5QQ==" 405834 mov esi, eax 405836 call Base64DecodeString ; Decoded function name "CreateDirectoryA" 40583B pop ecx 40583C push eax 40583D push esi 40583E call ds:GetProcAddress 405844 test eax, eax 405846 jz short loc_40585B 405848 push [esp+8+arg_4] ; 2° argument 40584C push [esp+0Ch+dirPathName] ; 1° argument 405850 call eax ; Function to call: CreateDirectoryA 405852 push esi 405853 mov edi, eax 405855 call ds:FreeLibrary 40585B mov eax, edi 40585D pop edi 40585E pop esi 40585F retn 40585F DecodeExecCreateDirectoryA endp
It decodes the name of the function and then it calls it. This piece of code is used to call all the functions requiring two arguments. What about functions with 1, 3 or more arguments? Well, the code is almost the same except few more push instructions before the call to the hidden function. At the end it turns out that the “.aspack” section was used to store these routines, I tried to give them understandable names:
405000 _aspack segment para public 'CODE' use32 405000 [00000812 BYTES: COLLAPSED FUNCTION Base64DecodeString] 405812 [00000006 BYTES: COLLAPSED FUNCTION NopCall] 405818 [00000048 BYTES: COLLAPSED FUNCTION DecodeExecCreateDirectoryA] 405860 [00000067 BYTES: COLLAPSED FUNCTION DecodeExecCreateProcessA] 4058C7 [00000041 BYTES: COLLAPSED FUNCTION DecodeExecCloseHandle] 405908 [00000048 BYTES: COLLAPSED FUNCTION DecodeExecWinExec] 405950 [00000058 BYTES: COLLAPSED FUNCTION DecodeExecWriteFile] 4059A8 [0000004D BYTES: COLLAPSED FUNCTION DecodeExecLoadResource] 4059F5 [00000051 BYTES: COLLAPSED FUNCTION DecodeExecFindResourceA] 405A46 [0000004D BYTES: COLLAPSED FUNCTION DecodeExecSizeofResource] 405A93 [0000004D BYTES: COLLAPSED FUNCTION DecodeExecGetTempPathA] 405AE0 [0000005E BYTES: COLLAPSED FUNCTION DecodeExecCreateFileA] 405B3E [0000012E BYTES: COLLAPSED FUNCTION CreateMaliciousDLLFromDecryptedResourceBytes] 405C6C [00000079 BYTES: COLLAPSED FUNCTION CleanTraces] 405CE5 [00000229 BYTES: COLLAPSED FUNCTION RunMaliciousDLL] 405F0E [00000060 BYTES: COLLAPSED FUNCTION CUDiskMonitorApp__Modified_InitInstance] 405F6E [00000023 BYTES: COLLAPSED FUNCTION CUDiskMonitorApp__ExitInstance] 405F91 align 80h 405F91 _aspack ends
The malware concept is pretty clear, the infection is done by a dropped dll. The name of the dll is random and its content comes from a resource item named “DAT” (the bytes are encrypted by a simple add-operation).
ClearTraces routine is called at the end, it deletes the dropper using a curious method:
cmd /c ping 127.0.0.1 -n 3&del <malware_file_path>
A sort of camouflage of del command.
I saved all these different snippets inside my Snippet Detector tool. I also added Base64DecodeString too because it often happens that the same encryption\protection_scheme is used inside the dropped files too.
If you carefully look at the routine names you’ll surely find out two almost obscure names:
The names come from various information I got browsing the net.
One of the first things I do when I start analysing a malware is to check the strings inside the target file. From all the encoded\decoded\clear strings I did focus my attention on this one: “firstname.lastname@example.org”.
I started gathering some information from this e-mail address. Google reveals a lot of links in the search result, mostly related to Chinese language pages. There’s a person behind this address, he is/was one of the Evil Octal forum crew and he uses an MSN alternative address too: email@example.com
So, I tried to combine the forum name with the two mail addresses into a new web search and among all the possible links I stumbled on a page containing a VC++ project named UDiskMonitor. It’s a complete solution, it does contain the compiled exe, and it’s used to secretly copy the content of a new plugged device. I gave a glance at the package and it turns out that the malware author uses this pack as a base for his evil intention. The malware is completely based on this UDiskMonitor project, it’s pretty easy to recognize the same skeleton. There’s a fundamental difference btw, the malware author added what I named RunMaliciousDLL inside the InitInstance routine (it explains the name CUDiskMonitorApp__Modified_InitInstance).
With only few web searches I had the possibility to study a malware in a really short time, that’s not bad and I think you can now understand the importance of the external information!
The dropper calls only one exported function from the DLL: InitSkin.
First of all I tried my Snippet Detector, it’s able to recognize one of the functions I loaded from the previous exe:
The DLL file uses the same base64 decoding routine, it means one thing only: strings are encoded.
There are a lot of hidden strings, and there’s another problem because the function names are encoded too:
A lot of unknown functions. I wanted to decode all the strings obtaining a browsable disasm. Something like:
from: “100044D9 call dword_1004DEC4”
to: “100044D9 call __SystemParametersInfoA”
How to solve this problem? I decided to start from the Base64_Decode_String routine obtained from my tool. All the xref entries to this function come from two distinct kinds of snippets:
Snippet #1: 1000384C push offset base64String ; Base64 encoded string 10003851 call Base64DecodeString ; Decode the name of the function 10003856 pop ecx 10003857 push eax 10003858 push dword_1004E254 1000385E call GetProcAddress ; Get the function address 10003864 mov dword_1004DEC4, eax ; Save the result 10003869 retn Snippet #2: 10001909 push offset base64String ; Base64 encoded string 1000190E call Base64DecodeString ; Decode it 10001913 pop ecx 10001914 mov dword_1004E274, eax ; Save the result 10001919 retn
Snippet #2 is used on every string ending with “.dll”, snippet #1 for the others. The xref list is really long, do I have to reveal every single entry by hand? IDA offers a great script system but this time it’s not easy to write something able to solve the puzzle, especially because I have to decode base64 encoded strings. There’s another powerfull tool you can use: IDA Python script system. Here is the code of the .py file I wrote:
import idaapi import base64 address = 0x1004B664 while (address < 0x1004D099): # base64 decode is already implemented decode = '_' + base64.b64decode(GetString(address, -1, ASCSTR_C)) # Set the name of the decoded string MakeNameEx(address, decode, SN_NOCHECK) # Set the name of the destination address if (decode.endswith('.dll')): MakeNameEx(Dword(DfirstB(address) + 12), '_' + decode, SN_NOCHECK) else: MakeNameEx(Dword(DfirstB(address) + 25), '_' + decode, SN_NOCHECK) address = NextHead(address) # skip 0x00 padding bytes address = NextHead(address)
The idea is simple: I scan all the encoded strings, decoding and setting the name of specific addresses. The result is notable:
I didn’t limited my approach to the standard tools only (which are necessary of course), but using something else I had the opportunity to turn an unreadable deadlist into an almost fully browsable deadlist in a short time.
This is the end of the post, it’s not my intention to force you to use some specific tools; I’m just saying it’s hard to change habits but sometimes an excursus out of the usual path can be really convenient!
Malware hash: 47d18761d46d8e7c4ad49cc575b0acc2bb3f49bb56a3d29fb1ec600447cb89a4