mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-20 06:20:58 +03:00
Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills: - scripts/agent.py: 80-150 line Python agents using real libraries (impacket, boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.) - references/api-reference.md: real API documentation with method signatures - LICENSE: MIT license for all skill folders
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anthropic Agent Skills Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,60 @@
|
||||
# API Reference: Static Malware Analysis with PE Studio Agent
|
||||
|
||||
## Overview
|
||||
|
||||
Performs automated static analysis of Windows PE binaries using pefile to inspect headers, sections, imports, strings, and resources for malware indicators.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| pefile | >= 2023.2.7 | PE file parsing and section analysis |
|
||||
| hashlib | stdlib | MD5, SHA-1, SHA-256 hash computation |
|
||||
|
||||
## Core Functions
|
||||
|
||||
### `compute_hashes(filepath)`
|
||||
Generates MD5, SHA-1, SHA-256 hashes and file size.
|
||||
- **Returns**: `dict` with `md5`, `sha1`, `sha256`, `size`
|
||||
|
||||
### `analyze_sections(pe)`
|
||||
Inspects PE sections for entropy, virtual/raw size ratios, and packing indicators.
|
||||
- **Flags**: `HIGH_ENTROPY` (>7.0), `HIGH_VR_RATIO` (>10x)
|
||||
- **Returns**: `list[dict]` - section analysis entries
|
||||
|
||||
### `detect_packer(pe)`
|
||||
Identifies known packer section names (UPX, ASPack, VMProtect, Themida) and low import counts.
|
||||
- **Returns**: `list[str]` - detected packer names
|
||||
|
||||
### `analyze_imports(pe)`
|
||||
Categorizes imports into Process Injection, Keylogging, Persistence, Evasion, Network, Crypto.
|
||||
- **Returns**: `list[dict]` with `category`, `dll`, `function`
|
||||
|
||||
### `extract_strings(filepath, min_length=6)`
|
||||
Extracts ASCII strings and classifies into URLs, IPs, emails, registry keys, file paths.
|
||||
- **Returns**: `dict[str, list[str]]` - categorized string indicators
|
||||
|
||||
### `analyze_resources(pe)`
|
||||
Inspects PE resources for high-entropy data and embedded PE files.
|
||||
- **Returns**: `list[dict]` with `type_id`, `size`, `entropy`, `flags`
|
||||
|
||||
### `analyze_pe(filepath)`
|
||||
Full analysis pipeline producing structured report.
|
||||
- **Returns**: `dict` - complete analysis report
|
||||
|
||||
## Suspicious Import Categories
|
||||
|
||||
| Category | Example Functions |
|
||||
|----------|-------------------|
|
||||
| Process Injection | VirtualAllocEx, WriteProcessMemory, CreateRemoteThread |
|
||||
| Keylogging | GetAsyncKeyState, SetWindowsHookExA |
|
||||
| Persistence | RegSetValueExA, CreateServiceA |
|
||||
| Evasion | IsDebuggerPresent, CheckRemoteDebuggerPresent |
|
||||
| Network | InternetOpenA, URLDownloadToFileA, WSAStartup |
|
||||
| Crypto | CryptEncrypt, CryptDecrypt |
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python agent.py suspect.exe
|
||||
```
|
||||
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Static malware analysis agent using pefile for PE binary inspection."""
|
||||
|
||||
import pefile
|
||||
import hashlib
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import datetime
|
||||
|
||||
|
||||
SUSPICIOUS_IMPORTS = {
|
||||
"Process Injection": [
|
||||
"VirtualAllocEx", "WriteProcessMemory", "CreateRemoteThread",
|
||||
"NtCreateThreadEx", "QueueUserAPC", "NtMapViewOfSection",
|
||||
],
|
||||
"Keylogging": [
|
||||
"GetAsyncKeyState", "SetWindowsHookExA", "SetWindowsHookExW",
|
||||
"GetKeyState", "GetKeyboardState",
|
||||
],
|
||||
"Persistence": [
|
||||
"RegSetValueExA", "RegSetValueExW", "CreateServiceA",
|
||||
"CreateServiceW", "RegCreateKeyExA",
|
||||
],
|
||||
"Evasion": [
|
||||
"IsDebuggerPresent", "CheckRemoteDebuggerPresent",
|
||||
"NtQueryInformationProcess", "GetTickCount", "QueryPerformanceCounter",
|
||||
],
|
||||
"Network": [
|
||||
"InternetOpenA", "InternetOpenW", "HttpSendRequestA",
|
||||
"URLDownloadToFileA", "URLDownloadToFileW", "WSAStartup",
|
||||
"InternetConnectA", "HttpOpenRequestA",
|
||||
],
|
||||
"Crypto": [
|
||||
"CryptEncrypt", "CryptDecrypt", "CryptAcquireContextA",
|
||||
"CryptGenKey", "CryptImportKey",
|
||||
],
|
||||
}
|
||||
|
||||
PACKER_SECTIONS = {
|
||||
".upx0": "UPX", ".upx1": "UPX", ".aspack": "ASPack",
|
||||
".adata": "ASPack", ".nsp0": "NsPack", ".vmprotect": "VMProtect",
|
||||
".themida": "Themida", ".enigma1": "Enigma", ".petite": "Petite",
|
||||
}
|
||||
|
||||
|
||||
def compute_hashes(filepath):
|
||||
with open(filepath, "rb") as f:
|
||||
data = f.read()
|
||||
return {
|
||||
"md5": hashlib.md5(data).hexdigest(),
|
||||
"sha1": hashlib.sha1(data).hexdigest(),
|
||||
"sha256": hashlib.sha256(data).hexdigest(),
|
||||
"size": len(data),
|
||||
}
|
||||
|
||||
|
||||
def analyze_sections(pe):
|
||||
sections = []
|
||||
for section in pe.sections:
|
||||
name = section.Name.decode(errors="replace").rstrip("\x00")
|
||||
entropy = section.get_entropy()
|
||||
raw_size = section.SizeOfRawData
|
||||
virtual_size = section.Misc_VirtualSize
|
||||
ratio = virtual_size / raw_size if raw_size > 0 else 0
|
||||
flags = []
|
||||
if entropy > 7.0:
|
||||
flags.append("HIGH_ENTROPY")
|
||||
if ratio > 10:
|
||||
flags.append("HIGH_VR_RATIO")
|
||||
sections.append({
|
||||
"name": name, "entropy": round(entropy, 2),
|
||||
"raw_size": raw_size, "virtual_size": virtual_size,
|
||||
"ratio": round(ratio, 2), "flags": flags,
|
||||
})
|
||||
return sections
|
||||
|
||||
|
||||
def detect_packer(pe):
|
||||
detected = []
|
||||
for section in pe.sections:
|
||||
name = section.Name.decode(errors="replace").rstrip("\x00").lower()
|
||||
if name in PACKER_SECTIONS:
|
||||
detected.append(PACKER_SECTIONS[name])
|
||||
import_count = 0
|
||||
if hasattr(pe, "DIRECTORY_ENTRY_IMPORT"):
|
||||
import_count = sum(len(e.imports) for e in pe.DIRECTORY_ENTRY_IMPORT)
|
||||
if import_count < 10:
|
||||
detected.append(f"SUSPECTED_PACKED (only {import_count} imports)")
|
||||
return detected
|
||||
|
||||
|
||||
def analyze_imports(pe):
|
||||
findings = []
|
||||
if not hasattr(pe, "DIRECTORY_ENTRY_IMPORT"):
|
||||
return [{"category": "PACKED", "dll": "N/A", "function": "No imports found"}]
|
||||
for entry in pe.DIRECTORY_ENTRY_IMPORT:
|
||||
dll_name = entry.dll.decode(errors="replace")
|
||||
for imp in entry.imports:
|
||||
if imp.name:
|
||||
func_name = imp.name.decode(errors="replace")
|
||||
for category, funcs in SUSPICIOUS_IMPORTS.items():
|
||||
if func_name in funcs:
|
||||
findings.append({
|
||||
"category": category, "dll": dll_name,
|
||||
"function": func_name,
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def extract_strings(filepath, min_length=6):
|
||||
indicators = {"urls": [], "ips": [], "emails": [], "registry": [], "paths": []}
|
||||
with open(filepath, "rb") as f:
|
||||
data = f.read()
|
||||
ascii_strings = re.findall(rb"[\x20-\x7e]{%d,}" % min_length, data)
|
||||
for s in ascii_strings:
|
||||
s_decoded = s.decode("ascii", errors="ignore")
|
||||
if re.search(r"https?://", s_decoded):
|
||||
indicators["urls"].append(s_decoded)
|
||||
if re.search(r"\b(\d{1,3}\.){3}\d{1,3}\b", s_decoded):
|
||||
indicators["ips"].append(s_decoded)
|
||||
if re.search(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", s_decoded):
|
||||
indicators["emails"].append(s_decoded)
|
||||
if re.search(r"HKLM|HKCU|CurrentVersion\\Run", s_decoded, re.IGNORECASE):
|
||||
indicators["registry"].append(s_decoded)
|
||||
if re.search(r"\.(exe|dll|bat|ps1|vbs|tmp)", s_decoded, re.IGNORECASE):
|
||||
indicators["paths"].append(s_decoded)
|
||||
for key in indicators:
|
||||
indicators[key] = list(set(indicators[key]))[:20]
|
||||
return indicators
|
||||
|
||||
|
||||
def analyze_resources(pe):
|
||||
resources = []
|
||||
if not hasattr(pe, "DIRECTORY_ENTRY_RESOURCE"):
|
||||
return resources
|
||||
for rtype in pe.DIRECTORY_ENTRY_RESOURCE.entries:
|
||||
if hasattr(rtype, "directory"):
|
||||
for rid in rtype.directory.entries:
|
||||
if hasattr(rid, "directory"):
|
||||
for rlang in rid.directory.entries:
|
||||
data = pe.get_data(
|
||||
rlang.data.struct.OffsetToData,
|
||||
rlang.data.struct.Size,
|
||||
)
|
||||
entropy = 0.0
|
||||
if len(data) > 0:
|
||||
freq = [0] * 256
|
||||
for b in data:
|
||||
freq[b] += 1
|
||||
for f in freq:
|
||||
if f > 0:
|
||||
p = f / len(data)
|
||||
entropy -= p * math.log2(p)
|
||||
flags = []
|
||||
if entropy > 7.0:
|
||||
flags.append("HIGH_ENTROPY")
|
||||
if data[:2] == b"MZ":
|
||||
flags.append("EMBEDDED_PE")
|
||||
resources.append({
|
||||
"type_id": rtype.id, "size": len(data),
|
||||
"entropy": round(entropy, 2), "flags": flags,
|
||||
})
|
||||
return resources
|
||||
|
||||
|
||||
def analyze_pe(filepath):
|
||||
hashes = compute_hashes(filepath)
|
||||
pe = pefile.PE(filepath)
|
||||
timestamp = pe.FILE_HEADER.TimeDateStamp
|
||||
compile_time = datetime.datetime.utcfromtimestamp(timestamp).isoformat() + "Z"
|
||||
report = {
|
||||
"file": os.path.basename(filepath),
|
||||
"hashes": hashes,
|
||||
"compile_time": compile_time,
|
||||
"sections": analyze_sections(pe),
|
||||
"packer_indicators": detect_packer(pe),
|
||||
"suspicious_imports": analyze_imports(pe),
|
||||
"string_indicators": extract_strings(filepath),
|
||||
"resources": analyze_resources(pe),
|
||||
}
|
||||
pe.close()
|
||||
return report
|
||||
|
||||
|
||||
def print_report(report):
|
||||
print("STATIC MALWARE ANALYSIS REPORT")
|
||||
print("=" * 40)
|
||||
print(f"Sample: {report['file']}")
|
||||
print(f"MD5: {report['hashes']['md5']}")
|
||||
print(f"SHA-256: {report['hashes']['sha256']}")
|
||||
print(f"Size: {report['hashes']['size']} bytes")
|
||||
print(f"Compile Time: {report['compile_time']}")
|
||||
if report["packer_indicators"]:
|
||||
print(f"\nPACKER: {', '.join(report['packer_indicators'])}")
|
||||
print("\nSECTIONS:")
|
||||
for s in report["sections"]:
|
||||
flags = f" [{', '.join(s['flags'])}]" if s["flags"] else ""
|
||||
print(f" {s['name']:8s} entropy={s['entropy']} raw={s['raw_size']}{flags}")
|
||||
print("\nSUSPICIOUS IMPORTS:")
|
||||
for imp in report["suspicious_imports"]:
|
||||
print(f" [{imp['category']}] {imp['dll']} -> {imp['function']}")
|
||||
indicators = report["string_indicators"]
|
||||
if any(indicators.values()):
|
||||
print("\nEXTRACTED INDICATORS:")
|
||||
for key, vals in indicators.items():
|
||||
if vals:
|
||||
print(f" {key}: {', '.join(vals[:5])}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python agent.py <pe_file>")
|
||||
sys.exit(1)
|
||||
result = analyze_pe(sys.argv[1])
|
||||
print_report(result)
|
||||
Reference in New Issue
Block a user