Fido2Int mailer v. 2.00 Key Generator
A tough Key File Based Protection Scheme

by Aesculapius
(13 September 1997)

Courtesy of Fravia's page of reverse engineering

Well, a very solid reverse engineering essay by a very solid cracker! Enjoy!

		   Fido2Int mailer v. 2.00 Key Generator
		 A tough Key File Based Protection Scheme
			      By Aesculapius

	This essay deals with a tough key file based protection scheme. 
Key file based schemes are those, where certain file, containing encrypted 
data unlocks all registered functions of the target program when it is valid 
and present. The name of this file could be different, but the file name 
extension is very frequently the word 'key' (*.key). To defeat these 
schemes, you must first find out which is the name of the valid key file. 
Some String Search utility (as Search and Replace for Windows 95/NT) could 
be used to gather the key file name. Search for the word 'key'. If you can't 
find it, then, load the main executable of the target program in SoftICE and 
set a breakpoint on BPINT 21H IF AH == 3DH (DOS target) or BPX CreateFile, 
BPX ReadFile (Windows target). You could also disassemble the target program 
with wdsm89 and search for relevant phrases: Unregistered, Registered, key, 
etc. Once you have figured out the key file name, it is time to seek the 
target code locations where this file is opened, read, and how this 
information is manipulated. Sometimes, you'll have the great advantage of 
having a valid key file (a legal valid key file or some key file another 
cracker created before you). If this is the case, you can study the key, to 
learn what's inside it, how many bytes are allocated in the key, what happen 
if you modify the key, etc. In this essay we wont have the great advantage 
of having a valid key. We must figure out everything (the key file name, how 
many bytes it has, how the information is stored inside it, the encryption 
process, etc.).

	Fido2Int, is a very interesting target, I choose it, because the 
encryption process is extremely clever. It took me more than two hours to 
generate a valid key file. You can find the target program at, the file is 328 Kb long. You'll need the following tools: 
Wdsm89, SoftICE for Windows 95 and TASM 5.0.

	Proceed to disassemble the file with wdsm89. Now search for the 
following word: 'UNREGISTERED'. We land here:

 * Referenced by a CALL at Address:00436F5F   
:00434578 55                      push ebp
:00434579 8BEC                    mov ebp, esp
:0043457B 83C4A0                  add esp, FFFFFFA0
:0043457E 803D68D8430000          cmp byte ptr [0043D868], 00; Flag Reg Byte
                                                             ; = 01 Reg.
                                                             ; = 00 Unreg.
:00434585 742F                    je 004345B6		     ; Beggar off!
* Possible StringData Ref from Code Obj ->"!- FIDO2INT 2.00 - REGISTERED "
                                        ->"TO: "
:00434587 BAF4454300              mov edx, 004345F4
:0043458C 8D45A0                  lea eax, dword ptr [ebp-60]
:0043458F E8A4E4FCFF              call 00402A38
:00434594 BAACD94300              mov edx, 0043D9AC
:00434599 8D45A0                  lea eax, dword ptr [ebp-60]
:0043459C B15D                    mov cl, 5D
:0043459E E865E4FCFF              call 00402A08
:004345A3 8D55A0                  lea edx, dword ptr [ebp-60]
:004345A6 8B4508                  mov eax, dword ptr [ebp+08]
:004345A9 8B80B0FDFFFF            mov eax, dword ptr [eax+FFFFFDB0]
:004345AF E828FAFFFF              call 00433FDC
:004345B4 EB26                    jmp 004345DC

* Referenced by a Jump at Address:00434585(C)

* Possible StringData Ref from Code Obj ->"?- FIDO2INT 2.00 - UNREGISTERED "
                                        ->"EVALUATION COPY, PLEASE REGISTER>- "
                                        ->"USE BEYOND THE EVALUATION PERIOD "
                                        ->"OF 21 DAYS IS NOT PERMITTED"
:004345B6 BA18464300              mov edx, 00434618
:004345BB 8B4508                  mov eax, dword ptr [ebp+08]
:004345BE 8B80B0FDFFFF            mov eax, dword ptr [eax+FFFFFDB0]
:004345C4 E813FAFFFF              call 00433FDC
:004345C9 BA58464300              mov edx, 00434658
:004345CE 8B4508                  mov eax, dword ptr [ebp+08]
:004345D1 8B80B0FDFFFF            mov eax, dword ptr [eax+FFFFFDB0]
:004345D7 E800FAFFFF              call 00433FDC

* Referenced by a Jump at Address:004345B4(U) 
:004345DC BA98464300              mov edx, 00434698 
:004345E1 8B4508                  mov eax, dword ptr [ebp+08] 
:004345E4 8B80B0FDFFFF            mov eax, dword ptr [eax+FFFFFDB0] 
:004345EA E8EDF9FFFF              call 00433FDC 
:004345EF 8BE5                    mov esp, ebp 
:004345F1 5D                      pop ebp 
:004345F2 C3                      ret

	Pretty obvious, doesn't it? if byte at memory location [0043D868]  
