I lost the description :(
Background
SquirelCTF challenge, called “bin fun”, TL;DR at end (to avoid spoilers).
Static Analysis
It’s not static but it is stripped, but finding main is not an issue as you can see it pass the arguments in libc_start_main.
In main, we see that it mprotects a region of code twice the length of the page size with the permissions “7”. 7 is read/write/execute (read | write | execute = 7).
If the above doesn’t fail to execute, a mystery sub is executed, with argv[1] (the first argument of the program) as the first argument of the mystery sub.
In the mystery sub, the code appears to be xoring what will be executed after a loop exits with 0x91 (it unpacks the next function).
Armed with this information, we can start using dynamic analysis
Dynamic Analysis
First we set a breakpoint before the unpack loop, run the program, hit the breakpoint, continue the code, wait for it to crash, and hit the back button (leading us back to the breakpoint and the unpacked code).
The most important part of the unpacked code is:
1 | .text:000000000040123B loc_40123B: ; DATA XREF: sub_401210:loc_401222↑o |
Remember that the first argument passed to this function was a pointer to our first argument (which is stored in rdi), but since we debugged this code without passing any arguments it is trying to grab data from a null pointer, leading to a crash. After this piece of code we see another unpacker function:
1 | .text:0000000000401247 loc_401247: ; CODE XREF: .text:0000000000401254↓j |
So, let’s pass a random argument to the program and perform the first step (set a breakpoint, run the program, hit the breakpoint, continue the code, wait for it to crash, and hit the back button (leading us back to the breakpoint and the unpacked code)). NOTE: Code isn’t being displayed? Undefine existing stuff, then make code (spam u at bytes and press c when you’re done). Here’s the most important part of the unpacked code:
1 | .text:0000000000401256 loc_401256: ; DATA XREF: sub_401210+2D↑o |
Basically, this code xors our first byte with 0xe7 and then compares it with 0x94, if they are equal, the code continues, if they aren’t, we return (and crash). This means that our first byte is 0xe7 ^ 0x94, which is 0x73, aka s, the first letter of the flag format. So if we set the first letter of our arg to s, we will pass this check. If you repeat the above steps (set a HARDWARE breakpoint (software actually modifies the code in memory, so when it gets xored it breaks everything) after the next unpack loop, run it, hit the breakpoint, continue, crash, hit the back button for the disassembly putting you back at the breakpoint, scroll down, xor the two values, append it to your first arg) you’ll find it repeats the pattern, so you can use this to find the whole flag.
The solve
squ1rrel{n1ce_r3v_sk3ll5_34289}