DodgeBox: A deep dive into the updated arsenal of APT41 | Part 1

  • ChatGPT paged: Each PDF page to text, then ChatGPT 4o (detailed)
  • Gemini 2.0: Full PDF with gemini-2.0-flash (8k output token limit)
  • Gemini 2.5: Full PDF with gemini-2.5-flash-preview-05-20 (65k output tokens limit)
  • Original: All text extracted from PDF

Original Text

DodgeBox, a reflective DLL loader written in C, showcases similarities to StealthVector in terms of concept but incorporates significant improvements in its implementation. It offers various capabilities, including decrypting and loading embedded DLLs, conducting environment checks and bindings, and executing cleanup procedures. What sets DodgeBox apart from other malware is its unique algorithms and techniques. During our threat hunting activities, we came across two DodgeBox samples that were designed to be sideloaded by signed legitimate executables. One of these executables was developed by Sandboxie (SandboxieWUAU.exe), while the other was developed by AhnLab. All exports within the DLL point to a single function that primarily invokes the main function of the malware, as illustrated below: void SbieDll_Hook() { if ( dwExportCalled ) { Sleep(0xFFFFFFFF); } else { hSbieDll_ = hSbieDll; dwExportCalled = 1; MalwareMain(); } } MalwareMain implements the main functionality of DodgeBox, and can be broken down into three main phases: 1. Decryption of DodgeBox’s configuration DodgeBox employs AES Cipher Feedback (AES-CFB) mode for encrypting its configuration. AES- CFB transforms AES from a block cipher into a stream cipher, allowing for the encryption of data with different lengths without requiring padding. The encrypted configuration is embedded within the .data section of the binary. To ensure the integrity of the configuration, DodgeBox utilizes hard-coded MD5 hashes to validate both the embedded AES keys and the encrypted configuration. For reference, a sample of DodgeBox's decrypted configuration can be found in the Appendix section of this blog. We will reference this sample configuration using the variable Config in the following sections. 2. Execution guardrails and environment setup After decrypting its configuration, DodgeBox performs several environment checks to ensure it is DodgeBox | ThreatLabz Yin Hong Chang, Sudeep Singh Technical Analysis Attack chain APT41 employs DLL sideloading as a means of executing DodgeBox. They utilize a legitimate executable (taskhost.exe), signed by Sandboxie, to sideload a malicious DLL (sbiedll.dll). This malicious DLL, DodgeBox, serves as a loader and is responsible for decrypting a second stage payload from an encrypted DAT file (sbiedll.dat). The decrypted payload, MoonWalk functions as a backdoor that abuses Google Drive for command-and-control (C2) communication. The figure below illustrates the attack chain at a high level. Figure 1: Attack chain used to deploy the DodgeBox loader and MoonWalk backdoor. DodgeBox analysis running on its intended target. Execution guardrail: Argument check DodgeBox starts by verifying that the process was launched with the correct arguments. It scans the argv parameter for a specific string defined in Config.szArgFlag. Next, it calculates the MD5 hash of the subsequent argument and compares it to the hash specified in Config.rgbArgFlagValueMD5. In this case, DodgeBox expects the arguments to include --type driver. If this verification check fails, the process is terminated. Environment setup: API Resolution Afterwards, DodgeBox proceeds to resolve multiple APIs that are utilized for additional environment checks and setup. Notably, DodgeBox employs a salted FNV1a hash for DLL and function names. This salted hash mechanism aids DodgeBox in evading static detections that typically search for hashes of DLL or function names. Additionally, it enables different samples of DodgeBox to use distinct values for the same DLL and function, all while preserving the integrity of the core hashing algorithm. The following code shows DodgeBox calling its ResolveImport function to resolve the address of LdrLoadDll, and populating its import table. // ResolveImport takes in (wszDllName, dwDllNameHash, dwFuncNameHash) sImportTable->ntdll_LdrLoadDll = ResolveImport(L"ntdll", 0xFE0B07B0, 0xCA7BB6AC); Inside the ResolveImport function, DodgeBox utilizes the FNV1a hashing function in a two-step process. First, it hashes the input string, which represents a DLL or function name. Then, it hashes a salt value separately. This two-step hashing procedure is equivalent to hashing the concatenation of the input string and salt. The following pseudo-code represents the implementation of the salted hash: dwHash = 0x811C9DC5; // Standard initial seed for FNV1a pwszInputString_Char = pwszInputString; cchInputString = -1LL; do ++cchInputString; while ( pwszInputString[cchInputString] ); pwszInputStringEnd = (pwszInputString + 2 * cchInputString); if ( pwszInputString < pwszInputStringEnd ) { do // Inlined FNV1a hash { chChar = pwszInputString_Char; pwszInputString_Char = (pwszInputString_Char + 1); dwHash = 0x1000193 * (dwHash ^ chChar); } while ( pwszInputString_Char < pwszInputStringEnd ); } v17 = &g_HashSaltPostfix; // Salt value: CB 24 B4 BA do // Inlined FNV1a hash, use previous hash as seed { v18 = v17; v17 = (v17 + 1); dwHash = 0x1000193 * (dwHash ^ v18); } while ( v17 < g_HashSaltPostfix_End ); A Python script to generate the salted hashes is included in the Appendix. In addition to the salted hash implementation, DodgeBox incorporates another noteworthy feature in its ResolveImport function. This function accepts both the DLL name as a string and its hash value as arguments. This redundancy appears to be designed to provide flexibility, allowing DodgeBox to handle scenarios where the target DLL has not yet been loaded. In such cases, DodgeBox invokes the LoadLibraryW function with the provided string to load the DLL dynamically. Furthermore, DodgeBox effectively handles forwarded exports and exports by ordinals. It utilizes ntdll!LdrLoadDll and ntdll!LdrGetProcedureAddressEx when necessary to resolve the address of the exported function. This approach ensures that DodgeBox can successfully resolve and utilize the desired functions, regardless of the export method used. Environment setup: DLL unhooking Once DodgeBox has resolved the necessary functions, it proceeds to scan and unhook DLLs that are loaded from the System32 directory. This process involves iterating through the .pdata section of each DLL, retrieving each function’s start and end addresses, and calculating an FNV1a hash for the bytes of each function. DodgeBox then computes a corresponding hash for the same function's bytes as stored on disk. If the two hashes differ, potential tampering can be detected, and DodgeBox will replace the in-memory function with the original version from the disk. For each DLL that has been successfully scanned, DodgeBox marks the corresponding LDR_DATA_TABLE_ENTRY by clearing the ReservedFlags6 field and setting the upper bit to 1. This marking allows DodgeBox to avoid scanning the same DLL twice. Environment setup: Disabling CFG Following that, DodgeBox checks if the operating system is Windows 8 or newer. If so, the code verifies whether Control Flow Guard (CFG) is enabled by calling GetProcessMitigationPolicy with the ProcessControlFlowGuardPolicy parameter. If CFG is active, the malware attempts to disable it. To achieve this, DodgeBox locates the LdrpHandleInvalidUserCallTarget function within ntdll.dll by searching for a specific byte sequence. Once found, the malware patches this function with a simple jmprax instruction: ntdll!LdrpHandleInvalidUserCallTarget: 00007ffefc8cf070 48ffe0 jmp rax 00007ffefc8cf073 cc int 3 00007ffe`fc8cf074 90 nop CFG verifies the validity of indirect call targets. When a CFG check fails, LdrpHandleInvalidUserCallTarget is invoked, typically raising an interrupt. At this point, the rax register contains the invalid target address. The patch modifies this behavior, calling the target directly instead of raising an interrupt, thus bypassing CFG protection. In addition, DodgeBox replaces msvcrt!_guard_check_icall_fptr with msvcrt! _DebugMallocator::~_DebugMallocator, a function that returns 0 to disable the CFG check performed by msvcrt. Execution guardrail: MAC, computer name, and user name checks Finally, DodgeBox performs a series of checks to verify if it is configured to run on the current machine. The malware compares the machine’s MAC address against Config.rgbTargetMac, and compares the computer name against Config.wszTargetComputerName. Depending on the Config.fDoCheckIsSystem flag, DodgeBox checks whether it is running with SYSTEM privileges. If any of these checks fail, the malware terminates execution. 3. Payload decryption and environment keying Payload decryption In the final phase, DodgeBox commences the decryption process for the MoonWalk payload DAT file. The code starts by inspecting the first four bytes of the file. If these bytes are non-zero, it signifies that the DAT file has been tied to a particular machine, (which is described below). However, if the DAT file is not machine-specific, DodgeBox proceeds to decrypt the file using AES- CFB encryption, utilizing the key parameters stored in the configuration file. In the samples analyzed by ThreatLabz, this decrypted DAT file corresponds to a DLL, which is the MoonWalk backdoor. Environment keying of the payload After the decryption process, DodgeBox takes the additional step of keying the payload to the current machine. It accomplishes this by re-encrypting the payload using the Config.rgbAESKeyForDatFile key. However, in this specific scenario, the process deviates from the configuration file's IV (Initialization Vector). Instead, it utilizes the MD5 hash of the current machine's GUID as the AES IV. This approach guarantees that the decrypted DAT file cannot be decrypted on any other machine, thus enhancing the payload's security. Loading the payload using DLL hollowing Next, DodgeBox reflectively loads the payload using a DLL hollowing technique. At a high level, the process begins with the random selection of a host DLL from the System32 directory, ensuring it is not on a blocklist (DLL blocklist available in the Appendix section) and has a sufficiently large .text section. A copy of this DLL is then created at C: \Windows\Microsoft.NET\assembly\GAC_MSIL\System.Data.Trace\v4.0_4.0.0.0__\.dll. DodgeBox modifies this copy by disabling the NX flag, removing the reloc and TLS sections, and patching its entry point with a simple return 1. Following the preparation of the host DLL for injection, DodgeBox proceeds by zeroing the PE headers, and the IMAGE_DATA_DIRECTORY structures corresponding to the import, reloc, and debug directories of the payload DLL. This modified payload DLL is then inserted into the previously selected host DLL. The resulting copy of the modified host DLL is loaded into memory using the NtCreateSection and NtMapViewOfSection APIs. Once the DLL is successfully loaded, DodgeBox updates the relevant entries in the Process Environment Block (PEB) to reflect the newly loaded DLL. To further conceal its activities, DodgeBox overwrites the modified copy of the host DLL with its original contents, making it appear as a legitimate, signed DLL on disk. Finally, the malware calls the entrypoint of the payload DLL. Interestingly, if the function responsible for DLL hollowing fails to load the payload DLL, DodgeBox employs a fallback mechanism. This fallback function implements a traditional form of reflective DLL loading using NtAllocateVirtualMemory and NtProtectVirtualMemory. At this stage, the payload DLL has been successfully loaded, and control is transferred to the payload DLL by invoking the first exported function. Call stack spoofing There is one last technique employed by DodgeBox throughout all three phases discussed above: call stack spoofing. Call stack spoofing is employed to obscure the origins of API calls, making it more challenging for EDRs and antivirus systems to detect malicious activity. By manipulating the call stack, DodgeBox makes API calls appear as if they originate from trusted binaries rather than the malware itself. This prevents security solutions from gaining contextual information about the true source of the API calls. DodgeBox specifically utilizes call stack spoofing when invoking Windows APIs that are more likely to be monitored. As an example, it directly calls RtlInitUnicodeString, a Windows API that only performs string manipulation, instead of using stack spoofing. Figure 2: Normal example of stack trace from explorer.exe calling CreateFileW. In contrast, the next figure shows the call stack recorded by SysMon when DodgeBox uses stack spoofing to call the CreateFileW function. Notice that there is no indication of DodgeBox’s modules that triggered the API call. Instead, the modules involved all appear to be legitimate Windows modules. Figure 3: Stack trace of DodgeBox calling CreateFileW using the stack spoofing technique. There is an excellent writeup of this technique, so we will only highlight some implementation details specific to DodgeBox: When the CallFunction is invoked, DodgeBox uses a random jmp qword ptr [rbp+48h] gadget residing within the .text section of KernelBase. DodgeBox analyzes the unwind codes within the .pdata section to extract the unwind size for the function that includes the selected gadget. DodgeBox obtains the addresses of RtlUserThreadStart + 0x21 and BaseThreadInitThunk + 0x14, along with their respective unwind sizes. DodgeBox sets up the stack by inserting the addresses of RtlUserThreadStart + 0x21, BaseThreadInitThunk + 0x14, and the address of the gadget at the right positions, utilizing the unwind sizes retrieved. Following that, DodgeBox proceeds to insert the appropriate return address at [rbp+48h] and prepares the registers and stack with the necessary argument values to be passed to the API. This preparation ensures that the API is called correctly and with the intended parameters. Finally, DodgeBox executes a jmp instruction to redirect the control flow to the targeted API. Explore more Zscaler blogs (sImportTable->ntdll_RtlInitUnicodeString)(v25, v26); However, call stack spoofing is used when calling NtAllocateVirtualMemory, an API known to be abused by malware, as shown below: CallFunction( sImportTable->ntdll_NtAllocateVirtualMemory, // API to call 0, // Unused 6LL, // Number of parameters // Parameters to the API -1LL, &pAllocBase, 0LL, &dwSizeOfImage, 0x3000, PAGE_READWRITE) The technique mentioned above can be observed in the figures below. In the first figure, we can see a typical call stack when explorer.exe invokes the CreateFileW function. The system monitoring tool, SysMon, effectively walks the call stack, enabling us to understand the purpose behind this API call and examine the modules and functions involved in the process.

Original Text ChatGPT 4o Paged

DodgeBox, a reflective DLL loader written in C, showcases similarities to StealthVector in terms of concept but incorporates significant improvements in its implementation. It offers various capabilities, including decrypting and loading embedded DLLs, conducting environment checks and bindings, and executing cleanup procedures. What sets DodgeBox apart from other malware is its unique algorithms and techniques. During our threat hunting activities, we came across two DodgeBox samples that were designed to be sideloaded by signed legitimate executables. One of these executables was developed by Sandboxie (SandboxieWUAU.exe), while the other was developed by AhnLab. All exports within the DLL point to a single function that primarily invokes the main function of the malware, as illustrated below: void SbieDll_Hook() { if ( dwExportCalled ) { Sleep(0xFFFFFFFF); } else { hSbieDll_ = hSbieDll; dwExportCalled = 1; MalwareMain(); } } MalwareMain implements the main functionality of DodgeBox, and can be broken down into three main phases: 1. Decryption of DodgeBox’s configuration DodgeBox employs AES Cipher Feedback (AES-CFB) mode for encrypting its configuration. AES- CFB transforms AES from a block cipher into a stream cipher, allowing for the encryption of data with different lengths without requiring padding. The encrypted configuration is embedded within the .data section of the binary. To ensure the integrity of the configuration, DodgeBox utilizes hard-coded MD5 hashes to validate both the embedded AES keys and the encrypted configuration. For reference, a sample of DodgeBox's decrypted configuration can be found in the Appendix section of this blog. We will reference this sample configuration using the variable Config in the following sections. 2. Execution guardrails and environment setup After decrypting its configuration, DodgeBox performs several environment checks to ensure it is

Phase: Initial Access

  • Technique: DLL Sideloading
  • Procedure: DodgeBox samples are designed to be sideloaded by legitimate signed executables, such as SandboxieWUAU.exe and another developed by AhnLab.

Phase: Execution

  • Technique: DLL Export Function Execution
  • Procedure: The exported function SbieDll_Hook() is invoked, which checks if dwExportCalled is set. If not, it sets the flag and calls MalwareMain(). This is how the main malicious functionality is executed.

Phase: Persistence

  • Technique: Reflective DLL Loading
  • Procedure: DodgeBox uses a reflective DLL loader to execute its payload, bypassing standard loading procedures and potentially avoiding detection by security tools.

Phase: Decryption Phase

  • Technique: Decryption of Embedded Configuration
  • Procedure: DodgeBox decrypts its configuration using AES-CFB mode. The configuration, which is embedded in the .data section, is validated using hard-coded MD5 hashes for integrity.

Phase: Execution Guardrails

  • Technique: Environment Checks and Setup
  • Procedure: Post-decryption, DodgeBox conducts a series of environment checks to ensure it is operating in a legitimate environment, which might include anti-virtualization, anti-sandbox, or other evasion techniques.

DodgeBox | ThreatLabz Yin Hong Chang, Sudeep Singh Technical Analysis Attack chain APT41 employs DLL sideloading as a means of executing DodgeBox. They utilize a legitimate executable (taskhost.exe), signed by Sandboxie, to sideload a malicious DLL (sbiedll.dll). This malicious DLL, DodgeBox, serves as a loader and is responsible for decrypting a second stage payload from an encrypted DAT file (sbiedll.dat). The decrypted payload, MoonWalk functions as a backdoor that abuses Google Drive for command-and-control (C2) communication. The figure below illustrates the attack chain at a high level. Figure 1: Attack chain used to deploy the DodgeBox loader and MoonWalk backdoor. DodgeBox analysis

Phase: Execution

  • Technique: DLL Sideloading
  • Procedure: The threat actor uses a legitimate executable, taskhost.exe, signed by Sandboxie to sideload a malicious DLL, sbiedll.dll.

Phase: Payload Decryption

  • Technique: Encrypted File Decryption
  • Procedure: The malicious DLL, DodgeBox, decrypts a second-stage payload from an encrypted DAT file, sbiedll.dat.

Phase: Command and Control

  • Technique: Application Layer Protocol - Google Drive
  • Procedure: The decrypted payload, MoonWalk, functions as a backdoor and uses Google Drive for C2 communication.

running on its intended target. Execution guardrail: Argument check DodgeBox starts by verifying that the process was launched with the correct arguments. It scans the argv parameter for a specific string defined in Config.szArgFlag. Next, it calculates the MD5 hash of the subsequent argument and compares it to the hash specified in Config.rgbArgFlagValueMD5. In this case, DodgeBox expects the arguments to include --type driver. If this verification check fails, the process is terminated. Environment setup: API Resolution Afterwards, DodgeBox proceeds to resolve multiple APIs that are utilized for additional environment checks and setup. Notably, DodgeBox employs a salted FNV1a hash for DLL and function names. This salted hash mechanism aids DodgeBox in evading static detections that typically search for hashes of DLL or function names. Additionally, it enables different samples of DodgeBox to use distinct values for the same DLL and function, all while preserving the integrity of the core hashing algorithm. The following code shows DodgeBox calling its ResolveImport function to resolve the address of LdrLoadDll, and populating its import table. // ResolveImport takes in (wszDllName, dwDllNameHash, dwFuncNameHash) sImportTable->ntdll_LdrLoadDll = ResolveImport(L"ntdll", 0xFE0B07B0, 0xCA7BB6AC); Inside the ResolveImport function, DodgeBox utilizes the FNV1a hashing function in a two-step process. First, it hashes the input string, which represents a DLL or function name. Then, it hashes a salt value separately. This two-step hashing procedure is equivalent to hashing the concatenation of the input string and salt. The following pseudo-code represents the implementation of the salted hash: dwHash = 0x811C9DC5; // Standard initial seed for FNV1a pwszInputString_Char = pwszInputString; cchInputString = -1LL; do ++cchInputString; while ( pwszInputString[cchInputString] ); pwszInputStringEnd = (pwszInputString + 2 * cchInputString); if ( pwszInputString < pwszInputStringEnd ) { do // Inlined FNV1a hash { chChar = *pwszInputString_Char; pwszInputString_Char = (pwszInputString_Char + 1);

Phase: Execution Guardrail

  • Technique: Argument Check with Hash Validation
  • Procedure: The malware checks command-line arguments by verifying the presence of a specific string (--type driver). It then calculates the MD5 hash of the following argument and verifies it against a pre-configured hash (Config.rgbArgFlagValueMD5). If validation fails, the process terminates.

Phase: Execution

  • Technique: API Resolution with Custom Hashing
  • Procedure: DodgeBox uses a custom API resolution technique by employing a salted FNV1a hash for both DLL and function names. This method helps bypass static detections by using unique hashes for resolving API functions such as LdrLoadDll.
  • Command: Calls ResolveImport function with parameters (DLL name, DLL name hash, function name hash) to dynamically resolve API addresses.
  • Example Code: c sImportTable->ntdll_LdrLoadDll = ResolveImport(L"ntdll", 0xFE0B07B0, 0xCA7BB6AC);

Phase: Execution

  • Technique: Custom Hashing for Detection Evasion
  • Procedure: Implements a two-step FNV1a hashing process to combine input string hashing (DLL/function names) with a separate salt value, effectively creating a unique hash.
  • Example Code Pseudo: pseudo dwHash = 0x811C9DC5; // FNV1a Hashing Loop through input string

This setup enables DodgeBox to perform its functions while evading detection through unique, salted hash values for API calls.

dwHash = 0x1000193 * (dwHash ^ chChar); } while ( pwszInputString_Char < pwszInputStringEnd ); } v17 = &g_HashSaltPostfix; // Salt value: CB 24 B4 BA do // Inlined FNV1a hash, use previous hash as seed { v18 = *v17; v17 = (v17 + 1); dwHash = 0x1000193 * (dwHash ^ v18); } while ( v17 < g_HashSaltPostfix_End ); A Python script to generate the salted hashes is included in the Appendix. In addition to the salted hash implementation, DodgeBox incorporates another noteworthy feature in its ResolveImport function. This function accepts both the DLL name as a string and its hash value as arguments. This redundancy appears to be designed to provide flexibility, allowing DodgeBox to handle scenarios where the target DLL has not yet been loaded. In such cases, DodgeBox invokes the LoadLibraryW function with the provided string to load the DLL dynamically. Furthermore, DodgeBox effectively handles forwarded exports and exports by ordinals. It utilizes ntdll!LdrLoadDll and ntdll!LdrGetProcedureAddressEx when necessary to resolve the address of the exported function. This approach ensures that DodgeBox can successfully resolve and utilize the desired functions, regardless of the export method used. Environment setup: DLL unhooking Once DodgeBox has resolved the necessary functions, it proceeds to scan and unhook DLLs that are loaded from the System32 directory. This process involves iterating through the .pdata section of each DLL, retrieving each function’s start and end addresses, and calculating an FNV1a hash for the bytes of each function. DodgeBox then computes a corresponding hash for the same function's bytes as stored on disk. If the two hashes differ, potential tampering can be detected, and DodgeBox will replace the in-memory function with the original version from the disk. For each DLL that has been successfully scanned, DodgeBox marks the corresponding LDR_DATA_TABLE_ENTRY by clearing the ReservedFlags6 field and setting the upper bit to 1. This marking allows DodgeBox to avoid scanning the same DLL twice. Environment setup: Disabling CFG Following that, DodgeBox checks if the operating system is Windows 8 or newer. If so, the code verifies whether Control Flow Guard (CFG) is enabled by calling GetProcessMitigationPolicy with the ProcessControlFlowGuardPolicy parameter. If CFG is active, the malware attempts to

Phase: Discovery

  • Technique: Import Address Resolution
  • Procedure: DodgeBox uses a combination of direct DLL string handling and hashing to resolve imports. It checks DLL names against hashes and dynamically loads DLLs using LoadLibraryW if necessary. It resolves functions using ntdll!LdrLoadDll and ntdll!LdrGetProcedureAddressEx.

Phase: Defense Evasion

  • Technique: Unhooking DLLs
  • Procedure: DodgeBox scans the .pdata section of DLLs loaded from System32, calculates an FNV1a hash for each function, and compares it against hashes from the original disk files. If discrepancies are found, it replaces in-memory functions with the originals. Marks processed DLLs by altering the LDR_DATA_TABLE_ENTRY.

Phase: Defense Evasion

  • Technique: Disabling Control Flow Guard
  • Command: Use GetProcessMitigationPolicy with ProcessControlFlowGuardPolicy to check CFG status.
  • Procedure: If Control Flow Guard is enabled, the malware attempts to disable or bypass it, allowing it to execute without triggering CFG protections.

disable it. To achieve this, DodgeBox locates the LdrpHandleInvalidUserCallTarget function within ntdll.dll by searching for a specific byte sequence. Once found, the malware patches this function with a simple jmprax instruction: ntdll!LdrpHandleInvalidUserCallTarget: 00007ffefc8cf070 48ffe0 jmp rax 00007ffefc8cf073 cc int 3 00007ffe`fc8cf074 90 nop CFG verifies the validity of indirect call targets. When a CFG check fails, LdrpHandleInvalidUserCallTarget is invoked, typically raising an interrupt. At this point, the rax register contains the invalid target address. The patch modifies this behavior, calling the target directly instead of raising an interrupt, thus bypassing CFG protection. In addition, DodgeBox replaces msvcrt!_guard_check_icall_fptr with msvcrt! _DebugMallocator::~_DebugMallocator, a function that returns 0 to disable the CFG check performed by msvcrt. Execution guardrail: MAC, computer name, and user name checks Finally, DodgeBox performs a series of checks to verify if it is configured to run on the current machine. The malware compares the machine’s MAC address against Config.rgbTargetMac, and compares the computer name against Config.wszTargetComputerName. Depending on the Config.fDoCheckIsSystem flag, DodgeBox checks whether it is running with SYSTEM privileges. If any of these checks fail, the malware terminates execution. 3. Payload decryption and environment keying Payload decryption In the final phase, DodgeBox commences the decryption process for the MoonWalk payload DAT file. The code starts by inspecting the first four bytes of the file. If these bytes are non-zero, it signifies that the DAT file has been tied to a particular machine, (which is described below). However, if the DAT file is not machine-specific, DodgeBox proceeds to decrypt the file using AES- CFB encryption, utilizing the key parameters stored in the configuration file. In the samples analyzed by ThreatLabz, this decrypted DAT file corresponds to a DLL, which is the MoonWalk backdoor. Environment keying of the payload After the decryption process, DodgeBox takes the additional step of keying the payload to the current machine. It accomplishes this by re-encrypting the payload using the Config.rgbAESKeyForDatFile key. However, in this specific scenario, the process deviates from the configuration file's IV (Initialization Vector). Instead, it utilizes the MD5 hash of the current