contains 00H then the software is Unregistered, if it contains 01H it is a 
Registered Copy. According to this, appropriate messages are written. 
Patching at this point is so evident that I wont discuss it, however, you 
should notice, that "a patch" is not acceptable in this case, because 
this software objective is to create mail packets that will travel around 
the world, therefore, all packets will contain a 'Registered to: Empty 
space-->Lamer sighted' Sentence!!! Yes, an elegant and massive way to inform 
millions of people that you DIDN'T PAY THE RIGHTS TO USE THIS APP!!!

	At this point, we know that the valid registration flag is stored at 
memory location CS:0043D868 and it will contain 01H if registered, so lets 
search where in the code a 01H is stored in the flag. At wdsm89 search for: 
'[0043D868], 01'. You land inside the key file decryption process itself:

:0042BF2E 66BAE00A      mov dx, 0AE0	; Load 2784 bytes from the key file
:0042BF32 8D8534EAFFFF  lea eax, dword ptr [ebp+FFFFEA34]; Point to first
							 ; Byte of memory
							 ; copy of the key
							 ; File

* Referenced by a Jump at Address:0042BF3F(C)
:0042BF38 8030FF        xor byte ptr [eax], FF		 ; XOR first byte of
							 ; the key file with
							 ; 0FFh
:0042BF3B 40            inc eax				 ; Move pointer
							 ; ahead
:0042BF3C 66FFCA        dec dx				 ; Decrement counter
:0042BF3F 75F7          jne 0042BF38			 ; Repeat Cycle
:0042BF41 66BA7105      mov dx, 0571			 ; Load 1393 bytes
:0042BF45 8D85A5EFFFFF  lea eax, dword ptr [ebp+FFFFEFA5]; Set pointer at
						         ; byte 1394 of the
							 ; key file

* Referenced by a Jump at Address:0042BF57(C)
:0042BF4B 8A08          mov cl, byte ptr [eax]		 ; Move byte 1394
							 ; to CL

:0042BF4D 30888FFAFFFF  xor byte ptr [eax+FFFFFA8F], cl  ;(First byte XORed
							 ; with 0FFh) XORed
							 ; with (Byte 1394
							 ; XORed with 0FFh)
:0042BF53 40            inc eax				 ;Move Pointer ahead	
:0042BF54 66FFCA        dec dx				 ; Decrement counter
:0042BF57 75F2          jne 0042BF4B			 ; Repeat cycle 
:0042BF59 66BB2102      mov bx, 0221			 ; Move 221H to BX
:0042BF5D 66BAE00A      mov dx, 0AE0			 ; 1393 bytes to 
							 ; load
:0042BF61 8D8534EAFFFF  lea eax, dword ptr [ebp+FFFFEA34]; Points to first
							 ; byte of the key
							 ; file

	The Decryption process has ended. We must explain what happened.
	The first 2784 bytes of the key files are XORed with 0FFh. Only 
the last four bytes of the initially encrypted file are not XORed. 
Immediately after this, next 1393 bytes of the key file (which were 
previously XORed with 0FFh) are now XORed with 1393 bytes from the beginning 
of the key file (which were also previously XORed with 0FFh). In other 
words: Byte 1 is XORed with 0FFh, the resulting byte is XORed with byte 1394 
which previously was also XORed with 0FFh, then, byte 2 is XORed with 0FFh, 
the result is XORed with byte 1395 which was previously XORed with 0FFh, and 
so on.

	The process is a little messy but not in anyway impossible to 
defeat, nevertheless, the most important fact of this decryption system is 
(as you probably already noticed) that the magic numbers necessary to 
complete the decryption process are located in the key file itself, which 
off course you wont have. This is a very important concept for the +HCU. 
+ORC refers that the basic weak point of any protection scheme using 
encrypted data is the presence of the decryptor inside the target itself 
(the decryptor must be there because otherwise the program wouldn't be able 
to check if the key file is valid). This could help to revert the encryption 
process. However, in this case, all important data is absent. Lets analyze 
the code a little further when a checksum is finally carried out:

* Referenced by a Jump at Address:0042BF72(C)
:0042BF67 33C9          xor ecx, ecx			 ; Delete ECX
:0042BF69 8A08          mov cl, byte ptr [eax]		 ; Move First
						 	 ; decrypted byte
							 ; to CL 
:0042BF6B 6603D9        add bx, cx			 ; ADD first byte
							 ; to CX=0h	
