Original post: https://develbranch.com/tutorials/deobfuscate-apt-malware.html
Introduction
I get this malware sample from my friend. I will show my experience with packers and manual unpacking. All about behaviors of malware, I will present in a new article.
1 minute for advertisement: If you have a similar sample, you may contact me by sending an email to contact[at]develbranch.com
or my fanpage fb.com/develbranch. I will help you and charge in case of necessity. If you think my article is valuable, you may donate to me so that I have the motivation to write the next article. I accept Paypal
Environment
- Windows 7 64 bit virtual machine. You can use windows 10.
- Hex-Rays IDA: https://www.hex-rays.com/
- A debugger: I love x64dbg.
- C++ compiler: I use Microsoft Visual Studio 2015. https://visualstudio.microsoft.com/
- CFF Explorer: Explorer Suite
Behavioral analysis
In all steps of malware analysis, we have to perform behavioral analysis to predict malicious actions partly. To do this, we need:
- The executable files of the malicious software and/or commands to run malicious code.
- Build exactly the environment where the malicious code will execute. For example: If the malicious code only runs on the windows server then you will never analyze the behavior if your environment is windows home.
We just have 4 files, no more clue, and we can not execute malware in our system. We need to guess by ourselves!
Detailed analysis
I noticed that the cachuri.dll
file was signed by Microsoft. I completely ignored this file.
This file is a module of IIS cache. It is not a default installed module:
cachuri.dll
imports functions from iisutil2.dll
, iisutil2.dll
does not have a valid signature.
The other files are not executable files at all. So we can guess: cachuri.dll
will be loaded by the IIS server (inetsrv). After loading the cachuri.dll
, malicious iisutil2.dll
is also loaded into the memory region of the process. iisutil2.dll
will probably use the remaining two files for some purpose. At this step, we still haven’t run malicious code, it’s just a guess.
Analyze iisutil2.dll
This file is obfuscated and it makes me be confused. This is the flow of program:
Find functions: CreateFileW
, ReadFile
, RtlDecompressBuffer
Open iisexpressshim.sdb
and read:
Decrypt code by using XOR
There is the structure of decrypted data:
- the first DWORD: The size of uncompressed data
- Compressed data
After that, the program uses RtlDecompressBuffer
to decompress data. This is the first layer of packer.
There is decryption code. Luckily, we have lznt1 decompressor from Google (https://twitter.com/nullandnull/status/772989022079586304). https://github.com/google/rekall/blob/e57446eb8ecbcf5019c1a978f469955a5078c829/rekall-core/rekall/plugins/filesystems/lznt1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
'''Decrypt iisexpressshim.sdb'''
import sys
import lznt1
def decrypt(buf):
out = ''
index = 0
for c in buf:
out += chr(ord(c) ^ (index % 0xff))
index += 1
return out
cdata = decrypt(open(sys.argv[1], 'rb').read())
open(sys.argv[1]+'.decrypted', 'wb').write(lznt1.decompress_data(cdata[4:]))
Result
I notice that VirtualSize, RawSize and RawAddress are equal to 0 . We can calculate all VirtualSize, RawSize and RawAddress by using VirtualAddress.
- VirtualSize = RawSize = (VirtualAddress of the next section - VirtualAddress of this section)
- RawAddress = VirtualAddress
After fixing it, we can load this file to IDA and check it. This is the main flow of this program: to replace export table of cachuri.dll
with new malicious export table.
I try to debug but I don’t have an actor to trigger malicious code.
Analyze iisexpressshim.sdb
I analyze DllGetClassObject
and notice that malware uses directory name as a CLSID.
To create a malicious object, we need a directory with a CLSID. There are main steps:
- Create a directory and the name of directory is
{CB8A1CEF-292D-421E-AC71-88451B5C7F2B}
. I choose it randomly. - Use this code to create an object.
CLSID clsid_malware; LPVOID ppv = NULL; HMODULE h = LoadLibraryA("cachuri.dll"); DLLGETCLASSOBJECT fnDllGetClassObject = (DLLGETCLASSOBJECT)GetProcAddress(h, "DllGetClassObject"); HRESULT hr = CLSIDFromString(TEXT("{CB8A1CEF-292D-421E-AC71-88451B5C7F2B}"), &clsid_malware); hr = fnDllGetClassObject(clsid_malware, IID_IClassFactory, &ppv); printf("ppv = %p\n", ppv);
We have a
CMalware2
object. I try to analyze all methods of this object and I realize thatCMalware2
object is a base object. If I callQueryInterface
with{839D7762-5121-4009-9234-4F0D19394F04}
, I will create a real malicious object.
This function will decrypt logo.png
and load another PE file to memory:
int main(int argc, char** argv) {
CLSID clsid_malware;
LPVOID ppv = NULL;
HMODULE h = LoadLibraryA("cachuri.dll");
DLLGETCLASSOBJECT fnDllGetClassObject = (DLLGETCLASSOBJECT)GetProcAddress(h, "DllGetClassObject");
HRESULT hr = CLSIDFromString(TEXT("{CB8A1CEF-292D-421E-AC71-88451B5C7F2B}"), &clsid_malware);
hr = fnDllGetClassObject(clsid_malware, IID_IClassFactory, &ppv);
printf("ppv = %p\n", ppv);
IUnknown *pMalware = (IUnknown*)ppv;
hr = CLSIDFromString(TEXT("{839D7762-5121-4009-9234-4F0D19394F04}"), &clsid_malware);
IMalware *malware_obj;
hr = pMalware->QueryInterface(clsid_malware, (LPVOID*) &malware_obj);
printf("main object = %p\n", malware_obj);
DWORD_PTR vptr = (DWORD_PTR)(*(DWORD_PTR*)malware_obj);
printf("vtbl = %08x\n", vptr);
DWORD_PTR ml_fn = *(DWORD_PTR*)(vptr + 3 * sizeof(DWORD_PTR));
RUNMALWARE run = (RUNMALWARE)(ml_fn - 0x5620 + 0x10B0);
run((void*)malware_obj); // extract malware
return 0;
}
- Malicious code will allocate a memory region via (
VirtualAlloc
) - Decrypt
logo.png
- Fixup relocation
- Resolve IAT.
- I use
pe_unmapper
to dump malicious code to file (https://github.com/hasherezade/pe_recovery_tools/tree/master/pe_unmapper)
Now, we have logo.dll
Analyze logo.dll
This DLL has a exported function: DllEntry
.
Pseudocode:
char __stdcall DllEntry(int a1, int a2, int a3, int a4)
{
char result; // al
SetErrorMode(0x8007u);
result = sub_100569F0((int)sub_100031C0);
if ( result )
{
result = sub_10055E20();
if ( result )
{
while ( 1 )
Sleep(0xFFFFFFFF);
}
}
return result;
}
After analyzing, I realize that this is another PE loader:
- Allocate memory and decrypt the embedded PE file.
- Resolve Import Address Table
- Execute malicious code at entry point
This loader removes all important fields in PE header. We can not rebuild PE file without header. I use debugger to trace and find the address of entry-point and dump memory to disk. This loader allocates 0x899400 bytes for new PE file
this loader skips 0x4E0000 bytes. I don’t know why.
As I say, all important fields are removed.
Rebuild
We have: Imagebase = 0x800000 + 0x4E0000 = 0xCE0000.
You can consider that this PE file has only 1 section. So we create section header:
NumberOfSections = 1
To resolve and fix IAT, I use Scylla : https://github.com/NtQuery/Scylla
Scylla is a great tool. I can recover all entries in IAT. We need to use Disassemble
function to resolve APIs if Scylla can not resolve them.
Remember:
- If malicious code uses
GetModuleHandle
function with NULL parameter (both Ansi and Unicode version), this function MUST return 0xCE0000.
Correct Import Address Table
Finally, I rebuild and rebase this file
Rebase PE file:
This is the last layer.
Bonus: C&C Server
1
2
3
4
5
6
7
8
cdn.arlialter.com:8888
cdn.arlialter.com:8531
var.alieras.com:8531
fbcn.enantor.com:8531
fbcn.enantor.com:8888
ww1.erabend.com:8888
var.alieras.com:8888
ww1.erabend.com:8531
Donation
If you think my article is valuable, you may donate to me so that I have the motivation to write the next article. I accept Paypal. Thank you so much! https://paypal.me/develbranch