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,83 @@
|
||||
---
|
||||
name: analyzing-api-call-traces
|
||||
description: 'Analyzes API call traces from a sandbox or API monitor (JSON) to group calls by
|
||||
category, reconstruct high-level behaviors (process injection, file drops, network, crypto), and
|
||||
flag suspicious call sequences. Activates for requests to analyze an API trace, interpret sandbox
|
||||
API logs, or identify behavior from Win32/Native API calls.'
|
||||
domain: cybersecurity
|
||||
subdomain: malware-analysis
|
||||
tags:
|
||||
- malware-analysis
|
||||
- dynamic-analysis
|
||||
- api-trace
|
||||
- winapi
|
||||
- sandbox
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1106
|
||||
- T1055
|
||||
- T1027
|
||||
d3fend:
|
||||
- D3-PSA
|
||||
- D3-SDA
|
||||
references:
|
||||
- 'MITRE ATT&CK T1106 Native API — https://attack.mitre.org/techniques/T1106/'
|
||||
- 'Windows API Index — https://learn.microsoft.com/windows/win32/apiindex/windows-api-list'
|
||||
---
|
||||
|
||||
# Analyzing API Call Traces
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have a JSON API trace (CAPE/Cuckoo "apistats"/calls, API Monitor export) from a detonation.
|
||||
- You need to translate raw API calls into high-level behaviors and flag suspicious sequences
|
||||
(e.g., `VirtualAllocEx` → `WriteProcessMemory` → `CreateRemoteThread`).
|
||||
|
||||
**Do not use** this as a substitute for detonation — it consumes an existing trace produced in an
|
||||
isolated sandbox.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A JSON API trace with at least an API name per call (and optionally arguments).
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Consume traces only; never execute the sample to generate one outside a sandbox.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Group calls by category
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py classify trace.json
|
||||
```
|
||||
|
||||
Buckets calls into process, memory, file, registry, network, crypto, and synchronization.
|
||||
|
||||
### Step 2: Detect behavior signatures
|
||||
|
||||
Matches ordered API sequences that indicate techniques — remote injection, hollowing,
|
||||
self-deletion, dynamic API resolution (`LoadLibrary`/`GetProcAddress` bursts).
|
||||
|
||||
### Step 3: Prioritize and report
|
||||
|
||||
Rank detected behaviors by severity and map each to ATT&CK.
|
||||
|
||||
## Validation
|
||||
|
||||
- Each API call is categorized; unknown APIs are reported, not dropped silently.
|
||||
- Injection-style sequences are detected only when the ordered prerequisites are present.
|
||||
- Detected behaviors map to ATT&CK techniques.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- Flagging individual benign APIs out of context — the sequence matters.
|
||||
- Assuming call order in the JSON equals execution order without a timestamp/index.
|
||||
- Ignoring failed calls (non-zero error) that never actually executed the behavior.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the classifier.
|
||||
- ATT&CK T1106 and the Windows API Index (linked in frontmatter).
|
||||
@@ -0,0 +1,42 @@
|
||||
# API Reference: Analyzing API Call Traces
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` classifies a JSON API trace into behavioral categories and detects ordered
|
||||
API sequences indicative of process injection, hollowing, dynamic API resolution, and crypto
|
||||
routines. It parses JSON only and executes nothing.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| (stdlib) | — | json, argparse |
|
||||
|
||||
## Accepted input shapes
|
||||
|
||||
- A list of strings (API names) or call objects with `api`/`name`/`function` keys.
|
||||
- A dict containing `calls`, `apis`, or a CAPE-style `apistats` mapping.
|
||||
|
||||
## Core functions
|
||||
|
||||
### `classify(path)`
|
||||
Returns total call count, per-category counts, detected behaviors (with ATT&CK IDs), and unknown
|
||||
APIs.
|
||||
|
||||
## Sequence signatures
|
||||
|
||||
`VirtualAllocEx → WriteProcessMemory → CreateRemoteThread` (T1055.002), hollowing (T1055.012),
|
||||
`LoadLibrary → GetProcAddress` (T1027.007), `CryptAcquireContext → CryptDecrypt` (T1027). Matching
|
||||
respects order via a sliding cursor.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py classify trace.json
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- MITRE ATT&CK T1106 Native API; T1055 Process Injection — https://attack.mitre.org/
|
||||
- Windows API Index — https://learn.microsoft.com/windows/win32/apiindex/windows-api-list
|
||||
- CAPE/Cuckoo report `behavior.apistats` structure (public sandbox schema)
|
||||
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Classify a JSON API call trace and detect behavior signatures.
|
||||
|
||||
Accepts a flexible JSON trace: a list of call objects, or a dict with a "calls"/"apis" list, or a
|
||||
CAPE-style apistats mapping. Categorizes API names and matches ordered sequences indicative of
|
||||
process injection, dynamic API resolution, and self-deletion. Parses JSON only; executes nothing.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
CATEGORIES = {
|
||||
"process": ["createprocess", "openprocess", "createremotethread", "ntcreatethreadex",
|
||||
"resumethread", "terminateprocess"],
|
||||
"memory": ["virtualalloc", "virtualallocex", "virtualprotect", "writeprocessmemory",
|
||||
"readprocessmemory", "ntmapviewofsection", "ntunmapviewofsection"],
|
||||
"file": ["createfile", "writefile", "readfile", "deletefile", "copyfile", "movefile"],
|
||||
"registry": ["regopenkey", "regsetvalue", "regcreatekey", "regqueryvalue"],
|
||||
"network": ["internetopen", "internetconnect", "httpsendrequest", "wininet", "winhttp",
|
||||
"send", "recv", "connect", "getaddrinfo"],
|
||||
"crypto": ["cryptencrypt", "cryptdecrypt", "cryptacquirecontext", "bcryptencrypt",
|
||||
"cryptstringtobinary"],
|
||||
"resolve": ["loadlibrary", "getprocaddress", "ldrloaddll", "ldrgetprocedureaddress"],
|
||||
"sync": ["createmutex", "openmutex", "createevent", "sleep", "waitforsingleobject"],
|
||||
}
|
||||
|
||||
SIGNATURES = [
|
||||
("remote_process_injection", ["virtualallocex", "writeprocessmemory", "createremotethread"],
|
||||
"T1055.002"),
|
||||
("process_hollowing", ["createprocess", "ntunmapviewofsection", "writeprocessmemory"],
|
||||
"T1055.012"),
|
||||
("dynamic_api_resolution", ["loadlibrary", "getprocaddress"], "T1027.007"),
|
||||
("crypto_routine", ["cryptacquirecontext", "cryptdecrypt"], "T1027"),
|
||||
]
|
||||
|
||||
|
||||
def _extract_calls(obj) -> list[str]:
|
||||
if isinstance(obj, list):
|
||||
out = []
|
||||
for c in obj:
|
||||
if isinstance(c, str):
|
||||
out.append(c)
|
||||
elif isinstance(c, dict):
|
||||
out.append(c.get("api") or c.get("name") or c.get("function") or "")
|
||||
return [c for c in out if c]
|
||||
if isinstance(obj, dict):
|
||||
for key in ("calls", "apis", "apistats"):
|
||||
if key in obj:
|
||||
val = obj[key]
|
||||
if isinstance(val, dict):
|
||||
return list(val.keys())
|
||||
return _extract_calls(val)
|
||||
return []
|
||||
|
||||
|
||||
def _category(api: str) -> str:
|
||||
low = api.lower()
|
||||
for cat, names in CATEGORIES.items():
|
||||
if any(n in low for n in names):
|
||||
return cat
|
||||
return "other"
|
||||
|
||||
|
||||
def classify(path: str) -> dict:
|
||||
data = json.loads(open(path, encoding="utf-8-sig").read())
|
||||
calls = _extract_calls(data)
|
||||
lowered = [c.lower() for c in calls]
|
||||
cats: dict[str, int] = {}
|
||||
unknown = set()
|
||||
for api in calls:
|
||||
cat = _category(api)
|
||||
cats[cat] = cats.get(cat, 0) + 1
|
||||
if cat == "other":
|
||||
unknown.add(api)
|
||||
detected = []
|
||||
for name, seq, tech in SIGNATURES:
|
||||
pos = 0
|
||||
for needle in seq:
|
||||
found = next((i for i in range(pos, len(lowered)) if needle in lowered[i]), -1)
|
||||
if found == -1:
|
||||
break
|
||||
pos = found + 1
|
||||
else:
|
||||
detected.append({"behavior": name, "attack": tech})
|
||||
return {
|
||||
"total_calls": len(calls),
|
||||
"categories": cats,
|
||||
"behaviors": detected,
|
||||
"unknown_apis": sorted(unknown)[:50],
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Classify an API call trace")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("classify")
|
||||
p.add_argument("trace")
|
||||
args = parser.parse_args(argv)
|
||||
print(json.dumps(classify(args.trace), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user