Hi this is Mad typing...

TERMINATE 5.0 CRACKING: PHASE TWO

Enclosed files: ter5key.asm (the generator)
                regist.lst  (terminate registration-routine listing)
                c.bat       (a small batch to compile source)
                TER5KEY.COM (executable generator)

AN INTRO NOTE
I could have used the Terminate 4.0 key i've got to trace program protection,
generated using the United Cracking Force prog. But cause this key appears
to be very strange, i preferred to start over without any clue.
When i say strange i mean: its length kept changing in every generation,
moreover it is fully filled with data. At first this scared me, cause i
thought Terminate protection was a real uncrackable one. This is why i decided
to figure out all of it on my own.
Now, that i got my generator, i ask me why UCF has used a so garbled prog...

THE SECOND AND DECISIVE APPROACH...
At the end of my first approach i got a registered Terminate 5.0, with my
perfect data. But in my testing session i came upon the TerMail program,
that relies on a good terminat.key. This one could also be an old 4.0 version,
cause no version checking is done, but we have not legally obtained the one
we got (remember we are using the UCF generated one). So, this is time to
start our real cracking project, to obtain our personal key-generator !!!
If, trying to understand this, you'll get swamped, don't worry. All the work
you can read here was done in 15 days (about 130 hours), without counting time
spent in the first approach... This means that at the end you will know
the routine you are dwelling in very well. Moreover, i'll not explain how
i figured out the program working, cause that was only a tracing work.
This was the hard part, but cannot be reproduced here: you should only try
it on yourself (this depends on your intuition and luck, not anymore: it can
take you 5 hours, or a month...) You must be patient and well determined to
accomplish this part; probably this is where a good cracker will distinguish
himself from an occasional one. What i can give here is only an advice:
when tracing a large routine like this one, remember to keep your attack at
different levels. The protection routine is written using a high level
language, so you will probably find many calls not really involved with what
you are studying. This means you must at first study it without tracing into
sub-calls, just to avoid to get lost in code guts. When you'll be knowing
all of the main loop, understanding where all relevant jumps are, you can
study it on deeper range.

SOME NOTES:
- when you know where our routine is, you can get the first ten bytes out of
  it, and calculating its length, you are able to find it in terminat.exe.
  This is the process i used to obtain an IDA disassembly; i select bytes
  belonging to our routine using HexWorkshop, then i saved them in a
  routine.bin file.  This will be easily (and speedily) disassembled by IDA.
  (Obviously IDA cannot understand the EXE relocation, cause we have stripped
  it, but we are working on this dead listing only for the educative part,
  so we just know enough of the code to understand the hell out of it)
- i think Terminate has too many back-doors:
  even if the key-file based protection is in some way the most advanced
  i've ever seen (for encryption and CRC code) contains many points where
  you can patch the code if you cannot understand its inner meaning.
- the routine is rather long, and you'll get in a real mess if you try to
  understand all of it. This is particularly due to the fact we have many
  fake calls (generated by the high level compiler) that are of no
  importance for the protection.
- when terminat.exe finds a good key and do its own inner checks, don't find
  any patch i've tried. So the auto CRC checking routine is in some way weak.
- if you want obtain a dead listing of decryption/CRC checking (but not the
  version 4.0 check) you can disassemble the INSTALL.EXE program from the
  original zip file. This reads a key if it finds one, and do some checks on
  it. Install.exe is a small exe, so easy to be disassembled (it is packed
  with LZexe 91, unpacked by UNP or another unpacker...)
- Terminate do some strange byte checking on the key-file, to see if it finds
  particular bytes in some location. Some of these bytes produces very
  interesting messages (like the version 4.0 illegal key), but all went ok
  if you don't mind of them and set all the key-file equal to 00. However,
  this can lead to a problem: if some of these bytes must be there, i have
  ignored them, and in a future version this could reject my key...

