TechFacts v1.3 - Tutorial

Local Download : v1.3 - (511k).


Now that you have everything you need to start cracking. All cracking sessions begin in a very simple way. Studying your target 'alive', letting it run inside your computer, looking for all possible limitations, shareware notices, window captions, full registration options, crippled functions and so on that may give you a broad idea of the KIND of protection scheme (or schemes) you will have to deal with.

Therefore have a first look at your target and run (and use) tekfct95.exe. Play a little with it, let it install itself and then try as many options as you feel like. As you will immediately notice, there is a short ugly coloured nag screen at the beginning and the mention <unregistered> in the main window caption. If you choose the option help / about TechFacts95, you'll see that the TechFacts95 'about' windows open, with version number and date (version 1.30, 7 March 1997). This 'about' window has an 'unregistered version' string as well, and a 'Use Reg Key' button. If you click it, you get a 'TechFacts95 registration' little window with three textfields ready for input :- First Name, Last Name and registration key.

Once you enter your data and click the button 'register', you get another window, with 'TechFacts95' as caption, stating 'Registration Key Failed'... in fact '12121212' does not seem to be the right key for us I'm afraid. Looking at Tekfct95's embedded help file you'll see the following notice :-

** What is your incentive to register? There is now an annoying splash screen that appears 
when starting the unregistered version as well as the word <unregistered> generously placed 
throughout the program. We had to add these features since we were getting lots of support 
calls from people who had not registered. In other words, you get support when you register! 

In fact the author of this target is an extremely correct person, and has de facto allowed an unrestricted and time-unlimited use of his software to everybody. This is also the reason I have chosen this target: I don't believe that this will damage him ... quite the contrary!. This target is extremely useful, extremely powerful and extremely cheap, as anybody using it will realise. Its users base deserves to be expanded and I hope that at least some of you will register and pay for its complete (new) version after having cracked black and blue its shareware (old) version ... it is the minimum you should do for the target that will have opened for you the hidden marvellous path to software reverse engineering!.

OK, we have examined our target's behaviour and we have taken notice of all the protection schemes we were able to find using our simple string search... as you'll see the data that we have collected is more than enough to crack this target.


First thing you need is to get a 'dead listing' of your target. We want to have somewhere (in a text file or on screen), the COMPLETE disassembly of our target's code, we will need it in order to pinpoint the various protection snippets. Run W32Dasm, choose Disassembler/File to Disassemble, and disassemble tekfct95.exe ... you may go and have a short break while W32Dasm works :-)

