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,101 @@
---
name: unpacking-upx-and-common-packers
description: 'Identifies and unpacks packed binaries: detecting packers from section names and
entropy, automatically unpacking UPX, and manually unpacking custom packers by finding the
OEP and dumping. Activates for requests to unpack a packed sample, detect a packer, or
recover the original binary from UPX or a custom packer.'
domain: cybersecurity
subdomain: reverse-engineering
tags:
- reverse-engineering
- unpacking
- upx
- packers
- entropy
- oep
version: 1.0.0
author: analyst-ai-pack
license: Apache-2.0
mitre_attack:
- T1027.002
- T1140
- T1480
d3fend:
- D3-FCR
- D3-PSA
references:
- 'UPX — https://upx.github.io/'
- 'Detect It Easy (DIE) — https://github.com/horsicq/Detect-It-Easy'
---
# Unpacking UPX and Common Packers
## When to Use
- A sample shows high entropy, few imports, or packer section names, and you need the original
code for static analysis or RE.
- You want to unpack UPX automatically or manually unpack a custom/modified packer.
- You are preparing a sample for Ghidra/IDA (decompiling packed code is pointless).
**Do not use** generic unpackers as a guarantee — modified UPX and custom packers defeat
`upx -d`. Fall back to debugger-based manual unpacking.
## Prerequisites
- Packer detection (Detect It Easy, or the bundled section/entropy heuristics).
- `upx` for standard UPX; x64dbg + Scylla for manual unpacking (see the x64dbg skill).
- Isolated lab.
## Workflow
### Step 1: Detect the packer
```bash
python scripts/analyst.py detect sample.bin
```
Signals: section names (`UPX0`/`UPX1`, `.aspack`, `.themida`), high section entropy, a tiny
import table, and a small `.text` with a large high-entropy section.
### Step 2: Try automated UPX unpacking
If standard UPX:
```bash
upx -d -o sample_unpacked.bin sample.bin
```
If `upx -d` fails on a UPX-like sample, the header was likely tampered (e.g. `UPX!` magic or
version bytes altered) — repair the marker or unpack manually.
### Step 3: Manual unpacking for custom packers
In x64dbg: break on `VirtualAlloc`/`VirtualProtect`, run until the unpacked region is written
and made executable, find the **tail jump** to the original entry point (OEP), and dump there.
### Step 4: Dump and rebuild imports
Use Scylla to dump the process and reconstruct the Import Address Table (IAT) so the dumped PE
loads in a disassembler.
### Step 5: Verify the unpacked result
Confirm the dump is a clean PE with a populated import table and readable strings/code.
## Validation
- The unpacked file has restored imports and meaningful strings absent from the packed sample.
- Entropy of the unpacked `.text` drops to normal code levels.
- The disassembler resolves API calls (IAT rebuilt correctly).
## Pitfalls
- Running `upx -d` on tampered UPX and concluding it is not UPX; check for renamed/edited
markers.
- Dumping before reaching the OEP, capturing still-encrypted code.
- Forgetting IAT reconstruction, leaving the dump unusable in Ghidra/IDA.
## References
- See [`references/api-reference.md`](references/api-reference.md) for the packer detector.
- UPX and Detect It Easy (linked in frontmatter).

View File

@@ -0,0 +1,43 @@
# API Reference: Unpacking UPX and Common Packers
## Overview
`scripts/analyst.py` detects common packers from PE section names and per-section entropy and
recommends an unpacking approach (automated UPX vs manual debugger unpacking). It parses the
PE section table directly and reads bytes only.
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| (stdlib) | — | struct, entropy |
## External tools
| Tool | Purpose |
|------|---------|
| upx | Automated pack/unpack for standard UPX |
| Detect It Easy (DIE) | Broad packer/compiler signature detection |
| x64dbg + Scylla | Manual unpacking, dumping, IAT rebuild |
## Core functions
### `detect(path)`
Returns packer signatures, sections with entropy, high-entropy sections, whole-file entropy,
a `likely_packed` flag, and an unpacking recommendation.
### `parse_sections(data)`
Minimal PE section-table parser (name, raw size, entropy).
## Usage
```bash
python scripts/analyst.py detect sample.bin
upx -d -o sample_unpacked.bin sample.bin # if standard UPX
```
## Sources
- UPX — https://upx.github.io/
- Detect It Easy — https://github.com/horsicq/Detect-It-Easy
- Common packer section-name conventions (DIE/PEiD signature knowledge)

View File

@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""Detect common packers from PE section names, entropy, and import sparsity.
Heuristic, signature-light packer detection on file bytes. It parses the PE section table
directly (no third-party deps), computes per-section entropy, and matches known packer
section names. It reads bytes only and never executes the sample.
"""
from __future__ import annotations
import argparse
import json
import math
import struct
import sys
from collections import Counter
from pathlib import Path
PACKER_SECTIONS = {
"UPX0": "UPX", "UPX1": "UPX", "UPX2": "UPX",
".aspack": "ASPack", ".adata": "ASPack",
".themida": "Themida", ".winlice": "WinLicense",
".vmp0": "VMProtect", ".vmp1": "VMProtect",
".petite": "Petite", ".mpress1": "MPRESS", ".mpress2": "MPRESS",
"FSG!": "FSG", ".nsp0": "NsPack", ".pec1": "PECompact",
}
def entropy(data: bytes) -> float:
if not data:
return 0.0
counts = Counter(data)
n = len(data)
return -sum((c / n) * math.log2(c / n) for c in counts.values())
def parse_sections(data: bytes) -> list[dict]:
if data[:2] != b"MZ":
raise ValueError("not a PE")
e_lfanew = struct.unpack_from("<I", data, 0x3C)[0]
if data[e_lfanew:e_lfanew + 4] != b"PE\x00\x00":
raise ValueError("no PE signature")
num = struct.unpack_from("<H", data, e_lfanew + 6)[0]
opt = struct.unpack_from("<H", data, e_lfanew + 20)[0]
base = e_lfanew + 24 + opt
sections = []
for i in range(num):
b = base + i * 40
name = data[b:b + 8].rstrip(b"\x00").decode("latin-1", "replace")
raw_size = struct.unpack_from("<I", data, b + 16)[0]
raw_ptr = struct.unpack_from("<I", data, b + 20)[0]
blob = data[raw_ptr:raw_ptr + raw_size]
sections.append({"name": name, "raw_size": raw_size,
"entropy": round(entropy(blob), 3)})
return sections
def detect(path: str) -> dict:
data = Path(path).read_bytes()
sections = parse_sections(data)
hits = sorted({PACKER_SECTIONS[s["name"]] for s in sections
if s["name"] in PACKER_SECTIONS})
high_entropy = [s["name"] for s in sections if s["entropy"] > 7.2]
whole = round(entropy(data), 3)
likely_packed = bool(hits) or whole > 7.2 or len(high_entropy) >= max(1, len(sections) - 1)
return {
"packer_signatures": hits,
"sections": sections,
"high_entropy_sections": high_entropy,
"whole_file_entropy": whole,
"likely_packed": likely_packed,
"recommendation": ("upx -d" if "UPX" in hits else
"manual unpack in debugger" if likely_packed else
"no packing indicators"),
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Detect common packers")
sub = parser.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("detect")
p.add_argument("file")
args = parser.parse_args(argv)
print(json.dumps(detect(args.file), indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())