A DISCURSIVE EXPLANATION OF THE PROTECTION
Cause this protection is large, i'm giving a panoramic view of it. Besides,
i'm writing this doc about ten days after i've ended the project. Obviously in
this doc i'm not describing all steps those led me to a complete understanding
of the program, cause this is the part where you must try, seek, go back,
be in despair, think and go sleepless...
When you run Terminate, this will look for a terminat.key in its directory.
This is the good place to land in the program (with a breakpoint on DOS file
open). When the program finds the key, we return with a F12 and we are in
the main routine (i always refer to this routine to be in segment 4342; this
can change in your case, but i used it to be clearer).
The program then enters in a loop where it reads the key-file in chunks of
162h bytes. This is done for 0Bh times (so we get the key-file size:
162h*0Bh=F36h - 3894 bytes). Doing the file reading, the program uses a
counter on which relies the decision about what to do with the read chunk.
We have some byte checks on the first block, a large routine in the 4th block,
a data retrieving from the 5th block and always the same loop in all 11 blocks.
Terminate calculates 3 CRC from the key-file: a general one, stored at the
end of the key, first checked; a second one that is later crypted, at the
end of the user data block, and a third one that is equal to the second + 10,
checked in a really garbled way. CRC generating also involves an array table
contained in terminat.exe. The key file then contains user data (4 lines)
that is crypted using a hard to trace routine; i've tried to reverse it at
first (painfully), then i realized this was too complex and based on XOR, so
this don't need reversing, we must only copy it.

A MORE DEEPER EXPLANATION
You can't find code here, cause this is contained in a separate file called
regist.lst. This is done cause i wanna include all the relevant code from
the routine, and this take about 50Kb. This listing is obtained using IDA,
and contain particular segment and offset reference; these could obviously
be different from yours (offset should be the same).
However to crack this program, i used only the live approach, so only the
good old Soft-ICE. We find a place to land in very easily with:
BPINT 21 IF (AH==3D)
this wake up the debugger on DOS file opening. To see what file is to be
opened we do a D DS:DX. On the first break, terminate is opening itself,
to load in memory (this is an overlaid program). The second break is the good
one. We return with a F12 to the main routine, and we should be on line
4342:4BB. To follow this code is essential to have the listing at hand.
The hard part of the routine is understanding we are in a large loop, and
what we are doing there. When you got what is going on, you can concentrate
on particular sub-routines. The CRC generating is seemingly complex, but we
can use it as it is. This use a reference to an array table, that is
self-contained in terminat.exe. Using the live approach we can derive first
bytes from this table, and then search for it using HexWorkshop. So we get
the table at offset 1D984 of terminat.exe (ending at 1D984+400=1DD83).
First and second CRC are generated using the same routine.
Encryption involves only the 4th block (so we know user data must be there)
and uses a 4 steps procedure. This uses a random number generator, based
on a value passed on AX, and three memory words. We must write down
initialization value and then copy this routine too.
What i did to understand the key protection, is to work on successive steps:
at first i generated a terminat.key file containing random data. Then i
got the exact file size (3894) so i setted it. I used a completely nulled key
at first, then i started inserting the end CRC. In the meantime i discovered
the CRC adding if particular bytes are present, so, cause i don't want any
adding, i inserted these bytes. All the times i was directly deriving the
correct CRC from the plain comparison. I inserted a random number where the
program seek for the 3rd CRC (at first i don't understand what this was used
for - and infact i got its meaning only at last). So, the program reached the
second part, where it decrypt data. Now i know the 4th block is a fundamental
one; this contains a CRC checking at the end, calculated using a known
procedure. I don't know what data is decyphered, but i can force the CRC
to be good. Then i get swamped in the terminat.exe check: this involves the
3rd CRC (discussed later). At the end i see many bytes checking, trying them
i found how the program recognize an illegally generated old key, and some
interesting messages. Then we have a lot of comparison between what i supposed
to be our inserted name and inner names. So i get how strings are stored
(a byte in front of the string identifies its length) and continuing in the
tracing (this was rather fast here, cause we have always same calls) i found
exact offsets of 4 user data lines. At this point i got all elements to
create a valid key on my own, using CRC generated by the prog. But this
requires to go back to tracing every time (even if now i have exact
breakpoint to CRC checking). So i decided to study CRC and decyphering routine
to write down directly my generator.
... this process is easily and speedily read, but hey - this is a real pain to
understand all the code... (you MUST have many time to spend on this - and
many sheets to write down all your discoveries)

THE 3RD CRC
This is the hardest CRC generating, cause this is not directly compared with
any good value. I admit trying to follow this here is rather impossible,
cause to continue code referring in different places. I've just reported
what i've done, so you have two choices:
- do it yourself (using this doc as reference) to completely understand it
- just read it to see what happens, only like a guided tour thru code guts
This CRC is contained at the end of the 5th block of 162h
bytes, offset 6E6/6E8 of terminat.key. This is used to generate 3 numbers,
to be stored in memory during key file reading.
This is the code:

