Log in

View Full Version : Serial fishing


marco_ul
January 31st, 2007, 12:37
Hi,

I'm trying to fish a serial number out of a registration. This program comes in two "version", the normal and the pro. I first downloaded the normal version; witch is a 30 days trial. I loaded the .exe in Ollydbg and after 5 mins, the good serial was found. So I thought... "hummm, what about the pro version now..." In my dreams... the protection scheme is different. It's not just a "compare the code entered to the code generated" this time.

The program asks you to enter your Name, Organisation and the key. You have a note that tells you that if you registration succeeds, the program is going to connect to the internet within a month to verify your registration, but this is not my concern for now.

I analysed the code with Ollydbg and IDA (my knowledge of assembly is not that bad, but I'm not that good too... I guess you'll figure it out when you'll read my comments). This is a small app and pretty much all the text strings are "written" in the .exe file, so I think it's a good target for a newbie like me.

I think I found the "critical" test. If I change the zero flag value of that particular test, the registration succeeds and the time limit is removed. Afterwards, the program immediately tries to connect to internet (hey, I thought I had a month... ). If I try to patch the "critical" test, I have "This program file has been modified and will be shut down." Since I can find this string in the .exe, I guess I could find where the CRC check is and bypass it (?), but I don't want to do this. I want it the "clean" way.

So anyway, enough talk. As an attachment you'll find the code and my comments. I think everything is there. Unfortunately, my knowledge of assembly/programming is not good enough to solve this "puzzle" and fish out the correct key. Any hint or comments would be really appreciated. Correction of my comments (if they are wrong) would help me too.

Thanks in advance

Marco

fr33ke
January 31st, 2007, 17:57
First a hash is created for the username at 0042933B until 00429371. Taking your name as an example:
Code:
Marco Osram -> marcoosram = 6D 61 72 63 6F 6F 73 72 61 6D
Now group per 4 and add them:

6D 61 72 63
6F 6F 63 72
61 6D
============ + (no carry)
3D 3D D5 D5

Then the serial is stripped from any hyphens. I don't think they are for an older version, just to make the serial easier to read.

Then last 8 characters (see 00429C1B) are converted into an int. After that the first n characters are converted, with 6 <= n = stringlength - 8. See 00429C2F.

In 00429BB0, you can see that the int from the last 8 (xor-ed with 0xE1E1E1E1) is used in some function that looks like modular exponentiation. 00429B20 is a probably mulmod, e.g. return (arg1 * arg2) % arg3.

Back to the first n characters, they are xor-ed with the result of the modular exponentiation. It is xor-ed with 0xE1E1E1E1 and then it should be the same as the hash.

By manipulating the first n characters it is quite easy to get it right.

Some comments on your disassembly/comments:

By using the disassembly from (I think) olly, it is hard to follow the offsets relative to the stack pointer. Using an IDA disassembly is much more readable.
The 0xFFFFFFFF at 00429C40 means ULONG_MAX, indicating that the value was too big to fit.
Just FYI, the checks before loops are probably inserted by the compiler and not by the programmer.

marco_ul
February 2nd, 2007, 15:13
thanks fr33ke, your help is really appreciated. I'm still trying to figure out all the calculation routine (bakward) to make a keygen, and I want to say that your comments are really usefull.

For the moment, I changed my strategy and I decide to patch the software. I bypassed the CRC check and made the prog think that my reg info is correct after creating a fake .ini file.

I'll let you know when futher developments will come up !

thanks again

Marco

FrankRizzo
February 2nd, 2007, 22:49
If you want to find the CRC check, set a READ breakpoint of the code location that you changed, and see where it breaks. THAT should be the CRC code, as nothing else should have a valid reason for scanning the code segment.

Since you said you wanted to "do it right" I figured I'd offer up a way to fix that little problem.

Silkut
February 3rd, 2007, 04:23
There is a great Anarchriz tutorial to learn how to reverse CRC's.

fr33ke
February 3rd, 2007, 04:31
There is also a CRC reversing paper by the CS dept of Humboldt university.
It goes deeper than the anachriz way and attacks the mathematical principles.

http://sar.informatik.hu-berlin.de/research/publications/index.htm#SAR-PR-2006-05

FrankRizzo
February 3rd, 2007, 11:39
Not to throw cold water on the parade of CRC papers, but the reality is that all he probably needs to do is to find the CRC routine, and set a breakpoint at the compare, and see where they get the checksum, and just change it to match what his new checksum is. Let the existing CRC routine do all the work, in case it's some funky algorithm, because when you boil it down, all he really cares about is making it match.

marco_ul
February 3rd, 2007, 15:08
This software is really an easy target. I patched the crc check routine by changing a JE to JMP. I'm glad that it worked so easily, but I learned nothing about CRC check... I'll take a look on those papers for sure. Like I said, a messagebox pops up and tells me "This program file has been modified and will be shut down." I looked for the stirng in the .exe and found it. Here's the routine (the part I had to patch):

00411FA6 |. 3BC8 CMP ECX,EAX
00411FA8 |. 74 4A JE SHORT MyApp.00411FF4
00411FAA |. 53 PUSH EBX ; /Arg3
00411FAB |. 6A 30 PUSH 30 ; |Arg2 = 00000030
00411FAD |. 68 70F64900 PUSH MyApp.0049F670 ; |Arg1 = 0049F670 ASCII "This program file has been modified and will be shut down."
00411FB2 |. E8 F2A60600 CALL MyApp.0047C6A9 ; \MyApp.0047C6A9

So basically what I did : I saw that "cmp ECX,EAX" followed by a "JE SHORT" and then my error message. I place a bpx on 00411FA8 and the jump was not taken when the exe was modified. I changed the JE for a JMP and voila ! The good CRC value is probably compared at 00411FA6, but I won't focus on that for now. Like I said i'm trying to figure out the calculation/generation routin for the serial.

About that, can I copy paste the routine in an assembler (like nasm) to make a keygen ??? Or maybe it is much better to patch the prog so he shows me the good serial ?? Using the software as a keygen...

naides
February 3rd, 2007, 15:27
Quote:
[Originally Posted by marco_ul;64159]

About that, can I copy paste the routine in an assembler (like nasm) to make a keygen ??? Or maybe it is much better to patch the prog so he shows me the good serial ?? Using the software as a keygen...


Some times, yes, but only if you are lucky.

Both methods you suggest, ripping the assembly code to make a keygen, and obligating the app to show the correct serial, have been implemented successfully; look into old tuts and you will find plenty of examples.

The point is,
Once you get the hang of it, the cracking of an app has very many solutions, provided you know what and where is the protection.

More important is to learn to apply several possible methods/resources in implementing the crack

Other protections won't be this easy, I guarantee you

FrankRizzo
February 3rd, 2007, 21:42
Quote:
[Originally Posted by marco_ul;64159]
Or maybe it is much better to patch the prog so he shows me the good serial ?? Using the software as a keygen...


This is my favorite way, as it's kind of a slap at the author for being stupid. Now, the determining factor for me on whether to do this or not is how they handle the serial. If they generate the valid code, and then just do a simple STRCMP kinda check on it, then you can rest assured that I'm going to do it that way. If they use the code that you typed in to generate a 32-bit number, and then compare that, obviously it wouldn't work. That would be the ideal case for the "extract the code and make a keygen" situation.

Naides is right, they all won't be this simple, but there will be some that are more so. No CRCing of the code, maybe even a case where everyone gets the same serial #! (Yes, I've seen it). Or the dongle program that read the dongle ONCE at startup, and then never again. There are idiot software authors out there, and you should make them learn better if you come up against them.

