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,99 @@
---
name: analyzing-elf-binaries-on-linux
description: 'Statically analyzes Linux ELF malware: ELF header and sections, dynamic symbols
and imports, segment permissions, embedded strings, and packing indicators to infer
capability without execution. Activates for requests to analyze an ELF binary, Linux
malware, or shared object.'
domain: cybersecurity
subdomain: malware-analysis
tags:
- malware
- static-analysis
- elf
- linux
- symbols
- entropy
version: 1.0.0
author: analyst-ai-pack
license: Apache-2.0
mitre_attack:
- T1027
- T1059.004
- T1129
d3fend:
- D3-FA
- D3-FCR
references:
- 'ELF specification (System V ABI) — https://refspecs.linuxfoundation.org/elf/elf.pdf'
- 'pyelftools — https://github.com/eliben/pyelftools'
---
# Analyzing ELF Binaries on Linux
## When to Use
- You have a Linux executable or shared object and need to assess it statically.
- You want to read the ELF header, segments, dynamic symbols, and strings to infer behavior.
- You are checking for static linking, stripped symbols, or packing.
**Do not use** symbol absence as proof of nothing — stripped or statically linked Go/Rust
binaries hide structure; switch to disassembly when static metadata is thin.
## Prerequisites
- `readelf`/`nm`/`strings` (binutils) or `pyelftools` (`pip install pyelftools`).
- The sample in neutralized form inside the lab.
## Safety & Handling
- Static only: parse the file; do not set it executable or run it.
## Workflow
### Step 1: Read the ELF header
```bash
python scripts/analyst.py analyze sample.elf
```
Note class (ELF32/64), endianness, type (EXEC/DYN/REL), machine (x86-64, ARM, MIPS), and
whether it is stripped.
### Step 2: Examine segments and section permissions
Writable+executable segments, or a single large segment, suggest packing or self-modifying
code. Compare `PT_LOAD` permissions against expectations.
### Step 3: Inspect dynamic symbols and needed libraries
Imported functions hint at capability: `socket`/`connect` (network), `ptrace` (anti-debug or
injection), `fork`/`execve` (process control), `crypt`/`EVP_*` (encryption).
### Step 4: Detect static linking and packing
Static binaries lack a dynamic symbol table and `NEEDED` entries. High whole-file entropy and
a tiny section table suggest a packer (e.g. UPX leaves `UPX!` markers).
### Step 5: Skim strings and constructors
Check `.init_array`/constructors (code before `main`), and strings for paths, URLs, and shell
commands.
## Validation
- Header `type` and segment permissions are consistent with the inferred behavior.
- Imported symbols correspond to plausible capabilities.
- Packing call (entropy + missing sections) matches the strings observed.
## Pitfalls
- Assuming dynamic symbols are complete — they only cover imported/exported names, not
internal functions.
- Treating a stripped Go binary as "empty"; its structure lives in runtime metadata, not the
symbol table.
- Ignoring constructors/`.init_array`, which run before `main`.
## References
- See [`references/api-reference.md`](references/api-reference.md) for the ELF analyzer.
- ELF/System V ABI spec and pyelftools (linked in frontmatter).

View File

@@ -0,0 +1,43 @@
# API Reference: Analyzing ELF Binaries on Linux
## Overview
`scripts/analyst.py` reports ELF header facts, dynamic symbols and `NEEDED` libraries, a strip
check, and capability groupings (network/process/crypto). It uses `pyelftools` when present
and falls back to a minimal header/entropy parse otherwise.
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| pyelftools | >= 0.30 | Full ELF parsing (optional) |
| (stdlib) | — | Header/entropy fallback |
## External tools
| Tool | Purpose |
|------|---------|
| readelf / nm (binutils) | Authoritative ELF inspection |
| strings | Embedded string review |
## Core functions
### `analyze(path)`
Dispatches to the pyelftools or minimal parser; returns header, symbols, needed libs, and
capability groupings.
### `entropy(data)`
Byte-level Shannon entropy for packing assessment.
## Usage
```bash
pip install pyelftools # optional
python scripts/analyst.py analyze sample.elf
```
## Sources
- ELF / System V ABI specification — https://refspecs.linuxfoundation.org/elf/elf.pdf
- pyelftools — https://github.com/eliben/pyelftools
- UPX section/marker conventions (vendor docs)

View File

@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""Static ELF analysis: header, sections, dynamic symbols, and packing hints.
Uses ``pyelftools`` when available; otherwise parses the ELF header and section table
directly so basic facts (class, type, machine, sections, entropy) are still reported.
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
_NETWORK = {"socket", "connect", "send", "recv", "bind", "listen", "gethostbyname"}
_PROC = {"fork", "execve", "ptrace", "clone", "kill", "system", "popen"}
_CRYPTO = {"crypt", "evp_encryptinit_ex", "aes_encrypt", "rc4"}
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 analyze_with_pyelftools(path: str) -> dict:
from elftools.elf.elffile import ELFFile # type: ignore
from elftools.elf.dynamic import DynamicSection # type: ignore
with open(path, "rb") as fh:
elf = ELFFile(fh)
header = {
"class": elf.elfclass,
"type": elf["e_type"],
"machine": elf["e_machine"],
"entry": hex(elf["e_entry"]),
}
symbols: list[str] = []
needed: list[str] = []
dynsym = elf.get_section_by_name(".dynsym")
if dynsym:
symbols = [s.name for s in dynsym.iter_symbols() if s.name]
for sec in elf.iter_sections():
if isinstance(sec, DynamicSection):
for tag in sec.iter_tags():
if tag.entry.d_tag == "DT_NEEDED":
needed.append(tag.needed)
stripped = elf.get_section_by_name(".symtab") is None
low = {s.lower() for s in symbols}
return {
"header": header,
"stripped": stripped,
"needed": needed,
"dynamic_symbol_count": len(symbols),
"capabilities": {
"network": sorted(low & _NETWORK),
"process": sorted(low & _PROC),
"crypto": sorted(low & _CRYPTO),
},
}
def analyze_minimal(path: str) -> dict:
data = Path(path).read_bytes()
if data[:4] != b"\x7fELF":
raise ValueError("not an ELF")
is64 = data[4] == 2
le = data[5] == 1
endian = "<" if le else ">"
e_type = struct.unpack_from(endian + "H", data, 16)[0]
e_machine = struct.unpack_from(endian + "H", data, 18)[0]
upx = b"UPX!" in data
return {
"header": {"class": 64 if is64 else 32, "type": e_type, "machine": e_machine},
"whole_file_entropy": round(entropy(data), 3),
"upx_marker": upx,
"note": "pyelftools not installed; minimal parse",
}
def analyze(path: str) -> dict:
try:
return analyze_with_pyelftools(path)
except ImportError:
return analyze_minimal(path)
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Static ELF analysis")
sub = parser.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("analyze")
p.add_argument("file")
args = parser.parse_args(argv)
print(json.dumps(analyze(args.file), indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())