Author Falcon
Target PhoX crackme 7
Public Release  Sunday,16 of July,2000
Author Contact falcon_geno@mail.ru
Dedication Irwin Shaw
Difficulty Level (1..7) 3 (MEDIUM)
Tools Required SoftIce 3.xx.;WinDasm;HIEW
 

Disclaimer: Please note, the information herein is copyright to Hellforge. No portion of this text may be duplicated. Furthermore, damage or problems arising after reading this text is left to the users disposal. Neither Hellforge, nor its members can be held responsible for any direct or indirect result of following this text. The full liability of following this text is on the reader (YOU). The information is provided for educational purposes, misuse of this information is strictly prohibited. If you do not agree with this agreement, then please hit the "back" button on your browser, and go to hell. - Mercution.
 

Introduction
 

Today I wanted to share with one of the methods that I used for cracking this nice program from Phox. Although, he was saying about 2 methods I could find only one of available. The interesting thing in this program is that it has a some aspects of REVERSING (It deals with proper functioning of the programs), as I said it, in this tutorial will be some stuff I did not talk in my previous tutorials about. The program requires patching, in fact we need to change 2 bytes. In this tutorial, you're going to understand how to make PATCHERs (Programs that change initial code to make it work as WE want) and how to make BRUTE FORCERs (A program  made by a cracker to calculate a number or a sequence of chars (word), later you will know all the rules about it.)
 
Tutorial
 
Beginning:
    The size of the CrackMe is relatively small, so I can conclude that it was coded in Winasm. Usually, this kind of programs break when you set following breakpoints:
1) GetWindowTextA
2) GetDlgItemTextA ...There are more breakpoints, but let's set only these 2.

-    Execute the program and activate Soft-Ice
-    Enter anything as your Serial
-    Set these breakpoints and Press 'OK' button, and you will break at GetWindowTextA
-    Press F11 and let's examine the code carefully, you'll see...

*Referance To: User32.GetWindowTextA, ord:0000h

004011E4    CALL   0040131E
004011E9    PUSH   DWORD PTR [00402044]
004011EF    CALL   0040126F
004011F4    CMP    EAX, 00000001
004011F7    JNE    00401217
004011F9    PUSH   00000030

 
*Possible StringData Ref from Data Obj -> "*BEATEN*"

004011FB    PUSH    0040208A
 
*Possible StringData Ref from Data Obj -> "*mumble*"

00401200    PUSH    00402093

Comments:

This piece of code was taken after DisAssembling this CrackMe using WinDasm... Examining this code, we can conclude that the main program code, where all calculations and comparing routines will take place in the CALL at 004011EF address, because after it goes a Compare operation after which the program Jumps (or does not Jump) depending on the value of EAX. So, the first thing that I did it was Tracing Into (F8) the CALL at 004011EF, so let's do it. YOU we see... Note: I will explain how to make this program say that we crack it from the very beginning, showing how to analyze the program code...

*Referenced by a Call at Address:
 :004011EF

0040126F    C8000000       enter    0000,00
00401273    53             push     ebx
00401274    52             push     edx
00401275    FF354C204000   push     dword ptr [0040204C]

*Reference To: User32.GetWindowTextLengthA, Ord:0000h

0040127B    E8AA000000     Call  0040132A   {See below comments about this CALL}
00401280    8BC8           mov   ecx, eax
00401282    33C0           xor   eax, eax
00401284    B89C204000     mov   eax, 0040209C
00401289    803800         cmp   byte ptr [eax], 00
0040128C    746A           je    004012F8
0040128E    33DB           xor   ebx, ebx
00401290    33D2           xor   edx, edx

Comments:

You may be thinking now- Why did that Falcon stopped just before the main Calculation Routine starts? I did it because this was the piece of code where I confused. You see, this API (GetWindowTextLengthA) takes the length of the serial that you specified in that EditBox of the form, but something strange happened when you traced through this line: 0040127B    E8AA000000           Call      0040132A As you, probably, know: When you trace this CALL, the EAX register should indicate the length or your Serial, and if you did Enter something it must show the length, but IT DOES NOT...The author did it unendingly, for confusing crackers from their primary objective (Serial), but let's not panic and do something...

