7.7 KiB
winpwn
Pwntools-style exploitation toolkit for Windows pwn/CTF tasks, written in Go.
pwntools targets Linux. winpwn targets the Windows equivalents: SEH instead of
signals, PE instead of ELF, msvcrt/ntdll instead of glibc, the Windows Debug
API instead of ptrace/GDB. Go is used for direct WinAPI access
(golang.org/x/sys/windows) and goroutine-based concurrent I/O.
Install / import
Library (used from a solve script):
import "winpwn"
func main() {
t, err := winpwn.Spawn("./target.exe")
if err != nil {
log.Fatal(err)
}
if err := t.SendLineAfter([]byte("Input: "), payload); err != nil {
log.Fatal(err)
}
t.Interactive()
}
The module is used locally via a replace directive; it is not published.
CLI (quick-answer wrapper):
go install ./cmd/winpwn
go install ./cmd/pwninit
Components
Core (context.go, log.go, cyclic.go, fiddling.go, packing.go)
Context: globalArch,LogLevel,Timeout,Newline(pwntools'context).Info/Success/Warn/Error: leveled logger to stderr, gated byContext.LogLevel.Cyclic/CyclicN/CyclicFind/CyclicFindN: de Bruijn pattern generation and offset lookup. Matches pwntools'cyclic/cyclic_findoutput.Hexdump/Enhex/Unhex/Xor.P16/P32/P64,U16/U32/U64: little-endian pack/unpack.
Tubes (tube.go, process.go, remote.go)
Spawn(local process) andRemote(TCP) return a*Tube.Send/SendLine/SendAfter/SendLineAfter/Recv/RecvUntil/RecvLine/RecvRegex/RecvPred/Interactive/Close.- Every method returns
error; the library never callsos.Exit/log.Fatal. SetTimeoutoverridesContext.Timeoutper tube (0 = block forever).
Named pipes (pipe_windows.go)
ServePipe(name)/DialPipe(name)overCreateNamedPipe(PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED) /CreateFile, both returning a*Tube.
PE analysis (pe.go, sections.go)
OpenPE,ImageBase,EntryPoint,Is64Bit(PE32 and PE32+).- Per-section
IsReadable/Writable/Executable/IsRWX,VirtualAddress(RVA),Offset(PointerToRawData, file offset),Entropy,LikelyPackedSections. SearchBytes: byte-pattern search across sections (analogue ofelf.search()).
Checksec (checksec.go, authenticode_windows.go)
(*PEFile).Checksec(): ASLR, HighEntropyVA, DEP, CFG (cross-checked against Load ConfigGuardFlags), SafeSEH (x86 only, gated bySEHApplicable), GS-cookie heuristic, Authenticode presence, .NET/CLR.VerifyAuthenticodeSignature: signature verification viaWinVerifyTrust(Windows-only, no network calls).
Imports / exports (exports.go, imports.go, imported_libs_windows.go)
ListExports/GetExportwith forwarder resolution.ListImports/FindImportwalking the IAT thunk arrays.ImportedLibs: distinct imported DLLs, eachLoadLibrary'd to report its live image base (system DLL bases are randomized per boot, not per process, so the address is valid machine-wide until reboot).
Live-process PE (procmem_windows.go, symbols_windows.go)
OpenPEFromProcess(pid, base): every PE accessor works against process memory (ReadProcessMemory), not just a disk file.ResolveModuleBase(pid, name): walksPEB->Ldr->InMemoryOrderModuleList.SpawnSuspended/ResumeMainThread: launch withCREATE_SUSPENDED.ResolveModuleBasereturns null until the loader runs post-resume.ProcessSymbols(NewProcessSymbols):Base,Symbol,Modules,AllSymbols.SymbolVA/ListLoadedModulesfor one-off lookups.
ROP gadgets (gadgets.go, rop.go)
NewROP(path): shells out torp-win.exe(a Windows build of rp++), resolved fromRP_WIN_EXEorC:\tools\rp-win\rp-win.exe. Run with--allow-branches, so results include JOP transit gadgets (indirectjmp reg/call reg) as well as ret-terminated ones.NewROPExternal(path, toolPath): explicit tool path.Find(pattern): ranked matches, index 0 is the cleanest usable gadget.Search/SearchRegex:(results, error)form.Disassemble(addr, count): native decode viagolang.org/x/arch/x86/x86asmfor verifying a chain in-script.
Patching (patch.go)
OpenPEForWrite,SetSectionCharacteristics/MakeSectionExecutable/MakeSectionWritable,DisableTLSCallbacks,PatchBytes/PatchBytesAtOffset,RecalculateChecksum.
Minidump (minidump.go)
OpenMinidump(path): parsesMINIDUMP_HEADER/MINIDUMP_DIRECTORYdirectly (nodbghelp.dll).Modules()(loaded modules + base addresses),Exception()(faulting thread/code/address/parameters),RawStream(type)for any other stream. Works withoutGOOS=windows.
Debugger (debugger_windows.go)
Attach(pid): wraps the Windows Debug API (DebugActiveProcess/WaitForDebugEvent/ContinueDebugEvent/Get/SetThreadContext), resolved viaLazyDLL.Events(): typed event channel (EventBreakpoint/EventException/EventCreateProcess/EventLoadDll/EventExitProcess/...).SetBreakpoint/RemoveBreakpoint: software INT3;Continuehandles the restore/single-step/re-arm sequence internally.GetContext/SetContext(registers),ReadMemory/WriteMemory.- No GUI-debugger (x64dbg/WinDbg) integration;
Attachuses the same Win32 API.
Heap struct parsing (heap.go, heap_lfh.go, heap_segment.go, heap_windows.go)
- Works against any
io.ReaderAt(*ProcessMemory,*Debugger, or a test buffer). OnlyListProcessHeapsrequires a live process (walks the PEB). - NT Heap:
ReadHeap,DecodeHeapEntry(XOR-decoding),WalkAllHeapEntries,SummariseEntries,AdjacentBusyPairs,EntriesInRange,EntriesWithUserData. - NT Heap LFH:
ReadLFHBuckets,FindLFHBucket,ActiveSubsegment,ReadLFHSubsegment,CalibrateLFHFirstBlockOffset,BlockAddress,SlotOf. - Segment Heap:
ReadSegmentHeap(VS/LFH context summaries). AdjacentAddressPairs/FindAdjacentPair: adjacency detection from leaked addresses, no chunk-header decode required.- Offsets confirmed on build 10.0.26100; verify on other builds. VS chunk headers
and LFH
EncodedOffsetsare XOR-encoded and not decoded — calibrate against a known address instead.
Spray (spray.go)
SprayAndFind: spray up to N times, check each attempt against all prior samples (plus an optional seed) via a caller-supplied relation, return the first match. Covers both equality (UAF reuse) and distance (adjacency) checks.
Shellcraft (shellcraft.go, shellcode_exec_windows.go)
ShellcodeWinExec(cmd): position-independent x64 shellcode resolving kernel32 via the PEB (source: shellcode/asm/winexec_x64.asm).ExecuteShellcode: runs a template locally for validation.
CLI (cmd/winpwn, cmd/pwninit)
winpwn:checksec,cyclic,hex/unhex,hexdump,rop,bytes,disasm,exports,imports,heap.pwninit: prints recon (arch, checksec, sections, imported libs) and scaffolds ago.mod+ minimalmain.gofor a new task.
Documentation
- USAGE.md — worked examples and a function-by-function reference.
- USAGE_RU.md — condensed reference (Russian).
- ROADMAP.md — implementation status and planned work.