NSIS Executable & Extracted Content |
.text:004010E0 _WinMain@16 proc near ; CODE XREF: start+12Fp .text:004010E0 .text:004010E0 var_4 = dword ptr -4 .text:004010E0 hInstance = dword ptr 4 .text:004010E0 hPrevInstance = dword ptr 8 .text:004010E0 lpCmdLine = dword ptr 0Ch .text:004010E0 nShowCmd = dword ptr 10h .text:004010E0 .text:004010E0 push ecx .text:004010E1 push offset OutputString ; "Jahuzejijas" .text:004010E6 call ds:OutputDebugStringA .text:004010EC push offset aWokynrxqmt ; "wokynrxqmt" .text:004010F1 push offset unk_40316C .text:004010F6 call Cejarinam ; calculate Logical Shift Key .text:004010F6 ; Imports from Cawizuhova.dll .text:004010F6 ; returns 1888 or 31 38 38 38 .text:004010FB push offset unk_403064 .text:00401100 call sub_401000 .text:00401105 push 4E00h ; unsigned int .text:0040110A call ??2@YAPAXI@Z ; operator new(uint) .text:0040110F add esp, 8 .text:00401112 mov dword_403168, eax .text:00401117 push offset String2 ; "fovuqonayura.mop" .text:0040111C push offset dword_403168 .text:00401121 push offset String2 ; "fovuqonayura.mop" .text:00401126 call Xugegisedumu .text:0040112B add esp, 8 .text:0040112E push eax ; lpString1 .text:0040112F call ds:lstrcmpiA .text:00401135 push 64h ; dwMilliseconds .text:00401137 mov dword_403054, eax .text:0040113C call ds:Sleep .text:00401142 call ds:GetCurrentThread .text:00401148 push eax .text:00401149 mov eax, _size ; 0x4E00 .text:0040114E push offset unk_40316C .text:00401153 push eax .text:00401154 push offset dword_403168 .text:00401159 call Tikeyicenapu ; Deobfuscated .text:0040115E mov ecx, hDlg .text:00401164 lea edx, [esp+4+var_4] .text:00401168 push ecx ; hDlg .text:00401169 push edx ; int .text:0040116A mov [esp+0Ch+var_4], 4
The code basically calls a function called Cejarinam imported from Cawizhhova.dll. This function/DLL is responsible for calculating the XOR key. Once that is completed a function named Xugegisedumu imported from Necacaza.dll opens and reads into a buffer named fovuqonayura.mop. The buffer is decoded by a function named Tikeyicenapu imported from Cawizuhova.dll. Below is the decoder function in Cawizuhova.dll.
.text:10001000 Tikeyicenapu proc near ; DATA XREF: .rdata:off_10002128o .text:10001000 .text:10001000 arg_0 = dword ptr 4 .text:10001000 arg_4_size = dword ptr 8 .text:10001000 arg_8 = dword ptr 0Ch .text:10001000 .text:10001000 xor ecx, ecx .text:10001002 cmp [esp+arg_4_size], ecx .text:10001006 jbe short loc_10001027 .text:10001008 push esi ; save off esi .text:10001009 .text:10001009 _loop: ; CODE XREF: Tikeyicenapu+24j .text:10001009 mov eax, [esp+4+arg_0] ; static .text:1000100D mov esi, [esp+4+arg_8] ; key = 1888 or 31 38 38 38 .text:10001011 mov edx, ecx ; edx = count .text:10001013 mov eax, [eax] ; address of data/buffer .text:10001015 and edx, 3 ; edx = count & 3 .text:10001018 add eax, ecx ; address/buffer[index] .text:1000101A mov dl, [edx+esi] .text:1000101D xor [eax], dl .text:1000101F inc ecx ; inc count/index .text:10001020 cmp ecx, [esp+4+arg_4_size] .text:10001024 jb short _loop .text:10001026 pop esi .text:10001027 .text:10001027 loc_10001027: ; CODE XREF: Tikeyicenapu+6j .text:10001027 push 5Ah ; index .text:10001029 push 0 ; hWnd .text:1000102B call ds:GetDC .text:10001031 push eax ; hdc .text:10001032 call ds:GetDeviceCaps .text:10001038 retn 10h .text:10001038 Tikeyicenapu endp
If we were to look at fovuqonayura.mop in a hex editor we would see obfuscated data. The recurring patterns is a sign that XOR was likely used.
Encoded Data |
key = (0x31, 0x38, 0x38, 0x38) f = open('fovuqonayura.mop', 'rb') byte = f.read(1) count = 0 data = '' while byte != '': data = data + chr(ord(byte)^key[count & 3]) byte = f.read(1) count += 1 o = open( 'out.bin', 'wb') o.write(data) o.close()
Below is the decoded file.
Decoded Data |
.text:10001000 zaxiwezu proc near ; DATA XREF: .rdata:off_10002118o .text:10001000 .text:10001000 var_3D0 = dword ptr -3D0h .text:10001000 var_32C = dword ptr -32Ch .text:10001000 var_320 = dword ptr -320h .text:10001000 var_104 = byte ptr -104h .text:10001000 var_103 = byte ptr -103h .text:10001000 arg_4 = dword ptr 0Ch .text:10001000 arg_8 = dword ptr 10h .text:10001000 .text:10001000 push ebp .text:10001001 mov ebp, esp .text:10001003 sub esp, 3D0h .text:10001009 push ebx .text:1000100A push esi .text:1000100B mov esi, [ebp+arg_8] .text:1000100E push edi .text:1000100F mov edi, ds:LoadLibraryA .text:10001015 lea eax, [esi+0E9h] .text:1000101B push eax ; lpLibFileName .text:1000101C call edi ; LoadLibraryA .text:1000101E lea ecx, [esi+106h] .text:10001024 mov [ebp+arg_4], eax .text:10001027 push ecx ; lpProcName .text:10001028 push eax ; hModule .text:10001029 call ds:GetProcAddress .text:1000102F mov ebx, eax .text:10001031 lea eax, [esi+0CCh] .text:10001037 push eax .text:10001038 push [ebp+arg_4] .text:1000103B call ebx
Details around the process injection will be excluded from this post. I was more interested in the single function multiple DLL technique. In summary we have an NSIS installer executable, that writes six files to the %TEMP% dir, the installer executes Sohozovi.exe, which import four functions from four separate DLLs, these DLLs are used to decode a data file, then from the DLL process space hollow out the executable process and then write an executable from the decoded data file to the executable process memory space. Interesting obfuscation technique.
Virustotal Results
Note:
If we were to follow out the process in debugging hollow processes we would have set a breakpoint at the entrypoint of the newly started thread in the hollow process. During my debugging attempts the address contained zeroed out memory. The error looks to be caused by not writing the decoded executable to the address space of the parent process Sohozovi.exe. This error could be caused by anti-debugging or something else that I missed.
I don't understand, why the NSIS installer and the multiple DLLs? The technique is not new at all but it's done in a complicated and inefficient way...
ReplyDeleteMaybe it's on purpose, to defeat antivirus heuristics? Or maybe the programmer just didn't know what the hell he/she was doing :)
"complicated and inefficient way" is the key there. The more complicated it is the less likely it will be unpacked or emulated.
Delete