Let's deactivate current breakpoint and ser another one.
-    Type bc *
-    Set bpx GetWindowTextLengthA
-    Press again the 'OK' button =>Soft-Ice breaks
-    Press F11 and you will be seeing...

004011C5    FF35502040000   push  dword ptr [00402050]

*Reference TO: User32.GetWindowTextLengthA

004011CB    E85A0100000     Call  0040132A         {Length of the Serial goes to EAX}
004011D0    83F800          cmp   eax, 00000000     {CoMPares if EAX is equal to Zero}
004011D3    7460            je    00401235         {Jump to 'Bad' message if Equal}
004011D5    33C0            xor   eax, eax         {EAX is equal to Zero after operation}
004011D7    6A28            push  00000028         {Stores in the stack this number (28h) }

Comments:

Was not it strange, that this time in EAX, was the correct Serial length? The reason to this is that BEFORE Soft-Ice breaks; A number, that is located at 00402050, is stored in the stack. Considering this number Program gets the right Serial length, so let's think a little bit and... We can conclude that in previous piece of code (Where I get confused), there was another number. Let's compare these two:

1) 00401275  FF354C204000    push   dword ptr [0040204C]    {This goes from confused code}
2)
004011C5  FF3550204000    push   dword ptr [00402050]    {This is right code}

So, what do we do?
Now, we are going to patch this Confused code, so that program takes GOOD Serial length.
-    Firstly, we have to find offset, where Bad code is located. For reaching this goal we are going to use WinDasm
-    Open this CrackMe with Wdasm and goto Address 00401275,
-    You have to memorize this offset
-    Open with CrackMe with HIEW, Press F5 and write this offset (It must be...875)
-    Press Enter and you are in the right place, now press F3 and change 4C to 50,
-    Press F9 for updating the program with changes, and that's all...(Or not???)
-    Set bpx GetWindowTextLengthA again and press once F5 and then F11 and you will see...

00401275    FF354C204000       push     dword ptr ([0040204C]  will become) [00402050]

*Reference To: User32.GetWindowTextLengthA, Ord:0000h

0040127B    E8AA000000   Call    0040132A                {And after this CALL, EAX takes real Serial length, so we did good job reaching second interesting part.}
00401280    8BC8         mov     ecx, eax               {MOVes length of Serial to ECX}
00401282    33C0         xor     eax, eax                {XORes EAX with EAX, so EAX=0}
00401284    B89C204000   mov     eax, 0040209C        {Here is interesting point, see below}
00401289    803800       cmp     byte ptr [eax], 00 {It check current char code with 00}
0040128C    746A         je      004012F8                {It will Jump if it's equal to 00.Without any additional preparation for getting to Calculations of Serial you will always Jump to the BAD routine, so let's see}
0040128E    33DB         xor     ebx, ebx
00401290    33D2         xor     edx, edx

Look again at the line at 00401284 address! It seems to me that to EAX register must be MOVed address where you Serial is located, BUT... when you type d 00402084, can you see your Serial? I guess not, so author made again the trick.

-    Let's examine the program code again.
-    Deactivate current breakpoint and set another one (bpx GetWindowTextA) {This API is used for storing information that you enter in the EditBox at address, so we have to point our attention to this brealpoint}
-    Press 'OK' button and you see...

004011D9    689C204000       push    0040209C
004011DE    FF354C204000     push    dword ptr [0040204C]

*Referance To: User32.GetWindowTextA, ord:0000h

004011E4    CALL   0040131E                      {See below comments about this CALL}
004011E9    PUSH   DWORD PTR [00402044]
004011EF    CALL   0040126F
004011F4    CMP    EAX, 00000001
004011F7    JNE    00401217
004011F9    PUSH   00000030