:0042BF6E 40            inc eax				 ; Move pointer 
:0042BF6F 66FFCA        dec dx				 ; Decrement counter
:0042BF72 75F3          jne 0042BF67			 ; Repeat Process
							 ; Checksum result
							 ; in BX

:0042BF74 8D9518F5FFFF  lea edx, dword ptr [ebp+FFFFF518]
:0042BF7A 8D8534EAFFFF  lea eax, dword ptr [ebp+FFFFEA34]
:0042BF80 B9E40A0000    mov ecx, 00000AE4 **		 ; The key file is
							 ; 2788 bytes long!
:0042BF85 E8AA68FDFF    call 00402834
:0042BF8A 33C0          xor eax, eax
:0042BF8C 8A45FA        mov al, byte ptr [ebp-06] 	 ; Move byte 2788
							 ; to AL
:0042BF8F 33D2          xor edx, edx
:0042BF91 8A55FB        mov dl, byte ptr [ebp-05]	 ; Move byte 2787
							 ; to DL

:0042BF94 C1E208        shl edx, 08			 ; Move value at EDX
							 ; to H.O.B.
:0042BF97 03C2          add eax, edx			 ; H.O.B. to EAX	
:0042BF99 0FB7D3        movzx edx, bx			 ; Checksum to EDX
:0042BF9C 3BC2          cmp eax, edx			 ; Final Checksum
:0042BF9E 7573          jne 0042C013			 ; Is checksum OK?
:0042BFA0 C60568D8430001mov byte ptr [0043D868], 01	 ; Yes, Flag= 01 Reg

As you can see, once the key file has been decrypted a checksum is carried 
out with the first 2784 bytes. The result + 221H is stored in EDX. The 
last 2 bytes of the decrypted file (these bytes are not touched in anyway 
during the encryption-decryption process) contain the reference checksum. 
Off course, you cannot know this value until the file is decrypted and you 
cannot decrypt it, because the magic numbers are absent. The decrypted data 
will contain the registration info (Your name, BBS System Name, etc.), 
and all this data will alter the result of the checksum. Tough, ain't it?

	Considering that we will never have access to the magic numbers, 
the following question stabs our mind: How can we open a safe box if we 
don't have the combination?

	This is the solution: If you XOR a byte 00h with 0FFH the result is 
0FFH, if you XOR the result with 0FFH again, you get the original value back 
(0FFH). If you create a key file filled with 00H, the decryption process (if 
you recall) will XOR the first 2784 bytes with 0FFH (so the data is now 
encrypted with 0FFh), from byte 1394 to 2784, XORing 00H with 0FFH will fill 
these bytes with 0FFH, then, the program decrypts again byte 1 with 1394, 2 
with 1395, 3 with 1396 and so on. If the first 1393 bytes were 
initially encrypted with 0FFH, the second attempt will revert the process 
because the last 1393 bytes are filled with 0FFh. The effect is XORing with 
0FFh twice, thereby the encryption system is defeated and the magic numbers 
are no longer necessary.

	Finally a BPX CreateFileA on SoftICE, pressing Ctrl-D twice and 
finally executing d eax, will inform you that the key file name is 

	Now, we'll proceed to create our Key Generator ...

;*	Key File Generator for Fido2Int v. 2.00               *
;*	Use TASM to compile as a *.COM file                   *

ORG     100H

; The following array data is divided for didactic purposes.
; The space between 'quotes' is not empty, it must be filled in
; your text editor ( will do) with character 00H (alt-0)

; The first 1393 bytes of the key contain your registration data and
; lots of bogus bytes to create the checksum

KEYMEMLOC    DB 1393 DUP (' ') ; Space between quotes filled with 00H

; Next 1393 bytes contain the magic numbers

MAGICNUMB    DB 1393 DUP (' ') ; Space between quotes filled with 00H

; Last two bytes contain the checksum reference value

CHECKS       DB 2    DUP (' ')

HANDLE       DW 0 ; Handle definition

LF           EQU 0AH ; Line Feed Declaration

CR           EQU 0DH ; Carriage Return Declaration

BEEP         EQU 07H ; Internal Speaker Sound Declaration

FILENAME     DB 'fido2int.key',0 ; Key file name

GETNAME      DB CR,LF,'Fido2Int v. 2.00 Key Generator'
             DB CR,LF,'Coded by Aesculapius - September 1997'
             DB CR,LF,'Home Page:'      
             DB CR,LF,'Email Box:',CR,LF
             DB CR,LF,'Please, Type Your First and Last Name: '
             DB '$'

             DB CR,LF,'Please, Type Your BBS System Name: '
             DB '$'

             DB CR,LF,'Key file fido2int.key successfully created!'
             DB CR,LF,'Now, you must copy it to Fido2int directory.',BEEP
             DB CR,LF,'$'

