reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: analyzing-pe-imports-and-exports
|
||||
description: 'Analyzes a PE file''s import and export tables to infer capability: mapping imported
|
||||
APIs to behaviors (networking, crypto, injection, persistence), spotting dynamic-resolution
|
||||
stubs, and reading exports of malicious DLLs. Activates for requests to analyze PE imports,
|
||||
inspect the IAT/exports, or infer capability from API usage.'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware-analysis
|
||||
- pe
|
||||
- imports
|
||||
- exports
|
||||
- capability
|
||||
- static-analysis
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1106
|
||||
- T1027
|
||||
d3fend:
|
||||
- D3-FCR
|
||||
- D3-DA
|
||||
references:
|
||||
- 'Microsoft PE/COFF specification — https://learn.microsoft.com/windows/win32/debug/pe-format'
|
||||
- 'pefile library — https://github.com/erocarrera/pefile'
|
||||
---
|
||||
|
||||
# Analyzing PE Imports and Exports
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have a Windows PE and want a fast capability read from its imported APIs.
|
||||
- You need to identify suspicious API clusters (injection, crypto, anti-analysis) before deeper
|
||||
reversing.
|
||||
- You are inspecting a malicious DLL's exports to find its callable entry points.
|
||||
|
||||
**Do not use** the import table alone as a verdict — packers stub imports and malware resolves
|
||||
APIs dynamically; a thin IAT can hide real capability.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `pefile` (`pip install pefile`); the sample handled inertly in the lab.
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Parse the PE statically; never run it during import analysis.
|
||||
- Keep the sample password-protected at rest and reference it by hash.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Parse imports
|
||||
|
||||
Enumerate imported DLLs and functions from the import directory (IAT). A sparse IAT plus a
|
||||
`GetProcAddress`/`LoadLibrary` pair suggests dynamic resolution.
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py imports sample.exe
|
||||
```
|
||||
|
||||
### Step 2: Map APIs to behaviors
|
||||
|
||||
Cluster imports into behavior buckets: networking (`Ws2_32`, `WinINet`), process/injection
|
||||
(`VirtualAllocEx`, `WriteProcessMemory`, `CreateRemoteThread`), crypto (`Crypt*`, `bcrypt`),
|
||||
persistence (`Reg*`, service APIs), and anti-analysis (`IsDebuggerPresent`).
|
||||
|
||||
### Step 3: Inspect exports
|
||||
|
||||
For DLLs, list exports (by name and ordinal). Unusual export names or a single exported
|
||||
`DllRegisterServer`/ordinal hint at how the module is invoked.
|
||||
|
||||
### Step 4: Flag dynamic resolution
|
||||
|
||||
Note `LoadLibrary`/`GetProcAddress`, ordinal-only imports, and tiny IATs as signs that the real
|
||||
capability is resolved at runtime — escalate to dynamic/RE workflows.
|
||||
|
||||
## Validation
|
||||
|
||||
- Import behavior buckets are consistent with other static signals (strings, sections).
|
||||
- A thin or stubbed IAT is recognized as a packing/dynamic-resolution indicator, not "benign".
|
||||
- Exports of a malicious DLL are enumerated with their invocation method identified.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Trusting a small IAT as low-capability when imports are resolved dynamically.
|
||||
- Ignoring delay-load and bound imports.
|
||||
- Reading ordinal-only imports without resolving them to function names.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the import/export parser.
|
||||
- Microsoft PE/COFF spec and pefile (linked in frontmatter).
|
||||
@@ -0,0 +1,36 @@
|
||||
# API Reference: Analyzing PE Imports and Exports
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` parses a PE's import and export tables with `pefile`, buckets imported APIs
|
||||
into behavior categories (networking, injection, crypto, persistence, anti-analysis,
|
||||
dynamic-resolution), and flags a thin IAT. It parses statically and never executes the sample.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| pefile | >= 2023.2.7 | PE import/export directory parsing |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `analyze(path)`
|
||||
Returns imported DLLs/functions, exports, capability buckets, and a `thin_iat` flag.
|
||||
|
||||
### `_bucketize(funcs)`
|
||||
Maps API names to behavior categories via substring matching.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
pip install pefile
|
||||
python scripts/analyst.py imports sample.exe
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- Microsoft PE/COFF specification (import/export directories) —
|
||||
https://learn.microsoft.com/windows/win32/debug/pe-format
|
||||
- pefile library — https://github.com/erocarrera/pefile
|
||||
- API-to-behavior mapping (e.g., VirtualAllocEx+WriteProcessMemory+CreateRemoteThread =
|
||||
injection), established static-analysis practice
|
||||
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Parse a PE file's imports/exports and bucket APIs into capability categories.
|
||||
|
||||
Uses ``pefile`` to enumerate imported DLLs/functions and exports, then maps imported API names to
|
||||
behavior buckets (networking, injection, crypto, persistence, anti-analysis) and flags
|
||||
dynamic-resolution indicators. It parses the PE statically and never executes it.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
BEHAVIOR = {
|
||||
"networking": ["wsastartup", "connect", "send", "recv", "internetopen", "httpopenrequest",
|
||||
"winhttpopen", "urldownloadtofile"],
|
||||
"injection": ["virtualallocex", "writeprocessmemory", "createremotethread",
|
||||
"ntunmapviewofsection", "queueuserapc", "setthreadcontext"],
|
||||
"crypto": ["cryptencrypt", "cryptdecrypt", "cryptacquirecontext", "bcryptencrypt",
|
||||
"cryptgenkey"],
|
||||
"persistence": ["regsetvalue", "regcreatekey", "createservice", "openscmanager",
|
||||
"schedule"],
|
||||
"anti_analysis": ["isdebuggerpresent", "checkremotedebuggerpresent",
|
||||
"ntqueryinformationprocess", "outputdebugstring"],
|
||||
"dynamic_resolution": ["loadlibrary", "getprocaddress", "ldrloaddll"],
|
||||
}
|
||||
|
||||
|
||||
def _bucketize(funcs: list[str]) -> dict:
|
||||
lowered = [f.lower() for f in funcs]
|
||||
out = {}
|
||||
for bucket, needles in BEHAVIOR.items():
|
||||
hits = sorted({f for f in lowered if any(n in f for n in needles)})
|
||||
if hits:
|
||||
out[bucket] = hits
|
||||
return out
|
||||
|
||||
|
||||
def analyze(path: str) -> dict:
|
||||
import pefile # type: ignore
|
||||
pe = pefile.PE(path)
|
||||
imports = {}
|
||||
all_funcs = []
|
||||
if hasattr(pe, "DIRECTORY_ENTRY_IMPORT"):
|
||||
for entry in pe.DIRECTORY_ENTRY_IMPORT:
|
||||
dll = entry.dll.decode("latin-1") if entry.dll else "?"
|
||||
funcs = []
|
||||
for imp in entry.imports:
|
||||
name = imp.name.decode("latin-1") if imp.name else f"ordinal_{imp.ordinal}"
|
||||
funcs.append(name)
|
||||
imports[dll] = funcs
|
||||
all_funcs.extend(funcs)
|
||||
|
||||
exports = []
|
||||
if hasattr(pe, "DIRECTORY_ENTRY_EXPORT"):
|
||||
for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols:
|
||||
exports.append({"name": exp.name.decode("latin-1") if exp.name else None,
|
||||
"ordinal": exp.ordinal})
|
||||
|
||||
return {
|
||||
"imported_dlls": len(imports),
|
||||
"imported_functions": len(all_funcs),
|
||||
"imports": imports,
|
||||
"exports": exports,
|
||||
"capabilities": _bucketize(all_funcs),
|
||||
"thin_iat": len(all_funcs) < 10,
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Analyze PE imports/exports")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("imports")
|
||||
p.add_argument("file")
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
print(json.dumps(analyze(args.file), indent=2))
|
||||
except ImportError:
|
||||
print("missing dependency: pefile (pip install pefile)", file=sys.stderr)
|
||||
return 2
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user