4342:06F8 loc_0_6F8:
4342:06F8                 cmp     word ptr ds:17D4h, 5
4342:06FD                 jz      loc_0_702
4342:06FF                 jmp     loc_0_79F
4342:0702 
4342:0702 loc_0_702:
4342:0702                 mov     di, [bp+6]
4342:0705                 les     di, ss:[di-106h]
4342:070A                 mov     ax, es:[di+15Eh]   <- So we must have some
4342:070F                 mov     dx, es:[di+160h]   <- data at this loc
4342:0714                 call    far ptr 1708h:170Bh

We land in line 702 when we read the 5th block. Lines 70A/70F retrieves data
from the key-file, to pass it to the call. Line 714 derives AX,BX,DX from
this CRC. We have the same call when we get the decrypted 2nd CRC.
This is how i understood what is going on:
i've inserted 11111111 in CRC location, just not to leave it 00, then i run
the prog. All went ok until it starts to check terminat.exe, showing
the progress bar in the screen. At this point the prog seems to enter in an
endless loop, and don't stop. The terminat.exe checking routine is at
4342:E31. So i started to trace thru it. Finally i found near the end of it
a series of conditional jump, all referring, in case of no success, to routine
restart. So the routine does its checks, and then relies on others memory
data to decide if to enter in an endless loop. If CRC is not good, at line
4B40:1B47 we have no jump, and we get lost. The jump can occur only if AX is
not F494. So i traced back until 4B40:1703 where we have AX setted to F494.
Just before this line we have a conditional jump, that obviously don't occur.
4B40:1701 jumps only if AL < 91, and at 16EA we have MOV AX,[BP-3A].
[BP-3A] get setted in 4B40:14ED with MOV AX,[BP+0C]
[BP+0C] derives directly from parameter passing from the main call
(This back tracing process is hard to follow in theory, but can be easily done
in 5 minutes using breakpointing on memory in the live approach)
So we are back to the main routine:
PUSH WORD PTR SS:[DI+FEE4] is where this data is passed (some lines before
the call at 4342:E31)
Location [DI+FEE4] is setted at 4342:DE9. Some lines above we have
4342:DC4        JMP DF8
This is a jump after the DE9 setting, so this could be interesting. This
unconditional jump belongs to a code block referenced by a conditional
jump at D43 (JZ D7D), and this conditional jump occur only if before the
call BX is equal to SI. BX is derived from the call at 4342:C3A (that generates
it using the 2nd crypted CRC) and adding 28h (the call at 4342:D27).
SI derives from the 3rd CRC and is generated at 4342:714 (see above code).
Routines called at 4342:714 and 4342:C3A are the same, so to have the exactly
same number derived from either two CRC they must be equal. But we have an
adding after the second call, so to be equal, BX from the first CRC must be
the 2nd CRC BX+28h. At this point we have to trace how AX,BX and DX are
generated by a CRC. I'll save you this tracing (you are tired enough of
reading); BX is the first word from the CRC (the one at offset 6E6 of
terminat.key) added to itself 2 times (this depends on the second word - and
so we obtain CRC_word1 * 4): so if we must have BX greater than the 2nd one
of 28h, we have to add 28h/4 (0Ah) to the first word of CRC.
Hence the 3rd CRC must be:
first word is equal to the second-CRC first word + 0Ah
the second word is equal to the second-CRC second word.
(The 3rd CRC is ok even if we subtract 0Ah, cause another routine will
do the same job to the 2nd CRC to obtain BX==SI. But adding 0Ah is the first
i've found, so i used this one)

A LAST NOTE
In the Strainer it's required to design a technique to assure the key will
be valid in future versions of Terminate. In my approach, i got no problem
about valid key checking. This is due to the fact i generated at first a
completely nulled key. I discovered only later, doing tracing tests, what
are bytes checked to see if a key is valid or invalid (offset 574h of the
key and following). But i continued to ignore them, cause if they don't
exist, the program will accept the key.
I really don't know if in this way i generated an everlasting key, or a key
that will be no more valid. However i tried my keys with Terminate 4.0 too,
and they worked... The fact is that the program simply checks to see if some
bytes are different, not equal, so we cannot have the original pattern; and
in the next version (if the encryption system and CRC checking is still the
same - i believe very unlikely at this point) author can introduce a new
byte checking that works with an original key, but not with a cracked one...
...hey, this is the neverending struggle between Good and Evil Forces,
between virus writers and antivirus programmers, and obviously between
crackers (the good ones) and protectors (the evil/lame ones)...

                                        Bye, Mad - 14/VI/1998
