CRACKING 101 - 1990 edition Lesson 2 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ DOC CHECK PRIMER ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ by Buckaroo Banzai Ok, in this textfile, I will start talking about removing doc check protection schemes. I find, the doc check scheme to be slightly more difficult to work on than normal INT 13 schemes. What is a doc check. Usually, a doc check when a program ask the user to enter a phrase or code supplied with the manual. Now, one might think that "Shit, we can just type all the codes in to a textfile and upload it with the DOCS", but that way of thinking breaks down on programs such as Future Classics where there are 6 pages with about 200 codes per page. So it is just better to remove the check completely. In this primer, I will get in to the theory of removing a doc check, then start with a simple example (Electronic Art's ESCAPE FROM HELL). Then in the next file, I will take you deeper in to the world of doc checks and work with more difficult examples. But for now, lets get started. A doc check, in basic theory works much like normal INT 13 copy protection. Somewhere in the beginning of the program before it really starts, the check is made. If the result is ok (ie the user enters the correct word or phrase) then the program continues. If not, then the program simply exits to dos. Simple right, well not really. Usually, the input routine is part of the standard input routine of the program so you just can't go about modify the call to INT 16h (the keyboard interrupt) like you could with INT 13h. So, where do we start. If you think back to cracking the old INT 13 protection schemes, you would use a program like PCWATCH or TRAP13 to get a rough idea of where the call resides. With doc checks, this is really not the best way to do it. I suggest that you try to break in to the program well before the protection is checked. Remember, we must remove the check without messing with the actual input routine so we want to come in highest level. So, how do we break in. By using a good debugger. I suggest Periscope. I find it is the best and easiest to use. Once we are in, all the is left is to trace through the program until we find the topmost call to the doc check. Now we're moving. So let's say we have broken in to the program and found the topmost call to the doc check. What next. We must try to figure out what the program does. There are 2 possibilities. First, the program could simply check the inputed string against a value in memory, and if they don't match simply exit to dos and if they do, just continue with the program; or if the input matches it can set a flag in memory that is checked by some routine later. So, on to the example. NOTE! All address might be different. This is how it looked when I cracked it. ALSO NOTE, you should be cracking without any memory resident programs. Make sure MEMORY is clear, and that you load the system the same way each time. Remember, if you load everything the same, everything will be in the same memory location. So, what is our first step. Well, I suggest picking out the right tools to do the job. In this case, You will only need PERISCOPE (and the addin program that comes with it called PSKEY) and a good file editor (when I say good I mean it can edit and search in hex). So let's get started. First, we load PERISCOPE (PS from now on). This is gonna be the debugger we use. Next, we need a quick way in to the debugger. Since ESCAPE FROM HELL (EFH from now on) is not all the picky about how it keeps a crackest out, PSKEY will do just fine but not without using a little trick. Normally, when using PSKEY (for those of you who do not know what PSKEY does, it allows up to break in to PS usings a TSR hotkey) and you hit the hotkey, PSKEY does an INT 2h (NMI). This then brings up PS and you are set. But, EFH revectors INT 2h (NMI) to simply an IRET so this method does not work. How do we get around this, well, INT 2h is the default used with PSKEY but not the only way to work it. You can also use INT 3h (Breakpoint interrupt) or INT 15h (Extended services interrrupt) to activate PS. In this case we will use INT 3h; so when we invoke PSKEY we add the command line parameter "3" (ie: "PSKEY 3CAL" invokes PSKEY using INT 3h setting the hotkey to CTRL-ALT-LEFT_SHIFT). So, now that we have a way in to EFH, where do we want to break out. Well boys (and Girls, and BTW: if there are any Fems reading this, give me a ring, I'd like to hear from ya) I don't have any formula to give, but remember, I suggest that we try to break in to the outermost loop. So, experiance (and a good fucking guess) tells me to break out in the title screen before the music begins. It just so happens that this time I was right (And noone had to get nail to anything -D.A.) Right after the title picture comes up, press your hotkey (oooh). The PS debugging screen should come up and you should see the follow section of code.. 2309:019C CF IRET 2309:019D 3D0085 CMP AX,8500 etc. This is the exit code from PSKEY. By usings the J(ump) command, and executing the IRET, you will be put back right to the spot where you pressed the hotkey (boy I'm getting excited). I would love to give you a code fragment here, but each time you press the hotkey you will end up at a different point. So what do we do next. Well, we will just have to keep executing code until we find some reference point. Remember how I said we wanted to break out before we reached to music at the title screen. Well, you can bet that we are in the outermost loop since the music comes before the doc check and we haven't reached the call to the music routine yet. So we start executing code. Then all of the sudden BOOM! you execute a CALL instruction and music bursts through the speaker. AHa, a reference point. We know we are on the right track. Press during the music so that we can skip the stupid intro for now. After pressing you should regain control at the instruction after the call to the music routine. From here on out, we want to procede rather slowly. Each time you reach a CALL instruction you want to write down the address where it is located. Sooner or later you will execute a CALL instruction and EFH will jump in to it's doc check routine. But damn, you have the address of the that call WRITTEN DOWN right. So simply reboot and reload everything. Break out in to PS at the title picture. Now, unassemble the address you wrote down. You should see something like this 21DD:3EA4 9AA5368132 CALL 3281:36A5 (current line) 21DD:3EA4 9A522F8132 CALL 3281:2F52 21DD:3EA4 C706BB070000 MOV WORD PTR [07BB],0000 21DD:3EA4 8BE5 MOV SP,BP 21DD:3EA4 5D POP BP 21DD:3EA4 CB RETF The first call, is the call to the doc check, therefore it can for now be assumed that the second call is to the actual game (remember, most programmers follow good programming practice and will exit the routine that does the doc check to finish the game). Please NOTE, from here on out, if I say go back to STEP 1, reboot the machine, reload and get to this point. Ok. Our first though in seeing code like this is shit maybe they just check the keyword and exit to dos if it's bad; if it it's good, then they just exit that subroutine and start the game. So having lots of time on our hands, we try just executing the second CALL and bypass the first (you can do that by setting the IP (instruction pointer) register to the offset of the second call [In our case 3EA9]). When you do this, the screen clears, and you see the character (Richard) on the screen. But just as you think it worked, it switches back to text mode and prints the message "Hell is HOT". Shit I hate it when that happens. So now we know that somewhere in the doc check routine, EFH sets a flag in memory. We must figure out where this flag is and figure out a way to fake it. So go back to step 1, this time, let's trace (using the T command) in to the doc check routine. I have included the entire outerloop of the doc check routine here. The small subroutines are not of any importants and infact when I first crack EFH, I never traced in to any of them. It wasn't until I was out getting this information that I took a look to see what they did. Here is the dos check code. I have place some basic instructions that should help you as you go along. Although you address might be different than mine, I will use mine for reference. Also, I have noted some special subroutines along the way. ( - Unassembled DOC CHECK for ESCAPE FROM HELL [outer loop] ) First, we start off with some initialization routines. You don't need to be all to concerned with them. 3281:36A5 55 PUSH BP 3281:36A6 8BEC MOV BP,SP 3281:36A8 83EC2A SUB SP,+2A 3281:36AB C746DE0000 MOV WORD PTR [BP-22],0000 3281:36B0 B80600 MOV AX,0006 3281:36B3 50 PUSH AX 3281:36B4 9AE3169900 CALL 0099:16E3 3281:36B9 59 POP CX 3281:36BA 48 DEC AX 3281:36BB 8946DA MOV [BP-26],AX 3281:36BE B80F00 MOV AX,000F 3281:36C1 50 PUSH AX 3281:36C2 9AE3169900 CALL 0099:16E3 3281:36C7 59 POP CX 3281:36C8 48 DEC AX 3281:36C9 8946DC MOV [BP-24],AX 3281:36CC C706CB070E00 MOV WORD PTR [07CB],000E 3281:36D2 C746D60000 MOV WORD PTR [BP-2A],0000 3281:36D7 E9C002 JMP 399A 3281:36DA C746D80000 MOV WORD PTR [BP-28],0000 3281:36DF E92501 JMP 3807 3281:36E2 9A9B479900 CALL 0099:479B 3281:36E7 B83866 MOV AX,6638 3281:36EA 50 PUSH AX 3281:36EB A03407 MOV AL,[0734] 3281:36EE B400 MOV AH,00 3281:36F0 50 PUSH AX 3281:36F1 B80C00 MOV AX,000C 3281:36F4 50 PUSH AX 3281:36F5 B8CF00 MOV AX,00CF 3281:36F8 50 PUSH AX 3281:36F9 8B46DC MOV AX,[BP-24] 3281:36FC BA5800 MOV DX,0058 3281:36FF F7E2 MUL DX 3281:3701 8BD8 MOV BX,AX 3281:3703 8A87F640 MOV AL,[BX+40F6] 3281:3707 B400 MOV AH,00 3281:3709 8BD8 MOV BX,AX 3281:370B 81C39400 ADD BX,0094 3281:370F D1E3 SHL BX,1 3281:3711 D1E3 SHL BX,1 3281:3713 FFB7F25D PUSH [BX+5DF2] 3281:3717 FFB7F05D PUSH [BX+5DF0] 3281:371B 9AE7019900 CALL 0099:01E7 3281:3720 83C40C ADD SP,+0C 3281:3723 8B46DA MOV AX,[BP-26] 3281:3726 3D0500 CMP AX,0005 3281:3729 7603 JBE 372E 3281:372B E9B200 JMP 37E0 3281:372E 8BD8 MOV BX,AX 3281:3730 D1E3 SHL BX,1 3281:3732 2E CS: 3281:3733 FFA73737 JMP [BX+3737] 3281:3737 43 INC BX 3281:3738 37 AAA 3281:3739 5E POP SI 3281:373A 37 AAA 3281:373B 7837 JS 3774 3281:373D 92 XCHG DX,AX 3281:373E 37 AAA 3281:373F AC LODSB 3281:3740 37 AAA 3281:3741 C637B8 MOV BYTE PTR [BX],B8 3281:3744 2000 AND [BX+SI],AL 3281:3746 50 PUSH AX 3281:3747 B82E01 MOV AX,012E 3281:374A 50 PUSH AX 3281:374B B88100 MOV AX,0081 3281:374E 50 PUSH AX 3281:374F B87348 MOV AX,4873 3281:3752 50 PUSH AX 3281:3753 9AD6029900 CALL 0099:02D6 3281:3758 83C408 ADD SP,+08 3281:375B E98200 JMP 37E0 3281:375E B82000 MOV AX,0020 3281:3761 50 PUSH AX 3281:3762 B82E01 MOV AX,012E 3281:3765 50 PUSH AX 3281:3766 B88100 MOV AX,0081 3281:3769 50 PUSH AX 3281:376A B88648 MOV AX,4886 3281:376D 50 PUSH AX 3281:376E 9AD6029900 CALL 0099:02D6 3281:3773 83C408 ADD SP,+08 3281:3776 EB68 JMP 37E0 3281:3778 B82000 MOV AX,0020 3281:377B 50 PUSH AX 3281:377C B82E01 MOV AX,012E 3281:377F 50 PUSH AX 3281:3780 B88100 MOV AX,0081 3281:3783 50 PUSH AX 3281:3784 B8AD48 MOV AX,48AD 3281:3787 50 PUSH AX 3281:3788 9AD6029900 CALL 0099:02D6 3281:378D 83C408 ADD SP,+08 3281:3790 EB4E JMP 37E0 3281:3792 B82000 MOV AX,0020 3281:3795 50 PUSH AX 3281:3796 B82E01 MOV AX,012E 3281:3799 50 PUSH AX 3281:379A B88100 MOV AX,0081 3281:379D 50 PUSH AX 3281:379E B8C748 MOV AX,48C7 3281:37A1 50 PUSH AX 3281:37A2 9AD6029900 CALL 0099:02D6 3281:37A7 83C408 ADD SP,+08 3281:37AA EB34 JMP 37E0 3281:37AC B82000 MOV AX,0020 3281:37AF 50 PUSH AX 3281:37B0 B82E01 MOV AX,012E 3281:37B3 50 PUSH AX 3281:37B4 B88100 MOV AX,0081 3281:37B7 50 PUSH AX 3281:37B8 B8E848 MOV AX,48E8 3281:37BB 50 PUSH AX 3281:37BC 9AD6029900 CALL 0099:02D6 3281:37C1 83C408 ADD SP,+08 3281:37C4 EB1A JMP 37E0 3281:37C6 B82000 MOV AX,0020 3281:37C9 50 PUSH AX 3281:37CA B82E01 MOV AX,012E 3281:37CD 50 PUSH AX 3281:37CE B88100 MOV AX,0081 3281:37D1 50 PUSH AX 3281:37D2 B80F49 MOV AX,490F 3281:37D5 50 PUSH AX 3281:37D6 9AD6029900 CALL 0099:02D6 3281:37DB 83C408 ADD SP,+08 3281:37DE EB00 JMP 37E0 3281:37E0 B82D00 MOV AX,002D 3281:37E3 50 PUSH AX 3281:37E4 B88200 MOV AX,0082 3281:37E7 50 PUSH AX 3281:37E8 9A96029900 CALL 0099:0296 3281:37ED 59 POP CX 3281:37EE 59 POP CX 3281:37EF B82849 MOV AX,4928 3281:37F2 50 PUSH AX 3281:37F3 9A3F039900 CALL 0099:033F 3281:37F8 59 POP CX 3281:37F9 837ED800 CMP WORD PTR [BP-28],+00 3281:37FD 7505 JNZ 3804 Here is the first point of interest. The call on the following line will display the "what is xxxx" message. Ä¿ ³ 3281:37FF 9A1B019900 CALL 0099:011B <ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ 3281:3804 FF46D8 INC WORD PTR [BP-28] 3281:3807 837ED802 CMP WORD PTR [BP-28],+02 3281:380B 7D03 JGE 3810 3281:380D E9D2FE JMP 36E2 3281:3810 8B46DA MOV AX,[BP-26] 3281:3813 3D0500 CMP AX,0005 3281:3816 7603 JBE 381B 3281:3818 E97401 JMP 398F 3281:381B 8BD8 MOV BX,AX 3281:381D D1E3 SHL BX,1 3281:381F 2E CS: 3281:3820 FFA72438 JMP [BX+3824] 3281:3824 3038 XOR [BX+SI],BH 3281:3826 6E DB 6E 3281:3827 38AC38EA CMP [SI+EA38],CH 3281:382B 3827 CMP [BX],AH 3281:382D 396439 CMP [SI+39],SP 3281:3830 B81000 MOV AX,0010 3281:3833 50 PUSH AX 3281:3834 16 PUSH SS 3281:3835 8D46E2 LEA AX,[BP-1E] 3281:3838 50 PUSH AX 3281:3839 9AFB149900 CALL 0099:14FB 3281:383E 83C406 ADD SP,+06 3281:3841 8D46E2 LEA AX,[BP-1E] 3281:3844 50 PUSH AX 3281:3845 9A0F00B81B CALL 1BB8:000F 3281:384A 59 POP CX 3281:384B 8B46DC MOV AX,[BP-24] 3281:384E BA5800 MOV DX,0058 3281:3851 F7E2 MUL DX 3281:3853 05F740 ADD AX,40F7 3281:3856 50 PUSH AX 3281:3857 8D46E2 LEA AX,[BP-1E] 3281:385A 50 PUSH AX 3281:385B 9A0E00661A CALL 1A66:000E 3281:3860 59 POP CX 3281:3861 59 POP CX 3281:3862 0BC0 OR AX,AX 3281:3864 7505 JNZ 386B 3281:3866 C746DEFFFF MOV WORD PTR [BP-22],FFFF 3281:386B E92101 JMP 398F 3281:386E B81000 MOV AX,0010 3281:3871 50 PUSH AX 3281:3872 16 PUSH SS 3281:3873 8D46E2 LEA AX,[BP-1E] 3281:3876 50 PUSH AX 3281:3877 9AFB149900 CALL 0099:14FB 3281:387C 83C406 ADD SP,+06 3281:387F 8D46E2 LEA AX,[BP-1E] 3281:3882 50 PUSH AX 3281:3883 9A0F00B81B CALL 1BB8:000F 3281:3888 59 POP CX 3281:3889 8B46DC MOV AX,[BP-24] 3281:388C BA5800 MOV DX,0058 3281:388F F7E2 MUL DX 3281:3891 050841 ADD AX,4108 3281:3894 50 PUSH AX 3281:3895 8D46E2 LEA AX,[BP-1E] 3281:3898 50 PUSH AX 3281:3899 9A0E00661A CALL 1A66:000E 3281:389E 59 POP CX 3281:389F 59 POP CX 3281:38A0 0BC0 OR AX,AX 3281:38A2 7505 JNZ 38A9 3281:38A4 C746DEFFFF MOV WORD PTR [BP-22],FFFF 3281:38A9 E9E300 JMP 398F 3281:38AC B81000 MOV AX,0010 3281:38AF 50 PUSH AX 3281:38B0 16 PUSH SS 3281:38B1 8D46E2 LEA AX,[BP-1E] 3281:38B4 50 PUSH AX 3281:38B5 9AFB149900 CALL 0099:14FB 3281:38BA 83C406 ADD SP,+06 3281:38BD 8D46E2 LEA AX,[BP-1E] 3281:38C0 50 PUSH AX 3281:38C1 9A0F00B81B CALL 1BB8:000F 3281:38C6 59 POP CX 3281:38C7 8B46DC MOV AX,[BP-24] 3281:38CA BA5800 MOV DX,0058 3281:38CD F7E2 MUL DX 3281:38CF 051941 ADD AX,4119 3281:38D2 50 PUSH AX 3281:38D3 8D46E2 LEA AX,[BP-1E] 3281:38D6 50 PUSH AX 3281:38D7 9A0E00661A CALL 1A66:000E 3281:38DC 59 POP CX 3281:38DD 59 POP CX 3281:38DE 0BC0 OR AX,AX 3281:38E0 7505 JNZ 38E7 3281:38E2 C746DEFFFF MOV WORD PTR [BP-22],FFFF 3281:38E7 E9A500 JMP 398F 3281:38EA B81000 MOV AX,0010 3281:38ED 50 PUSH AX 3281:38EE 16 PUSH SS 3281:38EF 8D46E2 LEA AX,[BP-1E] 3281:38F2 50 PUSH AX 3281:38F3 9AFB149900 CALL 0099:14FB 3281:38F8 83C406 ADD SP,+06 3281:38FB 8D46E2 LEA AX,[BP-1E] 3281:38FE 50 PUSH AX 3281:38FF 9A0F00B81B CALL 1BB8:000F 3281:3904 59 POP CX 3281:3905 8B46DC MOV AX,[BP-24] 3281:3908 BA5800 MOV DX,0058 3281:390B F7E2 MUL DX 3281:390D 052A41 ADD AX,412A 3281:3910 50 PUSH AX 3281:3911 8D46E2 LEA AX,[BP-1E] 3281:3914 50 PUSH AX 3281:3915 9A0E00661A CALL 1A66:000E 3281:391A 59 POP CX 3281:391B 59 POP CX 3281:391C 0BC0 OR AX,AX 3281:391E 7505 JNZ 3925 3281:3920 C746DEFFFF MOV WORD PTR [BP-22],FFFF 3281:3925 EB68 JMP 398F 3281:3927 B81000 MOV AX,0010 3281:392A 50 PUSH AX 3281:392B 16 PUSH SS 3281:392C 8D46E2 LEA AX,[BP-1E] 3281:392F 50 PUSH AX Next point of interest. When you execute this line, the game will pause and wait for you to enter the code word from the manual. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ 3281:3930 9AFB149900 CALL 0099:14FB <ÄÄÄÄÄÙ 3281:3935 83C406 ADD SP,+06 3281:3938 8D46E2 LEA AX,[BP-1E] 3281:393B 50 PUSH AX 3281:393C 9A0F00B81B CALL 1BB8:000F 3281:3941 59 POP CX 3281:3942 8B46DC MOV AX,[BP-24] 3281:3945 BA5800 MOV DX,0058 3281:3948 F7E2 MUL DX 3281:394A 053B41 ADD AX,413B 3281:394D 50 PUSH AX 3281:394E 8D46E2 LEA AX,[BP-1E] 3281:3951 50 PUSH AX 3281:3952 9A0E00661A CALL 1A66:000E 3281:3957 59 POP CX 3281:3958 59 POP CX 3281:3959 0BC0 OR AX,AX 3281:395B 7505 JNZ 3962 3281:395D C746DEFFFF MOV WORD PTR [BP-22],FFFF 3281:3962 EB2B JMP 398F 3281:3964 33D2 XOR DX,DX 3281:3966 B8B80B MOV AX,0BB8 3281:3969 52 PUSH DX 3281:396A 50 PUSH AX Next point of interest. This call is the final evaluation of the entered word (or phrase). On return, it checks a checksum value. This whole next section of code (up to 3281:39Ad) simply test the validity of the keyword you entered. I have marked the all jumps that happened when I entered my keyword with an " * ". 3281:396B 9A71139900 CALL 0099:1371 3281:3970 59 POP CX 3281:3971 59 POP CX 3281:3972 8946E0 MOV [BP-20],AX 3281:3975 8B46DC MOV AX,[BP-24] 3281:3978 BA5800 MOV DX,0058 3281:397B F7E2 MUL DX 3281:397D 8BD8 MOV BX,AX 3281:397F 8B874C41 MOV AX,[BX+414C] 3281:3983 3B46E0 CMP AX,[BP-20] 3281:3986 7505 *JNZ 398D 3281:3988 C746DEFFFF MOV WORD PTR [BP-22],FFFF 3281:398D EB00 JMP 398F 3281:398F 837EDE00 CMP WORD PTR [BP-22],+00 3281:3993 7402 *JZ 3997 3281:3995 EB0C JMP 39A3 3281:3997 FF46D6 INC WORD PTR [BP-2A] 3281:399A 837ED602 CMP WORD PTR [BP-2A],+02 3281:399E 7D03 *JGE 39A3 3281:39A0 E937FD JMP 36DA 3281:39A3 837EDE00 CMP WORD PTR [BP-22],+00 3281:39A7 7504 *JNZ 39AD 3281:39A9 0E PUSH CS 3281:39AA E8E8FC CALL 3695 This is the last point of interest. The next instruction is where we set the key (by moving FFFFh to the memory location DS:0744h). This is what we need to fake to allow the system to run. ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ 3281:39AD C7064407FFFF MOV WORD PTR [0744],FFFF <ÄÄÄÙ 3281:39B3 B8FFFF MOV AX,FFFF 3281:39B6 50 PUSH AX 3281:39B7 9AC0479900 CALL 0099:47C0 3281:39BC 59 POP CX 3281:39BD 8BE5 MOV SP,BP 3281:39BF 5D POP BP 3281:39C0 CB RETF Ok, we have now finished the doc check, and control has returned (when the RETF instruction was executed) to 21DD:3EA9. We are now ready to continue with the game. Notice the instruction at 3281:39AD. This is where EFH sets that external flag. But how did I determine this. Well, by luck. If you look through the entire routine, you will not find any other instructions placing a value in the data segment (DS). And since I decided a long time ago that EFH was written in a higher level language, we can assume that it is writting to some variable. So, hoping that we have found the flag, we go back to step 1. This time, we manualy edit the word at DS:0744 and place the value FFFFh there. We then skip over the call the the doc check and execute the game. Then before our eyes, shit happenes. The game comes up, and everything is fine. By George you've got it. So how do we fix the program to always return a good doc check. Well, we could go about it 2 ways. The first, is you could simple modify the instruction at 3281:3935 to perform a long jump to 3281:39AD. This would force set the value no matter what was typed. But who the fuck wants to have to type anything. I sure don't so lets think of another way. If we look at the entire doc check routine, we will see that it does nothing but handle the doc check (remember when we first bypassed the check. The screen came up and everything looked fine until it dropped you out. So we can assume that the actual screen is not setup in doc check. So I suggest placing a small patch right in the begining of the doc check. But what should this patch do? (BTW: it's late and I don't know If I'm using ?s right. So if not TOO FUCKING BAD). Well, all it should do is place the value FFFFh at DS:0744h. Here is the assembly language routine to do it. 50 PUSH AX B8FFFF MOV AX,FFFF 3E DS: A34407 MOV WORD PTR [0744],AX 58 POP AX CB RETF This small routine will place the value FFFFh at DS:744 and then exit back to the main loop. Simple huh (note, you don't really need the save AX or load AX with FFFFh for that matter but I did it for clarity). So now that we have the patch, and now where to put it, how do we get it there. Well, thats where the file editor comes in, but first you will need 2 things. The hex equivlent of out patch (in this case the 10 bytes : 50,B8,FF,FF,3E,A3,44,07,58,CB) and some string to search for. I suggest usings the first 14 bytes of the routines we are going to write over (the code at address 3281:36A5). Those bytes are 55, 8B, EC, 83, EC ,2A ,C7, 46, DE ,00 ,00, B8, 06, and 00. When selecting the search string, select only instructions that ARN'T call, jump, loop or any instruction that has a memory address in them. This value will NOT be the same when you do the search. Now, using for file editor (I used PCTOOLS, but NORTON's will do) search for our string (55,8B, etc). When it is found (somewhere near sector 200) write down the sector #. Now, go and edit that sector. Find our search string (55,8B, etc) and replace it with the patch string (50,B8,FF, etc). Now save the sector. Your down. Try playing the game. It should load up, and then go right from the title page (or the intro) to the game without stopping at the doc check. If your doesn't, then you fucked up. Restart from the beginning (NO, this file didn't fuck up, and I DON'T MAKE MISTAKES). Well, you did it. You have now removed your first doc check. Don't ya feel real good. With time, you will be able to remove any type of doc check. -BUCKAROO BANZAI At this time I would just like to say `ALL CRACKING GROUPS SUCK!'