My First Kernel
My First Kernel
Platform: hackerlab | Category: Reversing | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-04-06 | Status: Solved Techniques: static_reverse_engineering, loop_inversion, state_recovery
Summary
Task: a small 32-bit kernel binary prints a hint and runs a long arithmetic/XOR state update before checking three 32-bit words against constants. Solution: reverse one loop iteration, apply the inverse 0x1337 times to the target state, and decode the recovered little-endian dwords into the flag body.
My First Kernel — hackerlab
Description
Попробуй запустить моё первое ядро. Там есть вывод текста :)
English summary: we are given a 32-bit kernel-style ELF that prints text directly to the screen. The binary hints that the flag can be recovered by understanding and patching the right memory values.
Analysis
The first quick win is running strings on the binary. That reveals both the theme of the task and the exact direction for analysis:
Hi! This is my first core. If you want to get a flag, then you need to manually patch the values in memory. Hehe :)Great! Look in memory before the loop how they will look as a string, and then add them between curly brackets in CODEBY{}.
Disassembly of kmain shows a simple flow:
- write the intro string to VGA memory at
0xb8000, - initialize four local variables,
- run a loop while the counter is less than
0x1337, - compare the final state with three hardcoded constants,
- print the success message if all checks pass.
The relevant initial values are:
text read-only • copy allowed[ebp-0x8] = 0x1337 # loop count [ebp-0x20] = 1 # X [ebp-0x1c] = 1 # Y [ebp-0x18] = 1 # Z
After the loop, the program requires:
text read-only • copy allowed[ebp-0x8] == 0x1337 [ebp-0x20] == 0x82b9f885 [ebp-0x1c] == 0x05afcb5c [ebp-0x18] == 0x77e64835
The loop body performs this forward transform on three 32-bit words modulo 2^32:
text read-only • copy allowedB ^= A B += (C ^ 0x539) C -= (B ^ A) A ^= (B + C) B ^= (A - C) C ^= (B + A)
So the task is not to brute-force the state but to invert one iteration and walk backward from the checked constants.
Solution
Let the state after one forward round be (X, Y, Z). Reversing the operations in the opposite order gives:
text read-only • copy allowedz1 = Z ^ (Y + X) y1 = Y ^ (X - z1) x1 = X ^ (y1 + z1) z = z1 + (y1 ^ x1) y = y1 - (z ^ 0x539) x = x1 ^ y
All arithmetic is done modulo 2^32. Applying this inverse function 0x1337 times to the target state
text read-only • copy allowedX = 0x82b9f885 Y = 0x05afcb5c Z = 0x77e64835
yields the pre-loop values:
text read-only • copy allowedx = 0x53723166 y = 0x326b5f74 z = 0x6c654e72
These are not random numbers. Interpreting each dword as little-endian bytes gives:
text read-only • copy allowed0x53723166 -> f1rS 0x326b5f74 -> t_k2 0x6c654e72 -> rNel
Concatenating them produces the flag body REDACTED, so the final flag is CODEBY{REDACTED}.
Minimal solver:
python read-only • copy allowed#!/usr/bin/env python3 MASK = 0xffffffff def inv_round(x, y, z): z1 = (z ^ ((y + x) & MASK)) & MASK y1 = (y ^ ((x - z1) & MASK)) & MASK x1 = (x ^ ((y1 + z1) & MASK)) & MASK z0 = (z1 + (y1 ^ x1)) & MASK y0 = (y1 - (z0 ^ 0x539)) & MASK x0 = (x1 ^ y0) & MASK return x0, y0, z0 x, y, z = 0x82b9f885, 0x05afcb5c, 0x77e64835 for _ in range(0x1337): x, y, z = inv_round(x, y, z) flag_body = ( x.to_bytes(4, "little") + y.to_bytes(4, "little") + z.to_bytes(4, "little") ).decode() print(f"CODEBY{{{flag_body}}}")
Running it prints:
text read-only • copy allowedCODEBY{REDACTED}