Stage1 (22.exe) Loader Reversing, Part I: Stage Decryption, Evasion, and Attribution
Reverse engineering a staged loader that patches AMSI and ETW, decrypts an AES-256-CBC payload in memory, and hands off to a Vidar-like credential stealer.
A binary called 22.exe arrived from a delivery URL on cloudaxis[.]cc, wrapped in enough layers to suggest the author wanted to buy time before anyone looked inside. What followed was a fairly deliberate kill chain: silence the telemetry, decrypt a second-stage PE from an embedded blob, and reflectively load it without ever touching disk. This post walks through each of those steps – the evasion patches, the AES decryption internals, the anti-sandbox gating – and lays out the evidence that ties Stage2 to the Vidar stealer family. Part I stays on Stage1; Part II will pick up with the Stage2 config and C2 behavior.
Sample acquisition source: hXXps://cloudaxis[.]cc/gsmft/yueu/fkvqld/tvqqwh/ushu/22.exe
Summary
What is confirmed in this sample set:
- staged payload decryption from an embedded encrypted blob,
- in-memory AMSI and ETW patching before stage handoff,
- anti-sandbox/anti-analysis checks,
- reflective loading of a decrypted Stage2 PE,
- and working YARA coverage for stage1 and stage2 artifacts.
Attribution status:
- Observed: Stage2 is classified as Vidar by multiple commercial AV detections in sandbox telemetry.
- Inferred: Based on that plus the behavior in this write-up, I refer to the chain as Vidar-like for now.
- Confidence is medium until Stage2 config and command handling are fully decoded.
Quick Primer
AMSIis a Windows scanning interface used by security products to inspect scripts/content before execution.ETWis a Windows telemetry pipeline used to log behavior (process/runtime events).- A
patchhere means overwriting a few bytes in memory so a security-related function returns immediately. Reflective loadingmeans loading a PE from memory directly instead of writing a normal file to disk and launching it.
In plain English: this loader appears to reduce security visibility first, then unpack and run the next stage in memory.
Stage Flow
Sample Scope
Artifacts (SHA-256)
| Artifact | SHA-256 |
|---|---|
22.exe (Stage1 sample) | 0cb5a2e3c8aa7c80c8bbfb3a5f737c75807aa0e689dd4ad0a0466d113d8a6b9d |
stage2_dec_unpadded.bin (Decrypted Stage2) | 5fa52aa9046334c86da1e9746dfe9d7bb23ec69a8b2ab77d98efd2cb1af012f3 |
Downloads
Public analysis bundle:
- analysis_data / vidar_feb_2026
- scripts
- notebooks (output-cleared)
- IDA helpers
- reports and evidence artifacts
- XOR Mozilla reproduction report
- Upstream rule match evidence (gen_xor_hunting.yar)
- workflow flowchart files
YARA rules:
- YARA repository
- VIDAR folder
- Stage1 high-fidelity
- Stage2 high-fidelity
- Stage1 variant heuristic
- Stage2 variant heuristic
Stage1 Technical Findings
AMSI and ETW Patch Path
The loader uses dedicated routines to patch telemetry/scanning APIs in memory:
- AMSI patch bytes:
B8 57 00 07 80 C3(mov eax, 0x80070057 ; ret) - ETW patch bytes (primary):
31 C0 C3(xor eax, eax ; ret) - ETW patch bytes (fallback):
C2 14 00(ret 0x14)
Note: C2 14 00 (ret 0x14) is an x86-style stdcall stack-cleanup pattern. In this x64 sample, it appears as a fallback patch buffer and may not be exercised on the primary path.
Relevant functions:
sub_140002EA0for AMSI target selection (AmsiScanBuffer, fallbackAmsiOpenSession)sub_140002F00for ETW target selection (EtwEventWrite,EtwEventWriteTransfer,NtTraceEvent)- patch helper logic around memory-protection change + write + instruction cache handling
AMSI path
First, the dispatcher logic shows the AMSI targets and fallback behavior in a compact C-style view.
Under that dispatcher, the patch primitive performs memory-protection change and byte overwrite on the resolved export.
ETW path
The ETW dispatcher follows the same pattern, but fans out across multiple trace APIs (EtwEventWrite, EtwEventWriteTransfer, NtTraceEvent) and keeps a fallback branch.
Decompiler view of the same function confirms the call ordering and fallback composition clearly.
Finally, the data view shows the exact patch byte payloads used by the ETW routine.
Operationally:
- AMSI: it is often where decoded script/content gets inspected before execution. Short-circuiting these calls reduces that inspection window.
- ETW: it is heavily used by EDR/telemetry pipelines. Returning early from ETW writers reduces behavioral event visibility during the critical unpack/execute period.
- Together: one weakens in-line content scanning and the other weakens runtime logging, which increases the chance that the next stage runs with less detection pressure.
Anti-Analysis / Anti-Sandbox Logic
Observed markers include:
\\.\pipe\cuckoocuckoomon.dllSbieDll.dllSOFTWARE\WineSOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sandboxie- user/host/process markers such as
joe sandbox,SANDBOX,maltest,ProcessHacker.exe,injector.exe
This is not one single “if sandbox then quit” check. It looks more like a collection of environment checks that feed gating decisions.
Stage2 Decryption
Offsets used in this sample (sample-specific)
- encrypted blob VA:
0x140005140 - encrypted blob size VA:
0x1400A3560(observed0x9E410) - AES IV VA:
0x1400A3590 - AES key VA:
0x1400A35A0
Decrypt wrapper path
The wrapper at sub_140002FF0 allocates memory, copies encrypted bytes, expands key material, decrypts, and trims PKCS#7 padding before handoff.
Why AES is a defensible conclusion
I am not calling this AES because of naming alone. The disassembly behavior matches AES-256-CBC traits:
- key schedule routine (
sub_140002D00) operates on a 32-byte key, uses lookup tables in AES-like expansion style, and runs expansion rounds to 60 words (AES-256 schedule shape). - IV is handled as a separate 16-byte input and stored with context.
- decrypt core (
sub_140002820) processes 16-byte blocks and contains GF(2^8)-style arithmetic patterns (including0x1Breduction behavior typical in AES round math) plus block chaining behavior. - wrapper applies PKCS#7 unpadding semantics from the final plaintext byte.
Bottom line: the code is doing modern block-cipher style decrypt with a 32-byte key and IV, not a simple XOR/rolling key obfuscator.
Stage2 Findings (Current State)
Stage2 was recovered consistently through both script and notebook workflows.
Notable strings/import context observed:
ChromeBuildTools\\Network\\Cookies- long
%DOWNLOADS%token-like string - imports such as
CreateDesktopA,OpenDesktopA,EnumDisplayDevicesA,GetCurrentHwProfileA - single-byte XOR recoverable
Mozilla/5.0markers at offsets0x410(key0x33),0x22F1(key0xD5),0x2331(key0x63) - this behavior reproduces the community THOR/signature-base heuristic
SUSP_XORed_Mozilla_Oct19fromgen_xor_hunting.yar - running upstream
gen_xor_hunting.yardirectly against this decrypted Stage2 also returnsSUSP_XORed_Mozilla_Oct19
These are consistent with a credential/data collection stage. In the current static Stage2 artifact, I still do not observe cleartext C2 URLs/domains/IPs, which suggests network/config material is likely decoded at runtime or stored in a transformed form.
Reference links used for this check:
- Neo23x0/signature-base:
gen_xor_hunting.yar - CyberChef XOR brute-force recipe
- Nextron notes on VirusTotal matches
Notebook and Script Guide
Notebook
notebooks/vidar_22exe_deobfuscation_walkthrough.ipynb- Previously named with a
spectralviper_prefix. That label was an internal working name for this dataset/cluster during early triage and does not reflect a malware-family attribution. The notebook has been renamed to match the Vidar-like classification used throughout this analysis.
- Previously named with a
- What it does:
- lays out the stage flow and constants,
- extracts and decrypts Stage2,
- supports decrypt-from-hex for extracted stage/key material,
- reproduces XORed
Mozilla/5.0hunting on Stage2, - surfaces AMSI/ETW patch evidence,
- pulls Stage2 IOC/config triage output.
Why this matters: it gives you one repeatable path from raw sample to evidence artifacts without hand-clicking every step in IDA.
Python scripts
scripts/extract_stage2_from_22.py- deterministic extractor/decryptor using fixed sample offsets.
- outputs decrypt artifacts and
stage2_extract_report.json.
scripts/analyze_stage1_evasion.py- extracts AMSI/ETW patch bytes and anti-sandbox evidence from IDA sqlite.
- outputs
stage1_evasion_report.json.
scripts/hunt_stage2_iocs.py- Stage2 import/string triage for fast IOC surfacing (includes XORed
Mozilla/5.0hit extraction). - outputs
stage2_ioc_report.json.
- Stage2 import/string triage for fast IOC surfacing (includes XORed
scripts/hunt_stage2_xor_mozilla.py- reproduces THOR-style XORed
Mozilla/5.0detection with per-hit offsets/keys. - outputs
stage2_xor_mozilla_report.json.
- reproduces THOR-style XORed
scripts/assess_vidar_similarity.py- compares behavioral/string overlap against expected marker sets.
- outputs
vidar_similarity_report.json.
scripts/sv_analysis_lib.py- shared parsing/decrypt/util functions used across the other scripts and notebook. The
sv_prefix is a legacy artifact from the original internal working name.
- shared parsing/decrypt/util functions used across the other scripts and notebook. The
IDA Python Helpers
ida_python/sv_stage_decrypt_annotator.py
What it attempts to do on Stage1 (22.exe):
- rename core stage/decrypt/evasion functions,
- rename key globals (encrypted blob, key, IV, patch byte buffers),
- apply comments/types/frame var names,
- apply Hex-Rays local variable names where API support exists.
Net effect: faster orientation for the Stage1 to Stage2 handoff path.
ida_python/sv_stage2_hunt_annotator.py
What it attempts to do on decrypted Stage2:
- heuristic tagging of possible PEB-walk and API-hash style routines,
- suspicious string tagging,
- single-byte XOR
Mozilla/5.0hit tagging with per-hit XOR keys, - likely config blob/data candidate tagging by xref density,
- best-effort renaming/comments/struct+enum setup.
Important note: Stage2 tagging is heuristic, not ground truth. It should be treated as a triage accelerator, then validated manually function-by-function.
Detection Engineering
Prepared ruleset:
VIDAR_LIKE_22_STAGE1_HighFidelityVIDAR_LIKE_22_STAGE2_HighFidelityVIDAR_LIKE_22_STAGE1_Variant_HeuristicVIDAR_LIKE_22_STAGE2_Variant_Heuristic
Public rule location:
https://github.com/taogoldi/YARA/tree/main/stealers/vidar
Rule set note:
- this post includes all four rules (two high-fidelity and two broader heuristic hunting rules).
Validation snapshot:
- stage1 rule matches
22.exe - stage2 rule matches decrypted Stage2 outputs
- encrypted blob does not match (expected)
Attribution Status
Threat assessment
Current working assessment is Vidar-like with medium confidence. Multiple commercial AV vendors identify this Stage2 variant as associated with Vidar, and the collection-oriented Stage2 strings/imports are consistent with that direction. Confidence stays medium because we still need a fully decoded Stage2 config and verified end-to-end C2 behavior.
YARA Rules
Copy/paste-ready rules (single file):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import "pe"
rule VIDAR_LIKE_22_STAGE1_HighFidelity
{
meta:
author = "taogoldi"
date = "2026-02-24"
description = "High-fidelity rule for 22.exe-like stage1 loader/decryptor with AMSI+ETW patching"
version = 1
sha256 = "0cb5a2e3c8aa7c80c8bbfb3a5f737c75807aa0e689dd4ad0a0466d113d8a6b9d"
confidence = "high"
strings:
// API patch targets
$api1 = "AmsiScanBuffer" ascii wide
$api2 = "AmsiOpenSession" ascii wide
$api3 = "EtwEventWrite" ascii wide
$api4 = "EtwEventWriteTransfer" ascii wide
$api5 = "NtTraceEvent" ascii wide
// Anti-analysis cluster in this family/build
$anti1 = "\\\\.\\pipe\\cuckoo" ascii wide
$anti2 = "cuckoomon.dll" ascii wide
$anti3 = "SbieDll.dll" ascii wide
$anti4 = "SOFTWARE\\Wine" ascii wide
$anti5 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Sandboxie" ascii wide
$anti6 = "ProcessHacker.exe" ascii wide
$anti7 = "injector.exe" ascii wide
// Patch bytes used by stage1 routines
$patch_amsi = { B8 57 00 07 80 C3 }
$patch_etw1 = { 31 C0 C3 }
$patch_etw2 = { C2 14 00 }
// Orchestrator / decrypt wrapper / reflective handoff chains
$sig_orchestrator = {
53 48 83 EC 40 E8 ?? ?? ?? ??
C7 44 24 34 00 00 00 00
48 C7 44 24 38 00 00 00 00
E8 ?? ?? ?? ?? 85 C0 89 C3 75 ?? 31 DB
}
$sig_stage_decrypt_wrapper = {
41 B8 00 30 00 00
41 B9 04 00 00 00
FF 15 ?? ?? ?? ??
31 D2 48 85 C0 48 89 06 74 ??
41 89 D8 48 89 FA 48 89 C1 E8 ?? ?? ?? ??
48 8D 7C 24 20
4C 8D 05 ?? ?? ?? ??
48 89 F9
48 8D 15 ?? ?? ?? ??
E8 ?? ?? ?? ??
48 8B 16 41 89 D8 48 89 F9 E8 ?? ?? ?? ??
}
$sig_reflective_handoff = {
E8 ?? ?? ?? ?? 85 C0 74 ??
48 8B 4C 24 38
8B 54 24 34
48 89 4C 24 28
E8 ?? ?? ?? ??
31 D2
48 8B 4C 24 28
41 B8 00 80 00 00
}
condition:
uint16(0) == 0x5A4D and
pe.number_of_sections >= 6 and
all of ($api*) and
4 of ($anti*) and
$patch_amsi and $patch_etw1 and $patch_etw2 and
$sig_orchestrator and $sig_stage_decrypt_wrapper and $sig_reflective_handoff
}
rule VIDAR_LIKE_22_STAGE2_HighFidelity
{
meta:
author = "taogoldi"
date = "2026-02-24"
description = "High-fidelity rule for decrypted stage2 from 22.exe"
version = 1
sha256 = "5fa52aa9046334c86da1e9746dfe9d7bb23ec69a8b2ab77d98efd2cb1af012f3"
stage2_sha256 = "5fa52aa9046334c86da1e9746dfe9d7bb23ec69a8b2ab77d98efd2cb1af012f3"
confidence = "high"
strings:
$s1 = "ChromeBuildTools" ascii wide
$s2 = "\\Network\\Cookies" ascii wide
$s3 = "11111111111111111111111111111111111111111111111111111%DOWNLOADS%" ascii wide
condition:
uint16(0) == 0x5A4D and
pe.number_of_sections == 5 and
pe.imports("USER32.dll", "CreateDesktopA") and
pe.imports("USER32.dll", "OpenDesktopA") and
pe.imports("ADVAPI32.dll", "GetCurrentHwProfileA") and
pe.imports("USER32.dll", "EnumDisplayDevicesA") and
all of ($s*)
}
rule VIDAR_LIKE_22_STAGE1_Variant_Heuristic
{
meta:
author = "taogoldi"
date = "2026-02-24"
description = "Variant-oriented stage1 heuristic for this cluster (less strict than high-fidelity)"
version = 1
sha256 = "0cb5a2e3c8aa7c80c8bbfb3a5f737c75807aa0e689dd4ad0a0466d113d8a6b9d"
confidence = "medium"
strings:
$api1 = "AmsiScanBuffer" ascii wide
$api2 = "AmsiOpenSession" ascii wide
$api3 = "EtwEventWrite" ascii wide
$api4 = "EtwEventWriteTransfer" ascii wide
$api5 = "NtTraceEvent" ascii wide
$anti1 = "\\\\.\\pipe\\cuckoo" ascii wide
$anti2 = "cuckoomon.dll" ascii wide
$anti3 = "SbieDll.dll" ascii wide
$anti4 = "SOFTWARE\\Wine" ascii wide
$anti5 = "ProcessHacker.exe" ascii wide
$anti6 = "injector.exe" ascii wide
$sig_kexp = {
41 0F B6 4B 1F
41 B8 08 00 00 00
41 0F B6 6B 1E
48 8D 35 ?? ?? ?? ??
45 0F B6 53 1D
48 8D 3D ?? ?? ?? ??
41 0F B6 53 1C
}
$sig_stage_decrypt_wrapper = {
41 B8 00 30 00 00
41 B9 04 00 00 00
FF 15 ?? ?? ?? ??
31 D2 48 85 C0 48 89 06 74 ??
48 8D 7C 24 20
4C 8D 05 ?? ?? ?? ??
48 8D 15 ?? ?? ?? ??
E8 ?? ?? ?? ??
48 8B 16 41 89 D8 48 89 F9 E8 ?? ?? ?? ??
48 8B 16 8D 43 FF 0F B6 04 02
}
$patch_amsi = { B8 57 00 07 80 C3 }
$patch_etw1 = { 31 C0 C3 }
condition:
uint16(0) == 0x5A4D and
4 of ($api*) and
2 of ($anti*) and
($sig_kexp or $sig_stage_decrypt_wrapper) and
($patch_amsi or $patch_etw1)
}
rule VIDAR_LIKE_22_STAGE2_Variant_Heuristic
{
meta:
author = "taogoldi"
date = "2026-02-24"
description = "Variant-oriented stage2 heuristic from this cluster"
version = 1
sha256 = "5fa52aa9046334c86da1e9746dfe9d7bb23ec69a8b2ab77d98efd2cb1af012f3"
stage2_sha256 = "5fa52aa9046334c86da1e9746dfe9d7bb23ec69a8b2ab77d98efd2cb1af012f3"
confidence = "medium"
strings:
$s1 = "ChromeBuildTools" ascii wide
$s2 = "\\Network\\Cookies" ascii wide
$s3 = "%DOWNLOADS%" ascii wide
condition:
uint16(0) == 0x5A4D and
pe.imports("USER32.dll", "CreateDesktopA") and
pe.imports("USER32.dll", "OpenDesktopA") and
pe.imports("ADVAPI32.dll", "GetCurrentHwProfileA") and
2 of ($s*)
}
MITRE ATT&CK Mapping
| Technique ID | Technique Name | Observed Behavior |
|---|---|---|
| T1027 | Obfuscated Files or Information | Stage2 PE encrypted with AES-256-CBC inside Stage1 resource blob |
| T1140 | Deobfuscate/Decode Files or Information | Runtime AES decryption of embedded blob with PKCS#7 unpadding |
| T1620 | Reflective Code Loading | Decrypted Stage2 PE loaded directly from memory without disk write |
| T1562.001 | Impair Defenses: Disable or Modify Tools | AMSI patch (AmsiScanBuffer, AmsiOpenSession) returns error code to bypass scanning |
| T1562.006 | Impair Defenses: Indicator Blocking | ETW patch (EtwEventWrite, EtwEventWriteTransfer, NtTraceEvent) suppresses telemetry events |
| T1497.001 | Virtualization/Sandbox Evasion: System Checks | Checks for Cuckoo pipes, Sandboxie DLL, Wine registry keys, analysis tool process names |
| T1555.003 | Credentials from Password Stores: Credentials from Web Browsers | Stage2 strings reference ChromeBuildTools, \\Network\\Cookies, browser credential paths |
| T1082 | System Information Discovery | Stage2 imports GetCurrentHwProfileA, EnumDisplayDevicesA for host profiling |
IOC Appendix
File Hashes (SHA-256)
| Artifact | SHA-256 |
|---|---|
22.exe (Stage1) | 0cb5a2e3c8aa7c80c8bbfb3a5f737c75807aa0e689dd4ad0a0466d113d8a6b9d |
stage2_dec_unpadded.bin (Decrypted Stage2) | 5fa52aa9046334c86da1e9746dfe9d7bb23ec69a8b2ab77d98efd2cb1af012f3 |
Network IOCs
| Type | Value | Context |
|---|---|---|
| URL | hXXps://cloudaxis[.]cc/gsmft/yueu/fkvqld/tvqqwh/ushu/22.exe | Stage1 delivery URL |
Registry Keys
| Key | Context |
|---|---|
SOFTWARE\Wine | Anti-analysis: Wine environment check |
SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Sandboxie | Anti-analysis: Sandboxie detection |
File / Pipe Paths
| Path | Context |
|---|---|
\\.\pipe\cuckoo | Anti-analysis: Cuckoo sandbox named pipe |
cuckoomon.dll | Anti-analysis: Cuckoo monitor DLL |
SbieDll.dll | Anti-analysis: Sandboxie injection DLL |
Process Names (Anti-Analysis Markers)
| Process / String | Context |
|---|---|
ProcessHacker.exe | Analysis tool detection |
injector.exe | Analysis tool detection |
joe sandbox / SANDBOX / maltest | User/host environment string checks |
Stage1 Patch Byte Signatures
| Target | Bytes | Instruction Semantics |
|---|---|---|
AMSI (AmsiScanBuffer) | B8 57 00 07 80 C3 | mov eax, 0x80070057 ; ret |
| ETW (primary) | 31 C0 C3 | xor eax, eax ; ret |
| ETW (fallback) | C2 14 00 | ret 0x14 |
Stage2 XOR-Encoded Strings
| Offset | XOR Key | Decoded Value |
|---|---|---|
0x410 | 0x33 | Mozilla/5.0 |
0x22F1 | 0xD5 | Mozilla/5.0 |
0x2331 | 0x63 | Mozilla/5.0 |
Conclusion
Stage1 (22.exe) follows a well-structured loader pattern: neutralize AMSI and ETW telemetry through targeted in-memory patches, run a battery of anti-sandbox and anti-analysis checks, then decrypt an AES-256-CBC encrypted Stage2 PE from an embedded blob and reflectively load it – all without writing the payload to disk. The evasion work is not novel in isolation, but the combination of dual-target patching (both content scanning and event tracing), multi-tool sandbox detection, and crypto-backed stage separation puts this above a commodity dropper in terms of operational investment.
Stage2 static analysis shows strong indicators of credential and browser data collection – Chrome tooling strings, cookie paths, download tokens, and host-profiling imports – consistent with the Vidar stealer family. The XOR-encoded Mozilla/5.0 user-agent strings, confirmed independently by the upstream gen_xor_hunting.yar rule, further support that classification. Attribution remains at medium confidence pending full Stage2 config extraction and C2 validation, which Part II will address.
Four YARA rules (two high-fidelity, two heuristic) are published and validated against both stages. The accompanying scripts and notebook provide a reproducible path from the raw sample through decryption to IOC extraction, suitable for integration into broader hunting workflows.











