Thursday, December 15, 2011

ASM tutorial

Welcome to XLogic's Assembly KeyGen tutorial.

What you will need:
TASM 3.0 or higher (Comes with TD).
A Good Text Editor (EDIT.COM).
A Good Dos Debugger (I will use TD, S-ICE and DG are also Acceptable).
A File access monitor (SCANF is included).
An ASM Command Listing (go buy a book).
A GOOD (intermediate) knowledge of ASM. <-- Don't bug me for help.
X-Tract 1.51 (included).

1. Introduction.
This was the first key generator I ever wrote.  It taught me more about
assembly than any book I've read, considering that I originally
learned assembly from debugging stuff.

This is a very easy keygen to do, but you use the same process to write
other much more complex keygens.

The best way of writing a keygen in my experience is:
1.  Debug, dissasemble, do whatever is necessary to UNDERSTAND what the hell
    the program is doing.
2.  Extract the relevant code, reverse it or whatever needs doing to make it
    ready for the keygen.
3.  Write the keygen.
4.  Use a key you made, debug the program, and make sure it works 101%.

2. Let's Get Started!
Ok, look at the program, how it runs. See if it prompts for a reg number,
if it looks for a key file, any way it gets registration in.

With X-Tract, there are no prompts for reg numbers, or anything.
Ok, so now you run a file access monitor, to check if it looks for a reg
key.  (I have included a good file access monitor with the package, SCANF.
To make it put file access up on the screen, use "scanf con" to run it)
Bingo.  It looks for X-TRACT.KEY.

Now the debugging starts.  First create a file called X-TRACT.KEY in the
same directory as X-Tract, and load your debugger.  Step through with the
file access montior loaded to see where it opens the key file.

You trace over the following call, and the file monitor tells you that the
key has been opened.

  cs:366B 2EA27908       mov    cs:[0879],al
  cs:366F 9C             pushf
  cs:3670 E8D71A         call   514A

Now you restart debugging and trace one instruction into that function call.
You trace over the first function call, and notice that it displays the
startup banner:
X-TRACT (tm)   Executable File Extractor  Version 1.51  7-26-95
Copyright 1994-95 by Pablo Carboni. All Rights Reserved.

The next block of code uses an Int 21h call.
You notice that this is what opens the file.
Int 21h's usage is as follows:
ah = 3D                 ; Open file Handle for file access
al = 02                 ; file access code
dx = filename offset    ; Where the filename is in memory
Int 21h                 ; Try to open the file
jnb ok                  ; If the file exists, and has been opened, jump
jmp error               ; If the file hasn't been opened, jump.

So what this block of code does is try and open the file.
  cs:5150 B8023D         mov    ax,3D02
  cs:5153 BAFC21         mov    dx,21FC
  cs:5156 CD21           int    21
  cs:5158 7303           jnb    515D
  cs:515A E9ED00         jmp    524A

Since you made a file called X-TRACT.KEY before you started debugging
it should jump on the first jump.
You then end up here:
  cs:515D 2EA3D805       mov    cs:[05D8],ax
  cs:5161 B43F           mov    ah,3F
  cs:5163 2E8B1ED805     mov    bx,cs:[05D8]
  cs:5168 B99B00         mov    cx,009B
  cs:516B BABD00         mov    dx,00BD
  cs:516E CD21           int    21
  cs:5170 3D9B00         cmp    ax,009B
  cs:5173 7303           jnb    5178
  cs:5175 E9D200         jmp    524A

The first line stores the files handle for future access from AX to
memory location 05D8h.

Now, we see another Int 21h call coming up.  This time it is as follows:
ah = 3Fh                ; Read Data from the open filehandle in BX
bx = [05D8h]            ; get the file handle we saved just before.
cx = 9Bh                ; How many bytes we want to try and read.
dx = 0BDh               ; Where we want to put the read bytes.
Int 21h                 ; Do the deed

When this returns, AX will be the actual number of bytes read from the file.
So what is this next piece of code doing?
  cs:5170 3D9B00         cmp    ax,009B
  cs:5173 7303           jnb    5178
  cs:5175 E9D200         jmp    524A
Its checking if it could read 9Bh bytes from the file, and if it could,
continue.

As you should have noticed, if any of the previous tests have failed, they
jump to location 524Ah. Keep this in mind when you are debugging the code.

Now you hit this big lump of code:
  cs:5178 BEBD00         mov    si,00BD
  cs:517B BF5521         mov    di,2155
  cs:517E B99A00         mov    cx,009A
  cs:5181 0E             push   cs
  cs:5182 1F             pop    ds
  cs:5183 0E             push   cs
  cs:5184 07             pop    es
  cs:5185 FC             cld
  cs:5186 F3A6           rep cmpsb
  cs:5188 7403           je     518D
  cs:518A E9BD00         jmp    524A
rep cmpsb....... hmmm, a byte-by-byte compare statement.
how this is called is:
cx = Number of bytes to compare
DS:DI = First lot of bytes to compare
ES:SI = Second lot of bytes to compare
rep cmpsb       ; do the compare
je continue     ; jump here it the same
jmp error       ; jump here if not the same