Phase: Defense Evasion

  • Technique: Control Flow Guard (CFG) Bypass
  • Procedure:
    • Locate LdrpHandleInvalidUserCallTarget in ntdll.dll by searching for a specific byte sequence.
    • Patch the function with jmp rax to bypass CFG protection.
  • Assembly Modification:
    • ntdll!LdrpHandleInvalidUserCallTarget: 00007ffe`fc8cf070 48ffe0 jmp rax 00007ffe`fc8cf073 cc int 3 00007ffe`fc8cf074 90 nop
  • Technique: Modify Function Pointers
  • Procedure: Replace msvcrt!_guard_check_icall_fptr with msvcrt!_DebugMallocator<int>::~_DebugMallocator<int>.

Phase: Execution Guardrail

  • Technique: Execution Prevention via Environmental Checks
  • Procedure:
    • Compare machine’s MAC address against Config.rgbTargetMac.
    • Compare computer name against Config.wszTargetComputerName.
    • Check Config.fDoCheckIsSystem flag to ensure SYSTEM privileges.

Phase: Decryption

  • Technique: Encrypted Payload Execution
  • Procedure:
    • Inspect the first four bytes of the MoonWalk payload DAT file.
    • If non-zero, proceed with AES-CFB decryption using key parameters from the configuration file.

Phase: Environment Keying

  • Technique: Payload Re-encryption
  • Procedure:
    • Re-encrypt the payload using Config.rgbAESKeyForDatFile.
    • Use the MD5 hash of the current environment instead of the IV from the configuration file.

machine's GUID as the AES IV. This approach guarantees that the decrypted DAT file cannot be decrypted on any other machine, thus enhancing the payload's security. Loading the payload using DLL hollowing Next, DodgeBox reflectively loads the payload using a DLL hollowing technique. At a high level, the process begins with the random selection of a host DLL from the System32 directory, ensuring it is not on a blocklist (DLL blocklist available in the Appendix section) and has a sufficiently large .text section. A copy of this DLL is then created at C: \Windows\Microsoft.NET\assembly\GAC_MSIL\System.Data.Trace\v4.0_4.0.0.0__\.dll. DodgeBox modifies this copy by disabling the NX flag, removing the reloc and TLS sections, and patching its entry point with a simple return 1. Following the preparation of the host DLL for injection, DodgeBox proceeds by zeroing the PE headers, and the IMAGE_DATA_DIRECTORY structures corresponding to the import, reloc, and debug directories of the payload DLL. This modified payload DLL is then inserted into the previously selected host DLL. The resulting copy of the modified host DLL is loaded into memory using the NtCreateSection and NtMapViewOfSection APIs. Once the DLL is successfully loaded, DodgeBox updates the relevant entries in the Process Environment Block (PEB) to reflect the newly loaded DLL. To further conceal its activities, DodgeBox overwrites the modified copy of the host DLL with its original contents, making it appear as a legitimate, signed DLL on disk. Finally, the malware calls the entrypoint of the payload DLL. Interestingly, if the function responsible for DLL hollowing fails to load the payload DLL, DodgeBox employs a fallback mechanism. This fallback function implements a traditional form of reflective DLL loading using NtAllocateVirtualMemory and NtProtectVirtualMemory. At this stage, the payload DLL has been successfully loaded, and control is transferred to the payload DLL by invoking the first exported function. Call stack spoofing There is one last technique employed by DodgeBox throughout all three phases discussed above: call stack spoofing. Call stack spoofing is employed to obscure the origins of API calls, making it more challenging for EDRs and antivirus systems to detect malicious activity. By manipulating the call stack, DodgeBox makes API calls appear as if they originate from trusted binaries rather than the malware itself. This prevents security solutions from gaining contextual information about the true source of the API calls. DodgeBox specifically utilizes call stack spoofing when invoking Windows APIs that are more likely to be monitored. As an example, it directly calls RtlInitUnicodeString, a Windows API that only performs string manipulation, instead of using stack spoofing.

Phase: Defense Evasion

  • Technique: DLL Hollowing
  • Procedure:

    1. Randomly select a legitimate host DLL from the System32 directory that is not on a blocklist.
    2. Copy the selected DLL to C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Data.Trace\v4.0_4.0.0.0__<random bytes>\<name of chosen DLL>.dll.
    3. Modify the copy by disabling the NX flag and removing the reloc and TLS sections.
    4. Patch the entry point with return 1.
    5. Zero out the PE headers and IMAGE_DATA_DIRECTORY structures of the payload DLL.
    6. Insert the modified payload DLL into the selected host DLL.
    7. Load the modified host DLL into memory using NtCreateSection and NtMapViewOfSection.
    8. Update entries in the Process Environment Block (PEB).
    9. Overwrite the modified DLL with original contents to appear legitimate.
    10. Call the entrypoint of the payload DLL.
  • Technique: Reflective DLL Loading (Fallback)

  • Procedure:
    1. If DLL hollowing fails, use NtAllocateVirtualMemory and NtProtectVirtualMemory for traditional reflective DLL loading.
    2. Invoke the first exported function of the payload DLL.

Phase: Defense Evasion

  • Technique: Call Stack Spoofing
  • Procedure:
    1. Manipulate the call stack to obscure origins of API calls.
    2. Use call stack spoofing to make API calls appear as if they originate from trusted binaries.
    3. Directly call RtlInitUnicodeString for unmonitored string manipulation without spoofing.

Figure 2: Normal example of stack trace from explorer.exe calling CreateFileW. In contrast, the next figure shows the call stack recorded by SysMon when DodgeBox uses stack spoofing to call the CreateFileW function. Notice that there is no indication of DodgeBox’s modules that triggered the API call. Instead, the modules involved all appear to be legitimate Windows modules. Figure 3: Stack trace of DodgeBox calling CreateFileW using the stack spoofing technique. There is an excellent writeup of this technique, so we will only highlight some implementation details specific to DodgeBox: When the CallFunction is invoked, DodgeBox uses a random jmp qword ptr [rbp+48h] gadget residing within the .text section of KernelBase. DodgeBox analyzes the unwind codes within the .pdata section to extract the unwind size for the function that includes the selected gadget. DodgeBox obtains the addresses of RtlUserThreadStart + 0x21 and BaseThreadInitThunk + 0x14, along with their respective unwind sizes. DodgeBox sets up the stack by inserting the addresses of RtlUserThreadStart + 0x21, BaseThreadInitThunk + 0x14, and the address of the gadget at the right positions, utilizing the unwind sizes retrieved. Following that, DodgeBox proceeds to insert the appropriate return address at [rbp+48h] and prepares the registers and stack with the necessary argument values to be passed to the API. This preparation ensures that the API is called correctly and with the intended parameters. Finally, DodgeBox executes a jmp instruction to redirect the control flow to the targeted API. Explore more Zscaler blogs

Phase: Execution

  • Technique: API Call Spoofing
  • Procedure: DodgeBox uses stack spoofing to manipulate the call stack and hide its presence from detection mechanisms.

  • Stack Preparation:

  • Utilize a random jmp qword ptr [rbp+48h] gadget within the .text section of KernelBase.
  • Analyze the .pdata section to extract unwind sizes for functions to manipulate the stack accurately.
  • Obtain addresses and unwind sizes for RtlUserThreadStart + 0x21 and BaseThreadInitThunk + 0x14.

  • Stack Setup:

  • Insert addresses of RtlUserThreadStart + 0x21 and BaseThreadInitThunk + 0x14, along with the gadget address, at specific stack positions.
  • Use extracted unwind sizes to place addresses correctly.

  • Parameter Preparation:

  • Insert an appropriate return address at [rbp+48h].
  • Prepare the stack and registers with necessary arguments for the API call.

  • Execution:

  • Execute a jmp instruction to redirect control flow to the targeted API (CreateFileW), masquerading the call as being made by legitimate Windows modules.

(sImportTable->ntdll_RtlInitUnicodeString)(v25, v26); However, call stack spoofing is used when calling NtAllocateVirtualMemory, an API known to be abused by malware, as shown below: CallFunction( sImportTable->ntdll_NtAllocateVirtualMemory, // API to call 0, // Unused 6LL, // Number of parameters // Parameters to the API -1LL, &pAllocBase, 0LL, &dwSizeOfImage, 0x3000, PAGE_READWRITE) The technique mentioned above can be observed in the figures below. In the first figure, we can see a typical call stack when explorer.exe invokes the CreateFileW function. The system monitoring tool, SysMon, effectively walks the call stack, enabling us to understand the purpose behind this API call and examine the modules and functions involved in the process.

Phase: Memory Manipulation

  • Technique: API Call Spoofing for Memory Allocation
  • Procedure: The threat actor uses call stack spoofing to invoke the NtAllocateVirtualMemory API. This involves misleading tools like SysMon to disguise the origin of the API call, typically performed to allocate memory space for malicious purposes such as injecting code.

Example API Call:

  • Function: NtAllocateVirtualMemory
  • Parameters:
  • -1LL: Process handle (indicating current process)
  • &pAllocBase: Base address for allocation
  • 0LL: Zero bits
  • &dwSizeOfImage: Size of allocation
  • 0x3000: AllocationType (commonly used combination for commit and reserve)
  • PAGE_READWRITE: Memory protection constant allowing reading and writing
Gemini 2.0

Model: gemini-2.0-flash

Phase: Initial Access

  • Technique: DLL Sideloading
  • Procedure: The attacker utilizes a legitimate executable (taskhost.exe), signed by Sandboxie, to sideload a malicious DLL (sbiedll.dll).

Phase: Execution

  • Technique: Decryption of Embedded Data
  • Procedure: The malicious DLL (DodgeBox loader) decrypts a second-stage payload from an encrypted DAT file (sbiedll.dat) using AES-CFB. Integrity of the configuration is validated using hardcoded MD5 hashes of AES keys and the encrypted configuration.

  • Technique: API Resolution via FNV1a Hashing

  • Procedure: Resolve APIs used for environment checks and other processes using a salted FNV1a hashing algorithm.

  • Technique: Dynamic API resolution for DLLs not already loaded.

  • Procedure: Calls LoadLibraryW with the DLL string to load the DLL when the DLL is not already loaded.

  • Technique: DLL Unhooking

  • Procedure: Scan DLLs loaded from System32, compute FNV1a hashes of function bytes, and replace in-memory functions with original versions from disk if tampering is detected.

  • Technique: Control Flow Guard (CFG) Disabling

  • Procedure: Patch the LdrpHandleInvalidUserCallTarget function in ntdll.dll with jmp rax.
  • Procedure: Replace msvcrt!_guard_check_icall_fptr with msvcrt!_DebugMallocator<int>::~_DebugMallocator<int>.

  • Technique: Execution Guardrail

  • Procedure: Check if the process was launched with correct argument. Scan argv parameter for the szArgFlag value and calculates the MD5 hash of the subsequent argument, comparing it to rgbArgFlagValueMD5.

  • Technique: Environment Checks

  • Procedure: Compare the machine's MAC address, computer name against configured values (Config.rgbTargetMac, Config.wszTargetComputerName). Check for SYSTEM privileges (Config.fDoCheckIsSystem).

  • Technique: Re-encrypt Payload Using AES-CFB

  • Procedure: Re-encrypt payload with the AES Key defined in Config.rgbAESKeyForDatFile. Use the MD5 hash of the machine's GUID as AES IV.

  • Technique: Reflective DLL Loading via DLL Hollowing

  • Procedure:

    1. Select random host DLL from System32 excluding ones on a hardcoded blocklist. Ensure that selected DLL has a large .text section.
    2. Create copy of the host DLL in %windir%\\Microsoft.NET\\assembly\\GAC_MSIL\\System.Data.Trace\\v4.0_4.0.0.0_<random bytes from pcrt4!UuidCreate>\\<name of chosen DLL>.dll. Disable the NX flag.
    3. Remove relocations and TLS sections. Patch the entry point with return 1.
    4. Zero PE headers and IMAGE_DATA_DIRECTORY structures for import, reloc, and debug directories of the payload DLL.
    5. Insert the modified payload DLL into previously selected host DLL.
    6. Load host DLL copy into memory using NtCreateSection and NtMapViewOfSection APIs.
    7. Update relevant Process Environment Block (PEB) entries.
    8. Overwrite the copy of host DLL with original contents.
    9. Call entrypoint of payload DLL.
  • Technique: Call Stack Spoofing

  • Procedure: Use call stack spoofing during API invocations. Use trampoline gadget jmp qword ptr [rbp+48h] found in kernelbase.dll to redirect control flow to the API. Inserts the addresses of RtlUserThreadStart + 0x21, BaseThreadInitThunk + 0x14, at specific location in stack using the unwind codes.
Gemini 2.5

Model: gemini-2.5-flash-preview-05-20

Here's a structured breakdown of the attack procedures and techniques, suitable for red team emulation, based on the provided CTI report:

Phase: Initial Execution

  • Technique: DLL Sideloading
  • Procedure: The attacker initiates execution by utilizing a legitimate, signed executable to sideload a malicious DLL.
    • Executed Program (Legitimate): taskhost.exe
    • Executed Program (Legitimate): SandboxieWUAU.exe (or another legitimate executable developed by AhnLab, as observed in other samples)
    • Malicious Component: The sbiedll.dll file (DodgeBox loader) is sideloaded by the legitimate executable.

Phase: Loader Execution & Defense Evasion (DodgeBox)

  • Technique: Argument Validation (Anti-Analysis)
  • Procedure: The DodgeBox loader performs an argument check to ensure it was launched with specific parameters. If this check fails, the process terminates.
    • Expected Argument: --type driver (or similar, based on internal configuration Config.szArgFlag and Config.rgbArgFlagValueMD5).
  • Technique: API Resolution Evasion
  • Procedure: DodgeBox employs a salted FNV1a hashing function to resolve DLL and function names. It dynamically loads DLLs and resolves API addresses using LoadLibraryW, ntdll!LdrLoadDll, and ntdll!LdrGetProcedureAddressEx.
  • Technique: DLL Unhooking
  • Procedure: DodgeBox scans DLLs loaded from the System32 directory. It calculates an FNV1a hash of the bytes of in-memory functions and compares them to the corresponding bytes stored on disk. If differences are found (indicating potential tampering by security solutions), the in-memory function is replaced with the original version from the disk.
  • Technique: Disabling Control Flow Guard (CFG)
  • Procedure: If the operating system is Windows 8 or newer, DodgeBox attempts to disable CFG.
    • It locates and patches the ntdll!LdrpHandleInvalidUserCallTarget function by replacing its instructions with a jmp rax instruction.
    • It replaces msvcrt!_guard_check_icall_fptr with a function that returns 0 to disable CFG checks performed by msvcrt.
  • Technique: Environment Checks (Anti-Analysis/Targeting)
  • Procedure: DodgeBox performs a series of checks to verify if it is running on the intended machine.
    • Compares the machine's MAC address against a configured value.
    • Compares the computer name against a configured value.
    • Checks if it is running with SYSTEM privileges (depending on a configuration flag).
    • The malware terminates execution if any of these checks fail.

Phase: Payload Decryption & Loading

  • Technique: Payload Decryption
  • Procedure: DodgeBox decrypts the second-stage payload, identified as the MoonWalk backdoor, from an encrypted DAT file (sbiedll.dat) using AES-CFB encryption with keys from its configuration.
  • Technique: Payload Keying / Anti-Forensics
  • Procedure: After decryption, DodgeBox re-encrypts the payload using a configuration key but substitutes the Initialization Vector (IV) with the current machine's GUID. This effectively ties the payload to the specific machine, preventing its decryption elsewhere.
  • Technique: DLL Hollowing
  • Procedure: DodgeBox reflectively loads the MoonWalk payload using a DLL hollowing technique.
    • A legitimate host DLL is randomly selected from the System32 directory, ensuring it's not on a blocklist and has a sufficiently large .text section.
    • A copy of this host DLL is created at a new path, typically within C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Data.Trace\v4.0.0.0_ followed by random bytes and the chosen DLL name.
    • The copied DLL is modified by disabling the NX flag, removing reloc and TLS sections, and patching its entry point with a simple return 1 instruction.
    • The PE headers and IMAGE_DATA_DIRECTORY structures (import, reloc, and debug) of the MoonWalk payload DLL are zeroed out.
    • The modified MoonWalk payload DLL is inserted into the prepared host DLL.
    • The combined DLL is loaded into memory using NtCreateSection and NtMapViewOfSection.
    • Process Environment Block (PEB) entries are updated to reflect the newly loaded DLL.
    • The modified copy of the host DLL on disk is overwritten with its original contents to appear as a legitimate, signed DLL.
    • Control is transferred to the MoonWalk payload by invoking its first exported function.
  • Technique: Reflective DLL Loading (Fallback)
  • Procedure: If the DLL hollowing technique fails, DodgeBox employs a fallback mechanism of traditional reflective DLL loading using NtAllocateVirtualMemory and NtProtectVirtualMemory.

Phase: Defense Evasion (Post-Execution)

  • Technique: Call Stack Spoofing
  • Procedure: DodgeBox continuously employs call stack spoofing when invoking Windows APIs, particularly those susceptible to monitoring (e.g., NtAllocateVirtualMemory), to obscure the true origin of API calls. This makes them appear to originate from legitimate Windows modules.
    • It uses a jmp qword ptr [rbp+48h] gadget within KernelBase.dll.
    • It analyzes unwind codes from the .pdata section to determine unwind sizes.
    • It obtains addresses of RtlUserThreadStart + 0x21 and BaseThreadInitThunk + 0x14.
    • It manipulates the call stack by inserting these addresses and the gadget address at specific positions, preparing registers and stack for the API call.
    • It redirects control flow to the target API via a jmp instruction.

Phase: Command and Control

  • Technique: Google Drive for C2
  • Tool: MoonWalk Backdoor
  • Procedure: The MoonWalk backdoor establishes command-and-control (C2) communication by abusing Google Drive.