#------------------------------------------------------------------------------#
#                             - Challenge #1 -                                 #
#                                 by JaZZ                                      #
#------------------------------------------------------------------------------#

Contents:
1) Localisation of the protection
2) Analysis
3) The keymaker

#------------------------------------------------------------------------------#

1) Localisation.

To work efficiently on this target, I've used Softice 2.80 for dos, and IDA 3.7,
which seems to be the only disassembler beeing (by far) able to produce a
meaningful listing that you can use in conjunction  with  softice. Well, there
are no anti-debuging tricks as soon as you start softice ! I suppose these
one were supposed to be the use of overlays but IDA treats them quite right as
well.
We know that the babe needs a file to reg right so we just BPINT 21 ah=3D to
break whenever a file is opened. The second time Sice pops, ds:dx points to a
"terminat.key" string. Ok, this is the name. We then just create a bogus
terminat.key file, then BPINT 21 ah=3F to break on the reading. And we land
smack into it. In Ida it's referenced as ovr018.

2) Analysis of the  scheme.

I've provided a COMMENTED (with some vars renamed, please have a look...)listing
of the interesting part of overlay 18, to clarify my explanations, but i suppose
the reader has figured out how all this works :-) First the key file is divided
into 0B buffers of each 162h bytes long. The file must then be at least
162*B=F36 bytes long. There are several levels of
protection in this scheme. Let's examine the first.

a) A loop is reading all the buffers of the keyfile, and performs a global
checksum (through a dedicated function) on bytes [0,15D] of each one. The 2 last
words in each buffer (15E to 161) are either a checksum (local to this buffer or
global to the whole file) , or are not checked at all. It can be noted that the
checksum function actually uses a 1024 bytes area to perform its job (that's why
i've been forced to hardcode it in the keymaker). When the reading has been
achieved the resultant checksum is matched against the bytes 15E->161 of the
last 0B buffer. If the 2 words don't match, you are kicked off. During this
first loop, the author also tries to detect cracked terminat.key files. To
achieve this, he only checks constant patterns that always occur at the same
place in cracked files:

1)First buffer: cracked file if chars at positions B,1B,14 are respectively
equal to 'F','/',and '.'

2)Second buffer: cracked file if first five characters are equal.

3)0B buffer: cracked file if bytes 12C to 130 are equal OR if [15A,15D]= "_d+"
(ie DC 64 D9 E9)

If the program detects a cracked key, either it fills the general checksum with
bogus, or it displays a message saying you're using an anauthorized key file.
Anyway, it won't reg. To prevent the program from matching succesfully, i just
fill all the terminat.key with random at the beginning (the random generator is
the one used by terminat itself, seeded with the clock), and then put the
interesting data over it. It'll ensure that even for the SAME user input, a lot
of bytes will be different in the final keyfile. This will work as long as the
author doesn't check some "required" bytes !
			   -----------------------
b) the second part of the protection is dealing with the fourth buffer,
involving bytes from 5B to 161. Besides, the user input is encrypted in here.
The program will xor the whole area with FF at first. After it does the same
four times again, with a different xoring value each time. This value is
calculated by some kind of "random generator", seeded with defined DWORDS (not
really random then...). At the end of this process, the area is fully decrypted.
A new checksum then occurs onto this area, involving the same algo described in
a) : checksumming [5B,161] and comparing to the word in 15E. One more occasion
to be eventually rejected. If not the work is not done still: now you've got to
face the TERRIBLE integrity check call: though you may have gone through all the
previous doors, this call can enter a unfinite loop, or even worse crash the
PC while beeping continuously (apart from this, why this integrity check is
going backwards on the file ? a mystery). I summarize here quite a lot of work:
what is important are the parameters pushed before the call. Three of them are
interesting.

0D67		    mov	    cx,	ss:[di+FEDE] ; this is computed with
0D6C		    mov	    si,	ss:[di+FEE0] ; the checksum of #5 buffer
0D71		    mov	    di,	ss:[di+FEE2]
0D76		    call    sub_1708_1707 ;-------> this time it MUST give ZERO
0D7B		    jnz	    set_a_fucking_mess
A detail I didn't notice at first was the calculation that was performed with 
the two last bytes of 5th buffer. Finally the result of this calculus is in 
FEDE FEE0 FEE2. If the call above doesn't return z on (it compares aldxbx with 
clsidi), this nasty prog messes every parameters that'll be pushed, leading to  
the unfinite loop. Ok, this is, I think, the real difficult part of the scheme: 
find the last two words of 5th buffer. The first idea that came to me was to 
put the SAME checksum in the 5th than the one calculated for 4th. buffer. When 
tracing with sice you see that both follow the same transformation algo, except 
for this:

[FEDE,FEE2] holds the algo result for #5 buf.
[FED8,FEDC]  ""    ""  ""    """  for #4 buf.

0D48		    mov	    ax,	ss:[di+FED8]
0D4D		    mov	    bx,	ss:[di+FEDA]
0D52		    mov	    dx,	ss:[di+FEDC]
0D57		    mov	    cx,	84h ; ''
0D5A		    xor	    si,	si
0D5C		    mov	    di,	2000h
0D5F		    call    sub_1708_16EB

and then it's compared (see above). when returning, bx is lowered by 28h & 
that's all. Putting then the same checksum for the two fails because of this 
difference. So we'll have to find a checksum for 5th that through calculation 
gives [FEDA]-28h. Now this seems quite a laborious task, but is not really, if 
you remark that lowering [15E] by 1 lowers the [FFE0] by 4. It's fully linear. 
To lower the final result by 40 (=28h), we'll only have to take the [15E] word 
of the 4th buffer, lower it by Oa, and put the result in [15E] in 5th buf.

3) the keymaker. 
One more thing we'll have to find is how the user's personal info is stored in 
the key file. To achieve this, i simply cracked terminate.exe to allow every 
bogus file (with the sufficient nbr of bytes) to be a valid one. I won't discuss 
that much as there's only 3 or 4 bytes to change, and we don't want to patch 
it! Pressing ALT O in the program displays all the user info. All the info is 
stored in 4th buffer, at these positions (with sice you go on the decrypting 
process until you find the bogus displayed by ALT O):
[7A]=name length
[7B-AB]=name
[AD]=adress length
[AE-DE]=adress
[E0]=city length
[E1-E11]=city
[113]=country length
[114-144]=country

To realize the keymaker, we just follow the process the author uses in backwards 
direction (the listing is fully commented) 
- get user input with dos function. 
- initialize the area in memory with random. 
- copy the user data at the right 
place. 
- put a correct checksum in 4th buf and then deduct the one for 5th as explained 
above. 
- xoring the 4th buf succesively with 4 distinct values 
- performing the global checksum on all the buffers and putting the result in 
the right place of the last one. 
#------------------------------------------------------------------------------#