Files
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- Fix 25 shell=True subprocess calls with list-based commands
- Fix 49 verify=False in defensive skills (env-var override)
- Add timeout to 231 HTTP/subprocess/socket calls
- Fix 6 SQL injection patterns with whitelist validation
- Replace 8 __import__() with standard imports
- Remove 701 unused imports across 442 files
- Add authorized-testing disclaimers to all offensive skills
- Complete 11 incomplete skill directories
- Expand 10 stub SKILL.md files with full content
- Fix 2 YAML parse errors in frontmatter
- Fix 5 pre-existing syntax errors
- Convert 22 hardcoded paths/ports to environment variables
- Back up 21 redundant skill pairs to .bak
- Fix 2 global declaration errors
- 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE)
- 0 compile errors across all 724 agent.py files
2026-03-19 13:26:49 +01:00

218 lines
7.8 KiB
Python

#!/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 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)