Comments:
Firstly, I wanted to say something about line at 004011D9. The program PUSHes into the stack this address, because that's location of our Serial, but when you trace this line :  004011E4    CALL    0040131E and when you type:  d 0040209c   you do not see the Serial that you entered, but we can fix this. Author uses the same trick...004011DE    FF354C204000        push    dword ptr [0040204C]    Does this line reminds you something? Yeah, that's right! I remember that we had to change 4C to 50...Do it here also, use the same steps that I gave you for changing it... As, you did it, (Offset must be 7DE), set again bpx GetWindowTextA and when you got to Soft-Ice type: d 0040209C and you will see the Serial....WE HAVE ACCOMPLISHED THE PREPARATION PART, let's move to Serial Calculations. But before doing this let me show you how to make a PATCHER (for more convenience).

PATCHER:


{This patcher was made in PASCAL, and I am quite sure you will understand what it does...}
 

Uses Crt;

 Const A: Array[1..2] of Record
                          A : Longint;
                          B : Byte;
                         End =
((A:$877;B:$50),(A:$7e0;B:$50));

Var Ch:Char;
    I:Byte;
    F:File;

Begin
ClrScr;
 Writeln('Falcon''s Patch');
 writeln('Crack for Phox''s Crackme#7.0');
 Assign(F,'crackme7.EXE');
 {$I-} Reset(F,1); {$I+}
 If IOResult <> 0 then
    begin
    Writeln;
    writeln('File not found!');
    writeln('Make sure that this patcher is located with CrackMe in same folder!');

    Readln;
    halt(1);
    end
  Else
  Begin

For i:=1 to 2 Do
Begin
  Seek(F,a[i].a);        {This command move the cursor to the following offset}
  Ch:=Char(a[i].b);
  Blockwrite(F,Ch,1);  {Here we change byte to 50h}
End;

 Writeln('File successfully patched!');
 Write('Press Enter to terminate the program.');
 Readln;
 End;
End.
 

Let's figure out how to find the Serial for this CrackMe:

0040126F    C8000000       enter    0000,00
00401273    53             push     ebx
00401274    52             push     edx
00401275    FF354C204000   push     dword ptr [00402050]

*Reference To: User32.GetWindowTextLengthA, Ord:0000h

0040127B    E8AA000000     Call    0040132A                      {Moves the length of Serial to EAX}                    
00401280    8BC8           mov     ecx, eax                        {Value of EAX is MOVed to ECX}
00401282    33C0           xor     eax, eax                        {EAX xor EAX makes finally Zero}
00401284    B89C204000     mov     eax, 0040209C             {MOVes address where Serial is to EAX}
00401289    803800         cmp     byte ptr [eax], 00        {CoMPares first char code with 0}
0040128C    746A           je      004012F8                      {Jump if Equal}
0040128E    33DB           xor     ebx, ebx                        {EBX xor EBX makes finally Zero}                      
00401290    33D2           xor     edx, edx                        {EDX xor EDX makes finally Zero}

*Referenced by (U)nconditional or (C)onditional Jump at Address
 :004012A5

 
00401292    MOV    BL, BYTE PTR [EAX]                       {MOVes current char code to BL register}
00401294    PUSH   ECX                                                  {Value of ECX is stored in Stack}
00401295    XOR    CL, BL                                               {Now, ECX takes new value after CL=CL xor BL}
00401297    ROR    EBX, CL                                            {Rotates Operand (EBX) Right by CL units}
00401299    ROL    ECX, 03                                             {Rotates Operand (ECX) Left by 3 units}
0040129C    SHL    EBX, CL                                            {SHifts operand Left by CL units, in fact EBX=EBC*2^CL}
0040129E    POP    ECX                                                   {Restores value, that was pushed, in ECX }
0040129F    ADD    EDX, EBX                                         {ADDition of 2 operands, EDX=EDX+EBX}
004012A1    INC    EAX                                                  {shifts to the next char}
004012A2    CMP    BYTE PTR [EAX], 00                       {CoMPare char code with 0}
004012A5    JNE    00401292                                        {Jump to the start of the LOOP if Not Equal to 0}

Comments:

Actually, there is nothing much to say. All the operations are known for you, and considering the fact that WE do not know the Serial itself and the Serial length is also unknown, we have to create a Brute Forcer. When you pass this piece of code-the final value will be in EDX register and now, the only thing we need from Soft-Ice is to know what must be the chars after passing all these commands...

