Among the daily attacks observed by SOC analysts during security monitoring, stealer-type malware holds a prominent place. These malicious programs, which harvest credentials stored insecurely on endpoints, are widely leveraged by threat actors in campaigns to capture authentication data. Such attacks are simple, fast, and easily industrializable. Infostealers include well-known families such as Lumma Stealer, Vidar, RedLine, and others.
Around mid-July 2026, an EDR instance deployed at a client site blocked network communications originating from PowerShell execution. The SOC analysts escalated the alert to the ITrust CERT team, and although the attack was successfully mitigated, we were determined to analyze the underlying payload. This marked the beginning of our analysis of the new PureLogs Stealer campaign, a malware strain dating back to 2022-2023 that Hudson Rock previously reviewed in its article "Pure Logs Stealer Fails to Impress".
In this technical analysis, we dissect the new PureLogs campaign and observe that, while it may not yet be the most sophisticated stealer on the market, it has modernized and evolved compared to earlier iterations.
Initial Compromise Vector and PowerShell Stager
To briefly set the incident context, the compromise begins with a phishing email that triggers a multi-stage execution leading to PowerShell execution. This relies on a widespread social engineering technique known as "ClickFix", which tricks users into running malicious code on their system by simulating an error or a technical issue.
The executed command in question is the following:
This is a PowerShell cmdlet that performs an HTTP request, downloads, and executes remotely hosted arbitrary code within a single instruction—all performed entirely in-memory without writing any files to disk. This represents a highly effective initial compromise vector, comparable to various "ClickFix" campaigns. It leverages multiple defense evasion techniques, such as anti-signature polymorphism via randomly generated comments embedded directly into the command. The rationale behind this technique is to make each malicious code instance unique, thereby evading signature-based detections. Another notable element is found within the requested URL parameter, here “?sid= 1785227193742-lf6op6dy”, which appears to be a tracking mechanism deployed by the attacker to assign a unique identifier to each victim, complementing the polymorphic nature of the payload.
Following this execution chain, a secondary PowerShell execution command is initiated:
This command is written on a single line, which slightly complicates structural analysis, with obfuscation limited to variable names. A cleaned-up rewrite with deobfuscated variable names yields the following:
The command functions as a loader designed to fetch a resource from the URL 'hxxp[:]//158[.]94[.]211[.]92/s_enterprise' and load it directly into memory. Here, the threat actor employs classic in-memory injection techniques by leveraging kernel32.dll shared library APIs directly imported into the code. The in-memory execution and thread injection technique (Local Process Injection T1055) is fairly standard: the attacker dynamically allocates a memory region using the VirtualAlloc() API. The function arguments indicate that memory is allocated without initial restrictions, directly configured with ReadWrite permissions. The payload retrieved from the web response is written to the dynamically allocated buffer. A execution thread is then spawned within the current process via the CreateThread() API to execute the payload. If the thread handle is invalid—meaning the loader failed for any reason—the entire execution chain terminates. While this PowerShell loader remains standard, the malware's second loading stage introduces more notable characteristics.
Stage 1: Reverse Engineering the 's_enterprise' Downloader
The initial stage concludes by injecting the remotely retrieved "s_enterprise" binary into a memory thread. This payload was successfully retrieved in a controlled environment, and preliminary static analysis yields the following metrics:
| IDENTIFICATION | |
| File Name | s_entreprise |
| MD5 Hash | 287f1c7775b1e76cd31ed10033e1a111 |
| SHA-1 Hash | 155b0d50a983cf737394a1e5b9b69412e99f73b7 |
| SHA-256 Hash | 6270f38bdf27aebb108331a484220a8bc0b9a1e6a2c4bba6dad89a2f3665bca5 |
| Format | PE 32+, MS Windows 5.02 Console, x86-64 |
| DOS Header | MZER |
Several artifacts immediately stand out in these preliminary findings. Based on imported functions such as WinHTTPConnect(), we can infer web communication and downloading capabilities, pointing to a secondary loader. However, the most unconventional artifact resides in the file's header. The payload begins with the header 'MZER' ('MZ' typically identifying a Windows Portable Executable format). Theoretically, this would indicate a standard executable; however, the in-memory loading performed by the earlier PowerShell commands is too rudimentary for a typical PE. Executing a standard PE would require not only memory allocation, but also section mapping (.text, .data), import address table resolution, and base relocations. The attacker here uses a known technique frequently integrated into shellcode generation frameworks like Metasploit or Donut: exploiting the relationship between ASCII characters and assembly instructions, effectively using the MZER header as shellcode:
1. An alignment can be established between ASCII and assembly instructions. 'MZ' can be represented in hexadecimal as 0x4D5A, which corresponds to the instruction pop r10, while 'ER' translates to push r10 (0x4552). These two instructions effectively negate each other. Consequently, the binary remains a valid PE while simultaneously executing as viable shellcode.
2.In a Windows executable, memory addresses are protected by ASLR (the base loading address is unpredictable), meaning the shellcode must locate its own base at runtime. The following instructions represent a trick (commonly referred to as GetPC) designed to locate the position of the embedded shellcode in memory, enabling a subsequent jump to it. Call pushes the EIP address onto the stack, followed by the pop rcx instruction, which retrieves this address into RCX. At that specific moment, EIP is located at base+0x9 (0x2 for pop r10 + 0x2 for push r10 + 0x5 for call = 0x9).
3.RCX now contains the address of the start of the PE + 0x9. Here, the threat actor aims to return to the PE base address (without the 0x9 offset) and therefore executes a sub rcx, 0x9. The initial base position in memory has now been recovered despite ASLR.
4. It then executes a jump targeting a specific address within the PE (the beginning of the embedded shellcode) using a hardcoded offset. Execution shifts toward (base+offset) via the instructions mov rax, rcx ; add rax, 0xc000 ; call rax
All of these operations allow the payload to be handled both as an executable and as shellcode. Once the header-related instructions have run and the various redirections within the code have been followed, the shellcode loads the main function of the file.
2.1. Functional Analysis – Main Orchestrator
1. Downloading a payload
2. Retrieving the PID of svchost.exe
3. Fallback to explorer.exe if the svchost.exe lookup fails
4.Injecting the retrieved payload by creating a thread
5. Memory deallocation
Stage 2 Detonation
3.1. Sandbox Analysis
Detonation of the stage 2 payload clearly indicates that the threat is an infostealer. Within seconds, the malware queries sensitive registries and files in search of session keys, passwords, and crypto wallets.
It is also possible to observe the malware’s network communication with its C2 through an 892-byte exchange. Because these communications are encrypted, a PCAP network capture of these exchanges was performed to attempt offline decryption at a later stage. However, this is likely beaconing behavior or data exfiltration.
In the same manner as ‘s_enterprise.bin’, this is a PE/shellcode "hybrid" utilizing the MZER header. The multiple redirections executed from the header point to a loader located outside the declared sections (.reloc: 0x4B000 + 0x1000, whereas the complete file size is 0x4C600). This loader executes a second PE (an actual PE file in this instance) located at offset 0x1BA40, which corresponds to the PureLogs stealer.
3.2. Anti-VM/Debug Techniques, Evasion, Stealth, and Environment Checks
Through dynamic detonation and static analysis of this malicious program, various reconnaissance, anti-VM, and anti-debugging techniques were identified across the different execution stages. Across its distinct components, the malware enforces a series of environmental checks prior to executing its primary payload.
1. At the system level, it queries the WMI repository (using several hardcoded queries within the program) containing diverse telemetry from both physical hardware and the operating system. These artifacts establish a fingerprint of its runtime environment (manufacturer, graphics controller, CPU core count, temperature) and detect any dummy user/domain typical of automated analysis environments. It complements this verification by enumerating the registry for installed printers and monitoring USB device activity. The presence of active, usable hardware provides a strong indicator of a bare-metal physical machine rather than an easily detectable sandbox.
2.From an anti-debugging standpoint, the malware neutralizes the default Windows error reporting mechanism (SetUnhandledExceptionFilter) to curb the generation of exploitable Windows Error Reporting (WER) artifacts that allow post-crash memory dumps. It also implements an encryption key derivation mechanism based on runtime call stack (StackTrace) inspection. Consequently, any dynamic runtime instrumentation (breakpoints, API hooking) alters the program’s dedicated stack, thereby "silently" invalidating the key and rendering configuration data unreadable without raising an explicit error to the analyst.
3. During static analysis, the presence of an overlay was identified at offset 0x0004C000 with a relatively small footprint (1.6 kB). Absent from the initial static analysis of the first sample, it was uncovered during the investigation of the second. This overlay likely contains an encryption key or configuration block, kept protected and concealed outside runtime against any access attempts deviating from the intended execution flow.
4. More broadly, the code is shielded by multiple anti-analysis mechanisms: first, layered source-to-source obfuscation documented throughout this report, coupled with the "Debuggable" attribute disabling debug symbols during program compilation, which significantly hampers and degrades the fidelity of reverse-engineering tools and inspection attempts.
5. Finally, on multiple occasions, the sample incorporates timing delay logic implemented through various means, notably: execution delays lasting several dozen seconds, and scheduled infrastructure expiration at a predefined date. These mechanisms are engineered to outlast the typical monitoring window of heuristic detection engines as well as automated sandbox analysis routines.
File Name Payload.bin MD5 Hash 5e7c0273fb6a3e926a9d99af6e70a754 SHA-1 Hash 798db80c73642460864aad45402c8265da57f9b1 SHA-256 Hash 4a0a96834cc600a524d4b2348b00aec0361c2d7c97cca719372229e036961b0a Size 174,176 bytes Format PE 32+, MS Windows 4.00 (GUI), x86-64 Mono .NET Assembly DOS Header MZ
Stage 3 Reverse Engineering: PureLogs Stealer 4.1. Initial Findings
| IDENTIFICATION | |
| File Name | Payload.bin |
| MD5 Hash | 5e7c0273fb6a3e926a9d99af6e70a754 |
| SHA-1 Hash | 798db80c73642460864aad45402c8265da57f9b1 |
| SHA-256 Hash | 4a0a96834cc600a524d4b2348b00aec0361c2d7c97cca719372229e036961b0a |
| Size | 174,176 bytes |
| Format | PE 32+, MS Windows 4.00 (GUI), x86-64 Mono .NET Assembly |
| DOS Header | MZ |
This final payload is unencrypted. It consists of an embedded .NET PE that, once decompiled using ILSpy, yields a 311 KB C# source file. The binary is heavily obfuscated using bitwise XOR operations, strings built through chained append() calls, char concatenations, and multiple dead-code "junk" functions.
An initial inspection reveals a campaign ID in its configuration section (91cba2b9-bec8-45d3-ab2a-e7207f94ce93) along with a kill date set for September 1, 2026:
The IP associated with this campaign's C2 has already been reported multiple times on AbuseIPDB. An initial inspection reveals a campaign ID in its configuration section (91cba2b9-bec8-45d3-ab2a-e7207f94ce93) along with a kill date set for September 1, 2026:
Interestingly, within the Main() function, the malware checks the installed system languages and aborts execution if “ru-RU” is detected on the target machine:
4.2. Identified Capabilities
PureLogs' capabilities as an info-stealer are relatively standard:
Browser data theft (Chromium and Firefox-based) collecting credentials from “Login Data”, autofill/banking data from “Web Data”, session cookies, browsing history, encryption keys stored in “Local State”, web storage via “Local Storage”, and browser extension data to discover crypto wallets.
▸ Application targets:
- Steam configuration and session data (config.vdf, loginusers.vdf)
- API keys, session data, and GPS coordinates on Telegram
- Local cache and authentication token theft on Discord (LocalCache, leveldb)
▸ System reconnaissance:
- Win32_OperatingSystem to retrieve OS architecture, version, and language
- Win32_ComputerSystem to collect machine name, domain, and user
- Win32_VideoController to retrieve GPU details
- Registry query at “HARDWARE\DESCRIPTION\System\CentralProcessor\0” for CPU specifications
In addition to typical stealer behavior, it implements various payload execution and command-dispatching capabilities:
▸ Un module PowershellLauncher pour lancer des charges via “powershell.exe – NoProfile -ExecutionPolicy Bypass -File <file>”
▸ DLL execution module via rundll32 ▸ Obfuscation of critical injection strings related to “ntdll.dll” and “kernel32.dll”.
▸ Stealth execution leveraging the APC Queue Injection technique:
- IAT Camouflage using dynamic resolution. Result: no suspicious API functions appear in the Import Address Table.
Asynchronous Procedure Call (APC) is a Windows mechanism that enables tasks to be executed asynchronously, independently of the primary program thread.
In offensive development, this mechanism is often leveraged to queue a payload into the APC queue and execute it later in the process lifecycle. In this instance, the execution chain is implemented within a newly spawned process in a suspended state (EarlyBird APC Injection). PureLogs implements it as follows:
NtCreateSection (host577) –> NtMapViewOfSection RW (pulse7) –> shellcode copy –> NtMapViewOfSection RX (pulse7) –> NtQueueApcThread (wrap6) –> NtResumeThread (tail1) –> NtUnmapViewOfSection (finally)
This represents an evolution of the stealer compared to its previous version, which relied on a more standard APC injection implementation.
4.3. Frame Decryption
4.3.1 AES
Key The stealer configuration outlined above specifies an AES key. This key is used to encrypt communications with the C2 server. This marks an enhancement in PureLogs over earlier iterations that used DES encryption.
The AES key is hardcoded and extracted via a function called InitializeArray(array2, RuntimeFieldHandle). ILSpy failed to recover the static array containing the key during the decompilation process. By using objdump and xxd, the data can be retrieved directly from the .text section:
The header is located at 0x200 (offset retrieved using the command above). The initial bytes of the header reveal its size (here 0x48); the hex data immediately following can then be inspected:
At offset 0x248, we find the hardcoded 128-bit AES key: 7B41c330b576fa8d0ce909c2b1e4d150
4.3.2. IV Discovery
4.3.3. Network Capture Decryption
With the key obtained, it is now possible to decrypt the captured network traffic. The first captured exchange corresponds to the discovery and transmission of generic host information from the compromised system
This frame clearly matches a beacon sent to the C2. The network capture contained no further data. Several hypotheses may explain the absence of exfiltration, such as the malware awaiting specific instructions before exfiltrating gathered data.
Conclusion and Detection
Static detection of IoCs is primarily viable for Stages 1 and 2 using the malicious infrastructure's IP address and payload hashes. Indicators present in Stage 3 are obfuscated and, consequently, difficult to detect statically. Multiple firewall, EDR, and antivirus rules can be deployed to detect the campaign:
| IoCs | |
| Indicator | Value |
| IP C2 | 158.94.208.92 |
| Malicious Server IP | 158.94.211.92 (hosts payloads) |
| User-Agent | powershell |
| URLs | hxxp://*/entreprise/student_s.bin’ |
| AES-128 Key | 7B41C330B576FA8D0CE909C2B1E4D150 (Stage 3 Offset 0x248) |
| MD5 Hash | 287f1c7775b1e76cd31ed10033e1a111 |
| SHA-1 Hash | 155b0d50a983cf737394a1e5b9b69412e99f73b7 |
| SHA-256 Hash | 6270f38bdf27aebb108331a484220a8bc0b9a1e6a2c4bba6dad89a2f3665bca5 |
| MD5 Hash | 5e7c0273fb6a3e926a9d99af6e70a754 |
| SHA-1 Hash | 798db80c73642460864aad45402c8265da57f9b1 |
| SHA-256 Hash | 4a0a96834cc600a524d4b2348b00aec0361c2d7c97cca719372229e036961b0a |
Compared to previously analyzed variants, PureLogs has improved its stealth through this Early Bird APC injection technique. The analyzed sample remains otherwise consistent with earlier iterations. It continues to feature broad harvesting capabilities across desktop applications and web browsers, communicates with the threat actor's C2 via encrypted channels, and now actively targets password managers and cryptocurrency wallets. The observed evolution is not a full rewrite of the malware, but rather a modernization of its implementation. First identified in 2022, the malware continues to evolve and remains popular among cybercriminals primarily due to its low-cost model, as highlighted by FlashPoint in their 2023 blog post.
Article written by the ITrust CERT team