reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
Apache License 2.0 — see the repository root LICENSE file for the full text.
Copyright the AnalystAIPack contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0

View File

@@ -0,0 +1,98 @@
---
name: reverse-engineering-custom-c2-protocols
description: 'Reverses proprietary command-and-control protocols: locating send/recv routines,
recovering the message framing and encryption/encoding, and reconstructing the command set
to build a decoder or emulator. Activates for requests to reverse a custom C2 protocol,
decode beacon traffic, or document a malware command structure.'
domain: cybersecurity
subdomain: reverse-engineering
tags:
- reverse-engineering
- command-and-control
- protocol
- network
- decryption
- beacon
version: 1.0.0
author: analyst-ai-pack
license: Apache-2.0
mitre_attack:
- T1071
- T1095
- T1573
d3fend:
- D3-NTA
- D3-DA
references:
- 'MITRE ATT&CK T1071 Application Layer Protocol — https://attack.mitre.org/techniques/T1071/'
- 'MITRE ATT&CK T1573 Encrypted Channel — https://attack.mitre.org/techniques/T1573/'
---
# Reverse Engineering Custom C2 Protocols
## When to Use
- A sample uses a non-standard protocol (or a custom layer over HTTP/TCP) and you must decode
its traffic.
- You need to recover message framing, the encryption/encoding scheme, and the command set.
- You want to build a standalone decoder or emulator to parse captured beacon traffic.
**Do not use** this for documented protocols handled by existing dissectors — use the protocol
analyzer directly instead of reversing from scratch.
## Prerequisites
- A disassembler/debugger and a network capture (PCAP) of the sample's traffic where possible.
- The crypto/obfuscation skills for recovering keys and encodings.
## Workflow
### Step 1: Locate the network routines
Find `send`/`recv`/`WSASend`/`WinHTTP` calls (or the framework wrappers) and the buffers they
operate on. These bracket the serialization and crypto.
### Step 2: Recover framing
Trace how outbound buffers are built: magic bytes, length prefixes, sequence/ID fields, and
type/opcode fields. Document the header layout.
```text
[ magic(4) ][ len(4 LE) ][ opcode(1) ][ flags(1) ][ payload(len) ]
```
### Step 3: Recover crypto/encoding
Identify the transform applied before send / after recv (XOR with embedded key, RC4, AES,
base64). Recover keys from the binary or from the key-setup routine.
### Step 4: Reconstruct the command set
Map opcodes to handlers (shell, download, upload, sleep/jitter, exit) by following the
dispatch switch. Build a table of command → behavior.
### Step 5: Build a decoder and validate
Implement a parser/decryptor and run it against captured traffic; confirm it yields coherent
commands and recovers the beacon's config.
```bash
python scripts/analyst.py decode capture.bin --key 0x5a --magic 4d5a4331
```
## Validation
- The decoder parses every message in a real capture without desync.
- Decrypted payloads are coherent (printable commands / structured config).
- The opcode table matches the dispatch logic observed in the binary.
## Pitfalls
- Assuming fixed keys when the protocol negotiates a session key in the first exchange.
- Missing a length/sequence field and desynchronizing after the first message.
- Confusing transport (TLS) with the inner custom layer; decode the inner layer.
## References
- See [`references/api-reference.md`](references/api-reference.md) for the framing decoder.
- MITRE ATT&CK T1071 and T1573 (linked in frontmatter).

View File

@@ -0,0 +1,34 @@
# API Reference: Reverse Engineering Custom C2 Protocols
## Overview
`scripts/analyst.py` is a configurable reference decoder for a length-prefixed, XOR-obfuscated
framing (`[magic][len][opcode][flags][payload]`). Adapt the field sizes and crypto to the
protocol you reversed. It only parses a capture file and makes no network connections.
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| (stdlib) | — | struct parsing, file IO |
## Core functions
### `decode(stream, key, magic)`
Walks the byte stream, locates framed messages by magic, parses length/opcode/flags, and
XOR-decrypts each payload; returns parsed messages.
### `xor(data, key)`
Single-byte XOR helper used as the example payload transform.
## Usage
```bash
python scripts/analyst.py decode capture.bin --key 0x5a --magic 4d5a4331
```
## Sources
- MITRE ATT&CK T1071 Application Layer Protocol — https://attack.mitre.org/techniques/T1071/
- MITRE ATT&CK T1573 Encrypted Channel — https://attack.mitre.org/techniques/T1573/
- Common C2 framing patterns (magic + length prefix + opcode dispatch), general RE practice

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""Decode a simple length-prefixed, XOR-obfuscated C2 message stream.
This is a configurable reference decoder for the common framing
``[magic][len LE][opcode][flags][payload]`` with a single-byte XOR over the payload. Adjust the
field sizes/crypto to match the protocol you reversed. It only parses bytes from a capture
file; it makes no network connections.
"""
from __future__ import annotations
import argparse
import json
import struct
import sys
from pathlib import Path
def xor(data: bytes, key: int) -> bytes:
return bytes(b ^ key for b in data)
def decode(stream: bytes, key: int, magic: bytes) -> dict:
messages = []
off = 0
n = len(stream)
while off + 10 <= n:
if stream[off:off + len(magic)] != magic:
off += 1
continue
p = off + len(magic)
(length,) = struct.unpack_from("<I", stream, p)
opcode = stream[p + 4]
flags = stream[p + 5]
start = p + 6
end = start + length
if end > n:
break
payload = xor(stream[start:end], key)
messages.append({
"offset": off,
"opcode": opcode,
"flags": flags,
"length": length,
"payload_preview": payload[:64].decode("latin-1"),
})
off = end
return {"messages": messages, "count": len(messages)}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Decode custom C2 framing")
sub = parser.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("decode")
p.add_argument("file")
p.add_argument("--key", default="0x00", help="single-byte XOR key, e.g. 0x5a")
p.add_argument("--magic", default="", help="hex magic prefix, e.g. 4d5a4331")
args = parser.parse_args(argv)
stream = Path(args.file).read_bytes()
magic = bytes.fromhex(args.magic) if args.magic else b""
print(json.dumps(decode(stream, int(args.key, 0), magic), indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())