The story of one autopsy: how we reversed Hancitor

    For those who have already played enough with crackme puzzles , we brought up a fresh Trojan. In the wild, the Hancitor downloader is also found in its natural habitat - spam mailings. Currently, it is actively used to download the Panda banking trojan, which is a modification of the notorious Zeus.

    One cold summer evening we met him face to face, looking through email spam. If you like to watch what is there in the malware "under the hood", read our new reverse-analysis.

    Our malicious document looks like this:

    By default, the launch of macros is blocked, so the system warns: "Macros have been disabled." However, the content of the letter assures that macros should be included. Well, let's do it. After clicking on the Enable Content button, the computer becomes infected. And now let's see what kind of macro is being executed and how exactly the infection occurs. This can be done immediately in the Word by clicking on the View-> Vacros \ View Macros tab.

    You can do more professionally - use olevba from the oletools package. You can install the package in the same link. Next, type olevba doc_file –c –decode> source.txt and get the macro source.

    From the code I immediately want to say that the trojan belongs to the class of downloaders. The script simply downloads malvaru from somewhere. To prove this, let's decode the base64 strings. It is more convenient for us to do this right away through the hiew, so as not to copy and paste a hundred times. For this we use a special plugin, which is described here . Here's what happened:

    This is a malicious script, divided into two parts and saved as 1.hta. In principle, we are not particularly interested in how it works. It's all pretty trite. The only important point is to determine the URL where the malicious file is being downloaded. Let's try to find it, as this information may be useful to security guards . They can add network rules to block requests from such URLs, which can save the company from infection.

    Ha! There are no links. But where does the 6.exe file come from, which runs 1.hta? It's time to take another look at our Dokow file in the hiew, but more closely:

    Yes, an exe-file is embedded in the dock document. Yes, and heavily packed. Explain what happens. The macro drops the malicious script 1.hta into the Temp folder and launches it, and 1.hta starts in turn 6.exe from its directory. It's clear that 6.exe is the same packed PE file that we see on the screen. But we are now wondering how 6.exe drops in% temp%. And this happens because of an interesting feature in the Microsoft Office package. The point is that any other file in Ole10Native format can be embedded in any OLE document.

    If this is the case, then MS-Office itself, when launched, drops the file embedded in this way into the% temp% folder under the name specified in the header of the Ole10Native structure. Let's look at this object. We were helped by the plugin for FAR-manager - OLE2Viewer . Open our malicious document in the plugin, go to the ObjectPool \ _1593522492 directory and see this:

    Copy this file (Ole10Native) and open it in hiew.

    Here we see under what name our OLE-object - 5c.pif will drop into the% temp% folder. Now back to our macro. His task is to launch a dropped exe-shnik.

    In fact, to be precise, the macro starts the dropped file not always through 1.hta, but also like this: Shell "cmd.exe / c ping localhost -n 100 &&" & Environ ("Temp") & "\ 6 .pif ", vbHide

    The launch method, as we see, depends on the presence of the following processes in the system: bdagent.exe and PSUAMain.exe. Why then do you need to ping localhost -n 100? And this is an ancient Greek trick to create an artificial delay, just in case. Usually its variations are used for self-removal.

    At this stage, we have analyzed the scheme of the malicious document. It became clear to us that the document itself does not belong to malware like Trojan-Downloader, as it seemed at first glance, but it fits to type Trojan-Dropper. That's what happened at the start:

    Now it remains to disassemble the payload itself. We already realized that our Trojan is packed, so we must first unpack it. Usually this process is divided into two stages:
    1. Removal of the unpacked dump + restoration of the import table.
    2. Analysis and cleaning of global variables.

    We need the second stage because there are many API functions that, as a result of their work, return non-recurring values. For example, CreatHeap will return us a heap descriptor, which will then be used for work. Very often in the code there are type checks: if the heap descriptor == 0, then get the heap descriptor, otherwise use the already initialized one . But at the time of the dump, the variable containing the given descriptor was already initialized by it, and at that moment the descriptor was valid. When we try to launch a captured dump, the variable with our descriptor will contain the old value, that is, not equal to 0, which means it will be checked.

    After that, as soon as the program tries to use this descriptor, the OS will throw an exception, and the program will crash with an error. So, to avoid this, these variables need to be zeroed out. Usually they are in the writeable data section. Probably you offer to open this section in a hex editor and wipe everything with zeros? You are partly right, but you should not commit rash actions. There are such trojans that check variables not at 0, but at random DWORD. And depending on whether the test passes or not, different actions are taken. There is no need to go far for examples. Just look at the Cridex (recently disappeared somewhere from the radar, apparently completely upgraded to EMOTETA).

    So let's run our sample (on a virtual machine, of course). It is also desirable that the traffic that will leave the virtual machine go through the VPN.

    We launch our trojan, and it “just” hangs in the process. Wonderful! Typically, the Trojans "in a hurry" do their work, and then immediately terminate and delete themselves. Therefore, you have to look for places in the code that are responsible for these actions, put a bryak on them, and then dump them. In our case, we can do it just like that.

    For dump we use a wonderful utility - Process Dump, which can be taken here.. This utility not only finds all hidden executables and dumps them, but also restores the import table itself. The utility must be run as administrator in the following way: pd / pid xxxx, where xxxx is the Trojan process id. After that, the utility will dump all process modules. We deleted the extra ones and this is what remains:

    The name of the Trojan process executable file is 1.exe. It turns out that at the address 0x2C0000 there was an unpacked Trojan. Open it in hiew:

    Just happy eyes! Now the file is unpacked, it is clearly visible. The import table was also recognized. Let's open it in IDA-PRO.

    We have already renamed some of the functions while the sample is being parsed. The first thing a trojan starts working with is determining the load address of its module. And really: how can he know at what address his stub unpacked? This is done by an old proven technique - scribbling a page of memory back on 0x1000 relative to the current address until we stumble upon the “MZ” bytes. This works because executables always load the OS at a multiple of 0x1000. Check for yourself. In our case, the limit is set to 100 scans.

    If someone doesn’t understand where backing is, then this is where:
    result + = 0xFFFFF000 is equivalent to result - = 0x1000.

    After receiving the download address of its module, the unpacked Trojan receives the addresses of the functions necessary for its work. First of all, the addresses of two functions are searched for - LoadLibraryA and GetProcAddress. Knowing the addresses of these functions, you can use them to get all the rest. These functions are located in the kernel32 library. Its address is obtained by reading the first (zero - ntdll, first kernelbase, etc.) of the ring list element, which describes all the modules loaded in the initialization order by the _LDR_DATA_TABLE_ENTRY structure. A pointer to the list is pulled out of PEB.

    Having received the address of kernel32.dll (starting with Windows 7 - kernelBase.dll), the trojan can manually parse its export table and find the necessary two functions, which is predictably performed in the sub_EF1E60 subroutine.

    Now take a look at the function we called getHeap.

    Here we see exactly the situation described above. At the time of the dump, the variable hHeap contained the value 600000h. Therefore, GetProcessHeap will not be called. Instead, the program will go to the loc_EF11DD label, where HeapAlloc will be called with an invalid handle, which will give us an error. Therefore, we take the hex editor and zero this number. We counted six similar places.

    Next, the fun begins. Troyan generates a unique “client” ID, based on the serial number of the hard disk and the MAC address. Information obtained here:

    We also get the following: IP address, OS version, network name and username. Based on all this, an HTTP request to the admin panel is created, the address of which we do not know yet. In the lines it is not (even unpacked). And it is not there, because it is encrypted in the config. Its address can be pulled out of the code: The

    config weighs 0x2008 bytes and has the following format: the first 8 bytes are the RC4 key, 0x2000 bytes are the encrypted data.

    The fact that the RC4 encryption algorithm is used becomes clear from the following listing:

    Please note that the first 8 bytes themselves are not the key to RC4. The key is the SHA1 hash from these bytes. You also need to pay attention to the flag 0x280011 to the function CryptDeriveKey. In MSDN there is a reservation about this flag:

    From it it becomes clear that the older 16 bits of this flag set the key size in bits. Ie in bytes, the key size is: (0x280011 >> 16) / 8 = 5. Therefore, the key will be the first five bytes from the hash from the first eight bytes of the config. We will set up the config and write a script in python that will decrypt it to us. The script looks like this:

    The result of his work was the file config.rc4. Let's open it in hiew:

    We see the decoded list of admins. The first word - "19nep07" - build number. Under it allocated 16 bytes. Next comes the list of admin URLs separated by "|".

    So, the first call to the admin panel will have the following format:
    GUID = 3068075364164635648 & BUILD = 19nep07 & INFO = WIN-56G04BL06SL @ WIN-56G04BL06SL \ Reverse & IP = & TYPE = 1 & WIN = 6.1 (x32

    Then the generated request is sent to the first admin in the list.

    Then the answer is read from the admin panel, of course, if it is still alive. The answer must be base64 encoded. If this is not the case, the next admin from the list is taken. Sometimes live admins return a strange answer:

    Familiar, isn't it? Yes, these are the same numbers ! In fact, one author knows why the admin panel starts returning them! In normal form, the command is returned. Unfortunately, it is impossible to say with complete confidence what the response format will be, since there is no traffic, all admin panels are dead. The decoded file additionally splits into 0x7A:

    The answer must contain a command. If it does not exist, the next admin panel is accessed. The command code is encoded as “x:”, where x is the letter coding for a specific command. There are 7 of them in all: 'r', 'l', 'e', ​​'b', 'd', 'c', 'n'. Consider the commands "b" and "r".

    The handlers of these commands have the same function. We called it GetExe. Here's how it looks:

    I think everything is clear. The trojan makes an http request and returns the executable file in a compressed form, which is then compressed. Then variations are possible. In the case of the “b” command, the following three actions occur:

    1. Creating the svchost process in a frozen form

    2. Inject into the address space of the process of the downloaded module

    3. Transfer control to the boot module

    In the case of the “r” command, the following three actions occur:
    1. Download the executable file by calling the GetExe function.
    2. Saving the downloaded file to a temp folder under a random name.
    3. Run the drop file.


    PS Next time we can do a parsing of either the "Panda" or some cryptographer. Write in the comments which malware interests you the most (for research purposes, of course).

    Also popular now: