161 lines
7.7 KiB
Markdown
161 lines
7.7 KiB
Markdown
# 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.
|