PE manipulation

← maldev README · docs/index

Pure-Go Portable Executable analysis, sanitisation, identity cloning, signature grafting, and conversion-to-shellcode. The package tree is intentionally bottom-up: pe/parse and pe/imports are read-only walkers, pe/strip, pe/morph, pe/cert, pe/masquerade are byte-mutators on a []byte, and pe/srdi is the producer of position-independent shellcode that downstream inject/ chains consume. Runtime-side BOF and CLR loaders moved to runtime/bof and runtime/clr respectively.

flowchart LR
    subgraph offline [Offline / build-host]
        SRC[Source PE<br>signed donor]
        PARSE[parse + imports<br>read-only walkers]
        STRIP[strip<br>Go-toolchain scrub]
        MORPH[morph<br>UPX header rename]
        CERT[cert<br>Authenticode graft]
        MASQ[masquerade<br>manifest + icon<br>+ VERSIONINFO clone]
        SRDI[srdi<br>Donut PE → shellcode]
    end
    subgraph runtime [Runtime / target host]
        INJECT[inject/*<br>execute shellcode]
        BOF[runtime/bof<br>COFF loader]
        CLR[runtime/clr<br>.NET hosting]
    end
    SRC --> PARSE
    SRC --> STRIP
    SRC --> MORPH
    SRC --> CERT
    SRC --> MASQ
    SRC --> SRDI
    SRDI --> INJECT
    PARSE -. drives unhook scoping .-> RUNT[runtime evasion]

Packages

PackageTech pageDetectionOne-liner
pe/parse(covered here + doc.go)very-quietRead-only debug/pe wrapper for section / export / raw-byte access
pe/importsimports.mdvery-quietCross-platform import-table enumeration
pe/stripstrip-sanitize.mdquietGo pclntab wipe + section rename + timestamp scrub
pe/morphmorph.mdmoderateUPX header signature mutation
pe/certcertificate-theft.mdquietAuthenticode security-directory read / copy / strip / write
pe/masquerademasquerade.mdquietmanifest + icon + VERSIONINFO clone via .syso (preset or programmatic)
pe/srdipe-to-shellcode.mdmoderatePE / .NET / script → Donut shellcode
pe/dllproxydll-proxy.mdvery-quietPure-Go forwarder DLL emitter for DLL-hijack payloads

Quick decision tree

You want to…Use
…read every DLL!Function pair from a PEimports.List
…wipe the "Made in Go" markersstrip.Sanitize
…hide a UPX-packed binary from auto-unpackersmorph.UPXMorph
…graft a Microsoft signature onto an unsigned binarycert.Copy
…make Process Explorer render the implant as svchostpreset blank-import
…clone any PE's identity programmaticallymasquerade.Clone / Build
…convert a PE / .NET / script to position-independent shellcodesrdi.ConvertFile
…feed shellcode to remote-process injectionpe/srdiinject
…enumerate sections / exports for toolingpe/parse
…emit a forwarder DLL for hijack payloads (no MSVC)dllproxy.Generate

MITRE ATT&CK

T-IDNamePackagesD3FEND counter
T1027.002Obfuscated Files or Information: Software Packingpe/strip, pe/morph, pe/parseD3-SEA, D3-FCA
T1027.005Indicator Removal from Toolspe/stripD3-SEA
T1036.005Masquerading: Match Legitimate Name or Locationpe/masqueradeD3-EAL, D3-SEA
T1055.001Process Injection: Dynamic-link Library Injectionpe/srdi (consumer)D3-PA
T1106Native APIpe/importsD3-SEA
T1574.001DLL Search Order Hijackingpe/dllproxyD3-PFV
T1574.002DLL Side-Loadingpe/dllproxyD3-PFV
T1553.002Subvert Trust Controls: Code Signingpe/certD3-EAL
T1620Reflective Code Loadingpe/srdiD3-FCA, D3-PA

Layered scrub recipe

The full identity scrub for a Go-built implant is a six-step build-host pipeline. None of the steps is enough alone; together they survive triage long enough to matter.

  1. Build with garble — symbol obfuscation at compile time.
  2. pe/masquerade.Clone — clone svchost / cmd / explorer identity at link time via .syso.
  3. pe/strip.Sanitize — wipe pclntab + rename Go sections + scrub timestamp.
  4. UPX pack + pe/morph.UPXMorph — defeat signature-based unpackers.
  5. pe/cert.Copy — graft a Microsoft Authenticode blob.
  6. cleanup/timestomp.CopyFromFull — align MFT timestamps to the donor.

For payload delivery (separate from build):

  1. pe/srdi.ConvertFile — convert the implant or downstream payload to Donut shellcode.
  2. inject/* — deliver the shellcode via any of the documented techniques.

See also