Target : Easy Screensaver Maker Version 1.2 URL : http://www.easy-screensaver-maker.com Date : 27/10/2002 Tools : SoftICE (any version),W32Dism++,File insPEctor XL Written by : Khan (I wrote this tut same time while working on the program.It's kinda a tut of my thinking way.) ---------------------------------------------------------------------- For educational purposes only! I hold no responsibility of the mis-used of this material! ---------------------------------------------------------------------- After installing the program,let's analyze it first. Right click on screensavermaker.exe and choose "file insPEctor" . This file analyzer gives you information about the exe file.We see that it's compiled with Borland Delphi 3.0 ,good it's not a packed/protected file :) It means we will skip one step.Let's take a look at its imports, hmmmm we may try messageboxa in user32.dll if we have a "invalid registration code" message. Ok,let's start our program.Under help/enter registration code let's enter any name and key: Name : khan Key : 11112222 "Sorry, the registration code is wrong.Please check it and try again." Hmmmm,ok,let's check it then :) Let's disassemble our exe in w32Dism++.Find this message in String Ref. Double click on the message and we land here : * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004F55D3(C) | :004F569A 6A00 push 00000000 :004F569C 668B0DE4564F00 mov cx, word ptr [004F56E4] :004F56A3 B202 mov dl, 02 * Possible StringData Ref from Code Obj ->"Sorry, the registration code is " ->"wrong. Please check it and try " ->"again." | :004F56A5 B888574F00 mov eax, 004F5788 ------- (we land here) We see above that there's a conditional jump at 004F55D3.Let's go there : :004F55CC E82BB5FCFF call 004C0AFC :004F55D1 84C0 test al, al :004F55D3 0F84C1000000 je 004F569A :004F55D9 6A00 push 00000000 :004F55DB 668B0DE4564F00 mov cx, word ptr [004F56E4] :004F55E2 B202 mov dl, 02 * Possible StringData Ref from Code Obj ->"Thanks for registering!" | :004F55E4 B8F0564F00 mov eax, 004F56F0 Oh,nice :) There's a call at 004F55CC, then checking al and jump to Badboy or continue to GoodBoy message:"Thanks for registering."In other word,test if al=0. if so, jump to 004F569A (where leads us to badboy message).Otherwise, don't jump and go to goodboy message :) It's time to set a breakpoint in SoftICE. Let's check what's going on in the call 004C0AFC and what makes al=0 (bad) Our "Enter Registration Key" window is still open and we have fake name/key entered.We need to break into the program first to put a breakpoint on 4C0AFC. Press Ctrl+d to fire up SoftICE,type "bpx messageboxa" and Ctrl+d again to quit. Press OK to validate our fake name/key.Oh whaaaat? it didn't break on messagebox . Hmmmm let's check the imports in file insPEctor again. getwindowtexta? let's give it a try, nope, we failed again.Hmmm, destroywindow must break. Type "bpx destroywindow" and quit SoftICE. Press OK now, YESSSS we break :) Press F12 once to go back to screensavermaker.exe Ok we can set our breakpoint now :bpx 004C0AFC. Quit SoftICE and press OK. We break at the beginning of our call : :004C0AFC 55 push ebp :004C0AFD 8BEC mov ebp, esp :004C0AFF 83C4E8 add esp, FFFFFFE8 ................. All we have to do is to trace this subroutine step by step with F10 and try to understand what's going on. ................ :004C0B60 E8AB3FF4FF call 00404B10 :004C0B65 83F820 cmp eax, 00000020 :004C0B68 7407 je 004C0B71 :004C0B6A 33DB xor ebx, ebx :004C0B6C E9CA000000 jmp 004C0C3B ................ The call at 004C0B60 gets the length of the serial entered,then compares it to 20hex or 32decimal.If the length is not 32 characters,we jump to the end of the subroutine with al=0 in hand (bad!) So,we need to change our fake serial to a 32 char one.Let's set a breakpoint at 004C0B60 and quit SoftICE. Name : khan Key : 11112222333344445555666677778888 When we hit OK, SoftICE breaks.Now serial length check passes and we can keep tracing with F10 :) ............... :004C0B82 8B45F8 mov eax, dword ptr [ebp-08] : gets our fake serial into EAX :004C0B85 8B16 mov edx, dword ptr [esi] : EDX=0 :004C0B87 8A0410 mov al, byte ptr [eax+edx] : gets the 1st char. of our serial into AL. :004C0B8A E841FFFFFF call 004C0AD0 : this call compares AL to a letter/number train and loads ECX and EAX with the order number of AL in this train : ABCDEFGHIJKLMNOP QRSTUVWXYZabcdef ghijklmnopqrstuv wxyz0123456789 The order no is as follows (from left to right,in hex) : (A=0,B=1,C=2,...,O=E,P=F,Q=10,......e=1E,f=1F,g=20,....u=2E,v=2F,w=30,....... 1=35,2=36,....9=3D) This call simply determines the order no of AL and load ECX and EAX with this. Because our 1st char is 1, ECX=EAX=35) :004C0B8F 8BD8 mov ebx, eax : stores this no in EBX :004C0B91 8B07 mov eax, dword ptr [edi] : EAX=1 :004C0B93 8B55F8 mov edx, dword ptr [ebp-08] : EDX keeps fake serial :004C0B96 8A0402 mov al, byte ptr [edx+eax] : gets the 2nd char into AL :004C0B99 E832FFFFFF call 004C0AD0 : same call above :004C0B9E 8945F0 mov dword ptr [ebp-10], eax : EAX=35 again :004C0BA1 8D430F lea eax, dword ptr [ebx+0F] : EAX=1st char+0F =35+0F=44 :004C0BA4 B93E000000 mov ecx, 0000003E :004C0BA9 99 cdq :004C0BAA F7F9 idiv ecx : idiv divides 64 bit value in EDX:EAX by the operand (ECX here).EAX keeps the quotient and EDX keeps the remainder. 44/3E=1 quotient,6 remainder :004C0BAC 8BDA mov ebx, edx :EDX=EBX=6 :004C0BAE 3B5DF0 cmp ebx, dword ptr [ebp-10] :compares the value in EBX (remainder of the division) to the order no of 2nd char. :004C0BB1 7407 je 004C0BBA :if same jump :004C0BB3 33DB xor ebx, ebx :otherwise clear EBX :004C0BB5 E981000000 jmp 004C0C3B :jump to the end of routine :004C0BBA 83C704 add edi, 00000004 :004C0BBD 83C604 add esi, 00000004 :004C0BC0 FF4DF4 dec [ebp-0C] :loop this procedure 16 times :004C0BC3 75BD jne 004C0B82 :go to the start to compare the other chars of serial. ............... If we trace the code above step by step, we see that it takes a character from our serial,determines its order no in the train,adds 0F,divides the result by 3E and compares the remainder of this division to the second character's order no.It does this check 16 times. For example in the 1st loop, it takes the 1st char. of our serial :1. The order no in the train is 35. It adds 0F and we have 35+0F=44.Then it divides this by 3E and we have 6 as remainder of this division.It takes the 2nd char. of our serial :1. The order no in the train is 35 again. It compares this value to the remainder. Let's think a little bit here.Which character's order no in the train is 6? so that we can pass the comparision.(A=0,B=1,C=2,D=3,E=4,F=5,G=6,....) the answer is G. If we change the 2nd char of our serial from 1 to G 1G112222333344445555666677778888 we pass the 1st comparision. This is the logic we should follow.After we trace and change the 2nd chars for 16 loops,we get this serial: 1GHH2222H3K34J44555H6LK6I7LINJJ8 Let's keep tracing: :004C0BC5 8B45FC mov eax, dword ptr [ebp-04] :EAX holds our name :004C0BC8 8A00 mov al, byte ptr [eax] :al=6B (khan) :004C0BCA E801FFFFFF call 004C0AD0 :order no of k=24 :004C0BCF 8BD8 mov ebx, eax :004C0BD1 8D430F lea eax, dword ptr [ebx+0F] :24+0F=33 :004C0BD4 B93E000000 mov ecx, 0000003E :004C0BD9 99 cdq :004C0BDA F7F9 idiv ecx :EAX=0,EDX=33 :004C0BDC 8BDA mov ebx, edx :004C0BDE 8BC3 mov eax, ebx :004C0BE0 E803FFFFFF call 004C0AE8 :this call makes EAX=7A :004C0BE5 8B55F8 mov edx, dword ptr [ebp-08] :EDX holds serial :004C0BE8 8B0DDC7D4F00 mov ecx, dword ptr [004F7DDC]:ECX=10h :004C0BEE 3A040A cmp al, byte ptr [edx+ecx] :compares EAX=7A to the 17th (10h) char.of our serial=5. :004C0BF1 7404 je 004C0BF7 :if equal,jump :004C0BF3 33DB xor ebx, ebx :004C0BF5 EB44 jmp 004C0C3B :otherwise,BAD ! The code above gets the first char of our name (k),determines its order no in the train (24),adds 0F (24+0F=33),divides by 3E,gets the remainder,makes EAX hold the value in the train which remainder points (7A=z),compares this value to the 17th char. of serial=5. To be able to pass the comparision,all we need to do is changing 5 to z : 1GHH2222H3K34J44z55H6LK6I7LINJJ8 Let's keep tracing : :004C0BF7 8B45FC mov eax, dword ptr [ebp-04] :EAX holds our name :004C0BFA E8113FF4FF call 00404B10 :this call gets the length of our name =4 :004C0BFF 8B55FC mov edx, dword ptr [ebp-04] :004C0C02 8A4402FF mov al, byte ptr [edx+eax-01]: AL holds the last char. of our name =n or 6E :004C0C06 E8C5FEFFFF call 004C0AD0 : :004C0C0B 8945F0 mov dword ptr [ebp-10], eax :004C0C0E 8B45F0 mov eax, dword ptr [ebp-10] :004C0C11 83C00F add eax, 0000000F :004C0C14 B93E000000 mov ecx, 0000003E :004C0C19 99 cdq :004C0C1A F7F9 idiv ecx :004C0C1C 8955F0 mov dword ptr [ebp-10], edx :004C0C1F 8B45F0 mov eax, dword ptr [ebp-10] :004C0C22 E8C1FEFFFF call 004C0AE8 :this call makes EAX=32 :004C0C27 8B55F8 mov edx, dword ptr [ebp-08] :EDX holds serial :004C0C2A 8B0DE07D4F00 mov ecx, dword ptr [004F7DE0]:ECX=19h :004C0C30 3A040A cmp al, byte ptr [edx+ecx] :compares AL=32 to the 26th (19h) char. of our serial=7 :004C0C33 7404 je 004C0C39 :if equal,jump :004C0C35 33DB xor ebx, ebx :004C0C37 EB02 jmp 004C0C3B :otherwise,BAD! The code above gets the last char of our name (n),determines its order no in the train (27),adds 0F (27+0F=36),divides by 3E,gets the remainder,makes EAX hold the value in the train which remainder points (32),compares this value to the 26th char. of serial=7. To be able to pass the comparision,all we need to do is changing 7 to 2 (32h) : 1GHH2222H3K34J44z55H6LK6I2LINJJ8 We're almost at the end of routine.Let's keep tracing a little bit more, YESSS, AL becomes 01 and we get "Thanks for registering!" message :) That's all for now. See you next time. Khan Contact me: khanxir@hotmail.comsure that each character from K3 is printable. Each character will have an ASCII value between 20 and 7E. For instance, here we have K3: ]>QuH}