home *** CD-ROM | disk | FTP | other *** search
- -------------------------------------------------------------------------------
-
- Tragen's Crackme #1
-
- Another day, another crackme. After finding out that Tragen's #4
- crackme uses a hash of the
- serial and the only way to crack it is a brute force, I decided to try
- my hand at this
- crackme.
-
- Upon running the app, we are presented with 5 boxes, a Check button,
- and a Give Up button.
- I filled the boxes with 1234, 5678, 9012, 3456, and 7890. Being the app
- uses MFC 4.2 to
- hide what it is doing, I had to use SoftIce and set a bpx on
- GetDlgItemTextA. Clicking the
- Check button did not trigger the breakpoint though. I removed that
- breakpoint and bpx'd on
- GetDlgItemA and proceeded to re-check the serial. This time I got a
- hit. After fiddling
- around and getting back to our application's code, instead of in the
- MFC42 dll, we can
- scroll upwards to find a range of NOPs. This is a signal that we are at
- the top of the
- fuction, as all apps compiled with MFC 4.2 that I've found have been
- this way. The address
- should be 00401560.
-
- I prefer to do everything in W32Dasm so I proceeded to stop the app,
- open up W32Dasm, and
- debug from there. Almost immediately after 00401560 are 5 calls to
- MFC42.Ordinal:0C17. There
- are no pushes onto the stack that indicated a memory location to write
- the data to though.
- After letting one of the functions execute, 0x04D2 was returned. After
- looking at it for a
- few seconds, I realized that 1234 could be turned into hex and wondered
- what it's hex
- counterpart was. The hex counterpart is 0x04D2. Now we know what that
- Ordinal function is
- doing. Any values put in are turned from decimal into hex.
-
- After the 5 calls, we run into a loop. Looking thru the references to
- the stack, it can be
- noted that only the first byte in the values is referenced or used. It
- appears, at least so
- far, that it is just wanting values between 0 and 255 as the other
- bytes aren't being
- referenced. Below is a C version of the loop. Val1 and Val3 are the
- values from the serial
- positions.
-
- for(Counter1=1; Counter1 <= 0x0B09; Counter1++)
- {
- Counter2++;
- Counter3++;
-
- Key1 = Buffer3[Counter3] * Buffer2[Counter2];
-
- A = Buffer1[Counter1] * Val1;
- A = ((A * Val1) ^ A) + Val3;
- Key1 = Key1 ^ A;
-
- Counter5++;
- Key1 = Key1 ^ (Buffer4[Counter5] * Buffer4[Counter4+1] * Val1);
- Key1 = Key1 ^ (Buffer4[Counter4+1] + Val1) ^ Val1;
-
- Counter4++;
-
- if(Counter2 == 0x36)
- Counter2 = 0;
-
- if(Counter3 == 0xD8)
- Counter3 = 0;
-
- if(Counter4 == 5)
- Counter4 = 0;
-
- if(Counter5 == 10)
- Counter5 = 0;
- }
-
- Note, Key1 is always overwritten the next time it goes thru the loop.
- This means that the
- following code works just as well.
-
- A = 0x00 * Val1;
- A = ((A * Val1) ^ A) + Val3;
- Key1 = 0x87 ^ A ^ (0x00 * 0x00 * Val1) ^ (0x00 + Val1) ^ Val1;
-
- Of course, anything multiplied by 0x00 is 0. Anything xor'd against
- itself is 0x00,
- therefore the xor is not undone. If you do a little bit of math on the
- above function, you
- come up with the following.
-
- Key1 = 0x87 ^ Val3;
-
- Sure is a large loop for such an easy Key1 value. After the loop, Val1
- is set to Key1. OK.
- Maybe this was just a screwup somewhere due to the buffers. either way,
- This makes our life
- ALOT easier in figuring out Key1. Now to go on to the 2nd loop that is
- after this one. The
- next loop does the exact same thing as the above loop does except Val1
- is now Val2 and Val3
- is now Val4. This means that Val2 = 0x87 ^ Val4. That was easy. The
- loop after this is the
- same as the 2nd loop except Val3 is used instead of Val2. So Val3 =
- 0x87 ^ Val4. Val3 is
- not changed in memory on the 3rd loop but kept in a register.
-
- Now I am going to scratch my head and wonder why no one else has turned
- in a tutorial on
- this crackme. We are almost done. After those 3 terrible loops, we have
- 2 calls then some
- checks we have to pass.
-
- The function being called has 2 values passed to it. The function does
- the exact same thing
- as the above loop except that you pass in the values you want to
- manipulate. The first time
- thru, it does it with the 4th and 5th parts of the key. The 2nd time
- thru, it does it with
- the new Key1 and the original Val5. This means that the following is
- done.
-
- Val1 = Val3 ^ 0x87;
- Val2 = Val4 ^ 0x87;
-
- Now, the following must be true.
-
- Val1 = 0x6C
- Val2 = 0xF4
- Val4 ^ 0x87 = 0xF4
- Val5 ^ 0x87 = 0xFA
- Val3 ^ 0x87 ^ 0x87 = 0xEB
-
- Val1 must be 0x6C. Val1 is set to Val3 ^ 0x87. We have to find Val3
- then.
- 0x87 ^ 0x6C = 0xEB so Val3 is 235. This can be confirmed as Val3 ^ 0x87
- ^ 0x87 = 0xEB.
- 0x87 ^ 0x87 cancel each other so Val3 = 0xEB
-
- Val2 needs to be 0xF4 and it is set to Val4 ^ 0x87. So 0x87 ^ 0xF4 =
- 0x73. so Val4 is 115
- in decimal. This can be confirmed as Val4 ^ 0x87 must be 0xF4. 0x73 ^
- 0x87 = 0xF4
-
- Val5 ^ 0x87 must be 0xFA. 0xFA ^ 0x87 = 0x7D or 125 in decimal.
-
- Val1 and Val2 are never checked and are actually lost during the math.
- This means any valid
- serial has anything for the first 2 numbers then Val3, Val4, and Val5
- set correctly. Below
- is a working serial
-
- 0 0 235 115 125
-
- This crackme did not need any brute forcing and was very easy. The only
- thing that would
- throw people is that it uses the MFC 4.2 stuff AND it uses loops that
- are not needed. I'd
- give this a difficulty of 2 or 3.
-
- Lightning
-