Provided with the split-screen executable, find the flag.
Requirements: Ghidra and WSL on Windows. Run the executable (in WSL on Windows):
$ chmod +x ./split-screen
$ ./split-screen
[timeline] expectation and reality drift apart. press enter to sync>
you keep rewinding but nothing changes. try again later.
Loading the executable into the Dogbolt decompiler shows several versions of the code. Hex-Rays is the clearest, including the program’s messages and its argument handling.
if ((unsigned int)sub_401810(v16, 0)) {
printf("flag: %s\n", s);
return 0;
}
if (v16[0]) {
puts("You rewind too far. This scene is gone.");
puts("flag: roo{false_reflection_sequence}");
} else if (v16[1]) {
puts("You rewind too far. This scene is gone.");
} else {
puts("you keep rewinding but nothing changes. try again later.");
}
The binary recognizes --debug and --force-align, but neither is available in this build. The displayed roo{false_reflection_sequence} flag is a red herring. Since the executable is small, the easy approach is to short-circuit the condition that controls the real flag output.
Open the executable in Ghidra, analyze it, and trace from the entry point to main at 0x004011e0. The relevant decompilation is:
iVar2 = FUN_00401810(&iStack_a8, 0);
if (iVar2 == 0) {
// failure messages
} else {
printf("flag: %s\n", abStack_58);
}
The real flag prints only when FUN_00401810(&iStack_a8, 0) != 0. Rather than recreating its conditions, patch the conditional branch at 0x00401369.
00401367 85 c0 TEST EAX,EAX
00401369 0f 84 8e 00 00 00 JZ LAB_004013fd
0040136f 4c 89 e6 MOV RSI,R12
00401372 48 8d 3d ... LEA RDI,["flag: %s\\n"]
0040137b e8 ... CALL printf
TEST EAX, EAX sets the zero flag when EAX is zero; JZ then skips the printf call. Replace all six bytes of the JZ at 0x00401369–0x0040136e with 0x90 NOP instructions so execution falls through to printf.
In Ghidra, navigate to 0x00401369 with Ctrl+Alt+G, choose Patch Instruction, and write six 0x90 bytes. Export the modified binary as Original File, then run it:
$ chmod +x ./split-screen-shortcircuit
$ ./split-screen-shortcircuit
[timeline] expectation and reality drift apart. press enter to sync>
flag: roo{500_days_of_summer}
The challenge can also be solved by reverse-engineering the underlying conditions, but patching the branch gets the answer directly.