> For the complete documentation index, see [llms.txt](https://mapol.gitbook.io/home/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mapol.gitbook.io/home/blog/malware-analysis/loader/ghostfetch.md).

# GhostFetch

May 15, 2026

According to a report from Group-IB, during the first quarter of 2026, as the political situation continues, a cyberattack campaign occurred in the Middle East region. `The Olalampo campaign` is linked to an Iranian state sponsored threat actor group known as `MuddyWater`.

I found this sample on: [MalwareBazaar.](https://bazaar.abuse.ch/sample/8d2227f2c53d7e22a57e12c45cecdd43dbec08dbc3ab93e74e6df52cdf80548b/)

<figure><img src="https://3275977096-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FtSVMhiBgu1B4d2lBF9L3%2Fuploads%2Fu9ciAaITMamV1L2fVC2D%2Fimage.png?alt=media&amp;token=e09b69dc-d086-49ab-94dd-0112f1726a8b" alt=""><figcaption><p><a href="https://www.group-ib.com/blog/muddywater-operation-olalampo/">Group IB - Operation Olalampo</a></p></figcaption></figure>

***

### **Table of Contents** <a href="#e33d" id="e33d"></a>

1. [Sample Overview](#id-5e9f)
2. [Obfuscated Files or Information: Dynamic API Resolution (T1027.007)](#id-232d)
3. [Command and Scripting Interpreter (T1059)](#a9d0)
4. [Permission Groups Discovery: Local Groups (T1069.001)](#ef2f)
5. [System Owner/User Discovery (T1033)](#a2a7)
6. [Initial Process Discovery (T1057)](#id-9b6b)
7. [Deobfuscate/Decode Files or Information (T1140)](#id-5aea)
8. [Execution Guardrails: Mutual Exclusion (T1480.002)](#id-6f94)
9. [Debugger Evasion (T1622)](#id-6e28)
10. [Virtualization/Sandbox Evasion: User Activity Based Checks (T1497.002)](#id-8554)
11. [Virtualization/Sandbox Evasion: System Checks (T1497.001)](#e799)
12. [Virtualization/Sandbox Evasion: Time Based Checks (T1497.003)](#virtualization-sandbox-evasion-time-based-checks-t1497.003)
13. [Indicator Removal: Relocate Malware (T1070.010)](#id-396f)
14. [Final Process Discovery (T1057)](#f1dc)
15. [Encrypted Channel: Symmetric Cryptography (T1573.001)](#ed27)
16. [Application Layer Protocol: Web Protocols (T1071.001)](#d4da)
17. [Reflective Code Loading (T1620)](#id-2001)
18. [Execution Flow](#id-62e3)
19. [Conclusion](#id-9cdd)
20. [IOCs](#b959)
21. [YARA Rule](#d59a)
22. [Sigma Rule](#id-05cb)
23. [Additional Resources](#c225)

***

### **Sample Overview** <a href="#id-5e9f" id="id-5e9f"></a>

It was written in C++, using an IDE like Visual Studio 2022, and was compiled around January 27, 2026. Also, the sample appeared to have an overlay of carriage return and line feed plain text appended, which refers to `0d0a` or `\r\n`, as shown in Figure 2.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*aiYT-4qWKeguenlpUK-mgQ.png" alt="" width="563"><figcaption><p>Figure 1. Identified the compile time and languages used by the sample.</p></figcaption></figure>

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*RhfM31or2gW8rGz17qprvA.png" alt="" width="563"><figcaption><p>Figure 2. A carriage return and line feed.</p></figcaption></figure>

The overall entropy values show that the given sample does not implement any packing methods.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*0n1ZB7c8zKMRd6CIGl4y9A.png" alt="" width="563"><figcaption><p>Figure 3. The overall entropy values show that the given sample is not packed.</p></figcaption></figure>

***

### **Obfuscated Files or Information: Dynamic API Resolution (T1027.007)** <a href="#id-232d" id="id-232d"></a>

The sample implements a dynamic API resolution technique by calling functions such as `LoadLibraryA` and `GetProcAddress`, as shown in Figures 4 and 5.

For further analysis, the list of functions that begin to resolve will be processed and modified, as there are many of them.

<figure><img src="https://miro.medium.com/v2/resize:fit:485/1*o1TOAui1TCt8OMZknbmEgA.png" alt=""><figcaption><p>Figure 4. Dynamically loading the required library.</p></figcaption></figure>

<figure><img src="https://miro.medium.com/v2/resize:fit:604/1*Eu6Wo06JsZM9yFj1sHwPAg.png" alt=""><figcaption><p>Figure 5. Dynamically retrieving the required function address.</p></figcaption></figure>

***

### **Command and Scripting Interpreter (T1059)** <a href="#a9d0" id="a9d0"></a>

At first, the first argument of the process command line began to retrieved. During this step, 14 bytes of heap memory were allocated using `GetProcessHeap` as the allocation handle and `HeapAlloc` to allocate the memory space, with `8` specified as a flag to make sure that the allocated 14 bytes were initially filled with zero bytes.

After the heap allocation is completed, the word `static` is assigned, and each character is checked to see whether that the first argument of the process command line matches the word `static` or not.

<figure><img src="https://miro.medium.com/v2/resize:fit:836/1*3QBa_HHbjmOEO4jTBxFqQQ.png" alt="" width="563"><figcaption><p>Figure 6. Retrieved command line of the process.</p></figcaption></figure>

If the first argument of the command line matches the word `static`, then another heap allocation is performed, this time with 72 bytes of space, and `explorer.exe shell:RecycleBinFolder` is assigned to the allocated memory.

<figure><img src="https://miro.medium.com/v2/resize:fit:670/1*POq3G9676E1GqEGURa2q7Q.png" alt="" width="563"><figcaption><p>Figure 7. Specified command line for a new process.</p></figcaption></figure>

Now, heap memory is allocated again, this time 24 bytes and 104 bytes, followed by a call to the function `CreateProcessW` to create a process with the specified command line `explorer.exe shell:RecycleBinFolder`, which was assigned to memory earlier.

By that, the 24 bytes and 104 bytes allocated memory space are used to initialize the `STARTUPINFOW` and `PROCESS_INFORMATION` structures, where the values are set to zero.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*h7gWukmr2yZllWq9JPFhcA.png" alt="" width="563"><figcaption><p>Figure 8. Creating a new process with a specified command line.</p></figcaption></figure>

As seen in Figure 9, `RecycleBin` is spawned after `CreateProcessW` is called with the specified command line `static` during debugging of the sample.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*SlD-9YbRSzARSeWezUMwxA.png" alt="" width="563"><figcaption><p>Figure 9. The RecycleBin is opened.</p></figcaption></figure>

***

### **Permission Groups Discovery: Local Groups (T1069.001)** <a href="#ef2f" id="ef2f"></a>

Next, the sample calls the `AllocateAndInitializeSid` function, which’s used to create a SID with the specified authority `SECURITY_NT_AUTHORITY`, representing the local administrators group. Then, the `CheckTokenMembership` function is called to determine whether the current process token is associated with the local administrators group or not.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*ZvxqtWsBLwwtkrfmLHG4mA.png" alt="" width="563"><figcaption><p>Figure 10. Privilege check using the access token.</p></figcaption></figure>

***

### **System Owner/User Discovery (T1033)** <a href="#a2a7" id="a2a7"></a>

After that, the `GetUserObjectInformationW` function is called with `UOI_FLAGS`. This then checks whether the windows station it is running on is interactive or non-interactive, such as a headless server, for example windows Server Core. If it is running on a non-interactive windows station, `v22` will be set to zero, which’s later passed as an argument to the `sub_1400064C0` function.

This technique can also be used and implemented for sandbox evasion, especially in older sandboxes such as Cuckoo Sandbox, which use a non-interactive environment for automated analysis. That does not appear to be the case here, based on the analysis of this sample.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*WVmAEpdt4MhRRSanFrSkHA.png" alt="" width="563"><figcaption><p>Figure 11. Check the interactive windows station.</p></figcaption></figure>

***

### **Initial Process Discovery (T1057)** <a href="#id-9b6b" id="id-9b6b"></a>

After performing local group discovery, the sample checks the return value of the `sub_1400064C0` function, if the value is one, it terminates itself.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*CIwd54PzlWD_5NnFlqNfuQ.png" alt="" width="563"><figcaption><p>Figure 12. Condition check for self-termination.</p></figcaption></figure>

Stepping into the `sub_1400064C0` function, it checks the return value of the `sub_140004450` function, again, if it is one, it returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:514/1*0SmGIWQOCJrF67bmh2mFmg.png" alt="" width="563"><figcaption><p>Figure 13. Condition check for return value.</p></figcaption></figure>

Inside the `sub_140004450` function, a process discovery pattern is performed by calling `CreateToolhelp32Snapshot`, `Process32FirstW`, and `Process32NextW`, similar to what is done by many malware families and variants.

<figure><img src="https://miro.medium.com/v2/resize:fit:645/1*KzMUjpZ5bRUbwDE6qZnYCQ.png" alt="" width="563"><figcaption><p>Figure 14. Process discovery pattern.</p></figcaption></figure>

Now, the process discovery in this sample can be separated into two main phases, one for antivirus products and another for analysis tools and sandboxes.

As seen in Figure 15, some of the hexadecimal forms of decimal values can be directly resolved to their actual string values, such as `avp.exe`.

<figure><img src="https://miro.medium.com/v2/resize:fit:659/1*2WhYFCZfcdUSgHDaP6hryw.png" alt="" width="563"><figcaption><p>Figure 15. Directly resolving the antivirus string.</p></figcaption></figure>

However, some values are more heavily obfuscated and cannot be resolved directly, they must be deobfuscated by calling the `sub_140003FA0` function, which takes the address of the obfuscated value stored on the stack as an argument.

As the function returns, the result of the first deobfuscation process turns out to be the string `avastsvc.exe`, which correlates with the previously resolved value `avp.exe`. This shows and proves that the first phase of process discovery focuses on antivirus products.

Please see [**Deobfuscate/Decode Files or Information (T1140)**](#id-5aea) for more information about the deobfuscation process used in this sample.

<figure><img src="https://miro.medium.com/v2/resize:fit:873/1*6L-y_xfpE82I1BJdeLczow.png" alt="" width="563"><figcaption><p>Figure 16. sub_140003FA0 deobfuscates the antivirus string.</p></figcaption></figure>

After the deobfuscation process is completed, the do-while and while loops begin checking each character of the currently running processes in the snapshot, comparing them one by one with the previously deobfuscated antivirus process name.

By that, the loop is divided into two parts, each handling a specific antivirus process. If a process name in the snapshot matches one of the antivirus processes and its length is greater than or equal to seven, execution jumps to `LABEL_15`, and a value of one is returned.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*OZ4p6irN0HWF3kB1YOwEtA.png" alt="" width="563"><figcaption><p>Figure 17. Check for specific antivirus process names (1/2).</p></figcaption></figure>

For example, in Figure 18, the process name `avastsvc.exe` is the only one used for comparison with the currently running processes in the snapshot. Similarly, in Figure 17, `avp.exe` is the only process used for comparison within its own while loop.

<figure><img src="https://miro.medium.com/v2/resize:fit:594/1*1zzEGpGTbaXJVyDklYL6OA.png" alt="" width="563"><figcaption><p>Figure 18. Check for specific antivirus process names (2/2).</p></figcaption></figure>

Now, at `LABEL_15`, the `GetProcessHeap` function is called for a heap handle, followed by a call to `HeapFree` to free the allocated heap memory.

<figure><img src="https://miro.medium.com/v2/resize:fit:414/1*We2Xj7uROgJjesbUE5jwtg.png" alt="" width="563"><figcaption><p>Figure 19. Memory management and cleanup.</p></figcaption></figure>

After the first phase of process discovery is completed, the second phase begins. The same pattern is used, obfuscated values are stored on the stack, and the function is called to deobfuscate those values.

Please see the [**Conclusion**](#id-9cdd) for more information about the affected process names.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*06s4IXJ0D3GoMrnicHRVvg.png" alt="" width="563"><figcaption><p>Figure 20. Deobfuscation of multiple process names.</p></figcaption></figure>

In the second phase of process discovery, the implementation is similar to the first phase. Each character of each snapshotted process name is compared with a deobfuscated process name, if a match is found, execution jumps to `LABEL_33`.

<figure><img src="https://miro.medium.com/v2/resize:fit:624/1*qU_NCZe-fPoNVeEm9mKUlg.png" alt="" width="563"><figcaption><p>Figure 21. Check for specific analysis tools and sandboxes process names (1/2).</p></figcaption></figure>

However, if a process name in the snapshot does not match a deobfuscated process name, execution jumps to `LABEL_22` to compare the next process in the snapshot against the current deobfuscated process name.

This flow continues until all process names in the snapshot have been compared against the current deobfuscated process name. The next deobfuscated process name is then compared against all process names in the snapshot from the beginning, and the cycle repeats.

<figure><img src="https://miro.medium.com/v2/resize:fit:405/1*hwbmCWAbtm4CJ3kIXinmPA.png" alt="" width="563"><figcaption><p>Figure 22. Check for specific analysis tools and sandboxes process names (2/2).</p></figcaption></figure>

Now, if execution jumps to `LABEL_33`, a value of one is returned from the function, causing the sample to terminate itself due to its condition check.

On the other hand, at `LABEL_55`, if none of the process names in the snapshot match any of the deobfuscated names, a value of zero is returned.

<figure><img src="https://miro.medium.com/v2/resize:fit:265/1*6Eu2u5wzOCqqvXol8XoM3w.png" alt=""><figcaption><p>Figure 23. A value returned from the function.</p></figcaption></figure>

***

### **Deobfuscate/Decode Files or Information (T1140)** <a href="#id-5aea" id="id-5aea"></a>

To understand the overall concept of the deobfuscation process and algorithm, analyzing the `sub_140003FA0` function reveals a deobfuscation pattern that primarily uses subtraction operations on pointers to stack addresses where the obfuscated values, stored as decimal numbers, reside, in order to retrieve their original values.

<figure><img src="https://miro.medium.com/v2/resize:fit:495/1*xMxD1edsuNHHEW6AYE9-AQ.png" alt="" width="563"><figcaption><p>Figure 24. Deobfuscation algorithm for an obfuscated value.</p></figcaption></figure>

Also, the function used to deobfuscate the values is applied differently, but it still follows a familiar pattern. The differences are found in specific parts of the algorithm, such as how subtraction is performed, using values like `254`, `251`, `249`, and others, or how it is applied based on the index of interest.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*_elxr26aphCIpLkKL0_xPQ.png" alt="" width="563"><figcaption><p>Figure 25. Obfuscation algorithm pattern across various functions.</p></figcaption></figure>

Note that each function and position may use these values differently based on the arguments passed to the specified function. For example, in the first call to the `sub_1400054D0` function, `result[1] = v6 - 254` results in the letter `l`, as shown in Figure 26.

<figure><img src="https://miro.medium.com/v2/resize:fit:781/1*cOVEqXwJk7OgaaWRJUI7cA.png" alt="" width="563"><figcaption><p>Figure 26. Obfuscation algorithm operations results in different letters (1/2).</p></figcaption></figure>

On the other hand, in the first call to the `sub_140005920` function, the same operations is used, but the result is different, producing the letter `p`, as shown in Figure 27.

This shows that the deobfuscation process depends on the values passed as arguments, and that the algorithm is likely hardcoded differently in each function for each specific value to be deobfuscated by the threat actors.

<figure><img src="https://miro.medium.com/v2/resize:fit:791/1*ts7pfLA_61aW8JLY21SsYA.png" alt="" width="563"><figcaption><p>Figure 27. Obfuscation algorithm operations results in different letters (2/2).</p></figcaption></figure>

***

### **Execution Guardrails: Mutual Exclusion (T1480.002)** <a href="#id-6f94" id="id-6f94"></a>

Now, after process discovery is complete, the mutex is checked. This check is divided into three parts.

First, it verifies whether the token belongs to the local administrators group. If it does, `v12` is initialized using the return value of `sub_140003770`. If it is run on a non-interactive windows station, the return value of `sub_140003B20` is used instead. However, if none of these conditions are met, `sub_140003C00` is used.

<figure><img src="https://miro.medium.com/v2/resize:fit:498/1*T9dD8XWxRUx5njWFBPX9mg.png" alt="" width="563"><figcaption><p>Figure 28. The use of mutex strings depends on the privileges used.</p></figcaption></figure>

Inside these functions, the actual mutex strings are obfuscated. The function used to deobfuscate those strings is the same for each obfuscated mutex string, `sub_140003850`, where the deobfuscation algorithm and pattern are similar to those analyzed earlier in [**Deobfuscate/Decode Files or Information (T1140)**](#id-5aea).

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*Nnx1527g7nrePOMBcPaJTw.png" alt="" width="563"><figcaption><p>Figure 29. A comparison of each mutex string in the first phase in obfuscated form.</p></figcaption></figure>

After the deobfuscation is complete, it checks whether the mutex already exists. If it does, another set of mutex checks is performed. In this stage, the process is almost the same, where the actual mutex strings are obfuscated.

<figure><img src="https://miro.medium.com/v2/resize:fit:513/1*I0pSCtevRvItoejg89jF0g.png" alt="" width="563"><figcaption><p>Figure 30. If the first phase mutex exists, proceed to check the second</p></figcaption></figure>

Inside each function responsible for the obfuscated mutex strings, `sub_140003850` is again used to deobfuscate those strings, just as in the previous analysis.

Please see the [**Conclusion**](#id-9cdd) for more details about the deobfuscated mutex strings.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*Ht0cJgyyuWSt49OXteKBOg.png" alt="" width="563"><figcaption><p>Figure 31. A comparison of each mutex string in the second phase in obfuscated form.</p></figcaption></figure>

After the second phase of mutex deobfuscation begins, a check is performed. If the second phase mutex string already exists, the current running process will be terminated.

Otherwise, the second phase mutex string will be created instead, depending on the privileges under which the process is currently running.

<figure><img src="https://miro.medium.com/v2/resize:fit:688/1*JOhUweU6oMRqqcoT-SJ29Q.png" alt="" width="563"><figcaption><p>Figure 32. If both phase of mutexes exist, then terminate the current process.</p></figcaption></figure>

This is the same as in the first phase of mutex strings handling, if it does not yet exist, it will be deobfuscated and then created.

<figure><img src="https://miro.medium.com/v2/resize:fit:670/1*h7PD4ZMrL_W_qIXn-JBIEA.png" alt="" width="563"><figcaption><p>Figure 33. If the first phase mutexes does not exist, create them.</p></figcaption></figure>

***

### **Debugger Evasion (T1622)** <a href="#id-6e28" id="id-6e28"></a>

In the same function where the mutex are performed, several anti-analysis techniques are implemented.

At first, the function `sub_140006080` is called to perform a check before another code block continues, otherwise, it returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*U-wKLRj5WHeD52s5Si4QJA.png" alt="" height="371" width="700"><figcaption><p>Figure 34. Main anti-debug condition check.</p></figcaption></figure>

Inside the `sub_140006080` function, the PEB structure is used along with the `BeingDebugged` and `NtGlobalFlag` fields to determine whether the process is currently being debugged. If so, the function returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*je5UY7o-6-F4BOkelEp3SQ.png" alt="" height="89" width="700"><figcaption><p>Figure 35. The first anti-debug technique.</p></figcaption></figure>

Not just that, the `NtQueryInformationProcess` function is called with the `ProcessDebugPort` information class to determine whether the process is being debugged. If so, it returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*D7DtGIyGAHPU1JnMkQyUzA.png" alt="" height="408" width="700"><figcaption><p>Figure 36. The second anti-debug technique.</p></figcaption></figure>

Another anti-debugging technique is implemented by checking hardware breakpoints. The debug registers are checked for non-zero values, which could mean that the process is being debugged or that the hardware breakpoints are set. If so, again, the function returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:561/1*ALClr6QNlRVK3T4kKzYv7w.png" alt="" width="563"><figcaption><p>Figure 37. The third anti-debug technique.</p></figcaption></figure>

Also, that is not the end of the anti-debugging techniques. A function called `DebugBreak` is called to interrupt the debugger, forcing it to handle an exception instead of continuing normal debugging.

<figure><img src="https://miro.medium.com/v2/resize:fit:448/1*9ZjIkd3_QdY32MrfbKnIAg.png" alt="" width="563"><figcaption><p>Figure 38. The fourth anti-debug technique.</p></figcaption></figure>

Lastly, in this function, the obfuscated string `SampleOutput` is resolved and used as an argument for `OutputDebugStringW`, combined with `GetLastError`, to check whether the current process is being debugged. If a debugger is present, the function returns one, otherwise, it returns zero.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*5uCSr6ouOOBqQmvvK3iNZg.png" alt="" width="563"><figcaption><p>Figure 39. The fifth anti-debug technique.</p></figcaption></figure>

Now, stepping outside, if none of the anti-debugging techniques within the `sub_140006080` function are triggered, the `GetTickCount64` function is called as another anti-debugging technique to check for the presence of a debugger based on timing.

By that, a value of `100` is used as a applied. If the tick count is less than or equal to this value, another code block is executed, otherwise, the function returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*mpRjNk6CJOttik2bltXcag.png" alt="" height="367" width="700"><figcaption><p>Figure 40. The sixth anti-debug technique.</p></figcaption></figure>

***

### **Virtualization/Sandbox Evasion: User Activity Based Checks (T1497.002)** <a href="#id-8554" id="id-8554"></a>

From the previous analysis, if the tick count condition is met, a thread is created. However, if the thread fails to be created, execution will jumps to the `LABEL_36`.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*BmDGbOzOU15ZZwcm0TzXUQ.png" alt="" height="368" width="700"><figcaption><p>Figure 41. The function sub_1400040C0 begins running in a separate thread.</p></figcaption></figure>

Inside the thread, hooks are performed to monitor low-level mouse input events. The purpose is that if there is no mouse movement for a period of time, it may indicate that the process is running in a sandbox.

<figure><img src="https://miro.medium.com/v2/resize:fit:703/1*NXpJIccAOPIo6NOBeAP1NA.png" alt="" width="563"><figcaption><p>Figure 42. The first user activity based check for sandbox evasion technique.</p></figcaption></figure>

The idea is supported by the use of the `WaitForSingleObject` function, which waits up to twenty seconds for the thread to finish, followed by the `TerminateThread` and `UnhookWindowsHookEx` functions, which are self-explanatory.

In short, if no mouse movement occurs within twenty seconds, the thread is terminated and the mouse input hook is removed.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*hHLki7onHLs3V43QrBYY1A.png" alt="" height="368" width="700"><figcaption><p>Figure 43. The newly created thread will wait for a while before being terminated.</p></figcaption></figure>

***

### **Virtualization/Sandbox Evasion: System Checks (T1497.001)** <a href="#e799" id="e799"></a>

Now, the `EnumDisplayMonitors` function is called along with the `sub_140004260` function, where a condition check is performed to identify exclusions that result in a return value of zero instead of one.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*tLyr8pQ05vWsJfOSqOsOrg.png" alt="" height="362" width="700"><figcaption><p>Figure 44. The first system check for sandbox evasion technique.</p></figcaption></figure>

At first, it checks whether the screen resolution matches common values such as `1920`, `2560`, `1440`, `1080`, `1200`, `1600`, or `900` pixels. If the resolution does not match, a value of one is set as the fourth argument, which’s a pointer used in a previous conditional check.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*Pqd_UZjAhkwfWRTlht2-oQ.png" alt="" width="563"><figcaption><p>Figure 45. Various screen resolutions are used for checking.</p></figcaption></figure>

Inside the `sub_140004260` function, the `GetSystemInfo` function is called to check whether the number of CPU cores is less than two. This is followed by a call to `GlobalMemoryStatusEx` to check whether the RAM is less than `2 GB`.

<figure><img src="https://miro.medium.com/v2/resize:fit:526/1*Y1yeR-uyHMU_BQiLfOwjcw.png" alt="" width="563"><figcaption><p>Figure 46. The second system check for sandbox evasion technique.</p></figcaption></figure>

Then, the registry is also enumerated. The `USBSTOR` subkey is used to identify previously connected USB devices, and if fewer than two USB devices have been previously connected, the value of `v2` is set to one.

<figure><img src="https://miro.medium.com/v2/resize:fit:711/1*-ECQUFo1VPtwdU4Jjg9SNQ.png" alt="" width="563"><figcaption><p>Figure 47. Attached USB history begins to be enumerated.</p></figcaption></figure>

So, at the end of the function, if the machine has more than two CPU cores, at least two GB of RAM, and at least two previously connected USB devices, the function returns zero, otherwise, it returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:285/1*e2dcFSiLpeGVoMSdIwqMcw.png" alt="" width="563"><figcaption><p>Figure 48. Condition check for the system requirements of the sandbox evasion technique.</p></figcaption></figure>

***

### **Virtualization/Sandbox Evasion: Time Based Checks (T1497.003)**

After all system based sandbox evasion techniques have been checked and none are triggered, execution moves to `LABEL_36`. Inside this block, the `sub_1400062E0` function is called and its result is stored in `v22`, followed by a call to `GetTickCount64` to check whether the tick count is greater than or equal to the value of `v22`.<br>

However, if any one of the system based sandbox evasion techniques is triggered, the function immediately returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*Xva0wlqlmPeK_4Ucv8YVaw.png" alt="" height="369" width="700"><figcaption><p>Figure 49. The time based for sandbox evasion technique implemented.</p></figcaption></figure>

The value of `v22` is `1509`, meaning that if the tick count is greater than `1509`, the function returns zero, otherwise, it returns one.

<figure><img src="https://miro.medium.com/v2/resize:fit:703/1*U457XWIVc7XCZY0kfN-66A.png" alt="" width="563"><figcaption><p>Figure 50. The fixed value for the sandbox evasion technique is used.</p></figcaption></figure>

***

### **Indicator Removal: Relocate Malware (T1070.010)** <a href="#id-396f" id="id-396f"></a>

After all dependencies have been checked, whether related to anti-debugging, sandbox evasion, or privileges, the `sub_140006980` function is called. Within this function, the hardcoded string `%localappdata%\\Microsoft\\Windows`, is deobfuscated.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*zj78c-vrbSsPH1rz9qyl7g.png" alt="" width="563"><figcaption><p>Figure 51. Hardcoded %localappdata% path is deobfuscated.</p></figcaption></figure>

Then, it performs a check to determine whether the directory already exists. If not, the directory is created.

<figure><img src="https://miro.medium.com/v2/resize:fit:793/1*zDdZIXCUFXzXlekDx_lhrA.png" alt="" width="563"><figcaption><p>Figure 52. Directory existence check.</p></figcaption></figure>

Next, the string `BurnUtill` is deobfuscated and concatenated with the directory path `%localappdata%\\Microsoft\\Windows`, resulting in `%localappdata%\\Microsoft\\Windows\\BurnUtill`. After that, the same checking process is performed to determine whether the `BurnUtill` directory already exists, if not, it is created.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*Cr3ooS1JSWTJigitge1WBg.png" alt="" height="83" width="700"><figcaption><p>Figure 53. The BurnUtill directory is being setup.</p></figcaption></figure>

The same logic applies to the string `burn.exe`, which’s deobfuscated and concatenated with the previously constructed directory path `%localappdata%\\Microsoft\\Windows\\BurnUtill`, resulting in `%localappdata%\\Microsoft\\Windows\\BurnUtill\\burn.exe`.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*MjxAYFfRcy8WGrF6X8OkyA.png" alt="" height="84" width="700"><figcaption><p>Figure 54. The burn.exe file is being setup.</p></figcaption></figure>

However, this time the `CreateFileW` function is used instead, with the `GENERIC_READ` access right argument and the path of the currently running process.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*-RSnv46wYNGN94wZ4iJhQQ.png" alt="" height="123" width="700"><figcaption><p>Figure 55. The path of the current process is being setup.</p></figcaption></figure>

Then, the file handle created earlier is used together with the `GetFileSize` and `ReadFile` functions to read the contents of the file previously passed as an argument to the `CreateFileW` function, which’s the path of the currently running process.

<figure><img src="https://miro.medium.com/v2/resize:fit:845/1*cla08XTst4JD3jARwZoWww.png" alt="" width="563"><figcaption><p>Figure 56. The path of the current process is being read.</p></figcaption></figure>

Now, after reading the contents of the currently running process file, a file handle is created again using the `CreateFileW` function, this time with the `GENERIC_WRITE` access right as an argument.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*OV-ChdSiibTiQR2eLMfAhQ.png" alt="" width="563"><figcaption><p>Figure 57. A file creation handle is being setup.</p></figcaption></figure>

Lastly, in this function, the `WriteFile` function is used to create a file at the target path `%localappdata%\\Microsoft\\Windows\\BurnUtill\\burn.exe`, where the sample copies itself.

<figure><img src="https://miro.medium.com/v2/resize:fit:825/1*3dzFzw848gEqM4zmQ4jsBA.png" alt="" width="563"><figcaption><p>Figure 58. A file is copied to a new location.</p></figcaption></figure>

However, before copying itself to the new location, the PE sections are used for comparison. At first, the character length is compared with the length of the hardcoded string `.rsrc`. If the lengths match, each character is then compared one by one.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*8NDidBHuz7ofW-NHXtoEPw.png" alt="" width="563"><figcaption><p>Figure 59. Retrieval and comparison of PE sections.</p></figcaption></figure>

After the comparison is completed, the `.rsrc` section is filled with null bytes. As shown in Figure 60, `test.exe` is a modified sample used to experiment with and validate the null bytes hypothesis, while `burn.exe` is a newly self-copied of `test.exe`.

The results show that the prepared string `rsrctest` in the modified has been replaced with null bytes.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*98mZlWqyqadohy3bQkhiPg.png" alt="" width="563"><figcaption><p>Figure 60. The .rsrc section of a PE is being filled with null bytes.</p></figcaption></figure>

Now, after the self-copy process is completed, it checks whether the first-phase mutex has been created. If it has not yet been created, the recently self-copied sample, will be loaded into memory.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*oOg4APq05I4CUx4v7iXGLA.png" alt="" width="563"><figcaption><p>Figure 61. A mutex creation check is performed before process creation.</p></figcaption></figure>

However, if it has already been created, with `dword_140023B60` used as a condition flag, an infinite loop begins that uses `CryptAcquireContextW`, `CryptGenRandom`, and `Sleep` to generate delays before another set of mutex checks for each privilege is performed.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*7dJVy6iiI7K84JXrZttlWQ.png" alt="" width="563"><figcaption><p>Figure 62. If the mutex has already been created, jittering made before a backup check.</p></figcaption></figure>

This could be a re-check in case a bug occurs within the sample itself that causes the condition to be triggered, but if a mutex is not found, the infinite loop is breaks.

<figure><img src="https://miro.medium.com/v2/resize:fit:438/1*WCCPEiifNhwc1yPjwNliBg.png" alt="" width="563"><figcaption><p>Figure 63. Break the loop if the mutex does not exist.</p></figcaption></figure>

After the loop is break, meaning that the first phase mutex has not yet been created, the mutex is then created, followed by a call to `CreateProcessW`, where the recently self-copied sample is loaded into memory.

Please see [**Execution Guardrails: Mutual Exclusion (T1480.002)**](#id-6f94) for more information about mutexes.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*js4dbQaeVAl_w5K1xx6RQg.png" alt="" width="563"><figcaption><p>Figure 64. Creating a mutex for each privilege and creating a process.</p></figcaption></figure>

An unusual behavior was discovered during the analysis, after `burn.exe` was loaded into memory, multiple processes were spawned, causing the analysis machine to hang due to high CPU and memory usage, as processes and threads were repeatedly created.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*2bK4yXCq4WWOTPUzCInwtg.png" alt="" width="563"><figcaption><p>Figure 65. Multiple processes spawned in a short duration.</p></figcaption></figure>

***

### **Final Process Discovery (T1057)** <a href="#f1dc" id="f1dc"></a>

Now, stepping back for a moment, before the self-copy is performed, a series of process discovery checks are carried out using the same pattern.

However, the same antivirus process names in the previous analysis of [**Initial Process Discovery (T1057)**](#id-9b6b), `avp.exe` and `avastsvc.exe`, are used again.

<figure><img src="https://miro.medium.com/v2/resize:fit:600/1*rfjVzGS47bcRz_0aVFxZ2Q.png" alt="" width="563"><figcaption><p>Figure 66. The first two process names are repeatedly used.</p></figcaption></figure>

Other than that, various antivirus process names are used, following the same deobfuscation pattern seen in the previous analysis of [**Deobfuscate/Decode Files or Information (T1140)**](#id-5aea), where the decimal subtraction operations differ depending on the original strings.

Please see the [**Conclusion**](#id-9cdd) for more information about the affected antivirus process names.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*3t0AJ9c4wIUWaXSe54PM9g.png" alt="" width="563"><figcaption><p>Figure 67. Various antivirus process names are discovered.</p></figcaption></figure>

***

### **Encrypted Channel: Symmetric Cryptography (T1573.001)** <a href="#ed27" id="ed27"></a>

When the self-copied sample, was loaded into memory, the cryptographic setup began. By that, it acquired a handles for AES using CBC mode, with a 32 bytes key size. If the cryptographic setup failed, the current process was terminated.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*IUcd2YtwPBB9bFOYHRyaPA.png" alt="" height="324" width="700"><figcaption><p>Figure 68. AES cryptography setup.</p></figcaption></figure>

Stepping further, after the setup is completed, the data scheme for the data encryption is created inside the `sub_140002A50` function. First, the variable `v0` is initialized with the value from `Src`, which’s the path to where the sample copied itself.

<figure><img src="https://miro.medium.com/v2/resize:fit:821/1*Jy7bfELbs-4tRO_OtUAhJw.png" alt="" width="563"><figcaption><p>Figure 69. The path to the newly self-copied file is assigned to the v0 variable.</p></figcaption></figure>

Now, within the same function, it checks whether `CryptGenRandom` is able to return random bytes. If not, the fallback bytes sequence `123456789ABCDEF` is used instead, with both the fallback and random values having the same size of 15 bytes.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*T-barW-2XSYgosmu--ezTQ.png" alt="" height="178" width="700"><figcaption><p>Figure 70. Setup of random and fallback bytes.</p></figcaption></figure>

Next, a magic constant, `C99BF0F7F05E943088903AB588AD49FE`, with a size of 16 bytes, is used and appended after the first 15 bytes, whether they are fallback or random values.

<figure><img src="https://miro.medium.com/v2/resize:fit:829/1*Dbh2jWRw6pQ1saUODyerZQ.png" alt="" width="563"><figcaption><p>Figure 71. Setup of magic constant bytes.</p></figcaption></figure>

Lastly, the machine GUID is acquired and appended after the magic constant. Where the acquired GUID has a fixed size of 32 bytes.

<figure><img src="https://miro.medium.com/v2/resize:fit:843/1*EDGyWQl95cY8Y9ireaYOVg.png" alt="" width="563"><figcaption><p>Figure 72. Retrieved the machine GUID.</p></figcaption></figure>

To combine all of the recent analysis together, as shown in Figure 73, the original string, which’s the path to the recently self-copied sample, is replaced with either fallback or random bytes, constant magic, and machine GUID.

However, the total bytes size will depends on the size of directory path to which the self-copied sample is copied. The first three sections will remain the same bytes size, especially the second section, as it is magic constant with fixed bytes size no matter the condition.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*NRcFBpv0yXgF1OvV6qsnaA.png" alt="" width="563"><figcaption><p>Figure 73. Each section of the data scheme that is about to be encrypted.</p></figcaption></figure>

Next, it will uses the address pointing to the magic constant location, adding the `0x64`, and then jumps to the resulting address.

For example, if the address of the magic constant is `0x4BCD80`, adding `0x64` will results in `0x4BCDE4`, as shown in Figure 74.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*u0JRqtys07kF0bhvtp-Nbg.png" alt="" width="563"><figcaption><p>Figure 74. Address calculation for target bytes.</p></figcaption></figure>

Before jumping into the actual data encryption, a fixed obfuscated 32 bytes of key is already hardcoded within the sample.

<figure><img src="https://miro.medium.com/v2/resize:fit:770/1*WMpqyngOJkRJ5xI5QPbDVQ.png" alt="" width="563"><figcaption><p>Figure 75. Hardcoded deobfuscated encryption keys.</p></figcaption></figure>

This also applies to the 16 bytes initialization value, which’s also hardcoded within the sample, however, this time it is not obfuscated, with both values stored in hexadecimal format.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*r08flFRCmaeEVeFN0Q7-3A.png" alt="" width="563"><figcaption><p>Figure 76. Hardcoded initial values for encrpytion.</p></figcaption></figure>

Now, to encrypt the data, the `BCryptEncrypt` function is used. The first 68 bytes of the data scheme are retrieved as the target data for encryption, encrypted, and placed at the location calculated earlier using `0x64`, with padding data added.

As shown in Figure 77, the data after `42 00` is now scrambled.

<figure><img src="https://miro.medium.com/v2/resize:fit:835/1*7rxyz2Y7Gzb3fKchIEUkwQ.png" alt="" width="563"><figcaption><p>Figure 77. Result of encrypted data.</p></figcaption></figure>

To decrypt the data, since it uses symmetric encryption, the same key and initialization value used for encryption can also be used for decryption.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*iT3l_zK1mgFURTA_mOerQw.png" alt="" height="225" width="700"><figcaption><p>Figure 78. Symmetric encryption can be decrypted, the same way it used for encryption.</p></figcaption></figure>

As seen in Figure 79, the OpenSSL is used to decrypt the data with the `aes-256-cbc` argument, as the key size is 32 bytes. The result of decrypted data is shown in Figure 80.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*bK_dzAUi8Ujt5MmctaR_FA.png" alt="" width="563"><figcaption><p>Figure 79. Utilization of OpenSSL for decryption.</p></figcaption></figure>

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*wqaqxNyQ2KechurXnAyMjQ.png" alt="" width="563"><figcaption><p>Figure 80. Comparison result between encrypted and decrypted data.</p></figcaption></figure>

***

### **Application Layer Protocol: Web Protocols (T1071.001)** <a href="#d4da" id="d4da"></a>

Stepping into the `sub_140002C70` function, the sample begins making an HTTP request to download the second stage backdoor. A handle for the HTTP request is created by calling the `WinHttpOpen` and `WinHttpOpenRequest` functions.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*J0gV6G2OiLO_OgniCLBz1A.png" alt="" width="563"><figcaption><p>Figure 81. Handle creation for the HTTP connection.</p></figcaption></figure>

Meanwhile, the `WinHttpConnect` function is used to initialize the connection with the target server. As shown in Figure 82, the resolved C2 domain is already hardcoded within the sample.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*g1k9PNrv4d7SrC8Ae9-GSQ.png" alt="" width="563"><figcaption><p>Figure 82. The C2 server domain is being used.</p></figcaption></figure>

When the initialization is done, the deobfuscated URL path `/api/debut` is used. The deobfuscation algorithm is the same as the one used for other strings.

More information about the deobfuscation algorithm can be found in [**Deobfuscate/Decode Files or Information (T1140)**](#id-5aea).

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*tdgRHKVXH5u99ahyTJNqlA.png" alt="" width="563"><figcaption><p>Figure 83. A URL path for the C2 server domain is being used.</p></figcaption></figure>

After the URL path is set up, the request method used to send data to the server is the `POST` method. This is followed by a call to `WinHttpOpenRequest`, which’s used to open an HTTP connection request, as given its name.

<figure><img src="https://miro.medium.com/v2/resize:fit:809/1*QaIBM115Bh3mEaYar1cQjQ.png" alt="" width="563"><figcaption><p>Figure 84. The POST request method is used.</p></figcaption></figure>

Now, the data used as the body for the `POST` request is the encrypted section of the encryption data scheme. To retrieve this data, a calculation of the encryption data scheme address is performed.

For example, as seen in Figure 84, the default value of `R12` is `0x57CDE4`, which’s the address of the encrypted section of the encryption data scheme, adding it into `RDX`, which’s by default was `0x00`, this will results in `0x57CDE4`.

Later, the `WinHttpWriteData` function is called to send a `POST` request to `promoverse.org`, which serves as the C2 server, targeting the `/api/debut` path with the encrypted section of the data encryption scheme used as the request body.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*nT3TIns9QjAnEktH_hUgMw.png" alt="" width="563"><figcaption><p>Figure 85. Calculation of the encrypted data section address.</p></figcaption></figure>

After the request is sent, the `WinHttpReceiveResponse` function is called to wait for a response from the server. Then, the `WinHttpQueryHeaders` function is invoked with the `WINHTTP_QUERY_STATUS_CODE` flag to retrieve the HTTP status code.

If the received status code is `404`, the current running process is terminated. However, if the received status code is not equal to `200`, or if `WinHttpQueryDataAvailable` returns an error, it will jumps to the `LABEL_22`, where the data is sent again.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*1JSufOqPn0HFOj41JK9eYw.png" alt="" width="563"><figcaption><p>Figure 86. Status check of the HTTP response.</p></figcaption></figure>

Next, the `WinHttpReadData` function is called to read the response data from the server and store it at the location pointed to by the variable `a3`.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*wi7NCPDes3x-g3j9pdOtbw.png" alt="" width="563"><figcaption><p>Figure 87. Reading response data and storing it at the specified address.</p></figcaption></figure>

As shown in Figure 88, the third argument, `a3`, in the `sub_140002C70` function corresponds to the variable `v14`, where the variable `v15` is initialized with its value, which’s a pointer to the target buffer.

After the `sub_140002C70` function returns, with `v14` and `v15` now holding the address location of the response body from the server, the `BCryptDecrypt` function will now called to decrypt the data stored at those locations.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*u9bedPPeJGc3YMbC-7pkpA.png" alt="" height="358" width="700"><figcaption><p>Figure 88. Passing the response data address for decryption.</p></figcaption></figure>

***

### **Reflective Code Loading (T1620)** <a href="#id-2001" id="id-2001"></a>

Now, after the response data from the server has been decrypted, the sample begins loading the decrypted data into memory within the `sub_140003240` function.

First, it checks whether the buffer can be used. As analyzed previously, this buffer contains the decrypted response data retrieved from the server. This is followed by checks on the DOS and PE headers of the data contained in that buffer.

<figure><img src="https://miro.medium.com/v2/resize:fit:779/1*WpHalW80FRPopHrfORTIZw.png" alt="" width="563"><figcaption><p>Figure 89. Retrieving the DOS header.</p></figcaption></figure>

After the checks, the `BaseRelocationTable` and the `ImageBase` are retrieved, followed by the resolution of the `NtUnmapViewOfSection` function to unmap whatever is currently mapped at the image base address referenced by `v11`.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*tvVH40-nWAzwc4oa0HqhgQ.png" alt="" width="563"><figcaption><p>Figure 90. Retrieving the Base Relocation Table and ImageBase.</p></figcaption></figure>

Next, the `VirtualAlloc` function is called to allocate memory at the image base that was previously unmapped. The allocated size is equal to the `SizeOfImage` value of the decrypted response data, with the allocation type set to `MEM_COMMIT | MEM_RESERVE` and the memory protection set to `PAGE_EXECUTE_READWRITE`.

Later, the `SizeOfHeaders` value is retrieved, followed by the use of the `memcpy` function to copy data from the decrypted response data. The copied size is equal to the `SizeOfHeaders` value of the decrypted response data, and the destination is `v14`, which refers to the memory allocated earlier.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*0_gCL1HRr0ZjQXmgMxFsyA.png" alt="" height="392" width="700"><figcaption><p>Figure 91. Allocating a new memory and copying the PE header.</p></figcaption></figure>

After that, the start of the section headers is retrieved, where each section such as `.text`, `.rdata`, and `.data` is copied to the memory located after the PE headers copied earlier.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*_aNAMkEee7yTS3L5WqN-DQ.png" alt="" width="563"><figcaption><p>Figure 92. Retrieving each PE section and copying it.</p></figcaption></figure>

Next, the `ImportDirectory` is retrieved. This is used to dynamically load required libraries such as `kernel32.dll` and `shell32.dll` for further use, meaning that the imports must later be resolved.

Please see [**Obfuscated Files or Information: Dynamic API Resolution (T1027.007)**](#id-232d) for a clearer picture of this technique.

<figure><img src="https://miro.medium.com/v2/resize:fit:836/1*-mPTOpG8z4s8iLI-_zrXVw.png" alt="" width="563"><figcaption><p>Figure 93. Retrieving the ImportDirectory and resolving each required library.</p></figcaption></figure>

And last but not least, the `EntryPoint` of the decrypted response data is retrieved. It is then calculated based on the address of the memory allocated earlier, and execution is later transferred to it.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*s8fj_cyn8YpfFD6jEZTs1w.png" alt="" width="563"><figcaption><p>Figure 94. Calculating the entrypoint of the allocated memory and transferring execution to it.</p></figcaption></figure>

Now stepping backward for a bit, before execution begins, the `sub_140002550` function is called. Inside this function, the directory path `%localappdata%\\Microsoft\\Windows\\pib` is concatenated and later created.

<figure><img src="https://miro.medium.com/v2/resize:fit:584/1*aqiza_lj0IV48c0fnG_pWw.png" alt="" width="563"><figcaption><p>Figure 95. Concatenating the directory path.</p></figcaption></figure>

The data used in the creation comes from the memory allocated earlier, referenced by the variable `v14`, where the PE data was loaded.

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*Zj-yC3Sj2hR-YLZpO1jbDg.png" alt="" height="319" width="700"><figcaption><p>Figure 96. Creating a new file using the data copied to the previously allocated memory.</p></figcaption></figure>

***

### **Execution Flow** <a href="#id-62e3" id="id-62e3"></a>

<figure><img src="https://miro.medium.com/v2/resize:fit:875/1*AxrH9lDjilCKRmz-ZlLJpQ.png" alt="" height="475" width="700"><figcaption><p>Figure 97. GhostFetch Loader Execution Flow.</p></figcaption></figure>

***

### **Conclusion** <a href="#id-9cdd" id="id-9cdd"></a>

According to the report from Group-IB, at the initial stage of the operation, a phishing email was sent by the threat actor. The email contained a microsoft office document attachment embedded with macros designed to deploy the GhostFetch, which was later used to download and deploy the GhostBackdoor payload.

The GhostFetch was written in C++, and no packer was found to be implemented. However, all necessary strings were obfuscated using a custom algorithm. Also, when the GhostFetch starts, the command line argument `static` is checked for the purpose of spawning a Recycle Bin process, which appears to have a direct relationship with GhostBackdoor. According to the report from Group-IB , GhostBackdoor masks itself using the Windows Recycle Bin ClassID.

To prevent re-execution, various mutex checks are performed, which can be separated into two main phases. Each mutex used corresponds to a specific privilege level gained or the type of windows station being used.

The following is a list of deobfuscated mutexes found in the analyzed GhostFetch sample:

```
The First Phase Mutex:

1. Global\\4edrg5h6j7k8k8l9lmsq2342gyh89mfjrjgjv6722 (Local Administrator Group)
2. Global\\4thnfdseryhb2qws436ujko3l89mfjrjgjeffsq33 (Non-interactive windows station)
3. Global\\4andfghjkrtyuis4hnfdsej1jjasj456789dgdg11 (Neither)

The Second Phase Mutex:

1. Global\\5jdrkshnfdses58294789mf5rjgjfkfg789fffs55 (Local Administrator Group)
2. Global\\5oruiqhnfdseaiok89mfjrj6jrtldhosytsingf66 (Non-interactive windows station)
3. Global\\4hsjfghjk89hnfdsejuwebc4bdgfsyafffsfbs44 (Neither)
```

When it comes to anti-analysis techniques, the sample implements multiple methods ranging from process discovery and anti-debugging to sandbox evasion.

The following is a list of sandbox evasion techniques used by the GhostFetch:

```
1. Check for mouse movement over a period of time.
2. Enumerates monitors with specific pixels.
3. System requirement checks.
4. History of USB device attachments.
5. Time based evasion using tick counts.
```

The following is a list of processes targeted by the GhostFetch:

```
Antivirus:

1. avp.exe
2. avastsvc.exe
3. nortonsecurity.exe
4. nortonsvc.exe
5. ccsvchst.exe
6. sepwscsvc64.exe
7. mc-fw-host.exe
8. uiwinmgr.exe
9. msmpemg.exe
10. ekrn.exe
11. sspservice.exe
12. sedservice.exe

Sandbox:

1. joeboxcontrol.exe
2. joeboxserver.exe

Analysis Tools:

1. ollydbg.exe
2. processhacker.exe
3. tcpview.exe
4. autoruns.exe
5. autorunsc.exe
6. filemon.exe
7. procmon.exe
8. regmon.exe
9. procexp.exe
10. idaq.exe
11. idaq64.exe
12. immunitydebugger.exe
13. wireshark.exe
14. dumpcap.exe
15. hookexplorer.exe
16. importrec.exe
17. petools.exe
18. lordpe.exe
19. sysinspector.exe
20. proc_analyzer.exe
21. sysanalyzer.exe
22. sniff_hit.exe
23. windbg.exe
24. resourcehacker.exe
25. x32dbg.exe
26. x64dbg.exe
27. fiddler.exe
28. httpdebugger.exe
29. srvpost.exe
30. pestudio.exe
31. cheatengine-i386.exe
32. cheatengine-x86_64.exe
33. cheatengine-x86_64-sse4-avx2.exe
34. frida-helper-32.exe
35. frida-helper-64.exe
36. ida.exe
37. ida64.exe
```

In the communication phase, GhostFetch uses the HTTP protocol to communicate with its C2 server. However, the data sent to the C2 server is also encrypted using the AES algorithm. The same thing is applied during decryption. According to the report from Group-IB, the response data from the C2 server contains the GhostBackdoor payload.

To decrypt the GhostBackdoor payload, the following AES information can be used:

```
Key: B2E2E3AAD62367F9FD7354DAF0A2A5BC8A3EA83F93D3E4AE81C1418710E98C1F
IV: C7D2F1ADBB7158748111D9341180E582
```

As its name suggests, the loading process does not simply create a file on disk and execute it. Instead, the decrypted data is manually loaded directly into memory. However, the file is later created on disk at `%localappdata%\\Microsoft\\Windows\\pib`, which shares the same root path used during its self-copied process, `%localappdata%\\Microsoft\\Windows\\BurnUtill\\burn.exe`, as when the GhostFetch is copied, the `.rsrc` section of the PE file is filled with null bytes.

***

### **IOCs** <a href="#b959" id="b959"></a>

```
SHA256: 8d2227f2c53d7e22a57e12c45cecdd43dbec08dbc3ab93e74e6df52cdf80548b
MD5: 24725e2759db07e879a6a0f248a4dc0b
C2: promoverse[.]org
```

***

### **YARA Rule** <a href="#d59a" id="d59a"></a>

```
rule Mal_WIN_GhostFetch_Loader_PE {
        meta:
                description = "Use to detect GhostFetch loader."
                author = "Phatcharadol Thangplub"
                date = "05-15-2026"
                reference = "https://www.group-ib.com/blog/muddywater-operation-olalampo/"

        strings:
                /*
                        Mutex deobfuscation algorithm.
                */
                $hex1 = { 66 89 10 4? ba fb 00 00 00 66 89 48 04 4? bb fd 00 00 00 0f 
                        b7 53 02 0f b7 4b 06 66 4? 2b d1 66 89 50 02 66 83 e9 09 66 89 
                        48 06 ba ff 00 00 00 0f b7 43 08 b9 f9 00 00 00 66 2b c1 66 4? 
                        89 40 08 0f b7 43 0a 66 83 e8 03 66 4? 89 40 0a 0f b7 43 0c 66 
                        4? 2b c1 66 4? 89 40 0c 0f b7 43 0e 66 4? 2b c2 66 4? 89 40 0e 
                        0f b7 43 10 66 83 e8 03 66 4? 89 40 10 0f b7 43 12 66 4? 2b c1 
                        66 4? 89 40 12 0f b7 43 14 66 83 e8 08 66 4? 89 40 14 0f b7 43 
                        16 66 83 e8 03 66 4? 89 40 16 0f b7 43 18 66 2b c1 66 4? 89 40 
                        18 0f b7 43 1a 66 4? 2b c1 66 4? 89 40 1a 0f b7 43 1c 66 4? 2b 
                        c3 66 4? 89 40 1c 0f b7 43 1e 66 83 e8 05 66 4? 89 40 1e 0f b7 
                        43 20 66 2b c2 66 4? 89 40 20 0f b7 43 22 66 4? 2b c3 66 4? 89 
                        40 22 0f b7 43 24 66 2b c2 66 4? 89 40 24 0f b7 43 26 66 83 e8 
                        03 66 4? 89 40 26 0f b7 43 28 66 83 e8 02 66 4? 89 40 28 0f b7 
                        43 2a 66 4? 2b c1 66 4? 89 40 2a 0f b7 43 2c 66 83 e8 09 66 4? 
                        89 40 2c 0f b7 43 2e b9 f7 00 00 00 66 2b c2 66 4? 89 40 2e 0f 
                        b7 43 30 66 2b c1 66 4? 89 40 30 0f b7 43 32 66 83 e8 03 66 4? 
                        89 40 32 0f b7 43 34 66 83 e8 04 66 4? 89 40 34 0f b7 43 36 66 
                        83 e8 04 66 4? 89 40 36 0f b7 43 38 66 83 e8 06 66 4? 89 40 38 
                        0f b7 43 3a 66 4? 2b c3 66 4? 89 40 3a 0f b7 43 3c 66 83 e8 04 
                        66 4? 89 40 3c 0f b7 43 3e 66 83 e8 09 66 4? 89 40 3e 0f b7 43 
                        40 66 83 e8 06 66 4? 89 40 40 0f b7 43 42 66 2b c2 66 4? 89 40 
                        42 0f b7 43 44 66 83 e8 03 66 4? 89 40 44 0f b7 43 46 66 2b c1 
                        b9 fc 00 00 00 66 4? 89 40 46 0f b7 43 48 66 83 e8 06 66 4? 89 
                        40 48 0f b7 43 4a 66 4? 2b c2 66 4? 89 40 4a 0f b7 43 4c 66 83 
                        e8 03 66 4? 89 40 4c 0f b7 43 4e 66 83 e8 09 66 4? 89 40 4e 0f 
                        b7 43 50 66 83 e8 03 66 4? 89 40 50 0f b7 43 52 66 2b c1 b9 fa 
                        00 00 00 66 4? 89 40 52 0f b7 43 54 66 2b c1 b9 f6 00 00 00 66 
                        4? 89 40 54 0f b7 43 56 66 83 e8 06 66 4? 89 40 56 0f b7 43 58 
                        66 83 e8 04 66 4? 89 40 58 0f b7 43 5a 66 83 e8 03 66 4? 89 40 
                        5a 0f b7 43 5c 66 2b c1 66 4? 89 40 5c 0f b7 43 5e 66 83 e8 06 
                        66 4? 89 40 5e 0f b7 43 60 66 4? 2b c3 66 4? 89 40 60 }
                
                /*
                        Initialize the section of the encryption data scheme.
                */
                $hex2 = { c7 03 01 02 03 04 c7 43 04 05 06 07 08 c7 43 08 09 0a 0b 0c 
                        66 c7 43 0c 0d 0e c6 43 0e 0f }

                /*
                        Creation of the magic constant for the encryption data scheme.
                */
                $hex3 = { 4? 8d 53 0f 4? 8d 4a 0f 4? 8d 40 0f 4? 3b d0 77 ?? 33 c0 4? 
                        3b c8 72 ?? 4? 8d 0c 10 4? 2b c2 ba 10 00 00 00 4? 2b d0 0f 1f 
                        80 00 00 00 00 4? 0f b6 04 01 88 01 4? 8d 49 01 4? 83 ea 01 75 
                        ?? eb ?? 4? 0f 10 00 0f 11 02 }

                /*
                        Manual DOS and NT header resolution and checking.
                */
                $hex4 = { 4? 83 ec 70 4? 8b 05 [4] 4? 33 c4 4? 89 44 [2] b8 4d 5a 00 00 
                        4? 8b f9 66 39 01 0f 85 [4] 4? 63 41 3c 3d 00 04 00 00 0f 8f [4] 
                        81 3c 01 50 45 00 00 4? 89 7? ?? 4? 8d 34 01 0f 85 [4] 4? 85 f6 }

        condition:
                uint16(0) == 0x5A4D and filesize >= 180KB and ($hex1 and (($hex2 and $hex3) or $hex4))
}
```

### **Sigma Rule** <a href="#id-05cb" id="id-05cb"></a>

```yml
title: GhostFetch Loader - Execution with a specific command line argument
name: execute_with_a_specific_command_line
id: beac7ebd-c342-4a7c-ad2c-8bad7ed08530
status: experimental
description: Used to hunt the GhostFetch Loader, where it is executed with a specific command line argument.
references:
        - https://attack.mitre.org/
        - https://www.group-ib.com/blog/muddywater-operation-olalampo/
author: Phatcharadol Thangplub
date: 2026-05-15
modified: 2026-05-15
tags:
        - attack.T1059
logsource:
        product: windows
        service: sysmon
detection:
        selection_specific_process_command_line:
                EventCode: 1
                CommandLine|endswith:
                        - "static"
        condition: selection_specific_process_command_line
falsepositives:
        - Unknown
level: high
---
title: GhostFetch Loader - Replicate to a new location
name: self_replication
id: 4733053c-e7f8-441a-b6f5-d27246fcdbf3
status: experimental
description: Used to hunt the GhostFetch Loader when it replicates itself to a new location.
references:
        - https://attack.mitre.org/
        - https://www.group-ib.com/blog/muddywater-operation-olalampo/
author: Phatcharadol Thangplub
date: 2026-05-15
modified: 2026-05-15
tags:
        - attack.T1070.010
logsource:
        product: windows
        service: sysmon
detection:
        selection_self_replication:
                EventCode: 11
                TargetFilename:
                        - "C:\\Users\\*\\AppData\\Local\\Microsoft\\Windows\\BurnUtill\\burn.exe"
        condition: selection_self_replication
falsepositives:
        - Unknown
level: high
---
title: GhostFetch Loader - Download GhostBackdoor payload.
name: download_ghostbackdoor_payload
id: bafc79ac-3ed3-49eb-a5fe-d737bf30f536
status: experimental
description: Used to hunt the GhostFetch Loader, which downloads the GhostBackdoor payload.
references:
        - https://attack.mitre.org/
        - https://www.group-ib.com/blog/muddywater-operation-olalampo/
author: Phatcharadol Thangplub
date: 2026-05-15
modified: 2026-05-15
tags:
        - attack.T1105
logsource:
        product: windows
        service: sysmon
detection:
        selection_dns_query:
                EventCode: 22
                QueryName|startswith:
                        - "promoverse.org"
        condition: selection_dns_query
falsepositives:
        - Unknown
level: high
---
title: GhostFetch Loader - Create GhostBackdoor payload.
name: create_ghostbackdoor_payload
id: a79d7732-05c5-4897-a38c-40ac6e1e772b
status: experimental
description: Used to hunt the GhostFetch Loader when GhostBackdoor begins to be created on the system.
references:
        - https://attack.mitre.org/
        - https://www.group-ib.com/blog/muddywater-operation-olalampo/
author: Phatcharadol Thangplub
date: 2026-05-15
modified: 2026-05-15
tags:
        - attack.T1105
logsource:
        product: windows
        service: sysmon
detection:
        selection_create_ghostbackdoor_payload:
                EventCode: 11
                TargetFilename:
                        - "C:\\Users\\*\\AppData\\Local\\Microsoft\\Windows\\pib"
        condition: selection_create_ghostbackdoor_payload
falsepositives:
        - Unknown
level: high
---
title: GhostFetch Loader – Correlate execution, download, and creation.
id: c104aaa7-c7c8-4e8d-9894-ce4f8fc1786d
correlation:
        type: temporal
        rules:
                - execute_with_a_specific_command_line
                - self_replication
                - download_ghostbackdoor_payload
                - create_ghostbackdoor_payload
        group-by:
                - Computer
                - User
                - ProcessId
                - Image
        timespan: 1m
```

***

### **Additional Rources** <a href="#c225" id="c225"></a>

<https://attack.mitre.org/>

<https://www.group-ib.com/blog/muddywater-operation-olalampo/>

<https://learn.microsoft.com/en-us/windows/win32/debug/pe-format>

<https://g3tsyst3m.com/fileless%20techniques/Bypassing-EDR-using-an-In-Memory-PE-Loader/>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mapol.gitbook.io/home/blog/malware-analysis/loader/ghostfetch.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
