New 2 Cracking ~~~~~~~~~~~~~~ Tutorial Type : Tutorial Tutorial Topic : How to calculate a serial for Ashampoo Uninstaller 2001 Utilities : SoftICE, brain, mouse, keyboard Music : You choose it. Written by : PhANt0m [Editor : ParaBytes] Date : Dec. 6th, 2001 Remarks : you'll need the Ashampoo Uninstaller, get it from : http://www.ashampoo.com/products/0003 What we will deal with ====================== Fire up the program and at startup a nice nag screen shows up, wich asks us to enter a key or to do the trial. Let's go for the trial by now, we will see this baby later ;). Inside the program we see a comercials add at the bottom of the window, a shareware message in the right side of the status bar and in the Internet menu we have an option called "Enter Reg/Trial Key" (wich takes us to the initial nag) and one step up, an option to get some kind of shareware key. Why is this important? Well, if this program gets too dificult, we could go and get that free trial key, introduce it and see what the program does with a valid serial, even when it's not a full serial. But for now, let's try to do it all by ourselves. First aproach ============= Since it looks like we can introduce a serial, let's try to get a serial. So let's go to the "Enter Reg/Trial Key" window and let's type something in the serial (note it only has a serial protection, not name/serial). I puted '0987654321'. Next put the usual sice bpxs for serials: bpx GetDlgItemTextA bpx GetWindowTextA They might be old but still working :). Now hit "Register Key". Now this is nice... sice pop up on GetWindowTextA... I told you it still works ;). From now on we will need to keep track of what the program is doing with our serial and where it puts the serial on memory, so put a bpx on the second push instruction (.46153E) after the call to GetWindowTextA. ----------------- Cracking REFRESHING ----------------- Let's go to the Windows API help file (Win32.hlp) and search for GetWindowText. See the structure it has: int GetWindowText( HWND hWnd, // handle of window or control with text LPTSTR lpString, // address of buffer for text int nMaxCount // maximum number of characters to copy ); Since we are interested on the "address of buffer for text", this is why we set a bpx on the second push. ---------------------- End of CR ---------------------- Now we get out of sice and insert the serial again, so we break in the bpx we just seted. It's pushing EAX, so do a "d eax" to see what it has. Nothing... ok, sounds logic since the GetWindowTextA hasn't been executed. Let's trace further until GetWindowTextA is executed. What the fucking hell... It's not getting our serial... It's getting the text "Ashampoo UnInstaller 2000"... Prolly from the main window :(. Ok, so we have been working on a fake breakpoint. Well, let's think for a second (yes from time to time that is needed ;). The invalid key message hasn't appeared yet so, let's keep tracing until it does. Btw, alywas use F10 since we dont need to get into the calls, just to get out of them. We will go throught some calls and several conditional jumps until we reach the call at .49A2D3. This call is making the bad reg code to show up. Now we are in the middle of the routine, so we need to get out of there. But how far? We dont know how the program is getting our code so... let's try something else. Second aproach ============== Let's try to make sice pop up when all the process of geting the serial starts. let's try to break when the window shows up and asks us for the serial. How we'll do this? There are several ways like "bpx ShowWindowA" but anyone can do that... let's go for the messy way ;P. So we are one instruction up of .49A2D3. What we do now? Get out of the calls, obviously ;). Press F12 some times. How we know when it's enough F12'ing? See the code... Everytime the code is RET'ing there's nothing else it does. It may just calibrate some values doing some POP and PUSH but that's all. So you will press F12 5 times until you see something interesting: there will be a piece of code with several calls. See all the values it's LEA'ing... we should take a look at them, just in case. Wait a sec... look the thrd LEA at .4CC658... It sets a value to EAX wich points at 64C478 (just an example). And guess what is on that offset... our serial. Ok, so we are close of something :D. But let's remember we need to set a bpx before the main window is opened, so we are at the very start of the process. You can try seting some bpx on the starting code of this call but it wont work, the window will load, and then sice will break. So we press F12 once again and it calibrates some values again... Argh, this is getting annoying. Let's press it one more time. Uh, look at that. That's some interesting code. Let's set a bpx on the call we just got out of, which should be .4CC78B. Now get out of sice and try to introduce the code again. Perfect! Sice shows up BEFORE the main window does!! The code inside that call is what we need. So open the window again so u get into sice. Get into the call (F8) and start tracing. You will see the call that open the window is at .4CC4EF. This means in one of the calls after this one should be the routine geting the serial. A nice way of finding out when the serial is taken is to search in memory for it (s 0 l ffffffff '0987654321'), while u trace the calls just with F10. Finally, we are in the good stuff. Tracing and tracing =================== Now you just have to trace. The serial will appear in memory after the thrd call is executed. If you see the offsets wich are seted before executing it, u will see it moves [EBP-1C] to EDX. That place is filled with an offset when the call is executed, for example, 22365FC. And guess what is at 22365FC... Yep, our serial. Btw, note that the call too sets the length of the key in EAX (A in this case). In the next call the program seems to copy the serial to another place. Nothing we should care about. Then it calls some other procces at .4CC545, and executes two conditional jumps that sends us right to the invalid code message. Suspicious??? NNNNAAAAAAAAHHHHHHH.... ;) So we have .4CC545 where we are pretty sure it's making the serial. Bpx that place, run it again and get into it. Inside the call we see it calls some other process, but there's a very important signal that something is happening: the call at .4BEAB0 is returning with the value "A" (the lenght of our key) and then it's compared with "12". If they are equal the code keeps executing. Otherwise it quits. so we have to make the serial 012h (18) chars long. We add some characters to the serial and go back to this point. And as we thought, this time the routine keep executing. Then there is a call, two MOV's, another call, and a test like before. If you get into the first call you will be able to see it's getting the first three characters of the serial, and when it gets out it sets our serial in EDX, the word "UNI" in EAX, and it does a call... I dont know you, but i dont need to get in that call to see what it is going to do heh ;). But just to confirm, you can go inside it and you will see it compare both strings. If they are equal, set EAX to 0, which make the code keep flowing when it get out. So let's get out of sice, make the first three characters "UNI". By now, my key looks like this: UNI765432109876543 Ok, let's try one more time with this serial. In the next call (.4BEB0E, so you locate yourself) it's getting the 4th and 5th characters (7 and 6 in my key). This is the hardest part of all the routine for the simple reason that you dont know if both numbers are ok or not until you get out of all the routine and you realize it. You will see this later. The call that does this is at .4BEB16, and inside it, the call at .40ABCF. Once there, you will notice the program does this: * MOVs to BL the first character of the two in memory * Recognize what type of character it is, numeric, "-", "$", etc and take diferent ways taking in count this. I'll follow as if the it's a number. * Convert the number from an string (037h) to a real register number (07h). * When having EAX = 0 (first time) and EBX = your first number (7), executes this code: LEA EAX, [EAX*4+EAX] ADD EAX, EAX ADD EAX, EBX Then it gets the next character (6 in my key) and do the same. Notice that all this is just the asm translation of this math function: 1st_char * 0Ah + 2cnd_char 7 * 10 + 6 = 76 (04Ch) After doing this, the call (remember we are two calls inside the main keygen code) return with the value 4C on EAX and then do the same LEA and ADD the last call did, translating it in: EAX = EAX * 0Ah EAX = 76 * 10 = 760 (02F8h) Then it moves that value to [EDI]. No matter what you do, DON'T CLEAN THE BREAKPOINT AT THIS OFFSET (.4BEB16). You will need to come back here later. Ok, so we keep tracing and notice it gets 6th character ("5" on my key) and compare to "B". I guess this value dont change, but i'm not sure. Anyway, now we need to change the 6th number to B. So my serial now looks like this: UNI76B432109876543 Wake up, we are very close to get the serial :) So we have a final check starting at .4BEB87. This call gets the last 4 characters of the key (6543 for me) the next call copyes it to some other location, the next one converts it from string to a register number ("36 35 34 33" --> 6543) and the last call is the one that we are interested on. It makes a little checksum in the serial with the following code: 1: MOV EDX, [EBP-04] MOV DL, [EAX+EDX-01] AND EDX, 000000FF ADD CX, DX INC EAX CMP EAX, 0E JNZ 1 What this is doing is simply adding every byte from the 1st char until the 13th included. Then it gets out to the main keygen routine with the value in EAX (0306h in my case), and it checks this number with the last 4 numbers of the serial. In other words, we will have to make the last 4 numbers of our serial "0306". We have to add a "0" to the number because we have 4 numbers and the result is just 3 numbers lenght. Now we trace a little more... mmmm... look at that... it went out of the keygening routine... hey maybe we are done :D. Let's see what happen when we get out of sice. "Registration code OK!" "Thank you for registering!" Oh please, thank YOU ;D. Our actual key is UNI77B432109870306 But... wtf... The shareware message is still there, as well as the comercial nags in the bottom of the screen and the registering options on the Internet menu... Something is not good here. The hard part, making memory ============================ Once you get out of the keygening routine you will land at .4CC54A, which if you make some memory, is inside the code that send us to the bad key message. Using some logic we can guess the following code will be deciding what to do with our key. Now, if you pass some minutes examinating the code and how it handles the registers (either examinating it or just trial-n-error way ;) you will get to the conclusion that the real checking is being done starting from the call at .4CC583, which is giving out a result of 01 and we need it to be 05. But what is the program checking here?? Simple, the type of the key, this means, if it's a fake key, a trial extension key, etc. How you can know all this? Play around with the jumps and the registers, and see how the program react, how the shareware messages change. Ok, so by now we are fucking tired and just wanna delete the damn prog who has been bitchin us for so long. But no fear, we are really close. So we know we have a last (we hope ;) key check at .4CC583 which is giving out a value of 01 and it should be 05. So let's examin... Wait a sec... Hey!!! Look at that!! See the values the call is seting right before calling the last check... "02F8h". Doesn't this look familiar to you? It does to me :) Remeber where i told you not to take out the bpx, the math function it was doing: 1st_char * 0Ah + 2cnd_char 7 * 10 + 6 = 76 (04Ch) [...] EAX = EAX * 0Ah EAX = 76 * 10 = 760 (02F8h) YYYEEEESSSS!!!! Now we know what those 4th and 5th numbers are. They are the numbers that identify what kind of serial it is!! :D. So let's go back to what we where doing and look inside the .4CC583 call. It's substracting 0302h to the number the keygen routine created previously (02F8h). Check out where the jumps take... the only jump that set the number 05 as result of this function is the one at .4CC3DE, and it only jump if (our_number - 0302h = 0)... So we only have to go back in the code and make the original function = 0302h. Here it's all about maths, and i already went throught this so i'm gonna just give it to you. Let's change the 4th and 5th number in our serials to "7" and "7". The math in the function would go like this: 1st_char * 0Ah + 2cnd_char 7 * 0Ah + 7 = 04Dh [...] EAX = EAX * 0Ah EAX = 04Dh * 0Ah = 0302h Off course, you can try to find out another combination. Remember you just changed part of the serial that get checksumed in the next part of the keygen routine, so get back in the tutorial to that part and fix the checksum. By now the serial looks like this: UNI77B432109870306 and if we correct the checksum, it will be like this: UNI77B432109870307 So what now? Ofcourse, test thr key you just got!!! :D As a final resume of the whole tutorial, we can create the following structure about the serial: /------------/----- Checksumed part of the serial / / UNI??B????????0307 \ /|/|| || | | | |\ /\ / | | | \ / \/ | | | \ / \-- Checksum of the serial, from 1st chat to 13th char | | | \/ | | | \-------- Bunch of numbers that difference the serials | | \------------- Static value | \--------------- Key Identification (trial extend, full version etc) \----------------- Static value Greets: ~~~~~~~ DR, ENFUSiA and LUCiD ppl, N2C for giving newbies a choice, the whole scene if you wanna contact me, come to #New2Cracking in the EFnet and laeve me you e-mail at one of the operators, i'll contact you as soon as i'll get the message, PhANt0m.049E14C