marco_ul
March 7th, 2007, 18:38
I did it (finaly). Thanks to fr33ke. First time I replied I didn’t really understand all the stuff you posted. I had to go through the routine so many times and analyse each part and look what was happening to the register values. I really start understanding when I started to write a “keygen”. Anyway, thanks to you again, you were so right just by looking at my deadlisting, I wish I could do that with your ease…

So my “keygen” is done and it works. Because of the nature of the verification routine used by the software, my keygen is in fact a brute forcer. The serial entered needs to be 16 digits long (two 8-digit numbers in fact). Like fr33ke suggested, by playing with the first 8 digits, you can figure out the good serial. So what my “keygen” does is to try all the first possible 8 digits for each possible 8 last digits (starting at 10000000). I tried a couple names and the furthest I went to is the 13th second 8-digit number (it took about 10 min to calculate).

This solution is working, but is not the fastest. Is there a faster method to find a serial with this piece of code???

Thanks again.

Marco

owl
March 8th, 2007, 12:48
Quote:
[Originally Posted by marco_ul;64128] I bypassed the CRC check and made the prog think that my reg info is correct after creating a fake .ini file.
Marco


Did you have any good tuts or recommend documentation about reversing the .ini file?. I have been playing with a pgm on VB that uses .ini, I thought I got all the fields and labels but I am not so sure what is the data that should be populating the fields on the .ini file. Should I be looking for a specific API to populate the ini fields?

marco_ul
March 8th, 2007, 15:03
In this particular case, I didn't have to crack the ini file, I mean find out what it was suposed to contain. After I found the critical test/jump, I changed the Zero flag so the program thinks the serial was correct. This critical jump lead me to the registration routine instead to the "bad serial" routine. So I just followed every step carefully in my debugger (Ollydbg) and I could find out the fields "requied" in the .ini file. When the program starts, the info in the .ini file is also verified, so you can put a breakpoint there and analyse it to.

In my case, the .ini file was created after patching the jump, so by just opening it I knew everything about its structure.

In you case, dealing with a vb application, I don't know!! Wish you good luck.

naides
March 8th, 2007, 17:25
got cut

fr33ke
March 8th, 2007, 19:17
@owl: Check out the (Get|Write)PrivateProfile* API's, listed at the bottom of _http://msdn2.microsoft.com/en-us/library/ms724875.aspx

@marco_ul: we need to make the following equation true:
hash(username) = MyApp.00429B50(last8 ^ 0xE1E1E1E1, 0xE8B8D413) ^ first8 ^ E1E1E1E1
so:
Code:
hash(username) = MyApp.00429B50(last8 ^ 0xE1E1E1E1, 0xE8B8D413) ^ first8 ^ E1E1E1E1
hash(username) ^ hash(username) = MyApp.00429B50(last8 ^ 0xE1E1E1E1, 0xE8B8D413) ^ first8 ^ E1E1E1E1 ^ hash(username)
0 = MyApp.00429B50(last8 ^ 0xE1E1E1E1, 0xE8B8D413) ^ first8 ^ E1E1E1E1 ^ hash(username)
0 ^ first8 = MyApp.00429B50(last8 ^ 0xE1E1E1E1, 0xE8B8D413) ^ first8 ^ E1E1E1E1 ^ hash(username) ^ first8
first8 = MyApp.00429B50(last8 ^ 0xE1E1E1E1, 0xE8B8D413) ^ E1E1E1E1 ^ hash(username)


Just on a side note, after more analysis I realize MyApp.00429B50 is indeed a modexp function. The modulus is 0xF527789F, so what it does is:
((last8 ^ 0xE1E1E1E1) ** 0xE8B8D413) % 0xF527789F
I don't really get the point of it.

With ^ I mean XOR, with ** I mean exponentiation and with % modulus

owl
March 14th, 2007, 09:53
Thanks fr33ke, I''ll have a look at it.