▄████▄ ▄▄▄ ██▀███ ▄████▄ ▄▄▄ ██████ ██████
▒██▀ ▀█ ▒████▄ ▓██ ▒ ██▒▒██▀ ▀█ ▒████▄ ▒██ ▒ ▒██ ▒
▒▓█ ▄ ▒██ ▀█▄ ▓██ ░▄█ ▒▒▓█ ▄ ▒██ ▀█▄ ░ ▓██▄ ░ ▓██▄
▒▓▓▄ ▄██▒░██▄▄▄▄██ ▒██▀▀█▄ ▒▓▓▄ ▄██▒░██▄▄▄▄██ ▒ ██▒ ▒ ██▒
▒ ▓███▀ ░ ▓█ ▓██▒░██▓ ▒██▒▒ ▓███▀ ░ ▓█ ▓██▒▒██████▒▒▒██████▒▒
░ ░▒ ▒ ░ ▒▒ ▓▒█░░ ▒▓ ░▒▓░░ ░▒ ▒ ░ ▒▒ ▓▒█░▒ ▒▓▒ ▒ ░▒ ▒▓▒ ▒ ░
░ ▒ ▒ ▒▒ ░ ░▒ ░ ▒░ ░ ▒ ▒ ▒▒ ░░ ░▒ ░ ░░ ░▒ ░ ░
░ ░ ▒ ░░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
░ ░
v1.0.0
A Windows CLI tool for static analysis of PE (Portable Executable) files. Carcass parses and exposes PE internals — headers, imports, exports, and sections — without executing the binary. Built for red teamers, malware analysts, and reverse engineers who want a fast, dependency-free tool they can drop on any Windows box.
Carcass reads a PE file from disk into memory and parses it entirely statically — no execution, no injection, no runtime dependencies beyond the Windows SDK. It is structured as independent modules, each targeting a specific part of the PE format:
| Module | What it parses |
|---|---|
headers |
DOS header, NT headers, File header, Optional header |
imports |
Import Address Table (IAT) — DLLs and function names |
exports |
Export Address Table (EAT) — named, ordinal-only, and forwarded exports |
sections |
Section table — virtual / raw sizes, permissions, Shannon entropy |
All output goes to stdout by default. The imports and exports modules support JSON output via -o.
Red team / pre-engagement recon
- Identify what APIs a target binary imports to understand its capabilities before execution
- Spot process injection primitives (
VirtualAlloc,WriteProcessMemory,CreateRemoteThread), credential access APIs (LsaOpenPolicy,SamConnect), or network indicators - Check if a DLL exposes functions you can hijack or proxy
Malware analysis / triage
- Get a fast read on an unknown binary before detonating it in a sandbox
- Identify packing or obfuscation via section entropy
- Find forwarded exports that redirect to other DLLs, a common technique in malware loaders
- Dump imports to JSON and feed them into a pipeline or grep across samples
Reverse engineering
- Confirm entry point, image base, and architecture before opening in a disassembler
- Enumerate exports of a DLL you want to call or hook
- Verify section layout matches what your disassembler shows
Carcass targets Windows and requires the Windows SDK for PE struct definitions (windows.h). It has no other external dependencies.
MSVC (recommended)
cl main.c parser.c imports.c exports.c sections.c /Fe:carcass.exe /link /out:carcass.exe
MinGW / GCC on Windows
gcc main.c parser.c imports.c exports.c sections.c -o carcass.exe -lm
-lmis required forsections.cwhich useslog()for entropy calculation.
Parses the PE header chain and prints key fields from each layer.
What it reads:
- DOS Header —
e_magic(must beMZ/0x5A4D) ande_lfanew(offset to NT headers) - NT Headers — the
PE\0\0signature that confirms this is a valid PE - File Header — target architecture (
x86/x64), section count, compile timestamp, and characteristics flags - Optional Header — entry point RVA, image base, section/file alignment, image size, and subsystem type (GUI vs console)
Why it matters for recon: The compile timestamp can indicate when the binary was built (though it can be faked). The image base tells you where it expects to be loaded. The entry point RVA is where execution starts. Subsystem tells you if it will spawn a visible window.
Walks the Import Address Table and prints every DLL the binary depends on, along with each imported function name or ordinal.
What it reads:
- Each
IMAGE_IMPORT_DESCRIPTORentry (one per DLL) - For each DLL: the Original First Thunk (falls back to First Thunk if OFT is null, common in packed/bound binaries)
- Each
IMAGE_IMPORT_BY_NAMEentry for named imports, or raw ordinal values for ordinal-only imports
Flags:
--clean— stripsapi-ms-win-*andext-ms-*API set forwarder DLLs from the output. These are Windows internal abstraction layers that add noise when you're looking for meaningful capability indicators-all— explicit show-everything mode, overrides--cleanif previously set-o <file.json>— writes output as JSON instead of stdout
Why it matters for recon: The import table is one of the highest-signal parts of a PE for triage. A binary importing VirtualAllocEx + WriteProcessMemory + CreateRemoteThread is almost certainly doing process injection. CryptEncrypt or BCryptEncrypt alongside FindFirstFile suggests ransomware-like behavior. WNetAddConnection or InternetOpenUrl reveals network capability.
Walks the Export Address Table and prints every exported function, covering three cases the original PE format supports:
- Named exports — functions exported by name and ordinal
- Ordinal-only exports — functions exported purely by ordinal with no name (shown as
[unnamed / ordinal-only]) - Forwarded exports — exports whose RVA points back into the export directory itself, redirecting callers to a function in another DLL (shown as
Forwarded to: DLL.FunctionName)
What it reads:
IMAGE_EXPORT_DIRECTORYfor DLL name, function count, and named export count- The three parallel arrays: function RVAs, name RVAs, and name-ordinal mappings
- Builds a reverse map from ordinal index to name, then walks all function slots to catch ordinal-only entries the original code missed
Flag:
-o <file.json>— writes output as JSON
Why it matters for recon: When targeting a DLL for hijacking or proxying, you need the full export list including ordinal-only entries — otherwise your proxy DLL will be missing exports and the loader will fail. Forwarded exports are also worth noting: they tell you the actual implementation lives elsewhere.
Enumerates the section table and computes per-section Shannon entropy from the raw bytes on disk.
What it reads:
- Each
IMAGE_SECTION_HEADERentry - Virtual size, virtual address, raw size, raw offset, and characteristics flags
- Reads raw section bytes from the file buffer and computes Shannon entropy (0.0–8.0 scale)
- Decodes the
R,W,Xmemory permission bits from the characteristics field
Entropy scale:
| Range | Interpretation |
|---|---|
| 0.0 – 1.0 | Near-empty or highly repetitive (e.g. zero-filled BSS) |
| 4.0 – 6.5 | Normal compiled code or data |
| 7.0 – 7.2 | Compressed resources, dense data tables |
| 7.2 – 8.0 | Strong indicator of encryption or packing |
Why it matters for recon: High entropy in a .text section or a strangely named section is a strong indicator the binary is packed or the code is encrypted. A section with both W and X permissions (RWX or -WX) is a classic shellcode staging area or a sign of self-modifying code.
carcass <module> <target> [flags]
| Argument | Description |
|---|---|
module |
One of: headers, imports, exports, sections |
target |
Path to the PE file (.exe, .dll, .sys, etc.) |
| Flag | Module | Description |
|---|---|---|
--clean |
imports | Filter out api-ms-win-* and ext-ms-* forwarder DLLs |
-all |
imports | Show all DLLs including forwarder entries |
-o <file.json> |
imports, exports | Write output to a JSON file instead of stdout |
--cleanand-allare mutually exclusive. Passing both will produce an error.
# Parse PE headers of a binary
carcass headers malware.exe
# List all imports
carcass imports malware.exe
# List imports, filter out Windows API set noise
carcass imports malware.exe --clean
# Dump all imports to JSON for further processing
carcass imports malware.exe -o imports.json
# Dump cleaned imports to JSON
carcass imports malware.exe --clean -o imports.json
# List all exports of a DLL
carcass exports target.dll
# Dump exports to JSON
carcass exports target.dll -o exports.json
# Enumerate sections with entropy and permissions
carcass sections malware.exe
headers
[+] DOS Header
e_magic: 0x5A4D
e_lfanew: 0xE8
[+] NT Headers
Signature: 0x4550
[+] File Header
Machine: 0x8664 (x64)
NumberOfSections: 6
TimeDateStamp: 0x6324A192
Characteristics: 0x22
[+] Optional Header
AddressOfEntryPoint: 0x1430
ImageBase: 0x0000000140000000
SectionAlignment: 0x1000
FileAlignment: 0x200
SizeOfImage: 0x14000
Subsystem: 3 (Console)
imports
[+] Imports
KERNEL32.DLL
VirtualAlloc
VirtualFree
CreateThread
GetProcAddress
ntdll.dll
NtAllocateVirtualMemory
NtWriteVirtualMemory
exports
[+] Exports
DLL Name: example.dll
NumberOfFunctions: 4
NumberOfNames: 3
ExportedFunction
Ordinal: 1
RVA: 0x00001020
[unnamed / ordinal-only]
Ordinal: 2
RVA: 0x00001080
ForwardedFunc
Ordinal: 3
Forwarded to: NTDLL.RtlAllocateHeap
sections
[+] Sections
Count: 5
[1] .text
VirtualSize: 0x6A30
VirtualAddress: 0x1000
SizeOfRawData: 0x6C00
PointerToRawData: 0x400
Characteristics: 0x60000020
Entropy: 6.1042
Permissions: R-X
[2] .data
VirtualSize: 0x310
VirtualAddress: 0x8000
SizeOfRawData: 0x400
PointerToRawData: 0x7000
Characteristics: 0xC0000040
Entropy: 2.4817
Permissions: RW-
[3] .packed
VirtualSize: 0xF200
VirtualAddress: 0x9000
SizeOfRawData: 0xF200
PointerToRawData: 0x7400
Characteristics: 0xE0000020
Entropy: 7.9341
Permissions: RWX