EpochZero Learn
EpochZero LearnMulti-Domain Tech Learning Hub
Courses
LeaderboardAbout
Dashboard
EpochZero
EpochZero Learn
Multi-Domain Tech Learning Hub

Structured learning for Reverse Engineering, Cloud Security, Cryptography, and Web Development. Articles, videos, tests, and peer discussion.

Learn

  • Learning Path
  • All Articles
  • Video Lessons
  • Podcast
  • eBooks & PDFs
  • Question Banks
  • Cheatsheets
  • MCQ Banks

Tests & Forum

  • All Tests
  • REMA Tests
  • Cloud Tests
  • Forum
  • REMA Forum
  • Cloud Forum
  • Crypto Forum
  • Web Dev Forum

Campus

  • REMA Club
  • Full Stack Dev Club
  • Extension Activity
  • Events
  • CTF Competitions
  • Workshops
  • Industrial Visits

Platform

  • Dashboard
  • Leaderboard
  • About
  • Verify Certificate

© 2026 EpochZero Learn. Educational content for learning purposes.

Course Instructor: Ashish Revar

All articles
Educationconfig-extractionxorcobalt-strike

Protecting Embedded Data

How malware encrypts its configuration, C2 addresses, and string constants — multi-key XOR, encrypted config blocks in Cobalt Strike and Emotet, per-string encryption with zeroing, and FLOSS for runtime string recovery.

Ashish Revar12 May 202616 min read2 views

Sign in to mark this article as read and track your progress.

Related to this topic

Continue learning

Listen

The Art of Deception: Unmasking Anti-Analysis & Evasion Techniques

A technical examination of the self-defence mechanisms used by self-defending malware — how threats detect sandboxes, sabotage debuggers, and hide from automated analysis, and how analysts defeat each technique.

Reference material

eBook
REMA eBook 2026
v1.0
Open resource
Cheatsheet
REMA Cheatsheet 2026
v1.0
Open resource
MCQ Bank
REMA MCQ Bank 2026
v1.0
Open resource
Question Bank
REMA Question Bank 2026
v1.0
Open resource

External references

CobaltStrikeParser — Beacon Config Extractor

Python tool that automatically extracts Cobalt Strike beacon configuration including C2 addresses, sleep timers, and user-agent strings.

tool
FLOSS — FLARE Obfuscated String Solver

Mandiant tool for recovering stack strings and XOR-decoded strings without executing the binary.

tool
REMA eBook 2026 — Chapter 6, Embedded Data Protection

Full rolling XOR diagram and config extraction workflow in the REMA eBook Chapter 6.

ebook
More articlesTest your knowledge

Why Malware Encrypts Its Data

Static analysis tools (FLOSS, strings) scan the binary on disk and recover embedded strings. Malware protects against this by encrypting configuration data and decrypting only at runtime, in memory, immediately before use.

If simple XOR is writing your diary in pig latin, advanced data protection is writing it in a cipher that changes every page, burning each page after reading, and keeping the decoder ring in a different safe. The analyst must find the ring, crack the safe, and read fast before the pages turn to ash.

Multi-Key and Rolling XOR

Multi-byte cycling key

Instead of a single static byte, a multi-byte key is applied cyclically. The key length divides evenly into the buffer length:

    lea  esi, [encrypted_buf]
    lea  edi, [key_buf]         ; e.g., key = DE AD BE EF (4 bytes)
    xor  ecx, ecx               ; counter = 0
decrypt_loop:
    mov  al, [esi+ecx]
    mov  ebx, ecx
    and  ebx, 3                 ; ebx = ecx mod 4 — cycles through key
    xor  al, [edi+ebx]
    mov  [esi+ecx], al
    inc  ecx
    cmp  ecx, edx
    jl   decrypt_loop

Python decryption:

key = bytes([0xDE, 0xAD, 0xBE, 0xEF])
decrypted = bytes([b ^ key[i % len(key)] for i, b in enumerate(encrypted)])

Rolling XOR (key increments)

The key value changes with each byte, making frequency analysis ineffective:

    mov  al, initial_key        ; e.g., 0x41
rolling_loop:
    xor  [esi+ecx], al
    inc  al                     ; key increments each byte
    inc  ecx
    loop rolling_loop

Rolling XOR defeats the assumption of a fixed key — every byte is encrypted with a different value.

