Written by aaSSfxxx - 23 march 2013
When we load the executable for the first time in OllyDBG, we get this
As we can see, the malware calls two functions: the first function walks trough the PEB to find loaded DLLs, converts unicode dll name into ANSI one and then hash it to compare it to the first argument (the hash of the wanted dll). So we can call this function "findLibraryByHash". Here, the functions gives to us the image base of kernel32.dll, checks if function is null and jumps into bullshit if the result is null.
That's not the case here, so we go to the second function and we step into (F7)
The function begins to load some function by their hash (done by the function at 00401746, which i'll call getProcedureByHash).
Then the function set an exception handler (I'll explain later what it does), and there are some calls which are useless for us, except the call at 00401BF9 (the call before the two conditionnal jumps).
The call is used to get a string pointer (and also as anti-disassembler trick). The first instruction of the call is "pop esi", so esi registers contains the address of return address, which is a string pointer (esi points to "guard32.dll" string). We also notice a "INC BYTE PTR DS:[ESI+B]", which increments 0xFF (aka -1), to have a null byte-terminated string. Then there is a call to GetModuleHandleA to check it module is loaded or not (anti-emulation protection). Then the malware checks if some processes are present in memory, just like the previous version of the bot.
As I'm using VirtualBox (with additions, yeah I know it sucks but I can't live with additions :3), I get redirected to 00401E95, which pushes some arguments and calls a function: let's analyze it :)
The function first loads some ntdll APIs (ZwAllocateVirtualMemory, RtlRandom, and other, just see what happens in ollydbg), then allocates virtual memory. After that, first argument is put into ebx, and then we have this call
This function is a RC4 decryption function, where key is stored at [ebx] and sizes 16 bytes, and data is stored at [ebx+28h]. Then we have a call to a jCalg1 decryption function (just like previous andromeda version), and to avoid stepping into, just put a breakpoint at 00401FBB to avoid relocation shit.
Then the malware allocates again virtual memory and fills it with random bytes, before doing solving some APIs. But, after getting function address, the malware calls a strange function, which takes the random-filled memory space, the API address and an unknown variable... smells bad, so let's have a look into this.
This function calls another function which takes the address of the found function, and returns the length of the first instruction. Then this function compares if we have a jump, and if it is, follow the jump, otherwise copy the first instruction and then jump to the next instruction of desired API.
So, to bypass this shit, let's codecave a little to store original API address into the jump table (you can use both "Multiline Ultimate Assembler" or the integrated ollydbg assembler (there's only a few lines to assemble). We are lucky, there is some free space in 405150. in 401A4D (the "cmp eax,2"), make a jump to 405150, and assemble these lines:
- MOV EAX,DWORD PTR SS:[EBP+C]
- MOV DWORD PTR DS:[EAX],ESI
- JMP 00401A9B
As we saw before, the malware places an exception handler, and if we play with the code to escape anti-VM tricks (or if debug this on your real computer :]), you should see something like "OR WORD PTR DS:[EAX+46],80" which throws an exception (because adress is not writeable here) which get handled if the process is not debugged by the exception handler put by the malware. Let's see what the fuck happens in the exception handler with IDA (IDA is very good to deal with structs and shit like this).
- push sub_401AA2
- push dword_402058
- push 40h ; here is the fake return address, never called in fact
- jmp loaderingPayload
Here there is a lot of useless code (dealing with environment variables, creating pipes, etc) and it's never called for me (maybe it's debug stuff, learn how to use ifdef malware coders). It also load some strings depending if the malware runs in a priviligied account or not (to avoid UAC popups & other things like this), tries to allow itself in the Windows firewall, then the malware creates a thread, with contains the real bot logic (ThreadFunc is at 7FFA370B). The thread proc loads some additionnal DLLs (in ole32.dll and somme winhttp functions too), by calling the function at 7FFA19F4 and then call 7FFA2494, which places some hooks on ZwMapViewOfSection/ZwUnmapViewOfSection functions (maybe to protect its ass when loading another dll, I didn't understand what's really happening here). Then, it calls QueueUserAPC with its own callback (this function just seems to create a thread, according to its behaviour). So let's have a look into the callback function (with IDA, and sorry for the background glitches, too lazy to fix it):
- (not dwSize)|c&c URL with null byte encrypted|(not dwSize)|c&c URL|....|dwSize = 0
Here, we can see that the C&C response changed a lot: reply is still cyphered with RC4 and the RC4 key is still the field "id" sent by the bot to the C&C, but we have base64-encoded data encosed by "gn(" and ")". Once base64 data is decoded, protocol is the same, so just look my previous analysis of andromeda ;).
The last funny thing I could see in this malware is the usage of "RtlWalkHeap" by the malware: the bot walks trough the heap to recover the C&C urls it decoded before (with the index made by xoring the VolumeSerial with a constant which is incremented each time in the loop), and does some weird things with "CreateStreamOnHGlobal" and shit like this to get server's response.
If you are interested, you can find the sample I analyzed at http://www.kernelmode.info/forum/viewtopic.php?f=16&t=1670&start=50#p18497 and the IDA databases are here if you are interested :)
Btw (unrelated), R.I.P to my netbook which died last Friday :(