Module 24 of 22 — Bonus Module
Malware analysis is not about being smarter than the attacker. It is about being more patient. Every binary, every script, every encrypted blob is just data. If you can read it without executing it, you can map its capabilities, extract its indicators, and build defenses before it ever touches a real system.
Why this matters: The difference between a useful analyst and a dead analyst is discipline. Static analysis first. Dynamic analysis only in a disposable sandbox. Never let curiosity override containment. The backdoor we found in this module was discovered because we followed that rule.
Imagine you capture an enemy drone intact. You have two choices: turn it on in your barracks, or take it apart with the battery removed. The first choice might teach you something — or it might detonate. The second choice teaches you everything safely. Malware analysis is the same. Static analysis is taking the battery out before you touch the wires.
"The malware will tell you exactly what it does if you read it without running it."
Attackers rely on analysts being lazy, rushed, or overconfident. They hide payloads in encryption, obfuscation, and layers of loaders because they know most people will give up or run it. Your edge is methodical static inspection: strings, imports, network indicators, and behavioral patterns.
Red: If you write malware, assume it will be statically analyzed. Obfuscation raises the bar but does not make you invisible. Blue: Build detections from the behavior, not the packaging. A packed binary and a plain script do the same things in memory.
This module assumes you understand these concepts from earlier modules:
Malware taxonomy, static vs dynamic analysis, and safe lab practices. This module is the advanced practical application.
DLL injection, remote threads, and process manipulation primitives. Essential for recognizing injection code in static analysis.
Detection engineering, IOC extraction, and evidence-based verification. We will extract IOCs directly from the sample.
C2 infrastructure, exfiltration patterns, and HTTP-based receivers. The sample uses simple HTTP C2 endpoints.
The infostealer sample we will audit. Read this first to understand the protocol and the sanitized lab version.
Python fundamentals, networking basics, and command-line fluency. You will need all three to follow the audit.
During the build of Module 23, we discovered that the infostealer-poc-analysis repository contained two different artifacts:
| Artifact | File | Risk | Notes |
|---|---|---|---|
| Cleaned template | src/stealer_template.py | High | Reverse-engineered version with hardcoded C2 IP. No wallet hijacking. |
| Original dropper | src/original info staler as downloaded from target.txt | Critical | Fernet-encrypted loader with second-stage wallet hijacking payload. |
| Generator | src/generator.py | Medium | Builds EXE and prints PowerShell delivery commands. |
| Receiver | src/receiver.py | Low | Flask C2 server. Clean, no hidden endpoints. |
The original dropper is live malware. Do not execute it. Do not double-click it. Do not run it in a VM that has network access or shared folders. The analysis in this module was performed entirely with static tools: grep, read_file, and a standalone Fernet decryptor that did not execute the decrypted payload.
Static analysis means inspecting the malware without running it. It is slower than dynamic analysis but safer, and it often reveals capabilities that dynamic analysis misses — especially time-delayed or environment-conditioned behavior.
List all files. Note sizes, extensions, and anything unusual.
Grep for URLs, IPs, file paths, registry keys, and suspicious imports.
Identify loaders, encryption, packing, and entry points.
If a key is embedded, decrypt payloads statically. Do not execute.
Document network calls, file operations, persistence, and injection.
The first thing any analyst should do is understand what they are looking at. File sizes are already informative: a 533KB text file named like a note is almost certainly a payload.
Attackers often disguise payloads as innocuous files: readme.txt, notes.txt, original info staler as downloaded from target.txt. The size and entropy give it away. A real text note is a few kilobytes. A 533KB text file is hiding something.
Network indicators are the fastest way to understand who the malware talks to. We grep for URLs, IP addresses, and common network libraries.
Results from the template:
Results from the original dropper:
Three different IPs/domains for one sample is normal in malware operations. The builder points to a download server. The payload points to a C2 server. The error logger points to the same C2. Each endpoint has a role. Map them all.
The original dropper is not the final payload. It is a loader. It installs fernet, decrypts a blob, writes it to disk, and executes it.
The dropper is a Russian nesting doll. The outer script installs a decryption library, uses a hardcoded key to unlock the inner script, saves it as svc.py, and launches it through a hidden VBScript. The victim sees nothing. The analyst sees a key and a blob.
Because the Fernet key is hardcoded, we can decrypt the payload without executing anything. The critical rule: decrypt to disk, read with grep, never run.
decrypted_payload.py is live malware. Open it in a text editor or grep it. Do not type python decrypted_payload.py. The goal is to read the burglar's notebook, not invite him inside.
Now we grep the decrypted payload for the same patterns: network calls, process injection, persistence, and file operations.
This reveals the full picture: a second-stage payload with wallet hijacking, process injection, browser killing, and silent dependency installation.
The decrypted payload contains two functions that the cleaned template did not: inject_exodus() and inject_atomic(). These are not data-theft functions. They are supply-chain sabotage functions.
Function: inject_exodus(loguuid)
Location: Decrypted payload, lines ~872–891
Function: inject_atomic(loguuid)
Location: Decrypted payload, lines ~893–907
Stealing a wallet password is bad. Replacing the wallet software itself is catastrophic. The victim opens the same application they trust, enters their seed phrase or password, and the attacker's modified wallet sends everything to an address they control. The theft happens inside a program the victim believes is legitimate.
The decrypted payload revealed several additional capabilities that raise the operational sophistication:
| Capability | Code Evidence | Location |
|---|---|---|
| Silent dependency install | subprocess.Popen([sys.executable, "-m", "pip", "install", "pycryptodome", "pypiwin32", ...]) |
Lines ~23–27 |
| Self-restart on failure | subprocess.Popen([sys.executable, os.path.abspath(__file__)], ...) |
Lines ~42–47 |
| Anti-reinfection mutex | if os.path.exists(os.path.join(LOCALAPPDATA, "HD Realtek Audio Player")): sys.exit(0) |
Lines ~910–912 |
| Browser process termination | psutil.process_iter(...); p.kill(); shutil.copy2(cookie_file, dst) |
extract_v20_cookies() |
| Process injection primitives | VirtualAllocEx, WriteProcessMemory, CreateRemoteThread, LoadLibraryA |
Lines ~248–260, ~305–324 |
| Chrome app-bound encryption bypass | Embedded base64 DLL (WRAPPED_DLL) injected into Chrome |
Line ~49 |
These are the artifacts a blue team can hunt for across endpoints and network logs.
| Type | Value | Hunt Query |
|---|---|---|
| C2 Domain | marsalek.cy | DNS queries or TLS SNI containing marsalek.cy |
| C2 IP | 113.30.148.162:8080 | Outbound HTTP to this IP |
| Download IP | 46.120.173.142:8080 | PowerShell downloading .exe from this IP |
| Mutex Directory | %LOCALAPPDATA%\HD Realtek Audio Player | Creation of this directory |
| Staging Directory | %APPDATA%\Microsoft Store | Unexpected files under this path |
| Temp Payload | %TEMP%\svc.py | Python script dropped in temp |
| Temp Launcher | %TEMP%\r.vbs | VBScript launching Python hidden |
| Wallet Endpoints | /exodus, /atomic | HTTP GET to these paths |
| Error Endpoint | /logging/errors | HTTP POST with JSON error body |
Full verification report: GeoDefend/scanners/GEODEFEND_VERIFICATION.md.
Standalone verification scanners: rainfantry/GeoDefend
Operator guide — how to rebuild the wallet-hijack concept safely: README → Wallet-Hijack Concept
Private operator lab with realistic second-stage overwrite: 22div-wallet-hijack-lab (authorized training only)
This exercise uses the original dropper file from the infostealer-poc-analysis repository. You will not execute any malware. You will only read and decrypt.
marsalek.cy at your router if the VM has any network.Question: Which file is suspiciously large for a text file?
Question: How many distinct C2/download endpoints can you identify?
Question: What two wallet applications does the payload target?
Create a text file with every domain, IP, file path, and behavioral indicator you found. Compare it to the IOC table in this module.
Why is static analysis safer than dynamic analysis for unknown malware?
What is the primary purpose of the inject_exodus() function?
Which of the following is an anti-reinfection technique used by the payload?
%LOCALAPPDATA%\HD Realtek Audio Player and exiting if found.explorer.exe.What is the C2 domain used by the original decrypted payload?
113.30.148.162marsalek.cy46.120.173.142discord.com"The backdoor was always there. You just had to read far enough to find it."
Most malware is not cleverly hidden. It is lazily ignored. The wallet hijacking functions were sitting in plain text inside a decrypted payload. The only reason they stayed hidden is that most analysts stop at the outer layer. Don't be most analysts.
Red: Layer your payloads. Expect static analysis. Blue: Static analysis is your first and cheapest line of defense. Build it into your workflow.