A forum for reverse engineering, OS internals and malware analysis 

Forum for analysis and discussion about malware.
 #24861  by rinn
 Wed Jan 07, 2015 8:56 am
Hello.

During this sample reverse engineering I came across very familiar code. Bot itself uses high number of obfuscated system calls, here they
Code: Select all
.text:00403EDF NtAllocateVirtualMemoryStub
.text:00403FDF NtCloseStub
.text:0040421F NtCreateFileStub
.text:0040409F NtCreateKeyStub
.text:0040401F NtDeleteValueKeyStub
.text:0040415F NtEnumerateKeyStub
.text:00403E9F NtFlushInstructionCacheStub
.text:00403E5F NtGetContextThreadStub
.text:0040419F NtLoadKeyStub
.text:00403F9F NtNotifyChangeKeyStub
.text:004040DF NtOpenKeyStub
.text:00403F5F NtOpenProcessStub
.text:00403D1F NtProtectVirtualMemoryStub
.text:00403F1F NtQuerySystemInformationStub
.text:0040411F NtQueryValueKeyStub
.text:00403D9F NtReadVirtualMemoryStub
.text:00403DDF NtResumeThreadStub
.text:00403E1F NtSetContextThreadStub
.text:0040405F NtSetValueKeyStub
.text:004041DF NtUnloadKeyStub
.text:0040429F NtWaitForSingleObjectStub
.text:0040425F NtWriteFileStub
.text:00403D5F NtWriteVirtualMemoryStub
Each routine called by obfuscated ID through dedicated sysenter gate, but before call it of course deobfuscated and xored with global key created from GetTickCount during bot initialization (ntdll service ID extraction routine located at .text:00403A70).

Example
Code: Select all
.text:00403CF0 NtProtectVirtualMemoryStub proc near    ; CODE XREF: OpenProcessForce+7Bp
.text:00403CF0                                         ; WriteProcessMemoryWithFlush+25p ...
.text:00403CF0                 mov     ecx, 5B63D1D7h
.text:00403CF5                 call    GetServiceIdFromHash
.text:00403CFA                 cmp     dword_42150C, 0
.text:00403D01                 jz      short loc_403D19
.text:00403D03                 xor     eax, g_dwXorKey
.text:00403D09                 lea     edx, [esp+arg_0]
.text:00403D0D                 xor     ecx, ecx
.text:00403D0F                 call    large dword ptr fs:0C0h
.text:00403D16                 retn

.text:00403D19
.text:00403D19 loc_403D19:                             ; CODE XREF: NtProtectVirtualMemoryStub+11j
.text:00403D19                 xor     eax, g_dwXorKey
.text:00403D1F                 call    NtProtectVirtualMemoryStub_sysenter
.text:00403D24                 retn
.text:00403D24 NtProtectVirtualMemoryStub endp
.text:00403D24
.text:00403D25 NtProtectVirtualMemoryStub_sysenter proc near
.text:00403D25                                         ; CODE XREF: NtProtectVirtualMemoryStub+2Fp
.text:00403D25                 mov     edx, esp
.text:00403D27                 sysenter
.text:00403D29                 retn
.text:00403D29 NtProtectVirtualMemoryStub_sysenter endp
Interesting code located at address .text:00403640 in unpacked bot binary. This is force OpenProcess routine similar to http://www.kernelmode.info/forum/viewto ... 986#p18986, used by bot for process injection. What interested me here is how exactly it used if NtOpenProcess with PAGE_GUARD trick fails then it trying again NtOpenProcess this time using direct system call through dedicated stub.

Best Regards,
-rin
 #24896  by EP_X0FF
 Sat Jan 10, 2015 5:49 am
Gootkit author more info. Warning, nothing from this can be considered as 100% trustworthy information, however it is better than future John Dow #1.

Nickname: MzH
Age: in between 24-26
Current location: Russia, SPb, moved in 2011 (after completing education?) first blogpost in the end of 2011.
Hometown: Russia, Tomsk
Higher education: TUSUR, around 2007-2011, http://www.tusur.ru/en/about/ "intellectual heart of Russia and Siberia — the city of Tomsk", ROFL.
Prefered coding language: C
Interested in: ring0, Node.JS
Email used for authentification: mz@cih.ms
Website: http://mz.cih.ms (unavailable)
Profiles found at: damagelab, exploit.in (last post in the 2011)
Vkontakte profile (could be fake): https://vk.com/id146690248 (name Denis Turin), see interesting screenshot from source code, related to dll process injection from driver.
Former cat:
Image
 #25609  by tomchop
 Sat Apr 11, 2015 10:00 am