NAMESTOR     DB 18H,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

BBSSTOR      DB 18H,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

ERRORM1      DB CR,LF,'The key file could not be created!',BEEP,'$'

ERRORM2      DB CR,LF,'The key file could not be opened!',BEEP,'$'

ERRORM3      DB CR,LF,'I could not write the key file!',BEEP,'$'

ERRORM4      DB CR,LF,'The key file could not be closed!',BEEP,'$'


        MOV     DX, OFFSET FILENAME ; Create key file
        XOR     CX, CX
        MOV     AH, 3CH
        INT     21H
        JC      ERROR1
        MOV     DX, OFFSET FILENAME ; Open Key File
        MOV     AH, 3DH
        MOV     AL, 2
        INT     21H
        JC      ERROR2
        MOV     HANDLE, AX	    ; Save Handle
        JMP     RETURN


        MOV     AH, 09H
        MOV     DX, OFFSET ERRORM1
        INT     21H

        JMP     EXIT


        MOV     AH, 09H
        MOV     DX, OFFSET ERRORM2
        INT     21H
        JMP     EXIT




        MOV     AH, 09H
        MOV     DX, OFFSET GETNAME  ; Type your Name Message
        INT     21H

        MOV     AH, 0AH
        MOV     DX, OFFSET NAMESTOR ; Move name to memory storage location
        INT     21H

        MOV     SI, OFFSET NAMESTOR+1; Plus 1 byte (not two) on purpose
				     ; because the registration system
				     ; requires a byte different from
				     ; 00H right before the Name string

        MOV     DI, OFFSET KEYMEMLOC+3FBH ; Location to store user's name
        XOR     CX, CX			  ; Delete CX
        MOV     CL, [SI-1]	  	  ; Number of bytes in your name
        REP     MOVSB			  ; Move string to storage location
        XOR     CX, CX			 
        MOV     [DI], CL		  ; Terminate your name with 00H

        MOV     AH, 09H
        MOV     DX, OFFSET BBSNAME    ; Ask for BBS System Name
        INT     21H

        MOV     AH, 0AH
        MOV     DX, OFFSET BBSSTOR    ; Move it to storage location
        INT     21H

        MOV     SI, OFFSET BBSSTOR+1      ; Move it to SI
        MOV     DI, OFFSET KEYMEMLOC+438H ; Store it in the key file
					  ; memory location
        XOR     CX, CX
        MOV     CL, [SI-1]
        REP     MOVSB			  ; Move string to storage location
        XOR     CX, CX
        MOV     [DI], CL		  ; Terminate BBS Name with 00H



CHECKSUM        PROC    NEAR              ; Calculate checksum

        XOR     AX, AX
        XOR     BX, BX
        XOR     CX, CX
        XOR     DX, DX
        ADD     DX, 221H
        MOV     CX, 0AE0H	          ; 2784 bytes to add
AGAIN:  MOV     BL, [SI]
        ADD     DX, BX
        DEC     CX
        INC     SI
        XOR     BX, BX
        CMP     CX, 0H
        JNZ     AGAIN

; The gadget I deviced works perfectly with the first 1393 bytes,
; however, it wont work with the last 1393 bytes, so you must compensate
; the checksum with 6B8FH bytes

        ADD     DX, 6B8FH
        MOV     [SI+0AE2H], DX		; Store the checksum at the last two
					; bytes of key file



FILL_IT         PROC    NEAR            ; Fill key file with the data

        MOV     AH, 40H
        MOV     BX, HANDLE
        MOV     CX, 0AE4H
        INT     21H
        JC      WRITEERROR
        JMP     DONE


        MOV     AH, 09H
        MOV     DX, OFFSET ERRORM3
        INT     21H


FILL_IT         ENDP

CLOSE_IT        PROC    NEAR 	; Close File

        MOV     AH, 3EH
        MOV     BX, HANDLE
        INT     21H
        JC      CLOSEERROR
        JMP     OK


        MOV     AH, 09H
        MOV     DX, OFFSET ERRORM4
        INT     21H

OK:     RET


BEGIN           PROC    NEAR	; Main Program Engine

        CALL    GET_NAME
        CALL    CHECKSUM
        CALL    FILL_IT
        CALL    CLOSE_IT

        MOV     AH, 09H
        INT     21H

EXIT:   MOV     AX, 4C00H
        INT     21H

BEGIN           ENDP        

        END     START

	As always, if you have any doubt or question, don't hesitate to 
	email me.

					Aesculapius - September 1997
					Email Box:
					Home Page:     

(c) Aesculapius, 1997. All rights reversed.
You are deep inside fravia's page of reverse engineering, choose your way out:

homepage links red anonymity +ORC students' essays tools cocktails
academy database antismut search_forms mail_fravia
is reverse engineering legal?