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,89 @@
---
name: reverse-engineering-arm-binaries
description: 'Reverse engineers ARM/AArch64 malware by identifying the architecture and instruction
set state (ARM/Thumb), parsing ELF/Mach-O ARM headers, and orienting analysis around the ARM
calling convention. Activates for requests to reverse ARM binaries, analyze AArch64 malware, or
handle ARM/Thumb instruction-set decoding.'
domain: cybersecurity
subdomain: reverse-engineering
tags:
- reverse-engineering
- arm
- aarch64
- thumb
- disassembly
version: 1.0.0
author: analyst-ai-pack
license: Apache-2.0
mitre_attack:
- T1027
- T1059
- T1587.001
d3fend:
- D3-DA
- D3-SDA
references:
- 'Arm Architecture Reference Manual — https://developer.arm.com/documentation/'
- 'ELF for the Arm Architecture (AAELF) — https://github.com/ARM-software/abi-aa'
---
# Reverse Engineering ARM Binaries
## When to Use
- You have an ARM (32-bit) or AArch64 (64-bit) binary — IoT/mobile/Linux malware — and need to
identify the architecture, instruction-set state, and entry point before disassembly.
- You need to handle ARM/Thumb interworking correctly.
**Do not use** an x86 mindset for calling conventions/registers — ARM differs. This skill reads the
binary statically and executes nothing.
## Prerequisites
- The ARM binary (ELF or Mach-O), read inertly. Capstone optional for instruction decoding.
## Safety & Handling
- Read bytes statically; analyze on an isolated host (and emulate via QEMU separately if needed).
## Workflow
### Step 1: Identify architecture and format
```bash
python scripts/analyst.py identify sample.bin
```
Parses ELF/Mach-O headers to report ARM vs AArch64, endianness, entry point, and (for ELF) whether
the entry is Thumb (low bit set in `e_entry` or `$t` mapping symbols).
### Step 2: Set the correct disassembly mode
Disassemble AArch64 as A64; for 32-bit ARM, switch between ARM and Thumb per the entry/mapping
symbols.
### Step 3: Orient around the calling convention
Track arguments in `r0-r3`/`x0-x7`, return in `r0`/`x0`, and syscalls via `svc` with the syscall
number in `r7`/`x8`.
### Step 4: Proceed with analysis
Identify functions, strings, and syscalls; pair with emulation if dynamic insight is needed.
## Validation
- Architecture (ARM/AArch64) and endianness are read from the header.
- The entry point and ARM/Thumb state are reported.
- Disassembly mode matches the detected state.
## Pitfalls
- Missing Thumb state and decoding Thumb as ARM (garbage output).
- Big-endian ARM (rare but real) mis-parsed as little-endian.
- Statically linked musl/uClibc inflating the function set on IoT samples.
## References
- See [`references/api-reference.md`](references/api-reference.md) for the identifier.
- Arm ARM and AAELF references (linked in frontmatter).

View File

@@ -0,0 +1,42 @@
# API Reference: Reverse Engineering ARM Binaries
## Overview
`scripts/analyst.py` parses ELF and Mach-O headers to identify ARM vs AArch64, endianness, entry
point, and (for 32-bit ARM ELF) Thumb entry state. It reads bytes statically and executes nothing.
Capstone can be used downstream for instruction decoding.
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| (stdlib) | — | struct, JSON, file IO |
## Core functions
### `identify(path)`
Returns format, architecture, endianness, entry point, and Thumb-entry flag.
### `_parse_elf(data)` / `_parse_macho(data)`
Header parsers reading `e_machine`/`e_entry` (ELF) and CPU type (Mach-O).
## Machine types
- ELF: `0x28` ARM, `0xB7` AArch64.
- Mach-O: `0x0000000C` ARM, `0x0100000C` ARM64.
## Calling convention notes
Args in `r0-r3`/`x0-x7`, return `r0`/`x0`, syscall via `svc` with number in `r7`/`x8`.
## Usage
```bash
python scripts/analyst.py identify sample.bin
```
## Sources
- Arm Architecture Reference Manual — https://developer.arm.com/documentation/
- ELF for the Arm Architecture (AAELF), `$a`/`$t` mapping symbols — https://github.com/ARM-software/abi-aa
- ELF `e_machine` 0x28/0xB7 and Mach-O CPU types from the respective format specifications

View File

@@ -0,0 +1,73 @@
#!/usr/bin/env python3
"""Identify ARM/AArch64 binary architecture, endianness, entry point, and Thumb state.
Parses ELF and Mach-O headers to report the ARM machine type, bitness, endianness, and entry
point, flagging Thumb entry for 32-bit ARM ELF (low bit of e_entry). Reads bytes statically;
executes nothing. Capstone (optional) can be used downstream for actual decoding.
"""
from __future__ import annotations
import argparse
import json
import struct
import sys
from pathlib import Path
ELF_MACHINE = {0x28: "ARM (32-bit)", 0xB7: "AArch64 (64-bit)"}
MACHO_CPU = {0x0000000C: "ARM (32-bit)", 0x0100000C: "AArch64 (64-bit)"}
def _parse_elf(data: bytes) -> dict:
ei_class = data[4] # 1=32, 2=64
ei_data = data[5] # 1=LE, 2=BE
endian = "<" if ei_data == 1 else ">"
machine = struct.unpack_from(endian + "H", data, 18)[0]
if ei_class == 1:
entry = struct.unpack_from(endian + "I", data, 24)[0]
else:
entry = struct.unpack_from(endian + "Q", data, 24)[0]
thumb = bool(machine == 0x28 and (entry & 1))
return {
"format": "ELF",
"architecture": ELF_MACHINE.get(machine, hex(machine)),
"endianness": "little" if ei_data == 1 else "big",
"entry_point": hex(entry & ~1 if thumb else entry),
"thumb_entry": thumb,
}
def _parse_macho(data: bytes) -> dict:
magic = struct.unpack_from("<I", data, 0)[0]
big = magic in (0xFEEDFACF, 0xFEEDFACE) and data[0] == 0xFE
endian = ">" if big else "<"
cputype = struct.unpack_from(endian + "I", data, 4)[0]
return {
"format": "Mach-O",
"architecture": MACHO_CPU.get(cputype, hex(cputype)),
"endianness": "big" if big else "little",
"entry_point": "parse LC_MAIN/LC_UNIXTHREAD for entry",
"thumb_entry": False,
}
def identify(path: str) -> dict:
data = Path(path).read_bytes()
if data[:4] == b"\x7fELF":
return _parse_elf(data)
if struct.unpack_from("<I", data, 0)[0] in (0xFEEDFACE, 0xFEEDFACF, 0xCEFAEDFE, 0xCFFAEDFE):
return _parse_macho(data)
return {"error": "not an ELF or Mach-O binary"}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Identify ARM/AArch64 binaries")
sub = parser.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("identify")
p.add_argument("file")
args = parser.parse_args(argv)
print(json.dumps(identify(args.file), indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())