Notes on malware

To content | To menu | To search

Tuesday 28 October 2014

Quick analysis of yet another malware packer

So this morning I came across a Rovnix sample downloaded by a Zemot sample (kindly provided by @kafeine). The sample ran absolutely fine when executed on a vm but refused to let himself being debugged, not something I usually come across. I decided to take a deeper look into this malware packer to see why it was so reluctant to being debugged (disclaimer : this is a quick post, and there isn't any new techniques presented).

Trying to load the file in Ida gives us a load of errors.

We can see by looking at the PE Header that it is quite mangled : we have a lot of invalid directories (Export, Debug, Security directories) and we got special characters in the section names. Below is an example with the .text section name.

Offset    0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F   Ascii

000001D0  2E 74 65 78 01 01 FF 00 00 80 11 00 00 10 00 00  .texÿ..€....

Hopefully Ida does recognize most of the functions after acknowledging these errors and the FLIRT signature for the compiler does a good job. We now have a pretty straightforward Winmain which makes a call to _sprintf() and calls a function at 00519780. We create a function in Ida for this sub and we can already see a common antidebugger, OutputDebugString (Figure below).

Hopefully we don't want to click 270000 times on a message box displaying this string, so we just patch the conditionnal jump with NOPs. The next call is a simple XOR based api resolver using hardcoded hashes in input. Let's take a look at the two following antidbg now :

The first one is as you may have recognized ZwQueryInformationProcess(). We can see that the ProcessInformationClass is set to 7, which is the value for ProcessDebugPort. The doc says us that this is in fact an antidebug trick :

Retrieves a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the process is being run under the control of a ring 3 debugger

Just set this value to zero and let's move on with the next check, the ZwSsetInformationThread() call. The ThreadPriority parameter is set to 0x11, which stands for ThreadHideFromDebugger (no need to explain what it does). If you want to read a bit more on hiding threads from debuggers, I suggest you read this post from waleedassar. Let's patch this call and move on.

Straight after we get to a call decrypting data. A simple look at the constants and we can see that this is indeed a TEA based algorithm used. The 128 bits key is located at the beginning of the .data section on the 16 first bytes. We then have a pointer to the data following which is to be decrypted.

After a slightly obfuscated snippet of code retrieving the process image base from the PEB, the packer loads a RT_RCDATA resource present in the binary (130kb in size), which is probably encrypted data, and copy it into a newly allocated memory page. Here we have the first use of our TEA decrypted data. Out of the 256 bytes of data decrypted previously (see picture below), the first 128 bytes seem to be another key, and we are now retrieving the next dword which has a value of 0x18E00. This value is used as the size parameter to allocate a new memory page.

The first allocated memory page (containing the raw resource) is now copied into this newly allocated area, but with a little tweak.

Here is the copy algorithm :

i = 0;
CryptedSize = 0x18E00;

  if (CryptedSize)
      *(_BYTE *)(AllocatedMem + i) = *(_BYTE *)rsrc++;
      if ( !(i % 3))
    while ( i < CryptedSize );

We then have another TEA loop decrypting the data copied into the memory page with the 128 bits key decrypted previously. You just have to pass the loop to dump the decrypted MZ in memory.

Thursday 9 October 2014

Ursnif still in active development

So, today let's talk about ursnif and its recents evolutions. I saw yesterday evening this blogpost riddled with errors (rovnix and ursnif are two different malwares), so here is my take on this. The first sample I found that sparkled my interest is dated from 24/04/2014, but I wouldn't be surprised to see older samples with these characteristics as well. As you can see the kernelmode post I made with the sample config, "ISFB" is the internal ursnif (not rovnix !) name , and it was mainly the 2.2 version distributed at the time. I'd like to thank @kafeine for providing me with a lot of the samples analyzed in this post.

So, back to this 24/04/2014 sample. I was intrigued to see that there was now a string decryption function present in the binary. The function is quite simple. First we search for the .bss section which contains the encrypted strings. Then a XOR key is generated with the embedded date and the VirtualAddress + RawSize of the bss section. Here is what this function looks like with Hex-Rays :

The dll unpacking is almost the same (aplib). The only noticeable change is that the structure id is now "J1" instead of "FJ" in the PE Header (See picture below). One last big change is the injection of the Ursnif dll component in explorer, it was before dropped into %system32%. This injection is kinda crappy imo, the malware kills explorer and then spawn a new instance to inject itself into, not really that stealthy.

Onto the dll now. We got an url in the binary, maybe a C&C one ( We got onto the embedded configuration now, and as you can see it is quite different. As the C&C was dead when I came upon this sample, I can't provide anymore details on this.

600 -> ConfigTimeout
4320 -> ? <- encrypted data file
2022 -> Group

Next sample I got is from the 29/04/2014 and it has some interesting differences. We have some new strings which indicates the introduction of some anti-vm checks. The DLLs files are now stored as resources in the dropper with the names 'C132' and 'C164'. A PRNG has also been added. This PRNG is from the rovnix source code and is used to generate unique GUID (As seen in bksetup.c).

00401785   PUSH ursnif2_.0040519C                    ASCII "ISFB REG FILE"
00401792   PUSH ursnif2_.004051AC                    ASCII "ISFB REG KEY"
00401A7D   PUSH ursnif2_.004051CC                    ASCII "HARDWARE\ACPI\DSDT\PTLTD_"
00401AB0   PUSH ursnif2_.004051E8                     ASCII "HARDWARE\ACPI\DSDT\VBOX__"
00401AC7   PUSH ursnif2_.00405204                    ASCII "HARDWARE\ACPI\DSDT\AMIBI"

Let's talk about the dll module. Concerning the DGA / cab compression / C&C communication, the post does a good job analyzing it. I'll just add that the DGA tld are not always the same between the few variants I have seen using it. In this campaign, the tld used are : .eu / .cn / .biz / .net / .com. The C&C address is, now dead.

000000011C54   000010013654      0   c:\prj\ISFB\release(unpacked)\client.pdb <- pdb path found in the client.dll module

.bss0:00407000 0000004B C version=%u&user=%08x%08x%08x%08x&server=%u&id=%u&crc=%x&wdata=%04u%02u%02u
.bss0:0040704B 00000041 C version=%u&user=%08x%08x%08x%08x&server=%u&id=%u&type=%u&name=%s          
.bss0:0040708C 0000003D C version=%u&user=%s&server=%u&id=%u&crc=%x&wdata=%04u%02u%02u              
.bss0:004070C9 00000033 C version=%u&user=%s&server=%u&id=%u&type=%u&name=%s                        

Next sample I got has a timestamp dating it from the 10/06/2014, but no strings encryption this time. This is the sample 2 from the campaign 1 in the blog post, same variant as the previously described one. C&C I got with these :

Moving onto the next sample now, the first I got with Rovnix bootkit integration. It is interesting to note that Rovnix and Ursnif have been closely related in the past, sharing the exact same component unpacking code ("FJ" bytes in the structures in the PE Header to retrieve the aplib packed components), and the C&C infrastructure was the same (same panels). With the integration of the rovnix bootkit into ursnif the code of these two malwares is even more blended into ursnif. This sample has a timestamp dating it from the 20/06/2014. After unpacking the sample we can see that two new modules have been added into the dropper. These two new components are the Rovnix ring0 & MBR modules. The Rovnix bootkit install code is the same as the leaked install.c code.

RC6 Key : F223456789ABCDEF

Additionnal config in the dll :

Next bootkit sample I got is timestamped from the 01/08/2014. Interestingly enough, this time the C&C communication protocol is the cab one.

C&C urls :

Config :

This C&C was active until this week, and it reached ~70k bots in 3 months. Not bad for a Ursnif imo (sorry, no screenshots, I always forget). The panel wasn't that interesting anyway.

Intriguing thing, a few variants seems to be distributed at the same time in the wild. In a sample with a timestamp dating it from the 28/06/2014, we have no bootkit but instead the DGA variant. TLD used in this one are .tk / .ru / .biz. / .com / .net. The C&C address was and the RC6 key is 0123456789ABCE21. The decrypted configuration 10 60 10 60 30 gives us nothing interesting. The same campaign with a 03/08/2014 timestamp has a slightly different config : 60 60 60 60 30 1004. The 13/08/2014 timestamped version gives us two more C&C urls : and On the 18/08/2014 the RC6 key was changed to THe04ihgUaSZlMnP. Config was : 60 60 60 60 30 1000, and TLD were : .com / .net / .biz / .ru. On the 04/09/2014 I observed another big change in the C&C panel : they are now named IAP (see the picture below) and looks like a totally revamped version of the old panel. If you want to see the internals of a panel you can refer to the CSIS blogpost. Let's see the config for this sample :
300 60 300 300 300 10 4004

I got only one sample in july with a 23/07/2014 timestamp. This is very similar to the DGA variant with a few differences on the C&C / command parsing part (the main difference in fact is the disappearance of the DGA). This sample copies itself into %system32% and still injects its dll into explorer. RC6 Key for this variant: 5C3F6970EE00A01D, config : 10800 5400 300 600 300 60 1000. Let's see an example of a request to the C&C :

On the few samples I have seen of this variant, the paths have always been the same :

On the 10/09/2014 version :

I think I have covered almost all the important evolutions in ursnif from april to september. On the samples I got in september, there is nothing changing except the configs / c&c urls which are still being updated. It's time to draw some conclusions about this now. I think there are three actively distributed ursnif variants in the wild.

  1. The first one, with the RC6 key F223456789ABCDEF is the blended ursnif with rovnix. The first trace of this variant I found go back to april and it is still active.
  1. The second one is the DGA based variant.The RC6 keys seems to change quite often, and this is the variant described in the CSIS post. They are operating the IAP C&C.
  1. The third one (and I'm not 100% sure about this one) is the .su C&C based variant. Least frequent one.

I hope this post has shed some light on the state of the ursnif threat and its recent evolution.

Edit 05/12/2014 :

Further proof that multiple versions of Ursnif are distributed itw :

Debug string inside a Ursnif binary with timestamp 16/07/2014:

ISFB_0d10: ISFB client DLL version 3.5, client ID: 1000

Debug string inside a Ursnif binary with timestamp 01/12/2014

ISFB_0a10: ISFB client DLL version 2.12, build 398, group 1000

Sunday 5 October 2014

Malware Unpacking Part II : Dynamically allocated memory

So, after talking about the main ideas in malware unpacking, let's take a look at some examples to illustrate them. In this series second part, I'll talk about packers using dynamically allocated memory. I'll focus on techniques using allocated memory pages on this post, and I'll do another one about packers using memory allocation on the heap. I'll try to keep this short, simple, and focused on examples of these techniques.

Big thanks to Kafeine for providing the samples. Link to download them (mega).

First sample which we are going to look at is a Yorobun.A binary, a tiny and quite uninteresting downloader.

Second VirtualAlloc() break.

We have a round number, 0x800, but it seems quite small. However knowing this packer helped me to see it was indeed the size of the final binary. How did I recognize this packer will you ask ? When I break on the first VirtualAlloc(), it's size isn't a round number (0x16C8) and the execution time until the break is longer than usual (probably due to a long loop in between). By returning to the code I see the following part of code which is quite characteristic. This is the jump to the next stage of the packer.

Now, we just have to go back to the code after our second breakpoint. We have the address allocated in eax, and we can see right after it the aplib depack procedure. Now that we have our binary decompressed, we just trace a bit further to the decrypting loop, a simple XOR, and you have your unpacked exe.

Next example now : a Rovnix.I sample

We take a look at this break which seems interesting (size of 0x18E00) :

Next, we return to the code, and see a loop filling the memory area allocated. By going a bit further we arrive to the decryption part (1 on the picture) of the executable located in memory.

We can see the parameters of this functions on the stack (in 2) : 0x003E0000 is the address of the allocated memory page (seen in 3), 0x0040B808 is the address of the 256 bits key and 0x18E00 is the size of the crypted data. After looking at the function, it appears that the packer is using the RC4 algorithm. We will now have our MZ in memory after decryption. It's interesting to note that this packer used to use OutputDebugStringA() as an antidebugger and in his first version relied on RtlDecompressBuffer() to decompress the MZ.

Friday 3 October 2014

Malware Unpacking - Part I

So, let's inaugurate this blog by a series of post on malware unpacking. This is the first step for aspiring malwares analysts, as you will find almost no binary in the wild without any kind of packing / obfuscation applied on it. Almost all malwares are packed, but luckily for you most of these packers are easy to unpack. They mostly focus on stealth usually to avoid triggering unusual alerts on AV heuristics and frequently use anti-emulator stuff (e.g. unusual instructions non emulated, undocumented apis). Sometimes to avoid sandboxes, they use a long time sleep (e.g. 10mn) to ensure a timeout, but this is almost only seen in the decrypted binaries. Since the malwares authors don't focus on protecting their samples from AV / anti malwares researchers, it is also very rare to see antidebugging tricks / antivm in packers. I think in the last 3 months I have seen only one packer using an antidbg (it was OutputDebugStringA). If you encounter a packer focusing on anti-analysis tricks, most often it is a carded protector used by script kiddies (e.g asprotect, themida).

So, here are a few generic methods to unpack these malwares. We will then take a look at these methods in depth, with a blog post per methods describing several examples matching it. This will not be a series of posts on detailed analysis of these packers and their techniques, as this is available everywhere on the web and they almost all work the same way a few details aside. Let us begin then :

1) Monitoring the allocated memory. Usually VirtualAlloc() is called to allocate space to write the encrypted malware in memory. It is then dumpable and will run untouched. This is the most commonly used technique. You can sometimes find ZwAllocateVirtualMemory() calls too, when the author decides to uses native APIs. When you break upon these calls, there are a few things that may indicate if the memory allocated will be interesting or not : if the size is less than 0x2000, or if it isn't a round number (e.g. 0x1213456), usually it won't be interesting. When a zone seems interesting, I usually go back to the code (alt+F9) and trace a bit, usually a few calls later a MZ will appear in the memory allocated zone.

Example on a Fareit sample :

2) RunPE. Usually coded in Visual Basic / C#, but I have seen some in C++ too. This technique is also known as process hollowing. Basically, it creates the process in a suspended state, overwrites it with the decrypted code and resumes the thread. To dump the decrypted binary, usually a breakpoint on WriteProcessMemory() or ZwWriteVirtualMemory(). You can get the address of the bytes written on the stack with the lpBuffer parameter and find the decrypted MZ there.

Example on a Miuref sample :

3) Monitoring the heap allocated memory. Less used, but when this is the case it is often RtlAllocateHeap() used to allocate memory. I have seen some GlobalAlloc() calls as well in the past, on lockers if my memory is good. The principle stays the same as 1), but be aware that you will have a lot more breaks in your debugger by setting a breakpoint on these apis. It is advisable to set the breakpoints when we know that we are approaching the decrypting routine.