The last sample I got my hands on (I'm attaching the .dll here) uses the AppCompat database to ensure persistence on the system. They effectively use sdbinst to install patches that modify the .reloc section of kernel32.dll (after it's loaded I guess) and insert custom shellcode. A jump to that shellcode is made right before the OpenFile (IIRC) function. The patches are activated for a whole bunch of processes (~15), including explorer.exe and most web browsers. The "patch" read, decrypts and loads the .dll from another key (in my case it was HKCU\Software\AppDataLow, BinaryImage32_[012345]) and calls its DllMain function. It still uses the HKCU\Software\cxsw key for storing two smaller encrypted blobs, which do not have explicit names (GUIDS). BTW, I think the persistence watchdog code is in the shellcode itself but haven't checked. Let me know if you want it too.

I was wondering, does anyone know how I can recover the code (or at least the assembly) of the node.js (javascript) code of the malware? I've successfully managed to recover malware.js and spyware.js which have lots of "require" statements from things which seem to be compiled C (like the src_iedriver\SpywareJSWrappers.cc that was mentioned earlier). Some of them I could find traces of in the original .dll (like the keylogging functions) but I couldn't find the content of the encryption modules ("gootkit_crypto") or the network communication modules ("packet"). My final objective is 1) To decrypt network comms (e.g. network config, VNC modules, etc.), and 2) To decrypt the blobs in the cxsw key.
Attachments
main gootkit dll
(2.32 MiB) Downloaded 77 times
 #25610  by EP_X0FF
 Sat Apr 11, 2015 10:03 am
Hello tomchop,

do you have dropper of this gootkit version?
 #25612  by EP_X0FF
 Sat Apr 11, 2015 10:30 am
Thanks, it seems dropper is full of debug strings with meaningful names.
 #25614  by EP_X0FF
 Sat Apr 11, 2015 11:43 am
Unpacked dropper in attach. Sdb structure below:
Code: Select all
<?xml version="1.0" encoding="IBM437" standalone="yes"?>
<SDB xmlns:xs="http://www.w3.org/2001/XMLSchema" path="sdb.sdb">
  <INDEXES>
    <INDEX>
      <INDEX_TAG type="xs:short">28679</INDEX_TAG>
      <INDEX_KEY type="xs:short">24577</INDEX_KEY>
      <INDEX_FLAGS type="xs:int">1</INDEX_FLAGS>
      <INDEX_BITS type="xs:base64Binary" />
    </INDEX>
  </INDEXES>
  <DATABASE>
    <OS_PLATFORM type="xs:int">0</OS_PLATFORM>
    <NAME type="xs:string">explorer.exe</NAME>
    <DATABASE_ID type="xs:string" baseType="xs:base64Binary">{aacd0ce0-9f9b-40e9-b4c6-f59033a6dc87}</DATABASE_ID>
    <LIBRARY>
      <SHIM_REF>
        <PATCH>
          <NAME type="xs:string">patchdata0</NAME>
          <PATCH_BITS type="xs:base64Binary" />
        </PATCH>
      </SHIM_REF>
    </LIBRARY>
    <EXE>
      <NAME type="xs:string">explorer.exe</NAME>
      <APP_NAME type="xs:string">explorer.exe</APP_NAME>
      <EXE_ID type="xs:string" baseType="xs:base64Binary">{5a22af14-0691-4481-9358-4afbf16ae7f7}</EXE_ID>
      <MATCHING_FILE>
        <NAME type="xs:string">explorer.exe</NAME>
      </MATCHING_FILE>
      <PATCH_REF>
        <NAME type="xs:string">patchdata0</NAME>
        <PATCH_TAGID type="xs:int">108</PATCH_TAGID>
      </PATCH_REF>
    </EXE>
  </DATABASE>
  <STRINGTABLE>
    <STRINGTABLE_ITEM type="xs:string">explorer.exe</STRINGTABLE_ITEM>
    <STRINGTABLE_ITEM type="xs:string">patchdata0</STRINGTABLE_ITEM>
  </STRINGTABLE>
