# 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): ```go 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](context.go), [log.go](log.go), [cyclic.go](cyclic.go), [fiddling.go](fiddling.go), [packing.go](packing.go)) - `Context`: global `Arch`, `LogLevel`, `Timeout`, `Newline` (pwntools' `context`). - `Info`/`Success`/`Warn`/`Error`: leveled logger to stderr, gated by `Context.LogLevel`. - `Cyclic`/`CyclicN`/`CyclicFind`/`CyclicFindN`: de Bruijn pattern generation and offset lookup. Matches pwntools' `cyclic`/`cyclic_find` output. - `Hexdump`/`Enhex`/`Unhex`/`Xor`. - `P16`/`P32`/`P64`, `U16`/`U32`/`U64`: little-endian pack/unpack. **Tubes** ([tube.go](tube.go), [process.go](process.go), [remote.go](remote.go)) - `Spawn` (local process) and `Remote` (TCP) return a `*Tube`. - `Send`/`SendLine`/`SendAfter`/`SendLineAfter`/`Recv`/`RecvUntil`/`RecvLine`/ `RecvRegex`/`RecvPred`/`Interactive`/`Close`. - Every method returns `error`; the library never calls `os.Exit`/`log.Fatal`. - `SetTimeout` overrides `Context.Timeout` per tube (0 = block forever). **Named pipes** ([pipe_windows.go](pipe_windows.go)) - `ServePipe(name)` / `DialPipe(name)` over `CreateNamedPipe` (`PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED`) / `CreateFile`, both returning a `*Tube`. **PE analysis** ([pe.go](pe.go), [sections.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 of `elf.search()`). **Checksec** ([checksec.go](checksec.go), [authenticode_windows.go](authenticode_windows.go)) - `(*PEFile).Checksec()`: ASLR, HighEntropyVA, DEP, CFG (cross-checked against Load Config `GuardFlags`), SafeSEH (x86 only, gated by `SEHApplicable`), GS-cookie heuristic, Authenticode presence, .NET/CLR. - `VerifyAuthenticodeSignature`: signature verification via `WinVerifyTrust` (Windows-only, no network calls). **Imports / exports** ([exports.go](exports.go), [imports.go](imports.go), [imported_libs_windows.go](imported_libs_windows.go)) - `ListExports`/`GetExport` with forwarder resolution. - `ListImports`/`FindImport` walking the IAT thunk arrays. - `ImportedLibs`: distinct imported DLLs, each `LoadLibrary`'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](procmem_windows.go), [symbols_windows.go](symbols_windows.go)) - `OpenPEFromProcess(pid, base)`: every PE accessor works against process memory (`ReadProcessMemory`), not just a disk file. - `ResolveModuleBase(pid, name)`: walks `PEB->Ldr->InMemoryOrderModuleList`. - `SpawnSuspended`/`ResumeMainThread`: launch with `CREATE_SUSPENDED`. `ResolveModuleBase` returns null until the loader runs post-resume. - `ProcessSymbols` (`NewProcessSymbols`): `Base`, `Symbol`, `Modules`, `AllSymbols`. `SymbolVA`/`ListLoadedModules` for one-off lookups. **ROP gadgets** ([gadgets.go](gadgets.go), [rop.go](rop.go)) - `NewROP(path)`: shells out to `rp-win.exe` (a Windows build of rp++), resolved from `RP_WIN_EXE` or `C:\tools\rp-win\rp-win.exe`. Run with `--allow-branches`, so results include JOP transit gadgets (indirect `jmp 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 via `golang.org/x/arch/x86/x86asm` for verifying a chain in-script. **Patching** ([patch.go](patch.go)) - `OpenPEForWrite`, `SetSectionCharacteristics`/`MakeSectionExecutable`/ `MakeSectionWritable`, `DisableTLSCallbacks`, `PatchBytes`/ `PatchBytesAtOffset`, `RecalculateChecksum`. **Minidump** ([minidump.go](minidump.go)) - `OpenMinidump(path)`: parses `MINIDUMP_HEADER`/`MINIDUMP_DIRECTORY` directly (no `dbghelp.dll`). `Modules()` (loaded modules + base addresses), `Exception()` (faulting thread/code/address/parameters), `RawStream(type)` for any other stream. Works without `GOOS=windows`. **Debugger** ([debugger_windows.go](debugger_windows.go)) - `Attach(pid)`: wraps the Windows Debug API (`DebugActiveProcess`/`WaitForDebugEvent`/`ContinueDebugEvent`/ `Get/SetThreadContext`), resolved via `LazyDLL`. - `Events()`: typed event channel (`EventBreakpoint`/`EventException`/ `EventCreateProcess`/`EventLoadDll`/`EventExitProcess`/...). - `SetBreakpoint`/`RemoveBreakpoint`: software INT3; `Continue` handles the restore/single-step/re-arm sequence internally. - `GetContext`/`SetContext` (registers), `ReadMemory`/`WriteMemory`. - No GUI-debugger (x64dbg/WinDbg) integration; `Attach` uses the same Win32 API. **Heap struct parsing** ([heap.go](heap.go), [heap_lfh.go](heap_lfh.go), [heap_segment.go](heap_segment.go), [heap_windows.go](heap_windows.go)) - Works against any `io.ReaderAt` (`*ProcessMemory`, `*Debugger`, or a test buffer). Only `ListProcessHeaps` requires 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 `EncodedOffsets` are XOR-encoded and not decoded — calibrate against a known address instead. **Spray** ([spray.go](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](shellcraft.go), [shellcode_exec_windows.go](shellcode_exec_windows.go)) - `ShellcodeWinExec(cmd)`: position-independent x64 shellcode resolving kernel32 via the PEB (source: [shellcode/asm/winexec_x64.asm](shellcode/asm/winexec_x64.asm)). - `ExecuteShellcode`: runs a template locally for validation. **CLI** ([cmd/winpwn](cmd/winpwn/main.go), [cmd/pwninit](cmd/pwninit/main.go)) - `winpwn`: `checksec`, `cyclic`, `hex`/`unhex`, `hexdump`, `rop`, `bytes`, `disasm`, `exports`, `imports`, `heap`. - `pwninit`: prints recon (arch, checksec, sections, imported libs) and scaffolds a `go.mod` + minimal `main.go` for a new task. ## Documentation - [USAGE.md](USAGE.md) — worked examples and a function-by-function reference. - [USAGE_RU.md](USAGE_RU.md) — condensed reference (Russian). - [ROADMAP.md](ROADMAP.md) — implementation status and planned work.