by XxcoralloxX
This is a windows executable, let’s start looking at what it does.
So, it looks like a key-checker, let’s see what IDA think about it.
Here we have the main. As usual, on the left, the program ends if there aren’t enough arguments (1). On the right, the function Y2hlY2tLZXk it’s called, to check our input. Very standard.
Now, let’s have a look at the check function, conveniently renamed.
Here, we note that the function is recursive
test al, al
...
add [ebp+arg_0], 1
mov eax, [ebp+arg_0]
mov [esp], eax
call CheckFun
checks if we are at the end of the string, if yes, it returns,
else it calls itself adding 1 at the address of the string (the next char).
Ok, but what it does? there’s a bigger block of instruction which is the main part of the function, we need to take a closer look. Slowly.
Here what’s going on:
I’m going to name
“Key” the password provided by the user (which is ebp+arg_0)
“Mask” the string contained in the variable a2V5QXJy
“checkString” the string contained in the variable _c29tZUtleQ__
1 - 2) The address Key is moved to EAX, then it’s value is moved to ECX.
3) The index variable i is moved into EAX.
4) a logic and between EAX (index i) and 3 is performed. The result will be the 3 lower bits of EAX (i % 3)
5) Mask[i%3] moved into EAX
6) EAX XOR with our Key (remember that this function is recursive, here we have 1 char of our Key).
6.5) This result is moved into EDX
7-8-9-10) checkString[i] moved into EAX
11) taking lower part of EAX
12) comparing it with EDX ( the result of Key[i] XOR MASK[i%3]).
Long story short, this kind of check is made:
for(i=0;i<Len;i++){
if(Key[i]^Mask[i%3]!=checkString[i]){
exit()
}
}
okay, we can fairly easily find which is the right key doing this operation in the opposite way, we only need:
the mask:
the checkString:
and a few lines of C to perform that XOR.
And voilà, easy peas… oh.. no…
Ok, a big breath and let’s start again.. Looking at the rest of the program, we can find another function: c2VjcmV0RnVuY3Rpb24 and this is it:
Several bytes are moved into two “Strings maybe?”
Some of them are “checked”, and if all the checks are correct, some memory is allocated:
Then a for through one of the two string is performed (on the right) and on the left, we can see “Your flag is %s”.
Okay okay, so let’s patch the program, we want it to call this function, instead of the “Fake check”.
Still not working. Debugging with gdb we can see that some checks fail. Let’s have a look at them:
They are quite simple, but strange, the value inside that memory address is moved only once and never used before the check. So it seems deliberately wrong. (???)
Then what about trying to patch them? I’m going to change that 4 bytes to the value they should be.
And run it… oh.. we broke it?
Ok.. let’s see with gdb.. At some point, after the for loop, but before the printf of the flag, a call to EAX is performed..
But these instructions seem too strange, maybe they are wrong? Well Push Ebp Mov Ebp, Esp it’s quite common after a call.. maybe this first part is correct? Looking back to ida, we can have a better look at that call. the address is lpAddress which is the memory allocated after the check..
Remember the “fake function”? Ok, it uses a mask of 4 bytes to decode some data. which is interesting, since we also patched 4 bytes to make the program proceeds..
the old values was: 0x46 0xbe 0x96 0x51
the new is: 0x55 0x89 0xe5 0x60
a xor between those 4 gives us: 0x13,0x37,0x73,0x31 which is the Mask of the fake function!
Now we do what we did in the fake function, let’s take all the bytes from the second string (the one executed by the call). and use the script made for the old function
And our output is: 55 89 e5 60 31 c0 be 44 33 22 11 bf dd cc bb aa ac 84 c0 74 5 34 17 aa eb f6 61 89 ec 5d c3
(Spoiler c3 is a return, great!)
Now we patch all the bytes and running the program one last time we get:
A nice challenge imho :D
XxcoralloxX
tags:reverse
windows
noxCTF2018