Once finished, have a look at the strings inside your dead listing, (W32Dasm has a special 'Refs' option where you can choose 'string data references'. You'll arrive at the following code-snippet searching for the string '<unregistered version>', which is, as we have seen, the caption of our target's main window. Since you may not know ANYTHING about machine code (or assembly) language, we will begin examining very thoroughly the FIRST instruction of the code-snippet below ... just one in 'deep'. Locate the following snippet (from W32Dasm) ON YOUR SCREEN. You'll see some slight differences, yet the instructions will be exactly the same :-


:004805F9 CMP BYTE PTR [004CF31A], 00 <- A compare followed
:00480600 JE 00480624 <- by a jump, both
:00480602 MOV DL, 01 <- located just before
:00480604 MOV EAX, DWORD PTR [EBX+000001C4] <- the string below!
:0048060A CALL 00416D54
:0048060F MOV EDX, 00480718 <- 00480718 = "<unregistered version>"
:00480614 MOV EAX, DWORD PTR [EBX+000001E0]
:0048061A CALL 00416E28
:0048061F JMP 004806EB <- jump here from Address 00480600(C)
:00480624 XOR EDX, EDX
:00480626 MOV EAX, DWORD PTR [EBX+000001C4]
:0048062C CALL 00416D54
:00480631 MOV EDX, 00480738 <- "Licensed Version. Do Not Copy!"
:00480636 MOV EAX, DWORD PTR [EBX+000001E0]
:0048063C CALL 00416E28

This code snippet actually tells you EVERYTHING you need to know. An average cracker would already know what to do. The two strings revealed by the disassembler are preceded by a compare instruction which is the key of the whole protection scheme. The target has a very simple protection indeed. I'll now explain to you the above code step by step. The first instruction (the first line) will be used to explain the hexadecimal notation (for dummies) :-

:004805F9 803D1AF34C0000 CMP BYTE PTR [004CF31A], 00

LOOK AT THE FIRST CODE LINE - This is an INSTRUCTION, situated at location 4805F9. Your target code is represented in hexadecimal notation, and each byte (or series of bytes) has a particular meaning. This is assembly, the so called 'machine language' :- 80 3D 1A F3 4C 00 00

Why hexadecimal? Why don't they use good old easy decimal? Good question, you'll understand now, once for all, why. (The following requires a small effort, but it will pay out in spades, and you'll later even have a lot of cracking fun with hexadecimals, believe it or not). At location 4805F9 the target's code looks like this :-

80 3D 1A F3 4C 00 00

This correspond to assembly command CMP BYTE PTR [004CF31A], 00, whose meaning we'll investigate in a minute, but these same hexadecimal bytes correspond also to the underlying 'real' binary code, here it is ... for each hexadecimal a byte is each composed of 8 bits (either one or zero) :-

80       3D       1A       F3       4C       00       00
10000000 00111101 00011010 11110011 01001100 00000000 00000000

Now, just look at the binary code ... look at the number THREE, for instance (inside 3D and inside F3)... you get it? 3 is always 0011, let's have a look at the same code once more, this time divided in 4 bit pieces :-

8    0    3    D    1    A    F    3    4    C    0   ...
1000 0000 0011 1101 0001 1010 1111 0011 0100 1100 0000...

Now everything should be clear and you have your explanation before your eyes. Hexadecimal code allows a precise and immediate representation of the UNDERLYING binary code, which as you (should) know is the only code that your computer is capable to understand (power on / power off). Binary is elementarily simple: 0=0000; 1=0001; 2=0010; 3= 0011; 4=0100; 5=0101; 6=0110; 7=0111 and so on. 4 bits give 16 possibilities (0-F: 0000-1111, decimal 0-15); 8 bits (a byte) give 256 possibilities and range from 0 (which is 00000000) to FF (which is 11111111 and corresponds to 255... 0-255 are 256 possibilities). The following are all the same :-


This means [compare what is inside the memory location number [004CF31A] with zero]... or, if you prefer, [let's see if a zero has been stored inside that memory location]. Technically, this 'compare' is considered an arithmetic operation, because the source operand (here zero), is subtracted from the destination operand (here the content of location [004CF31A]). The result, however is used for setting the flags and it is not stored anywhere. Flags are single (0/1) bits of a special register, which are VERY important, inter alia, for our cracking purposes ... more about flag-bits and register-bytes later.

CMP BYTE PTR [004CF31A], 00

Hexadecimal expression, ... you will probably not yet understand this, yet it should already be somehow more transparent... Let's imagine that you know that 80 (like 3B) means (often enough) compare, i.e.'cmp', and that 803D means specifically 'cmp byte ptr' (that is "compare a memory location I'm pointing you to"), well, in that case you would immediately guess that (after 803D) the following part: 1A34C00, represents a memory location in inverted format, and that the last byte, zero, corresponds to the right operand of our instruction.

So, this is assembly 'reversed'... from hexadecimal bytes to the relative instructions. In fact you'll NOT find in many books (or for that matter on the Web itself) a 'raster' like the following snippet (out of my own personal 'home-made' one), which is a very useful reference for OUR purposes) :-

8039E9                  cmp byte ptr [ecx], E9
803A20                  cmp byte ptr [edx], 20
803B22                  cmp byte ptr [ebx], 22
803C0000                cmp byte ptr [eax+eax], 00
803C1826                cmp byte ptr [eax+ebx], 26
803C2400                cmp byte ptr [esp], 00
803D35E04C0000          cmp byte ptr [004CE035], 00  <- This is like 'our' instruction above
803B22                  cmp byte ptr [ebx], 22
807B0122                cmp byte ptr [ebx+01], 22
807B4800                cmp byte ptr [ebx+48], 00
807E4800                cmp byte ptr [esi+48], 00
80BC064C0100001A        cmp byte ptr [esi+eax+0000014C], 1A

80F861                  cmp al, 61
80F91A                  cmp cl, 1A
80FA61                  cmp dl, 61
80FB20                  cmp bl, 20
80FF64                  cmp bh, 64

Now, if you take a couple of minutes out of your patience bag and look hard at the hexadecimal codes of the raster above, you'll make out some easy and clear patterns ... Most of the compare instructions above regard the various REGISTERS of your microprocessor : AX (which is divided into AL and AH), BX, CX... and so on... more about registers later.

Today (almost) only crackers, virii writers and real assembly wizards do know assembly from the 'hexadecimal' perspective (and are therefore able to reverse any software, no matter in which language has been written). Most snotty programmers don't know NOTHING about all this. They program in 'high level' languages, huge, slow and bugged applications and are anyway so far from the machine code that if you would tell them that hexadecimal 80 is (often enough) the beginning of a 'cmp' instruction they would look at you pretty puzzled for quite a while before continuing their discussions about the last 'classes' of the last version of the last overbloated operating system they are using ... in fact that is the very reason that explains why we can crack a 13 million bytes long application, whose source code we DO NOT have, modifying at hexadecimal level a single byte somewhere inside its code :-).

CMP BYTE PTR [004CF31A], 00
10000000001111010001101011110011010011000000000000000000 << BINARY NOTATION

The long row of zero and ones above is a binary expression... you would probably not want to understand what that means even if somebody would pay you for it. Yet now that you have read the above text you could eventually (slowly) understand that in this awful sequence of 1 and zero there is a compare, and then a memory location in inverted format: 004CF31A, and then a last byte, 00, which is therefore the source operand of the compare... This is the way your microprocessor gets the code from the program. Don't worry, you'll (almost) NEVER have to reverse binary notation when you crack :-).

"So, dass hätten wir hinter uns", would the Germans say... well, we have seen only ONE instruction from the code snippet of the first protection scheme of our target... "Man, it will take ages... I'll never be able to do it"... will you cry in utter desperation, already regretting to have embarked in this cracking stuff. Yet we are over the top of the hill for this lesson... from now on everything will be downwards, walk along.

In fact, even if I had a lot to explain, this target is a 'three minutes' very easy crack. Believe me: you yourself will crack this kind of targets very quickly once you finish reading this. C'mon, have a break, sip a cocktail, think once more at what you have learned until now... quite a lot I believe, and prepare yourself for the following code.


:004805F9 803D1AF34C0000          cmp byte ptr [004CF31A], 00   ; discussed above
:00480600 7422                    je 00480624
:00480602 B201                    mov dl, 01
:00480604 8B83C4010000            mov eax, dword ptr [ebx+000001C4]
:0048060A E84567F9FF              call 00416D54
:0048060F BA18074800              mov edx, 00480718  ->"<unregistered version>"
:00480614 8B83E0010000            mov eax, dword ptr [ebx+000001E0]
:0048061A E80968F9FF              call 00416E28
:0048061F E9C7000000              jmp 004806EB

jump here from Address:00480600(C)
:00480624 33D2                    xor edx, edx
:00480626 8B83C4010000            mov eax, dword ptr [ebx+000001C4]
:0048062C E82367F9FF              call 00416D54
:00480631 BA38074800              mov edx, 00480738  ->"Licensed Version. Do Not Copy!"
:00480636 8B83E0010000            mov eax, dword ptr [ebx+000001E0]
:0048063C E8E767F9FF              call 00416E28

I will not keep you hours on this. The code above means what my comments say, just try to understand why.

:004805F9   cmp byte ptr [004CF31A], 00  <Do we have a zero in memory location CF31A?
:00480600   je 00480624                  <if so jump to 624... (THIS IS A GOOD JUMP!)
:00480602   mov dl, 01                   <else bad luck! Load 1 inside register dl
:00480604   mov eax, dword ptr [ebx+1C4] <and load in eax the address at ebx+1C4
:0048060A   call 00416D54                <and call the subroutine at 16DC4; then then
:0048060F   mov edx, 00480718            <point to string "<unregistered version>"
:00480614   mov eax, dword ptr [ebx+1E0] <and load in eax the address at ebx+1E0
:0048061A   call 00416E28                <and call the subroutine at 16E28
:0048061F   jmp 004806EB                 <and jump away WITHOUT executing the following code

jump here from Address:00480600(C)
:00480624  xor edx, edx                  <load a zero in dx (this is a GOOD GUY flag)
:00480626  mov eax, dword ptr [ebx+1C4]  <and load in eax the address at ebx+1C4
:0048062C  call 00416D54                 <and call the subroutine at 16DC4; then
:00480631  mov edx, 00480738             <point to string "Licensed Version. Do Not Copy!"
:00480636  mov eax, dword ptr [ebx+1E0]  <and load in eax the address at ebx+1E0
:0048063C  call 00416E28                 <and call the subroutine at 16E28

You will notice that this code can EITHER load 'flag' 1 in register dl and then point to "unregistered version" OR load 'flag' 0 in register dl (dl is a part of dx, therefore if dx is zero dl is zero as well) and then point to "Licensed version". You also see that this 'flag' depends on the contents of memory location [004CF31A]... if it is zero you will have flag zero inside register dl and "Licensed Version. Do Not Copy!", if it is NOT ZERO (e.g. 1) you will have flag ONE in dl and "unregistered version" inside the caption of your target's main window. Well... the crack is already finished... yet just for the records, let's have a quick look at all other occurrences of our suspect' string... and look and behold! The same memory location [004CF31A] appears every time...

:004811E6 803D1AF34C0000          cmp byte ptr [004CF31A], 00
:004811ED 742D                    je 0048121C
:004811EF BA44134800              mov edx, 00481344 <- TechFacts 95 Help "<unregistered>"

:004B9445 803D1AF34C0000          cmp byte ptr [004CF31A], 00
:004B944C 740F                    je 004B945D
:004B944E BA78944B00              mov edx, 004B9478  <- TechFacts 95 "<unregistered>"

OK, it's confirmed, we have enough proof. Every time the target nags us with the 'unregistered' string, there is a check of memory location CF31A. Let's get ready to crack now!. Since everything depends on a single memory location, called a 'triggering flag') let's see where this memory location is SET (i.e. not just checked through a compare, let's see where it is modified, where something is LOADED into it... being a flag it will be loaded either with zero or with one. )Zero is good and one is evil in this case).

