You are browsing as a guest. Sign up (or log in) to start making projects!

6h 34m 57s logged

Reversing was the one category left. Trawl had nothing for it.

Everything else was covered by the time the tour shipped: steganography, cryptography (Hill and Playfair joined a few weeks back, along with columnar transposition wide enough that brute force stops working), PDF documents read the same way a ZIP already was, object by object, checked against what the file’s own index claims. Drop a binary, though, and the best Trawl could do was name the format and stop there.

I’m not building a decompiler. Ghidra and IDA earned that word over years of real compiler-engineering work, and half a decompiler is worse than none: wrong pseudocode still reads as confident, and confidently wrong is the last thing a forensics tool should ever hand someone. What Trawl does instead is the pass every real session starts with anyway, before a disassembler even opens: the header, the section table, what the binary calls, what it offers, and whether it was actually built with the defenses that matter, NX, ASLR, RELRO, a stack canary, Control Flow Guard.

Two formats that don’t agree on anything

ELF went first, since it’s most of what a CTF binary actually is. Then PE, the Windows half, which turned out to be a different kind of problem. An ELF section header says outright where its bytes sit in the file. A PE barely says anything that way. It addresses its import and export tables by where they’ll land in memory once the loader gets to them, so reading either one means walking the section table first, just to translate an address nobody gave you a file offset for. The two parsers ended up sharing almost nothing except a type underneath them, built so one panel could read both. Where a protection has no equivalent in the other format, the panel just leaves it out instead of guessing. A PE has nothing RELRO would describe, and showing RELRO: none there would report a defense as missing that the format never offered to begin with.

The bug where the layout only worked on files I made up myself

Testing this against binaries I built myself went fine, because of course it did. I wrote them to go fine. So I went and found real ones instead. gcc output straight out of WSL: a stripped build, a static build, a shared library. Real Windows system binaries too, notepad.exe and kernel32.dll. I checked every one byte for byte against readelf and objdump until the entry points and export counts lined up exactly.

Then I compiled a tiny C++ file. Three lines, a map of vectors, nothing unusual. Its export name came out at 286 characters. That’s what name mangling does to the plainest code without even trying.

My import list rendered each name as a small chip, capped with a percentage-based max-width so nothing would run off the page. It did nothing. A grid item won’t shrink below its own content unless you tell it to, and I hadn’t, so the chip just kept going: clipped mid-character, no ellipsis, dragging the whole panel sideways with it. Fine on every file I’d invented. Broken on the first real one I pointed it at.

AI helped with the writing and most of the parsing code, same as always. The real time went into finding bytes I hadn’t written myself to test it against, a real compiler, a real linker, a symbol nobody designed to be readable. Testing against your own fixtures only ever proves the code agrees with itself.

Next up: Windows registry hives, for tracing which USB stick was plugged in when.

0
69

Comments 0

No comments yet. Be the first!