We shall call the first type return by register which is like a higher-level language function that returns a Boolean (true or false) value. Figure 1 is an example of this.
Function DocCheck : Boolean; BEGIN ..Code to do the check .. function returns true if .. check was ok. END; BEGIN IF DocCheck THEN MainProgram; ELSE PirateExit; END. |
What happens here is that the doc check function returns a boolean true if the user has entered the correct word or phrase. All compilers use AX to return a boolean value from a function. This means that the check will be something that compares AX to some value. You may use HackmanÆs unassembler to determine the exact offset. Next figure 2, shows a typical type 1 doc check including call to check function and code to check the return value.
xxxx:0001 CALL DocCheck xxxx:0003 OR AX,AX xxxx:0005 JZ 0100 |
DocCheck returns a value in AX register as shown in figure 1. The OR AX,AX statement tests to see if the value is 0. The JZ jumps if a value of 0 is returned. That simple.
LetÆs sneak in the second doc-check type. It is a routine that during the middle sets a value. Figure 3 is an example of this type written is pseudo-pascal code. Right at the end of the doc check routine, the program sets a global variable. This variable is checked later in the program. To tell if you have to deal with a type-2 doc check, if after the call to the routine the program just seems to go on with other business (i.e. no CMP AX,value, no OR AX,AX etc.) we can assume that itÆs type 2.
VAR PirateCopy : Boolean; PROCEDURE DocCheck; BEGIN ShowInfo; GetStr; If Str=Right THEN PirateCopy:=TRUE; ELSE< PirateCopy:=FALSE; END BEGIN DocCheck .. Does Something IF NOT PirateCopy MainProgram; END. |
Our final step is to crack the routine.