-    Let's see...

004012A7    PUSH    EDX
004012A8    PUSH    00402058
004012AD    PUSH    004020B5                {As I said before the address that is pushed to stack before API that I described before will be the address where the final sum, (from EDX register ) will appear as String}
004012B2    CALL    USER!wsprintA         {This procedure will store the final resul that is in EDX register by the address from which it will take all the numbers one by one for comparing, you will see it right away...}

004012B7    XOR     EBX,EBX
004012B9    MOV    EBX, 004020B5          {Loads the addres,where the SUM is located, to EBX Register. Now, it will compare numbers...Here, you will see that your sum is a string, the author made it being so, for comparing all chars of this string with 'GOOD' ones}
004012BE    CMP    BYTE PTR [EBX], 44                 {CoMpare first char of the SUM with 'D' }
004012C1    JNZ    004012F8                                 {Jump to 'Bad cracker' if they are not equal }
004012C3    CMP    BYTE PTR [EBX+1], 33            {CoMpare second char of the SUM with '3' }
004012C7    JNZ    004012F8                                 {Jump to 'Bad cracker' if they are not equal }
004012C9    CMP    BYTE PTR [EBX+2], 46            {CoMpare second char of the SUM with 'F'}
004012CD    JNZ    004012F8                                 {Jump to 'Bad cracker' if they are not equal }
004012CF    CMP    BYTE PTR [EBX+3], 38            {CoMpare second char of the SUM with '8' }
004012D3    JNZ    004012F8                                 {Jump to 'Bad cracker' if they are not equal }
004012D5    CMP    BYTE PTR [EBX+4], 42            { CoMpare second char of the SUM with 'B'}
004012D9    JNZ    004012F8                                {Jump to 'Bad cracker' if they are not equal }
004012DB    CMP    BYTE PTR [EBX+5], 31            {CoMpare second char of the SUM with '1' }
004012DF    JNZ    004012F8                                {Jump to 'Bad cracker' if they are not equal }
004012E1    CMP    BYTE PTR [EBX+6], 30            {CoMpare second char of the SUM with '0' }
004012E5    JNZ    004012F8                                 {Jump to 'Bad cracker' if they are not equal }
004012E7    CMP    BYTE PTR [EBX+7], 43            {CoMpare second char of the SUM with 'C' }
004012EB    JNZ    004012F8                                 {Jump to 'Bad cracker' if they are not equal }
004012ED    MOV    EAX, 00000001                  {If you pass all these compares then EAX takes value of 1..}
004012F2    POP    EDX                                       { Restores last info, that was pushed, from stack to EDX }
004012F3    POP    EBX                                       { Restores pre-last info, that was pushed, from stack to EDX }
004012F4    LEAVE                                             {Almost Abandoned the CALL }
004012F5    RET                                                  {RETurn from CALL to main program }
004011F4    CMP    EAX, 01                                     { If EAX =1 then jump to good message }
004011F7    JNZ    004011D1                                 { If EAX is not equal to 1 then jump to 'BAD' }

Calculation of the Serial:

Before we prepare a Brute Forcer, let me explain what it is. A bit of theory will be just good...

BRUTE FORCER

