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.