</SDB>
Quite interesting code injection technique, I don't remember anything like that before in malware, usually in case of "hard patches" they use invasive code modification at binary level.
Attachments
pass: infected
(80.28 KiB) Downloaded 69 times
 #25615  by rinn
 Sat Apr 11, 2015 12:54 pm
Hello, EP_X0FF.

Just did a quick looking on that exe, seems reproducible.
Should we again try to recover it? :)

If only it can work on Win10...
Code: Select all
int __fastcall sub_102DE7(int a1, int a2, int a3)
{
  int v3; // ebx@1
  int v4; // esi@1
  int v5; // edi@1
  char v6; // al@2
  int result; // eax@4
  void *v8; // eax@8
  int v9; // eax@10
  bool v10; // zf@10
  int v11; // esi@10
  int v12; // eax@11
  size_t v13; // ecx@11
  void *v14; // eax@11
  int v15; // ecx@13
  void *v16; // ebx@14
  int v17; // edi@14
  void *v18; // ST144_4@16
  int v19; // esi@22
  int v20; // eax@23
  void *v21; // ecx@23
  void *v22; // eax@23
  void *v23; // eax@23
  int v24; // eax@25
  void *v25; // ecx@25
  void *v26; // eax@25
  int v27; // esi@27
  char v28; // [sp+130h] [bp-450h]@0
  unsigned int v29; // [sp+140h] [bp-440h]@10
  int v30; // [sp+140h] [bp-440h]@22
  unsigned int v31; // [sp+144h] [bp-43Ch]@22
  int v32; // [sp+148h] [bp-438h]@1
  int v33; // [sp+14Ch] [bp-434h]@11
  int v34; // [sp+150h] [bp-430h]@10
  unsigned int v35; // [sp+154h] [bp-42Ch]@13
  int v36; // [sp+158h] [bp-428h]@11
  int v37; // [sp+15Ch] [bp-424h]@1
  int v38; // [sp+160h] [bp-420h]@1
  int v39; // [sp+164h] [bp-41Ch]@8
  int v40; // [sp+168h] [bp-418h]@13
  int v41; // [sp+16Ch] [bp-414h]@11
  int v42; // [sp+170h] [bp-410h]@8
  char v43; // [sp+180h] [bp-400h]@18

  v32 = -1;
  v3 = a1;
  v4 = a2;
  v38 = a1;
  v5 = SdbCreateDatabase(a3, 0);
  v37 = v5;
  if ( !v5 )
  {
    v6 = GetLastError();
    OutputDebugPrint("GTK: SDBCreateDatabaseFromAppData : SdbCreateDatabase() failed %d", v6);
  }
  if ( SdbDeclareIndex(v5, 0x7007, 0x6001, 1, 1, &v32) )
  {
    if ( SdbStartIndexing(v5, v32) )
    {
      SdbStopIndexing(v5, v32);
      SdbCommitIndexes(v5);
      v39 = SdbBeginWriteListTag(v5, 0x7001);
      SdbWriteDWORDTag(v5, 0x4023, 0);
      v8 = ToUnicode((void *)v4);
      SdbWriteStringTag(v5, 0x6001, v8);
      if ( CoCreateGuid(&v42) )
        OutputDebugPrint("GTK: SafeCoCreateGuid : CoCreateGuid failed", v28);
      SdbWriteBinaryTag(v5, 36871, &v42, 16);
      v9 = SdbBeginWriteListTag(v5, 0x7002);
      v29 = 0;
      v10 = *(_DWORD *)(v3 + 4) == 0;
      v11 = *(_DWORD *)(v3 + 8);
      v34 = v9;
      if ( !v10 )
      {
        do
        {
          v33 = SdbBeginWriteListTag(v5, 0x7009);
          v12 = SdbBeginWriteListTag(v5, 0x7005);
          v13 = *(_DWORD *)(v11 + 12) + 8;
          v41 = v12;
          *(_DWORD *)(v11 + 16) = v12;
          v14 = MyHeapAlloc(v13);
          v36 = (int)v14;
          if ( v14 )
          {
            v35 = 0;
            v10 = *(_DWORD *)(v11 + 8) == 0;
            v15 = *(_DWORD *)(v11 + 20);
            v40 = *(_DWORD *)(v11 + 20);
            if ( !v10 )
            {
              v16 = v14;
              v17 = v15;
              do
              {
                memcpy(v16, *(const void **)v17, *(_DWORD *)(v17 + 4));
                v16 = (char *)v16 + *(_DWORD *)(v17 + 4);
                v17 = *(_DWORD *)(v17 + 8);
                ++v35;
              }
              while ( v35 < *(_DWORD *)(v11 + 8) );
              v5 = v37;
              v18 = v16;
              v3 = v38;
              v14 = v18;
            }
            *(_DWORD *)v14 = 0;
            *((_DWORD *)v14 + 1) = 0;
          }
          else
          {
            OutputDebugPrint("GTK: SDBGetPatchDataBuffer : Failed to allocate memory\n", v28);
          }
          wsprintfW(&v43, L"patchdata%d", v29);
          OutputDebugPrint("GTK: SDBCreateDatabaseFromAppData : write tag %ws", (unsigned int)&v43);
          SdbWriteStringTag(v5, 24577, &v43);
          SdbWriteBinaryTag(v5, 36866, v36, *(_DWORD *)(v11 + 12) + 8);
          MyHeapFree((void *)v36);
          SdbEndWriteListTag(v5, v41);
          SdbEndWriteListTag(v5, v33);
          v11 = *(_DWORD *)(v11 + 24);
          ++v29;
        }
        while ( v29 < *(_DWORD *)(v3 + 4) );
        v9 = v34;
      }
      SdbEndWriteListTag(v5, v9);
      SdbStartIndexing(v5, v32);
      if ( *(_DWORD *)(v3 + 4) > 0x3E7u )
        OutputDebugPrint("GTK: SDBCreateDatabaseFromAppData : Too many patches, this can be increased if needed", v28);
      v31 = 0;
      v19 = *(_DWORD *)(v3 + 8);
      v30 = *(_DWORD *)(v3 + 8);
      if ( *(_DWORD *)(v3 + 4) )
      {
        do
        {
          v20 = SdbBeginWriteListTag(v5, 28679);
          v21 = *(void **)v3;
          v33 = v20;
          v22 = ToUnicode(v21);
          SdbWriteStringTag(v5, 24577, v22);
          v23 = ToUnicode(*(void **)v3);
          SdbWriteStringTag(v5, 24582, v23);
          if ( CoCreateGuid(&v42) )
            OutputDebugPrint("GTK: SafeCoCreateGuid : CoCreateGuid failed", v28);
          SdbWriteBinaryTag(v5, 36868, &v42, 16);
          v24 = SdbBeginWriteListTag(v5, 28680);
          v25 = *(void **)v19;
          v34 = v24;
          v26 = ToUnicode(v25);
          SdbWriteStringTag(v5, 24577, v26);
          if ( *(_DWORD *)(v19 + 4) )
            SdbWriteDWORDTag(v5, 16395, *(_DWORD *)(v19 + 4));
          SdbEndWriteListTag(v5, v34);
          v27 = SdbBeginWriteListTag(v5, 28682);
          wsprintfW(&v43, L"patchdata%d", v31);
          OutputDebugPrint("GTK: SDBCreateDatabaseFromAppData : write patch %ws", (unsigned int)&v43);
          SdbWriteStringTag(v5, 24577, &v43);
          SdbWriteDWORDTag(v5, 16389, *(_DWORD *)(v30 + 16));
          SdbEndWriteListTag(v5, v27);
          SdbEndWriteListTag(v5, v33);
          ++v31;
          v19 = *(_DWORD *)(v30 + 24);
          v30 = *(_DWORD *)(v30 + 24);
        }
        while ( v31 < *(_DWORD *)(v3 + 4) );
      }
      SdbEndWriteListTag(v5, v39);
      SdbCloseDatabaseWrite(v5);
      result = ShimFlushCache(0, 0, 0, 0);
    }
    else
    {
      result = OutputDebugPrint("GTK: SDBCreateDatabaseFromAppData : Failed to start indexing", v28);
    }
  }
  else
  {
    result = OutputDebugPrint("GTK: SDBCreateDatabaseFromAppData : Failed to declare index", v28);
  }
  return result;
}
Best Regards,
-rin
  • 1
  • 2
  • 3
  • 4
  • 5
  • 7