-is a program that was prepared by a cracker for finding the final result using the power of his/her Personal Computer. Usually it is prepared when the Serial is HardCoded and when the Serial is Encrypted.
a) If the final goal is a Number then the principle is like this:
-    Coder declares a COUNTER, that will undergo all the calculations that are necessary for reaching the final value. Usually, the initial value is COUNTER=0, but it can be changed depending on the calculations in the program, but this can be decided only by experienced cracker.
-    As it passed all the calculations, the counter is compared with final value and if it is not equal to it then the counter is increased by one, and cracker must start all the calculations from the beginning, and it will last until computer find a Real Serial (Number)
b) If the final goal is a Word (Like in this CrackMe) the principle is a little bit different:
-    Firstly, cracker should know the length of the Serial, otherwise it will be very hard to get the right Serial (btw: here we also do not know what's the length of Serial), and depending on the length of Serial he/she will construct the proper code
-    Cracker constructs as many loops as is the length of the Serial, but these loops must be one in another (you will see it soon), and the calculations on chars of the word are in the final loop.
-    Comparison with Final Word is also in the final loop, and if it's not equal, just counter of this loop increases not begins from the beginning, so let's see, huh?

BRUTE FORCER:

It was prepared in Delphi, almost the same as PASCAL, so I think also will be understandable, also here is a piece in inline ASM, that will be for sure not a problem!

procedure TForm1.Button1Click(Sender: TObject);
const
     n=6; {Number of loops}
     Comp_Number:cardinal=$d3f8b10c;
var
        UserName:string[20];
        F:File;
        Serial:string;
        Main_Number:cardinal;
        a,b,c,d,e:byte;
        aa:byte;
        ar:array [1..n] of byte;
        t:byte;  {counter for array}
Begin
Serial:='';
UserName:=Form1.Edit1.Text;
AssignFile(F,'Result.txt');
ReWrite(F,30);
 

For a:=65 to 122 Do
Begin
  For b:=65 to 122 Do
  Begin
      For c:=48 to 122 Do
      Begin
         For d:=48 to 122 Do
         Begin
             For e:=48 to 122 Do
             Begin
               For aa:=48 to 122 Do
               Begin

                  ar[1]:=a;
                  ar[2]:=b;
                  ar[3]:=c;
                  ar[4]:=d;
                  ar[5]:=e;
                  ar[6]:=aa;

                  asm
                      mov esi,edi
                      xor ecx,ecx
                      add esi,n
                      mov byte ptr [esi+n],00h
                      mov cl,n

                      xor ebx,ebx
                      xor edx,edx
                      mov eax,esi
                 @1:  mov bl,byte ptr [eax]
                      push ecx
                      xor cl,bl
                      ror ebx,cl
                      rol ecx,03h
                      shl ebx,cl
                      pop ecx
                      add edx,ebx
                      inc eax
                      cmp byte ptr [eax],00
                      jnz @1

                      Mov Main_Number,edx
                  end;

                 Serial:='';

                 If Main_Number=Comp_Number Then
                 Begin
                  For t:=1 to n Do
                    Serial:=Serial+chr(ar[t]);

       { Here you could add one more command, as you reached this point you can jump out of the program to terminate it using GOTO command, in fact that would be better to do, 'coz until the program finishes your PC can explode }
                    BlockWrite(F,Serial[1],1);
                  End;
                            End;
                     End;
             End;
      End;
End;
End;

end;

Comments:
    You may ask me, how did I know that the length of Serial will be 6, in the beginning I did not know it!
I had to check what should that be?! I thought that there is no name for a parfume with less than 4 chars in it, so my Brute Forcer consisted, firstly, from 5 loops. I failed to find the Serial, so I changed it to 6, and I was RIGHT!

Serial: 2XDrvB

If I was wrong somewhere or if you like this tut, or you have any complains just mail me, I will think about your suggesting.
 
Final Thoughts
 
I remember when Phox suggested this crackme to me, saying 'You will like it Falcon...', let me give you one advice, if you people want somebody to like your crackmes very much try to find a very good Mathematical algorithms that does not require Brute Forcing...Anyway, that's my opinion.
 
Greetings to...
 

All members from Genocide Crew     http://www.genocidecrew.cjb.net/

All members from Hellforge                http://www.hellforge.org
Enormous thanks goes and Mercution {his design of this tut} for providing HellForge with glorious LOGOs

To every one who makes tutorials…
Cool coders:
        Terminal Cilla, AntiXrist, Chafe, The+Q, LaZaRuS, defiler, Lucifer48, Fatboy Joe
        CzDrillard { he is great in making good Math algos}
Crackers  :
        SiFLyiNG, mIST, C_DKnight, TSCube (my special greetings to you, friend), and everybody I forgot to add...
Special greetings:
        Eternal Bliss and ID people

 
The end.
Any mistakes, corrections, or comments may be mailed to the members individually, or to the group : hellforge@hellforge.org.