Deadbeef
Deadbeef
Platform: rev_kids20 | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-06-15 | Status: Solved Techniques: exhaustive_32bit_bruteforce, iat_thunk_following, little_endian_dword_to_ascii, magic_constant_compare, win32_io_pattern_recognition
Summary
Task: tiny hand-written MASM PE32 console binary reads input and prints OK/NO based on a ror/rol/xor transform of the first dword compared to a magic constant. Solution: follow IAT thunks to recover the Win32 I/O pattern, extract the transform and compare constant 0x395547a2, then brute-force all 2^32 inputs in C since X is used on both sides; printable solution 0x49684179 = little-endian 'REDACTED'.
Deadbeef — rev_kids20
Description
This small but ugly binary ... Flag is the input that makes app say "OK".
A tiny PE32 console executable deadbeef.exe (Intel 80386, hand-written MASM, no
symbols). It reads input from stdin and prints either OK or NO. The flag is
the exact input that makes the program print OK. The flag is submitted via a
POST flag parameter to the platform (rev-kids20.forkbomb.ru).
Analysis
The binary is hand-written MASM with no symbol info, so the disassembly is read
by following the IAT thunks. Image base is 0x401000.
Imports (via IAT thunks)
Three kernel32 functions are reached through jump thunks:
| Thunk | Function |
|---|---|
jmp [0x402008] | GetStdHandle |
jmp [0x402000] | ReadFile |
jmp [0x402004] | WriteFile |
Data
At 0x401020 there are the output strings and the magic constant:
0x401020: "OK" ; [0x401020] = 'O','K'
0x401022: "NO" ; [0x401022] = 'N','O'
0x401024: dd 0x395547a2 ; compare constant (bytes: a2 47 55 39)
main
GetStdHandle(-0xb) -> stdout, saved @ 0x403000 ; STD_OUTPUT_HANDLE
GetStdHandle(-0xa) -> stdin, saved @ 0x403004 ; STD_INPUT_HANDLE
ReadFile(stdin, buf=[ebp-0x64], 0x64, ...) ; read user input into stack buffer
call transform @ 0x401029 ; operates on FIRST dword of buf
cmp [ebp-0x64], [0x401024] ; transformed first dword == 0x395547a2 ?
equal -> WriteFile("OK")
else -> WriteFile("NO")
transform @ 0x401029
Operates on the first DWORD X of the input buffer:
eax = 0xcafebabe
eax ^= X
eax = ror(eax, 7)
eax ^= 0xdeadbeef
eax = rol(eax, 0x15)
eax ^= 0x13373389
X = X ^ eax ; result written back to buf[0]
So the program prints OK iff a 4-byte input X satisfies:
X ^ f(X) == 0x395547a2
where f(X) = ((ror(0xcafebabe ^ X, 7) ^ 0xdeadbeef) rol 0x15) ^ 0x13373389
Because X appears on both sides of the equation, the relation is not
trivially invertible. With only a 32-bit search space, exhaustive brute force in
C finishes in a few seconds.
Solution
Brute-force every 32-bit X:
c read-only • copy allowed#include <stdint.h> #include <stdio.h> int main(void) { uint32_t T = 0x395547a2; for (uint64_t x = 0; x < 0x100000000ULL; x++) { uint32_t X = (uint32_t)x; uint32_t e = 0xcafebabe ^ X; e = (e >> 7) | (e << 25); // ror 7 e ^= 0xdeadbeef; e = (e << 0x15) | (e >> 11); // rol 0x15 e ^= 0x13373389; if ((X ^ e) == T) printf("%08x\n", X); } return 0; }
Compile and run:
bash read-only • copy allowedgcc -O2 db.c -o db && ./db
Four solutions:
0x1c3d142c
0x49684179 <- printable
0xb697be86
0xe3c2ebd3
The printable one is X = 0x49684179. As a little-endian dword the bytes are
0x79 0x41 0x68 0x49 decodes to REDACTED.
Verification in Python:
python read-only • copy alloweddef f(X): e = (0xcafebabe ^ X) & 0xffffffff e = ((e >> 7) | (e << 25)) & 0xffffffff # ror 7 e ^= 0xdeadbeef e = ((e << 0x15) | (e >> 11)) & 0xffffffff # rol 0x15 e ^= 0x13373389 return (X ^ e) & 0xffffffff X = int.from_bytes(bytes.fromhex("79 41 68 49"), "little") # 0x49684179 assert f(X) == 0x395547a2
Submitting REDACTED as the input makes the binary print OK.