Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Performs static analysis of Windows PE (Portable Executable) malware samples using PEStudio to examine file headers, imports, strings, resources, and indicators without executing the binary. Identifies suspicious characteristics including packing, anti-analysis techniques, and malicious imports. Activates for requests involving static malware analysis, PE file inspection, Windows executable analysis, or pre-execution malware triage.
.claude/skills/performing-static-malware-analysis-with-pe-studio/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 85% | 21 |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | — | — |
| case-21 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-16 | ✗→✗ | = Same ✗ | — | — |
| case-08 | ✗→✗ | = Same ✗ | — | — |
Do not use for dynamic behavioral analysis requiring execution; use a sandbox (Cuckoo, ANY.RUN) for runtime behavior observation.
pefile library for scripted PE analysis (pip install pefile)Generate cryptographic hashes for identification and intelligence lookup:
bash# Generate MD5, SHA-1, and SHA-256 hashes md5sum suspect.exe sha1sum suspect.exe sha256sum suspect.exe # Check hash against VirusTotal curl -s -X GET "https://www.virustotal.com/api/v3/files/$(sha256sum suspect.exe | cut -d' ' -f1)" \ -H "x-apikey: $VT_API_KEY" | jq '.data.attributes.last_analysis_stats' # Get file type with magic bytes verification file suspect.exe
Open the sample in PEStudio and inspect structural properties:
PEStudio Analysis Points:
━━━━━━━━━━━━━━━━━━━━━━━━━
File Header: Compilation timestamp, target architecture (x86/x64)
Optional Header: Entry point address, image base, subsystem (GUI/console)
Section Table: Section names, virtual/raw sizes, entropy values
High entropy (>7.0) in .text/.rsrc suggests packing
Signatures: Authenticode signature presence and validityScripted PE Header Analysis with pefile:
pythonimport pefile import hashlib import math pe = pefile.PE("suspect.exe") # Compilation timestamp import datetime timestamp = pe.FILE_HEADER.TimeDateStamp compile_time = datetime.datetime.utcfromtimestamp(timestamp) print(f"Compile Time: {compile_time} UTC") # Section analysis with entropy calculation for section in pe.sections: name = section.Name.decode().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 print(f"Section: {name:8s} Entropy: {entropy:.2f} Raw: {raw_size:>10} Virtual: {virtual_size:>10} Ratio: {ratio:.2f}") if entropy > 7.0: print(f" [!] HIGH ENTROPY - likely packed or encrypted") if ratio > 10: print(f" [!] HIGH V/R RATIO - unpacking stub likely present")
Identify suspicious API imports that indicate malware capabilities:
python# Extract and categorize imports suspicious_imports = { "Process Injection": ["VirtualAllocEx", "WriteProcessMemory", "CreateRemoteThread", "NtCreateThreadEx"], "Keylogging": ["GetAsyncKeyState", "SetWindowsHookExA", "GetKeyState"], "Persistence": ["RegSetValueExA", "CreateServiceA", "SchTasksCreate"], "Evasion": ["IsDebuggerPresent", "CheckRemoteDebuggerPresent", "NtQueryInformationProcess"], "Network": ["InternetOpenA", "HttpSendRequestA", "URLDownloadToFileA", "WSAStartup"], "File Operations": ["CreateFileA", "WriteFile", "DeleteFileA", "MoveFileA"], "Crypto": ["CryptEncrypt", "CryptDecrypt", "CryptAcquireContextA"], } for entry in pe.DIRECTORY_ENTRY_IMPORT: dll_name = entry.dll.decode() for imp in entry.imports: if imp.name: func_name = imp.name.decode() for category, funcs in suspicious_imports.items(): if func_name in funcs: print(f"[!] {category}: {dll_name} -> {func_name}")
Use FLOSS for obfuscated strings and standard strings extraction:
bash# Standard strings extraction (ASCII and Unicode) strings -a suspect.exe > strings_ascii.txt strings -el suspect.exe > strings_unicode.txt # FLOSS for decoded/deobfuscated strings floss suspect.exe --output-json floss_output.json # Search for network indicators in strings grep -iE "(http|https|ftp)://" strings_ascii.txt grep -iE "([0-9]{1,3}\.){3}[0-9]{1,3}" strings_ascii.txt grep -iE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" strings_ascii.txt # Search for registry keys grep -i "HKLM\\|HKCU\\|SOFTWARE\\|CurrentVersion\\Run" strings_ascii.txt # Search for file paths and extensions grep -iE "\.(exe|dll|bat|ps1|vbs|tmp)" strings_ascii.txt
Examine the PE resource section for embedded payloads or configuration:
python# Extract resources from PE file if hasattr(pe, 'DIRECTORY_ENTRY_RESOURCE'): for resource_type in pe.DIRECTORY_ENTRY_RESOURCE.entries: if hasattr(resource_type, 'directory'): for resource_id in resource_type.directory.entries: if hasattr(resource_id, 'directory'): for resource_lang in resource_id.directory.entries: data = pe.get_data(resource_lang.data.struct.OffsetToData, resource_lang.data.struct.Size) entropy = calculate_entropy(data) print(f"Resource Type: {resource_type.id} Size: {len(data)} Entropy: {entropy:.2f}") if entropy > 7.0: print(f" [!] High entropy resource - possible embedded payload") # Check for PE signature in resource (embedded executable) if data[:2] == b'MZ': print(f" [!] Embedded PE detected in resource") with open(f"extracted_resource_{resource_type.id}.bin", "wb") as f: f.write(data)
Determine if the binary is packed or protected:
bash# Detect packer with Detect It Easy (DIE) diec suspect.exe # Check with PEiD signatures (command-line version) python3 -c " import pefile pe = pefile.PE('suspect.exe') # Check for common packer section names packer_sections = {'.upx0': 'UPX', '.aspack': 'ASPack', '.adata': 'ASPack', '.nsp0': 'NsPack', '.vmprotect': 'VMProtect', '.themida': 'Themida'} for section in pe.sections: name = section.Name.decode().rstrip('\x00').lower() if name in packer_sections: print(f'[!] Packer detected: {packer_sections[name]} (section: {name})') # Check import table size (very few imports suggest packing) import_count = sum(len(entry.imports) for entry in pe.DIRECTORY_ENTRY_IMPORT) if import_count < 10: print(f'[!] Only {import_count} imports - likely packed') "
Compile all findings into a structured triage report:
Document the following for each analyzed sample:
- File identification (hashes, file type, size, compile timestamp)
- Packing/protection status and identified packer
- Suspicious imports categorized by capability
- Network indicators extracted from strings (IPs, domains, URLs)
- Embedded resources and their characteristics
- Overall threat assessment and recommended next steps (sandbox execution, YARA rule creation)| Term | Definition | |------|------------| | PE (Portable Executable) | The file format for Windows executables (.exe, .dll, .sys) containing headers, sections, imports, and resources that define how the OS loads the binary | | Import Address Table (IAT) | PE structure listing external DLL functions the executable calls at runtime; reveals program capabilities and intent | | Section Entropy | Statistical measure of randomness in a PE section; values above 7.0 (out of 8.0) indicate compression, encryption, or packing | | FLOSS | FireEye Labs Obfuscated String Solver; automatically extracts and decodes obfuscated strings that standard strings misses | | Packing | Compression or encryption of a PE file's code section to hinder static analysis; requires runtime unpacking stub to execute | | PE Resources | Data section within a PE file that can contain icons, dialogs, version info, or attacker-embedded payloads and configuration data | | Compilation Timestamp | Timestamp in the PE header indicating when the binary was compiled; can be forged but often reveals development timeline |
Context: SOC receives an alert on a suspicious executable attached to a phishing email. The file needs rapid triage to determine if it is malicious before committing sandbox resources.
Approach:
Pitfalls:
STATIC MALWARE ANALYSIS REPORT
=================================
Sample: suspect.exe
MD5: d41d8cd98f00b204e9800998ecf8427e
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
File Size: 245,760 bytes
File Type: PE32 executable (GUI) Intel 80386
Compile Time: 2025-09-14 08:23:15 UTC
PACKING STATUS
Packer Detected: None (native binary)
Section Entropy: .text=6.42 .rdata=4.89 .data=3.21 .rsrc=7.81
Note: .rsrc section entropy elevated - check resources
SUSPICIOUS IMPORTS
[INJECTION] kernel32.dll -> VirtualAllocEx
[INJECTION] kernel32.dll -> WriteProcessMemory
[INJECTION] kernel32.dll -> CreateRemoteThread
[EVASION] kernel32.dll -> IsDebuggerPresent
[NETWORK] wininet.dll -> InternetOpenA
[NETWORK] wininet.dll -> HttpSendRequestA
[PERSISTENCE] advapi32.dll -> RegSetValueExA
EXTRACTED INDICATORS
URLs: hxxps://update.malicious[.]com/gate.php
IPs: 185.220.101[.]42, 91.215.85[.]17
Registry Keys: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\svchost
File Paths: C:\Users\Public\svchost.exe
EMBEDDED RESOURCES
Resource 101: Size=98304 Entropy=7.89 [!] Embedded PE detected
Resource 102: Size=4096 Entropy=2.14 (configuration XML)
ASSESSMENT
Threat Level: HIGH
Classification: Dropper with process injection capabilities
Recommended: Execute in sandbox, extract embedded PE for separate analysis| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +14 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.