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,108 @@
---
name: reverse-engineering-shellcode
description: 'Analyzes position-independent shellcode: disassembling raw bytes at the right
architecture, recognizing PEB-walk API resolution and egg hunters, and emulating execution
to recover behavior and payloads. Activates for requests to analyze shellcode, disassemble
raw position-independent code, or emulate a shellcode blob.'
domain: cybersecurity
subdomain: reverse-engineering
tags:
- reverse-engineering
- shellcode
- emulation
- position-independent
- peb-walk
- disassembly
version: 1.0.0
author: analyst-ai-pack
license: Apache-2.0
mitre_attack:
- T1055
- T1106
- T1027
d3fend:
- D3-PSA
- D3-FCR
references:
- 'Capstone disassembly framework — https://www.capstone-engine.org/'
- 'Unicorn CPU emulator — https://www.unicorn-engine.org/'
---
# Reverse Engineering Shellcode
## When to Use
- You extracted a raw code blob (from a document, exploit, injected memory region, or beacon)
with no PE/ELF headers.
- You need to determine the architecture, recover the API-resolution method, and understand
what the shellcode does.
- You want to emulate the shellcode safely to recover staged payloads or C2.
**Do not use** a file-format parser on shellcode — there is no header. Treat it as a flat byte
stream at a known base and disassemble/emulate.
## Prerequisites
- Capstone (`pip install capstone`) for disassembly; Unicorn (`pip install unicorn`) for
emulation.
- Knowledge of the likely architecture/bitness (x86 vs x64) and calling context.
## Workflow
### Step 1: Determine architecture and entry
Try disassembling as x86 and x64; the one that yields coherent instructions (and a sane
prologue) is correct. Shellcode usually starts executing at offset 0.
```bash
python scripts/analyst.py disasm shellcode.bin --arch x64
```
### Step 2: Recognize API resolution
Windows shellcode typically walks the PEB to find `kernel32`, then resolves exports by hash:
```text
mov rax, gs:[60h] ; PEB (x64) / mov eax, fs:[30h] (x86)
... traverse Ldr -> InMemoryOrderModuleList
... hash export names, compare to embedded constants
```
Recovered hash constants feed the API-hash resolver (see the obfuscation skill).
### Step 3: Identify the technique
Look for egg hunters (searching memory for a tag), socket setup (reverse/bind shell), or a
download-and-exec stager (`WinINet`/`WinHTTP` resolution then a URL).
### Step 4: Emulate to recover behavior
Emulate with Unicorn, hooking memory and (optionally) faking API calls, to observe the
control flow and extract strings/URLs the static view hides:
```bash
python scripts/analyst.py emulate shellcode.bin --arch x64 --base 0x140000000
```
### Step 5: Extract IOCs and payload
Recover C2 URLs/hosts, embedded second stages, and the resolved API set for the report.
## Validation
- The chosen architecture yields a coherent prologue and no garbage instruction stream.
- Recovered API hashes resolve to a sensible function set (LoadLibrary/GetProcAddress, network
APIs).
- Emulation reaches the network/exec stage consistent with the static read.
## Pitfalls
- Disassembling at the wrong bitness and chasing nonsense.
- Emulating without bounding execution, looping forever on unresolved calls.
- Ignoring self-modifying decoders — emulate through the decode stub to reach real code.
## References
- See [`references/api-reference.md`](references/api-reference.md) for the disassembler and
emulator wrapper.
- Capstone and Unicorn (linked in frontmatter).

View File