Let's now search for THIS LOCATION, not for the string 'unregistered' any more, inside our dead listing. You may search this location as text ('CF31A') or as code in inverted notation (1AF34C00). Do whatever you want (you may also just search for 'registration key'... there are many ways to catch the guts of this incredibly naïve protection scheme). However you search you'll immediately land inside the following code snippets, where the target SETS our triggering flag inside memory location CF31A.


:0047BA54 B898BB4700      mov eax, 0047BB98            ;"Registration Key accepted!"
:0047BA59 E83EBEFBFF      call 0043789C                ;call this and that
:0047BA5E C6051AF34C0000  mov byte ptr [004CF31A], 00  ;good guy, let's give him zero
:0047BA65 EB11            jmp 0047BA78                 ;go ahead


:004CBB67 E834F7FAFF      call 0047B2A0               ;after executing this subroutine
:004CBB6C 84C0            test al, al                 ;check the returned value with AND
:004CBB6E 7509            jnz 004CBB79                ;jump good flag if zero flag clear
:004CBB70 C6051AF34C0001  mov byte ptr [004CF31A], 01 ;mark the non registered
:004CBB77 EB07            jmp 004CBB80                ;beggar off without good flag
:004CBB79 C6051AF34C0000  mov byte ptr [004CF31A], 00 ;get good flag