Identify by: tight XOR loop where the key register is incremented inside the loop body.

Encrypted Configuration Blocks

Professional malware families store their full configuration — C2 addresses, port numbers, campaign IDs, encryption keys — in an encrypted blob within the binary.

Cobalt Strike Beacon

Cobalt Strike beacon configuration is stored in a PE resource and protected using XOR encoding with key 0x69 in older versions, followed by a custom transform in newer versions:

PE Resource (.rsrc section)
  → Resource type 0 or type 10
  → Contains: 0x69-XOR-encoded configuration blob
  → Config structure: C2 host, C2 port, sleep timer, jitter, user-agent, campaign ID

Extraction tools:

# CobaltStrikeParser — automated config extraction
python3 parse_beacon_config.py beacon.exe

# Output:
{
  "BeaconType": "HTTPS",
  "C2Server": "evil.com,/updates",
  "Port": 443,
  "SleepTime": 60000,
  "Jitter": 10,
  "UserAgent": "Mozilla/5.0 (compatible; MSIE 9.0)"
}

Emotet

Emotet stores its C2 list and RSA public key in the .data section, AES-CBC encrypted with a hardcoded key:

# EmotetConfigExtractor
python3 emotet_extractor.py emotet_sample.exe
# Outputs: list of C2 IPs and ports

General Config Extraction Approach

When no dedicated extractor exists:

1. Identify encrypted region:
   → High entropy in .data or .rsrc
   → Referenced by a function that loops over it with XOR/AES operations

2. Set breakpoint AFTER decryption function returns

3. Dump the decrypted buffer from memory:
   x64dbg → right-click decrypted address → Dump to file

4. Inspect the dump for structured config data:
   → IP:port pairs
   → Domain names
   → Base64 strings (further encoded layers)

Per-String Encryption with Zeroing

Individual strings are encrypted separately and decrypted one at a time immediately before use. After the API call returns, the decrypted string is zeroed:

    ; Decrypt string immediately before use
    call  decrypt_string       ; decrypts to [ebp-100h]
    push  [ebp-100h]           ; pass decrypted string to API
    call  RegOpenKeyExA
    ; After API returns — zero the decrypted string
    lea   edi, [ebp-100h]
    xor   eax, eax
    mov   ecx, string_length
    rep   stosd                ; fill with zeros

The decrypted string exists in memory for microseconds — only during the API call. FLOSS cannot find it because it never persists.

Bypass: Set a breakpoint on the API call (RegOpenKeyExA). When it fires, the string is on the stack. Read it before the function returns.

FLOSS for Runtime String Recovery

FLOSS emulates short function sequences and captures decoded string values — recovering strings that the zeroing technique tries to hide.

floss --no-static suspicious.exe    # skip plain strings, show decoded only
floss -o decoded_strings.txt suspicious.exe

FLOSS works by:

  1. Identifying all functions that return a string (heuristic)
  2. Emulating each function with symbolic inputs
  3. Capturing the output string before any zeroing code runs

Limitation: FLOSS emulates in isolation — it cannot follow complex multi-function decryption chains. For those, breakpoint at the final decryption output.

Cobalt Strike String XOR Example

Cobalt Strike payload strings are XOR-encoded with key 0x69:

# Decode Cobalt Strike 0x69-XOR encoded string
key = 0x69
encoded = bytes([0x21, 0x15, 0x1A, 0x00, 0x1B, 0x09, ...])
decoded = bytes([b ^ key for b in encoded])
print(decoded.decode('utf-8', errors='ignore'))
# Output: "http://evil.com/updates"

Searching for 0x69 XOR loops in the disassembly of a suspected Cobalt Strike beacon confirms the family and reveals the decryption key location.

Complete Data Extraction Workflow

1. Run FLOSS → recover statically accessible decoded strings
2. For encrypted config blocks:
   a. Identify high-entropy region in .data or .rsrc
   b. Find the decryption function (references the encrypted region)
   c. Set breakpoint after decryption completes
   d. Dump decrypted buffer from memory
3. For per-string encryption:
   a. Set breakpoints on sensitive APIs (CreateFile, RegOpenKey, URLDownload)
   b. When breakpoint fires, read string argument from stack/register
4. For known families: use dedicated extractors (CobaltStrikeParser, EmotetExtractor)
5. Record all extracted strings as IOCs