@@ -0,0 +1,37 @@
# API Reference: Reverse Engineering Shellcode
## Overview
`scripts/analyst.py` disassembles raw shellcode with Capstone and emulates it with Unicorn under
a bounded instruction count, capturing executed addresses. Both operate inside the
disassembler/emulator; the shellcode never runs as a real process.
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| capstone | >= 5.0 | Linear disassembly of x86/x64 bytes |
| unicorn | >= 2.0 | CPU emulation for self-decoding stubs |
## Core functions
### `disasm(data, arch, base, limit)`
Returns disassembled instructions (address, mnemonic, operands) at the chosen architecture.
### `emulate(data, arch, base, max_insns)`
Maps memory, writes the blob, hooks each instruction, and runs with a bounded count; returns
executed-instruction stats and the stop address.
## Usage
```bash
pip install capstone unicorn
python scripts/analyst.py disasm shellcode.bin --arch x64 --base 0x140000000
python scripts/analyst.py emulate shellcode.bin --arch x64
```
## Sources
- Capstone disassembly framework — https://www.capstone-engine.org/
- Unicorn CPU emulator — https://www.unicorn-engine.org/
- PEB-walk API resolution in Windows shellcode (kernel32 export hashing), standard technique

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""Disassemble and (optionally) emulate raw shellcode.
``disasm`` uses Capstone to linearly disassemble a flat byte blob at a chosen architecture.
``emulate`` uses Unicorn to run the blob in an isolated emulator with bounded instruction
count, capturing executed addresses — useful for self-decoding stubs. Both operate in-process
on the emulator/disassembler; nothing runs on the real CPU as a process.
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
def disasm(data: bytes, arch: str, base: int, limit: int = 200) -> list[dict]:
from capstone import ( # type: ignore
Cs, CS_ARCH_X86, CS_MODE_32, CS_MODE_64,
)
mode = CS_MODE_64 if arch == "x64" else CS_MODE_32
md = Cs(CS_ARCH_X86, mode)
out = []
for i, insn in enumerate(md.disasm(data, base)):
if i >= limit:
break
out.append({"addr": hex(insn.address), "mnemonic": insn.mnemonic,
"op_str": insn.op_str})
return out
def emulate(data: bytes, arch: str, base: int, max_insns: int = 5000) -> dict:
from unicorn import ( # type: ignore
Uc, UC_ARCH_X86, UC_MODE_32, UC_MODE_64, UcError,
)
from unicorn.x86_const import UC_X86_REG_RIP, UC_X86_REG_EIP # type: ignore
mode = UC_MODE_64 if arch == "x64" else UC_MODE_32
mu = Uc(UC_ARCH_X86, mode)
region = 0x10 * 1024 * 1024
map_base = base & ~0xFFF
mu.mem_map(map_base, region)
mu.mem_write(base, data)
executed: list[int] = []
def hook_code(uc, address, size, user_data): # noqa: ANN001
executed.append(address)
if len(executed) >= max_insns:
uc.emu_stop()
from unicorn import UC_HOOK_CODE # type: ignore
mu.hook_add(UC_HOOK_CODE, hook_code)
error = None
try:
mu.emu_start(base, base + len(data), count=max_insns)
except UcError as exc:
error = str(exc)
reg = UC_X86_REG_RIP if arch == "x64" else UC_X86_REG_EIP
return {
"instructions_executed": len(executed),
"first_addrs": [hex(a) for a in executed[:20]],
"stopped_at": hex(mu.reg_read(reg)),
"error": error,
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Shellcode disasm/emulate")
sub = parser.add_subparsers(dest="cmd", required=True)
p_d = sub.add_parser("disasm")
p_d.add_argument("file")
p_d.add_argument("--arch", choices=["x86", "x64"], default="x64")
p_d.add_argument("--base", default="0x1000")
p_e = sub.add_parser("emulate")
p_e.add_argument("file")
p_e.add_argument("--arch", choices=["x86", "x64"], default="x64")
p_e.add_argument("--base", default="0x1000")
args = parser.parse_args(argv)
data = Path(args.file).read_bytes()
base = int(args.base, 0)
try:
if args.cmd == "disasm":
print(json.dumps(disasm(data, args.arch, base), indent=2))
else:
print(json.dumps(emulate(data, args.arch, base), indent=2))
except ImportError as exc:
print(f"missing dependency: {exc} (pip install capstone unicorn)", file=sys.stderr)
return 2
return 0
if __name__ == "__main__":
sys.exit(main())