So what should be at the start of the rego key?
Whatever is at ES:DI.  The other location has what was in the rego key
that you created.

Now you get to this:
  cs:518D AC             lodsb
  cs:518E 3CE0           cmp    al,E0
  cs:5190 741B           je     51AD
And a few more with different compares.  It is checking if one of these
is equal to the byte it loaded from DS:DI (its there from after the 1st
compare).

Could it be checking for the type of registration?  Lets continue and see.
  cs:51AD 2EA28008       mov    cs:[0880],al
  cs:51B1 B43F           mov    ah,3F
  cs:51B3 2E8B1ED805     mov    bx,cs:[05D8]
  cs:51B8 B92A00         mov    cx,002A
  cs:51BB BABD00         mov    dx,00BD
  cs:51BE CD21           int    21
  cs:51C0 3D2A00         cmp    ax,002A
  cs:51C3 7403           je     51C8
  cs:51C5 E98200         jmp    524A

It saves the byte it just checked to cs:880h.
Then it does what it did before with Int 21h, it reads 2Ah bytes from the
file to ds:00BDh.  If it could read 2Ah bytes, it continues on, otherwise
it quits.

Now would be a good time to get out of the debugger and make the key file.
9Bh + 2Ah bytes (add the two cx vaules from the file read Int 21h's) is
equal to 197 bytes, so now would be a good time to get out, make a file of
size 197 bytes, With the first lot of data it compared (that string of
bytes), then either a E0h, E1h, E2h or E3h, which it looked for.  I will
use a E0h.

You've got your registration key half done.  After making it, you
should be able to pass all of the tests it performs to the point where we
left off.  If you had problems, have a look at the key that I provided
called XLOGIC.REG to get some hints.

Now you hit this:
  cs:51C8 BEBD00         mov    si,00BD
  cs:51CB 8BFE           mov    di,si
  cs:51CD B92A00         mov    cx,002A
  cs:51D0 2E8A1E8008     mov    bl,cs:[0880]
  cs:51D5 AC             lodsb
  cs:51D6 32C3           xor    al,bl
  cs:51D8 AA             stosb
  cs:51D9 80EB22         sub    bl,22
  cs:51DC E2F7           loop   51D5

Now before i tell you, try and work out what this does.

Here is what it is doing:
1. si = 0BDh    ;the location to start from
2. di = si      ;set the second location to start from
3. cx = 2Ah     ;how many times to loop
4. bl = cs:880h ;get that byte that it checked for earlier
5. lodsb        ;load a byte from ES:SI into al, increment si by 1
6. xor al,bl    ;xor al by bl
7. stosb        ;store al to DS:DI, increment di by 1
8. sub bl,22    ;decrement bl by 22h
9. loop 5       ;loop cx times.

Now, step through this, watching what this does.
What does it do?
It decripts the data after the 0E0h, in the keyfile, using the above process.

If you can't understand this, just keep watching it and debugging it,
because if you can't understand this, you won't be able to write a keygen.

Now it has tried to decrypt your name, and what we're about to look at.

Check this code out:
  cs:51DE BEBD00         mov    si,00BD
  cs:51E1 8BFE           mov    di,si
  cs:51E3 B92800         mov    cx,0028
  cs:51E6 2E8A1E8008     mov    bl,cs:[0880]
  cs:51EB 33D2           xor    dx,dx
  cs:51ED 33C0           xor    ax,ax
  cs:51EF AC             lodsb
  cs:51F0 03D0           add    dx,ax
  cs:51F2 E2FB           loop   51EF
  cs:51F4 2E3B14         cmp    dx,cs:[si]
  cs:51F7 7551           jne    524A

Whats it doing?
You should understand the first 7 lines, actually, you should understand
the whole thing if you have a good grasp of Assembly.

It adds all the bytes together of what "Should" be you name, into dx.
Then it compares dx to the number stored at cs:si.  This is what is called
a CRC check.  This is only a simple one, and all it does is check if any
of the bytes in the string have changed.

If it is the same, it is ok, and continues, otherwise it quits.

Now it sets cs:2220 to 01h, to tell the program it is registered.
  cs:51FC 2EC606202201   mov    cs:byte ptr [2220]
Then it checks the 0E0h byte.  This is where we find out what it does.
  cs:5202 2E803E8008E0   cmp    cs:byte ptr [0880]
  cs:5208 7424           je     522E
So we let it jump:
  cs:522E BA9B22         mov    dx,229B
  cs:5231 E81D00         call   5251
  cs:5234 C3             ret
And it prints on the screen "REGISTERED VERSION".
So what do the other "0E?h" values do?
Go back and try the others to find out for yourself.

IMPORTANT.
If you don't understand all of the above, go over and over it until you do.

2. Writing The KeyGen.

Now I am going to get lazy.  I will tell you what the steps are,
give you my commented source file, and leave you go from there.

Here is what it is doing:
1. Open the Rego File.
2. Read the Header.
3. Check it.
4. Read the Rego Name and CRC.
5. Decrypt them.
6. Calculate the CRC.
7. Check the CRC.
8. Display the Rego type.
9. Continue on with the program.

Here is what you have to do:
1. Read the Rego Name.
2. Calculate the CRC.
3. Encript the Rego name and CRC.
3. Store the Rego type.
4. Write the whole block (including the header) to the Rego file.

Now for the assembly file:
-------------------------------------------------------------------------------
.386p
seg_a segment byte public use16
assume cs:seg_a, ds:seg_a

org 100h

xtract_keygen   Proc Far
start:
                mov     dx,offset title_text       ;load the startup banner
                call    print_text                 ;print it on the screen
                mov     dx,offset max_ent_length   ;load the text entry offset
                mov     ah,0Ah                     ;function=get text string
                int     21h                        ;get the text
                cmp     byte ptr entry_length,01h  ;check if mor than 1
                                                   ;character was entered
                jae     short reg_type_sel         ;jump if 1 or more
                mov     dx,offset no_entry         ;not enough was entered
                jmp     short exit                 ;jump to exit

reg_type_sel:
                mov     dx,offset reg_type_text    ;load rego type selection
                call    print_text                 ;display it
                xor     ax,ax                      ;clear ax
                int     16h                        ;get a char from the keybd
                int     29h                        ;display it
                cmp     al,31h                     ;check if its 1
                jl      reg_type_sel               ;jmp if lower than
                cmp     al,34h                     ;check if its 4
                ja      reg_type_sel               ;jmp if above
continue:
                add     al,0AFh                    ;add 0AFh to input, to get
                                                   ;"E" value.
                mov     reg_type,al                ;store it in the rego type
                mov     dl,0Ah                     ;1 These lines store
                mov     dh,al                      ;2 the rego type
                mov     bx,offset max_ent_length   ;3
                mov     [bx],dx                    ;4
                call    make_key                   ;make the key
                mov     dx,offset done_text        ;load done text
exit:
                call    print_text                 ;display the output result
                retn                               ;exit to dos/windoze
xtract_keygen   endp

print_text      proc    near                       ;put text up on the
                mov     ah,9                       ;screen
                int     21h
                retn
print_text      endp

make_key        proc    near                      
                mov     si,offset name_input       ;this should look
                mov     dx,si                      ;familiar :)
                mov     cx,28h                     ;
                mov     bl,reg_type                ;
                xor     dx,dx                      ;
                xor     ax,ax                      ;