Example : Mystic Compressor on an old Pornolocker sample

4) RtlDecompressBuffer() call. Just set a breakpoint on the API, and when it breaks you get the address where the decompressed executable will be written on memory with the UncompressedBuffer parameter. You just have to dump it.

Example on a Redyms sample :

75% of the malwares should fit in those categories (Yes, this is an empirical made-up percentage).

Now for the tools to use in unpacking : I use Ollydbg 1.10 (for some plugins, and I'm accustomed to it), a plugin to hide the debugger (phant0m), a few plugins to dump executables / memory areas (OllyDump / Olly Advanced / PE Dumper ). I also have a plugin to import ida .map files (Godup) and a plugin named commandbar to set the breakpoints easier, but they are not really that useful in unpacking. You also need ImpREC (import reconstructor) in case the binary is not dumpable in memory and we have to reach the original entrypoint of the binary (OEP) and dump there. As the import tables of the process has already been initialized at this stage, we will need to reconstruct it. I also use an external dumper tool, Lord PE deluxe, for when I'm in need to dump portions of a memory area. All of those should be found on the tuts4you tools section.

This should now suffice (as tools) to unpack at least 90% of the malwares found in the wild.

Usually when I unpack a process I load it in olly directly to see if I recognize the packer, if I don't I take a look with CFF Explorer (best PE Editor imo), and if I still don't recognize it I set a breakpoint on each one of the APIs mentionned above. You will almost surely break somewhere, and from where I go a bit blindly on the loader to see if I recognize some patterns to unpack the process. I recognize a packer by noticing some patterns :

  • Names / number of sections (Are the names random / wiped ? Any unusual name ? Is there an abnormal number of sections ?)
  • Entrypoint appearance (Does it look heavily obfuscated ? Does it look like a known compiler ?)
  • Strings Data References (Not very reliable, but can be useful in some cases)
  • Data sections (Do I have some constants / recurring patterns ?)

Most of the time, you will recognize a packer by it's entrypoint appearance as the obfuscation patterns are usually similar on malwares packed with the same thing. If you don't have gathered enough information to get an idea of the packer family, usually a look at the unpacking stage 2 will help you. I look for :

  • APIs calls patterns (CALL register ? CALL dword ptr ss: register ?)
  • Obfuscation patterns (JMP splicing ? Heavy use of stack / data manipulating instructions ?)
  • Address space of the stage 2 (Am I on the stack, the heap, or an allocated memory area ?)
  • API resolving loop
  • Names of the resolved APIs

Usually some of these will give you strong leads as to how to unpack this malware in the most efficient way (aka less time consuming). One little thing to conclude this post. On a few samples you may encounter what is called multipacking, which is the act of combining multiple packers. Usually this is not a problem at all for the analyst, it's main interest is to reduce the size of the malware binary. To give a few examples, the Winwebsec rogue family used to have PECompact 2 in second layer, Kelihos had UPX, and I've seen some instances of Zemot using Aspack. The one you're most likely to encounter is of course UPX, as it is quite widespread and effective.