home *** CD-ROM | disk | FTP | other *** search
- 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.
-
-