patch2
patch2
Platform: CUSTOM | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: little_endian_dword_reconstruction, peb_beingdebugged_antidebug, rol_inverse, ror_xor_transform_reversal, static_disassembly
Summary
Walkthrough of the CUSTOM Reversing patch2. Task: tiny ~3KB PE32 console crackme that reads 4 bytes from stdin, applies ror+xor and compares to a constant, with a PEB.BeingDebugged anti-debug tweak to the rotate amount. Solution: reverse the tr
Description
rev-kids20.forkbomb.ru — task2.exe (PE32 console crackme). Find the input that makes the program print "OK".
task2.exe is a ~3KB PE32 (Intel 80386, MS Windows) console crackme written in C. It imports only GetStdHandle, ReadFile, and WriteFile from kernel32.dll. It reads bytes from stdin, transforms the first 4 bytes, and prints "OK" or "NO". The goal is to find the input that yields "OK".
Analysis
The .rdata segment holds the adjacent 2-byte messages "OK" (at 0x401020) and "NO" (at 0x401022), forming the string OKNO.
Transform function at 0x401028
asm read-only • copy allowed401028: push ebp 401029: mov ebp, esp 40102b: push ecx 40102c: mov eax, fs:[0x18] ; TEB 401032: mov eax, [eax+0x30] ; PEB 401035: movzx ecx, byte [eax+2] ; PEB.BeingDebugged 401039: add ecx, 0x0e ; cl = BeingDebugged + 14 40103c: mov eax, [ebp+8] ; input dword (first 4 bytes) 40103f: ror eax, cl 401041: xor eax, 0x64198234 401046: pop ecx 401047: pop ebp 401048: ret
Main routine at 0x401049
- GetStdHandle(-11) -> STD_OUTPUT_HANDLE @ 0x403000
- GetStdHandle(-10) -> STD_INPUT_HANDLE @ 0x403004
- ReadFile(hStdIn, buf=ebp-0x64, 0x64, &read, 0)
- eax = *(dword*)buf ; first 4 input bytes
- call 0x401028 ; transform
- cmp eax, [0x401024] ; [0x401024] = 0xf1d833fd
- jne fail
success: WriteFile(hStdOut, 0x401020 "OK", 2, ...)
fail: WriteFile(hStdOut, 0x401022 "NO", 2, ...)
The compared constant 0xf1d833fd is read from 0x401024, which overlaps the byte stream fd 33 d8 f1 lying inside the code region just before the function — a reuse-of-bytes trick typical of tiny crackmes.
Anti-debug twist (the "patch" theme)
The rotate count is cl = PEB.BeingDebugged + 14. When not under a debugger, BeingDebugged = 0, so cl = 14. Under a debugger the rotation amount changes (cl = 15), so the required input would differ — a small anti-debug detail that breaks naive dynamic solving. Solving statically with cl = 14 gives the correct answer.
Solution
We need: ror(input, 14) ^ 0x64198234 == 0xf1d833fd
ror(input, 14) = 0xf1d833fd ^ 0x64198234 = 0x95c1b1c9
input = rol(0x95c1b1c9, 14) = 0x6c726570
Little-endian dword 0x6c726570 = bytes 70 65 72 6c = b'REDACTED' (p=0x70, e=0x65, r=0x72, l=0x6c).
python read-only • copy allowed#!/usr/bin/env python3 import struct def ror(x, n): n %= 32; return ((x >> n) | (x << (32 - n))) & 0xffffffff def rol(x, n): n %= 32; return ((x << n) | (x >> (32 - n))) & 0xffffffff TARGET = 0xf1d833fd XORK = 0x64198234 # Reverse: undo xor, then undo ror (cl = BeingDebugged(0) + 14 = 14) rotated = TARGET ^ XORK # = 0x95c1b1c9 inp_dword = rol(rotated, 14) # = 0x6c726570 answer = struct.pack('<I', inp_dword) print(answer) # b'REDACTED' # Verify forward assert (ror(struct.unpack('<I', answer)[0], 14) ^ XORK) == TARGET
Feeding the 4-byte input REDACTED to the program on stdin makes it print "OK". This is a kids-series crackme with no FLAG{...} wrapper — the accepted answer string is REDACTED.
Key Takeaways / Lessons
- Mastering little_endian_dword_reconstruction, peb_beingdebugged_antidebug, rol_inverse, ror_xor_transform_reversal, static_disassembly was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-06-25 • CUSTOM • patch2 • Difficulty: Easy