crc_loop:                                          ;
                lodsb                              ;
                add     dx,ax                      ;
                loop    crc_loop                   ;
                mov     bx,offset checksum_dat     ;
                mov     [bx],dx                    ;store the crc

                mov     si,offset name_input       ;this should also look
                mov     di,si                      ;familiar :)
                mov     cx,2Ah                     ;
                mov     bl,reg_type                ;
encription_loop:                                   ;
                lodsb                              ;
                xor     al,bl                      ;
                stosb                              ;
                sub     bl,22h                     ;
                loop    encription_loop            ;

                mov     ah,3Ch                     ;open the file to write
                mov     dx,offset key_name         ;
                int     21h                        ;
                xchg    bx,ax                      ;put filehand in bx
                mov     ah,40h                     ;write the key to disk
                mov     dx,offset key_data         ;
                mov     cx,0C5h                    ;
                int     21h                        ;
                mov     ah,3Eh                     ;close the file handle
                int     21h                        ;
                retn
make_key        endp

title_text      db 'X-Tract 1.51 Key File Generator by XLogic', 0Dh, 0Ah
name_prompt     db 'Enter your name: $'
reg_type_text   db 0Dh,0Ah,'Please Choose Registration Type:',0Dh,0Ah
                db '1. Registered Version',0Dh,0Ah
                db '2. Beta-Test Version',0Dh,0Ah
                db '3. Distro-Site Version',0Dh,0Ah
                db '4. Special Version',0Dh,0Ah
                db 'Enter the number corresponding to the type: $'
no_entry        db 0Dh,0Ah,'You must enter a name.$'
done_text       db 0Dh,0Ah,'Key file X-TRACT.KEY created.$'
key_name        db 'X-TRACT.KEY',0
reg_type        db 0
key_data        dd 073696854h,020736920h,072756F79h,067657220h,072747369h,06F697461h,0656B206Eh,06F662079h
                dd 02D582072h,043415254h,050202E54h,07361656Ch,064202C65h,06F6E206Fh,069642074h,069727473h
                dd 065747562h,021746920h,063280A0Dh,039312029h,062203439h,06F572079h,02C79646Fh,065754220h
                dd 020736F6Eh,065726941h,041202C73h,04E454752h,0414E4954h,06150202Eh,0206F6C62h,06576694Ch
                dd 06F532073h,06877656Dh,020657265h,054206E49h,054206568h,02E656D69h
                db 0Dh
max_ent_length  db 26h
entry_length    db 0
name_input      db 40 dup ('$')
checksum_dat    db 2 dup (0)
seg_a ends
end start
-------------------------------------------------------------------------------

Ok, there it is in all its glory.  I hope you've learned something from this,
and if you did, let me know.  If you didn't, good for you.  Tell me how to
improve this tutorial.

I can be contacted in #PC97 or #cracking on EFNET.

Cya Round.

XLogic.