Challenge: Playing with Pointers · CTF: DalCTF 2026 · Category: Crypto · Difficulty: Easy
I watched a youtube video earlier showing off this funny trick you can do with pointers. I forget what it’s called though. Maybe I’ll go play some Quake to think about it.
That little flavor-text is the whole challenge. Hold onto the word Quake — it’s not decoration, it’s the hint.
The Files
We’re handed two things: a C source file and a text file full of suspiciously large numbers.
Playingwithpointers.c
| |
playing.txt
| |
Thirty lines, each a 32-bit-ish integer hovering around 1.1–1.2 billion.
Reading the Code
Let’s trace what the program actually does, line by line.
char FLAG[]holds the real flag (here stubbed out as"DalCTF{test}"so the source doesn’t give it away).float fflag[...]is an array of floats.long lflag[...]is an array of longs.- The loop walks every character of the flag and does two things:
fflag[i] = (float) FLAG[i];— convert the character’s ASCII code to a floating-point number. So'D'(68) becomes68.0f.fflag[i] = fflag[i] * fflag[i];— square it.68.0f * 68.0f = 4624.0f.
- Then there’s a missing line marked by the comment, and…
- The second loop prints
lflag[i]— the long array — as integers.
Here’s the catch that makes this a puzzle: lflag is never written to. The squared values all go into fflag (the float array), but the program prints lflag (the long array). As written, this code would just print uninitialized garbage.
So the missing line — the one the author “forgot” — has to be the bridge that moves data from fflag into lflag. And the comment tells us exactly how to find it:
Maybe I should play some quake to think about it.
The Quake Connection
The most famous “funny trick you can do with pointers” in all of programming comes from the source code of Quake III Arena: the fast inverse square root. Its legendary line is:
| |
That snippet does something delightfully cursed: it takes the address of a float (&y), reinterprets that address as a pointer to a long ((long *)), and dereferences it (*). The result is that you read the raw bit pattern of the float as if it were an integer — no conversion, no rounding, just the underlying IEEE-754 bytes reinterpreted.
That’s the missing line. Filled in, the loop body is:
| |
So each number in playing.txt is the IEEE-754 bit representation of (char × char) stored as a 32-bit float, then printed as an integer.
That also explains why the numbers are around 1.1 billion. A small positive float like 4624.0 has an exponent that lands its bit pattern in exactly that range when read as an int.
Reversing It
To get the flag back, we just run the pipeline backwards. For each integer n in playing.txt:
- Pack
nas a 32-bit integer to get its raw 4 bytes. - Unpack those same bytes as a 32-bit
float— this is the type-pun in reverse, recovering the squared value (e.g.4624.0). - Square-root it to undo the
fflag[i] * fflag[i]step (sqrt(4624) = 68). - Round and convert to a character (
68 → 'D').
A quick note on why we use a 32-bit float and int even though the C source says
long: the printed values fit in 32 bits and were produced from a 4-bytefloat. Thelong/floatsize mismatch is part of the trap in the original code, but the bit pattern that was actually printed is the 32-bit float reinterpretation, so that’s what we decode.
Here’s the solve script:
| |
Running it:
| |
The Flag
| |
Takeaways
- Read the flavor text. “Quake” + “trick with pointers” is a direct pointer (pun intended) to the fast inverse square root and its
*(long*)&ytype-pun. - Spot the dead variable. The squared values went into
fflag, but the program printedlflag. The only way that makes sense is if a line copies bits across — and the kind of copy (reinterpret vs. cast) is what the whole challenge hinges on. - Type-punning ≠ casting. A normal cast
(long)fflag[i]would have given4624. Reinterpreting the bits with*(long*)&fflag[i]gives1166821376. The challenge lives entirely in that distinction. - Reversing was straightforward once the transform was understood:
int bits → float → sqrt → char.
A clean little 50-pointer that rewards recognizing one of the most famous lines of C ever written.