CrackMe2 by Pride
2025–07–08
First post! Here is my write up against the CrackMe2 binary by Pride, now kept on crackmes.one, previously *.de.
When opening the program itself, we’re greeted with three major prompts and inputs:
- Asking for your name and inputting (it can take a string),
- Asking for a serial (which is asked to be a whole number),
- Asking for a master-serial, which seems to be a second stage serial.
Couldn’t seem to get much further than that when putting in a long string or a large number in either of these prompts and we’ll play by the rules and assume the serial needs a number truly before fudging around with it.
Let’s open this up in OllyDbg to understand the assembly, the underlying structure of the program we’re running!
Enter NOW
When attaching OllyDbg as a debugger to the .exe, we have a very quaint start with not much of interest:
PUSH EBP
MOV EBP, ESP
SUB ESP,8
MOV DWORD PTR SS:[ESP], 1
We’re setting up the stack pointer and growing the stack.
Not too much is interesting here and we have a CALLs ahead of us with no idea if we have anything juicy yet or just a bunch of obfuscations, so let’s simply step-over
to jump out of anything distressing until we can’t go any further because the program is pending out input into the buffer.
Let’s set a breakpoint after this call (address 0x401448
) where we enter a name and then step-over
to continue.
For the rest of this writeup you’ll see that simply setting a breakpoint after a call that stops us because the program is pending input is a great initial move to understand what the program is doing.
What is this string up to
If we now step-in
a few lines and jump into the CALL on 0x401458
, and move a bit down the call after inputting our serial, we see that the address 0x43C33A
is using strlen() and storing this into a DWORD offset from the EBP, interesting… we are getting the length of an inputted string from our name
for future use.
On 0x40147B
, we jump into the CALL for putting in the serial. Let’s set a breakpoint on the address after this call to step line by line what we are doing! This is at 0x401480
of course. Another call up ahead, and we will set another breakpoint after it at 0x40148B
with ADD EAX, 0CA
.
Interesting! When breaking at this address before it runs through the addition, where ADD will do the following in pseudocode:
ADD <into this>, <this value>
We can see that EAX has been populated with the value of strlen()! For me, this was B (decimal 11), and we’re adding 0xCA which should go to 0xD5 given 0xB.
The next line is more arithmetic, so let’s step-into/continue execution.
The next line is XOR EAX, 3D8D40F
, meaning we now need to perform eXclusive OR against register EAX and 0x3D8D40F. eXclusive OR (XOR) is like a not-equality operation, in that the truth table is going to be as such:
A | B | A XOR B 1 | 0 | 1 1 | 1 | 0 0 | 1 | 1 0 | 0 | 0
Since one value (at EAX) is likely going to be way smaller than 0x3D8D40F (64541711), we’re going to get something close to this value as all leading bits ahead of our much smaller number will be 0.
Given 0xD5
, we’ll get 0x3D8D4DA
(64541914).
The next lines are interesting in that it is clear we’ll likely be comparing this:
MOV DWORD PTR SS:[EBP-38], EAX ;storing our result
MOV EAX, DWORD PTR SS:[EBP-30] ;getting a value further down the stack to EAX
CMP EAX, DWORD PTR SS:[EBP-38] ;we are comparing the two values!!!!!!!
JNZ SHORT CrackMe#.004014C6 ; the the apsr flags say its not zero(equal), lets jump
; if not, we can continue to "Gratz"!
Awesome! So the first serial check is solved. In short:
- Enter name, any str
- CrackMe checks strlen(name) and stores somewhere
- We get strlen(name) + 0xCA
- This sum is XOR 0x3D8D40F
- Chcked for equality with stored value in EBP-30, which is a constant value.
Now we can get back and do the next keygen! Given this, we can get by with knowing the values for further debugging.
Master Serial
This one is a lot easier and we can use the same debugging techniques here. Make sure to set a breakpoint on any execution after the address that gets stuck running awaiting input!
We get stuck on 0x40152A
calls to input the master serial now, and what is interesting without even going in is that we have a very similar set of instructions after we RET from this input call:
MOV EAX, DWORD PTR SS:[EBP-2C] ; we are getting a value from -2C
ADD EAX, DWORD PTR SS:[EBP-38] ; hey... we've seen this guy before....
ADD EAX, 0D75E9 ; add a value to our beautiful EAX
MOV DWORD PTR SS:[EBP-3C], EAX
MOV EAX, DWORD PTR SS:[EBP-34]
CMP EAX DWORD PTR SS:[EBP-3C]
JNZ CrackMe#.00401569
... ; see you space cowboy...
Hopefully it’s a little clearer now what we may be doing with some static analysis and with a warmup from our dynamic searching of the first serial.
We are putting back in our first serial that is correct and adding it to EAX which as a value from EBP-2C
. We then ADD 0x0D75E9
and put it away into EBP-3C
for safekeeping before checking it. When running the program, we can see that EBP-2C at 0x40152F
is a static value of 0x183A0
So this means in short:
- MOV 0x183A0 to EAX
- ADD the previous serial to EAX
- ADD 0xD75E9 to EAX
- Put it away for safekeeping
- Pull in EBP-34 which is our 'true' master serial
- Check and jump if not equal!
Easy enough! This one is a lot more easier since this is just addition and some moving around values in the stack.
Simply get the previous correct serial, add 0x183A0
(99232) and 0xD75E9
(882153) and we’re in business!
Keygen
Lovely simple keygen for this one, but great fun doing a little easy practice on x86 ASM. Let’s put all we know into use now in a tidy script:
def main():
name = input()
nameLen = int(len(name))
serial1 = nameLen + 0xCA
serial1 = serial! ^ 0x3D8D40F
print("First Serial: " + serial1)
serial2 = serial1 + 0x186A0 + 0xD75E9
print("Second Serial" + serial2)
if __name__ == "__main__":
main()
This was a great little crackme, if a bit simple!