Since our memory location is SET only three times inside our target... two times as we like it (to zero, at 47BA5E and 4CBB79) and only once as we do NOT want it to be (to one at 4CBB70), the crack is straightforward ... you only need to change ONE SINGLE BYTE of the code and this target will be always registered: You just need to change original code.

:004CBB70 C6051AF34C0001  mov byte ptr [004CF31A], 01 ;bad flag

Into cracked code.

:004CBB70 C6051AF34C0000  mov byte ptr [004CF31A], 00 ;good guy

Of course inside the target we will have somewhere a routine that checks if the input numbers of the registration are correct and that sets our triggering call bad or good as a consequence... we COULD NOT CARE LESS. The mathematical manipulations of our input do not have any relevance for us: as you will see once you crack it there is not even a mention anywhere of your name and serial number. The one byte above, changed from one to zero is enough.

That's all. Run your cracked target (and eventually buy its new version if you like it... you'll notice that tekfct95.exe offers indeed some very useful functions for our endeavours). That's it, you are a cracker, today you have examined some 'hidden' alien code, you have reversed engineered the meaning of some memory locations and flags and you have then 'patched' a target in order to eliminate a protection scheme... yet this is NOT illegal if you have done it in order to learn AND if you reverse software that you have LEGALLY obtained (either bought or downloaded in its "trial" or "shareware" versions).

If you want to steal or "pirate" software you have landed at the wrong address :- crackers crack protections and reverse alien code, they don't steal software ... they often enough do the contrary :- they BUY software they don't need at all (or at least they buy magazines carrying CD-ROM's full packed of trial versions :-) just in order to crack, not in order to use it. So if all that interests you is to get some software for free, then I'm afraid you have chosen a rather uselessly complicated way to get it.

There is nothing easier than to fetch stolen software without any effort on the web : you'll have all the complete and full working versions of whatever game or commercial application you want in a million different places! Search for 'warez' (or 'gamez' or 'appz', or whatever) and beggar off. Farewell. For those among you that want to learn the difficult 'white art' of reverse engineering, heed my words: you'll have to study a lot, read a lot and search a lot. You'll have to learn to discriminate between very well packed useless crap-information and almost unreadable fragments of very important knowledge. You'll have to grasp techniques so new and so quickly evolving that even their names may vary from one researcher to another. A huge new world awaits you: spring in.

Well, I reckon that's enough for this first lesson.
(c) fravia+ November 1997. All rights reserved.