SOME PROBLEMS WITH INTEL's INTThe INT instruction is the source of a great deal of theflexibility in the PC architecture, because the ability to getand set interrupt vectors means that system services (includedDOS itself) are infinitely extensible, replaceable andMONITORABLE. Yet the Int instruction is also remarkablyinflexible in two key ways:- an interrupt handler DOES NOT KNOW which interrupt number invoked it.- the int instruction itself expects an IMMEDIATE operand: you cannot write MOV AX,x21, and then INT AX; you must write INT x21.That would be very good indeed for us cracker... unfortunatelymany high level language compilers compile interrupts into PUSHFand FAR CALL instruction sequences, rather than do an actual INT.Another method is to PUSH the address of the handler on the stackand do RETF to it. Some protection schemes attempt to disguise interrupt calls, 1) camouflaging the code, 2) putting in substitute interruptinstructions which look harmless and modifying them "on the fly"or 3) replicating whole interrupt routines inside the code. Thisis particularly frequent in the various "disk access" protectionschemes that utilize INT_13 (the "disk" interrupt) and will therefore be thoroughly explained in -> lesson 5. A LITTLE BASIC ASSEMBLERIn order to understand the protection schemes and to defeat them,you must acquire a passing knowledge of assembler, the "machinelanguage" code. You can find a lot of good, well explained codefor free: viruses are one of the best sources for good "tight andtricky" assembler code. You can find the source code of almostall viruses on the web: oddly all the would be hackers seem tohave an aberrant passion for this kind of stuff instead ofstudying cracking techniques. But there are millions of lines ofgood explained "commercial" assembler code on the net, just fishit out and study it: the more you know, the better you crack.I'll restrict myself to some observations, sprinkled throughoutthis tutorial. Let's start with some must_know:------------------------ STRINGS ----------------------------The string instructions are quite powerful (and play a great rolein password protection scheme). ALL of them have the propertythat:1) The source of data is described by the combination DS:SI2) The destination of data is described by the combination ES:DI3) As part of the operation, the SI and/or DI register(s) is(are) incremented or decremented so the operation can be repeated.------------------------- JUMPS -----------------------------JZ ero means what it saysJNZ ero means what it saysJG reater means "if the SIGNED difference is positive"JA bove means "if the UNSIGNED difference is positive"JL ess means "if the SIGNED difference is negative"JB elow means "if the UNSIGNED difference is negative"JC arry assembles the same as JB, it's a matter of aesthetic choiceCRACKING PASSWORD PROTECTED PROGRAMS Refer to lesson one in order to understand why we are usinggames instead of commercial applications as learn material: theyoffer the same protection used by the more "serious" applications(or BBS & servers) although inside files that are small enoughto be cracked without loosing too much time. A whole series of programs employ copy protection schemesbased upon the possess of the original manual or instructions.That's obviously not a very big protection -per se- coz everybodynowadays has access to a photocopier, but it's bothering enoughto motivate our cracks and -besides- you'll find the same schemeslurking in many other password protected programs. Usually, at the beginning of the program, a "nag screen"requires a word that the user can find somewhere inside theoriginal manual, something like: "please type in the first wordof line 3 of point 3.3.2". Often, in order to avoid mistakes, theprogram indicates the first letter of the password... the usermust therefore only fill the remaining letters.Some examples, some cracks: ---------------------------------------------------UMS (Universal Military Simulator) version 1by Dr Ezra SIDRAN(c) 1987 Intergalactic DevelopmentEuropean Union: Rainbird SoftwareUnited States: Firebird Software --------------------------------------------------- This very old EGA program is one of the first I cracked inmy youth, and it's very interesting coz it employs a very basilarprotection scheme (a "PRIMITIVE"! More than 80% of the protectionschemes used to day (January 1996) are directly derived from oneof the 12 primitives. The nag screen snaps at the beginning and keeps indefinitely asking your answer, only the use of CTRL+C will bring you out ofit, back to DOS. That's a clear sign of older protection schemes:newer schemes let you in for only 3 attempts or even only one,and pop out to the OS if you fail. In UMS, besides, there is no"first letter" aid, a later improvement. The cracking procedure for password protected programs is,first of all, to find out where are stored the letters that youtype in. So examine your memory map, find out where the programdwells in memory, do a snap save of these memory areas and aseries of snap compares as you type your password in. Strangely enough, in the case of UMS, as you type yourpassword there seems to be no difference at all in the memorylocations where this program dwells... yet the data must besomewhere... Usually such a situation is a clear sign that anhooked interrupt is used to hide the data. Checking the hooked vectors you find out the following:vecs 00, 02, 22 are hooked where needs bevecs 34-3D are hooked at xxxx:0vec 3E is hooked at xxxx:00CA Ha! Let's have a closer look at this bizarre 3E hook. Let'ssearch for some words used in the nag_screen and then let's dumpthe area where we find them (in UMS that will be at 3E_hookaddress + 7656) and loo! You'll see the content of the nag screenand, immediately afterwards, ALL the passwords "in extenso", i.e.not encoded, not scrambled, nothing at all... THERE THEY ARE(that's a very old protection scheme indeed). You could now, forinstance, easily patch all the different passwords to (forinstance) "PASS", and this would work... it's a very primitiveprotection, as we said, nevertheless the use of a hooked vectoras hiding place for the protection code is not yet obsolete...we'll find it elsewhere, in many "more modern" programs. Now let's go deeper and examine the "compare" mechanism, wewant to crack, here, not just to patch. Password protected programs (and access protection routinesfor server and BBS, for that matter) have quite a lot of weakpoints. The most obvious one (you 'll find out the other whenyou'll high crack) is that they MUST compare the password of theuser with the original one(s). So you do not need to steal apassword, you just need to "ear" the echo of the original one inthe memory locations used for the compare, or, and that's morecorrect, to crack the compare mechanism itself so as to make itlet you in even with a totally false password. The compare mechanism of UMS can be found setting abreakpoint on the memory range that covers the three locations where the password is stored (and you 'll find these with yoursearch capabilities and with a pair of snap compares):ES:0F8E (here you 'll see a copy of the password that the program is asking)ES:0F5C (here you 'll see a copy of the password that the user types in)INT_3E hook_address + 7656 (here are all the possible passwords in extenso).Here is how the protection scheme looks out:MOV CX,FFFF Charge MAX in CXREPNZ SCASB Scan ES:DI (the user password)NOT CX Now CX holds the number of the character that the user typed in MOV DI,SI Real password offset to DILDS SI,[BP+0A] User password offset in SIREPZ CMPSB Compares DS:SI with ES:DI (user password and real password) then snap out at CX=0 or at char_different, whichever comes first.Nice, we found the compare schema... how do we crack it now?There are many elegant solutions, but let's remain on a basiclevel... you look at the code that follows the CMPSB searchingthe "snapping schema"... here it is immediately afterwards(that's the case in most of the primitives). Remember: we sprungout of the CMPSB check at the first different char, OR at the endof the count of the user chars. Here it is what follows: MOV AL,[SI-01] loads in AL the before_different char of the user password (should be zero) SUB AL,ES:[DI-01] subs with the before_different char of the real password (should be zero) CBW zero flag set, "TRUE", if OK_matchWell let's now look for the next JZ near (it's a "74" code) CS:IP 740D JZ location no_goodWait, let's continue a little... is there another check (oftenyou have a double check on DI)... yes there is! CS:IP 7590 JNZ location no_goodCracking such a schema is very easy: you just need to substitute75 to 74 and 74 to 75: transform your JZ in a JNZ and the JNZ ina JZ... now you will always pass, no matter what you write,unless you exactly guess the password!Now let's quickly crack it: ------------------------------------------------CRACKING UMS.EXE (by +ORC, January 1996)ren ums.exe ums.dedsymdeb ums.ded- s (cs+0000):0 Lffff 74 0D 1E B8 C2 3F(nothing)- s (cs+1000):0 Lffff 74 0D 1E B8 C2 3F(nothing)- s (cs+2000):0 lffff 74 0D 1E B8 C2 3Fxxxx:yyyy (this is the answer of the debugger)- e xxxx:yyyy 75- e xxxx:yyyy+17 74- w- qren ums.ded ums.exe------------------------------------------------- In the debug/symdeb crack above we use as search string thebytes comprising and following immediately the first JZ.I know, I know... we saw them in [Soft-ice] and we could havemodified them there, but I'm teaching also pupils who may nothave [Soft-ice]. Note that the program is x431A0 bytes long, and thereforehas a BX=4 sectors adding to the CX=31A0 in the initialregisters... that's the reason I wanted to examine all thesectors (even if I knew that the snap was in sector (cs+2000):that's good practice! If you do not find your string in the first sector you must search for it in the next sectors, till you findit, coz in many programs there may be MORE THAN ONE repetitionsof the same schema (more about this double check later).That's it, pupils, that's the way to crack old [UMS.EXE].Let's go over, now, to more elaborate and more modern password protection schemes.-------------------------------------------------------- LIGHTSPEED, from Microprose (we crack here version 461.01) -------------------------------------------------------- This program, released in 1990, operates a more "modern"variation of the previous scheme. You 'll find this variation inmany access routines of remote servers (and this makes it veryinteresting indeed). Let's begin as usual, with our hooked vectors examinationand our snap compares.Hooked vectors: 00, 08, 1B, 22, 23: nothing particular.The snap_comparisons of the main memory area -as you type thepassword in- gives more than six pages of changing locations...that's clearly much too much to examine.What now? Sit down, have a Martini Wodka (I'm afraid that onlyMoskovskaja 'll do) and meditate. Get the memory map of theprogram's layout. Start anew: snap_save (before typing anythingin). Type as password "ABCDE". Get the print of the snapcompares. Sit down, sip Martini Wodka, relax. You know that thecode for A is x41, for B x42, for C x43 and so on... and in thesnap_compares, that you made between letters, you 'll have onlysome locations with these values changing. Focus on these. You 'll soon enough find out that for LIGHTSPEED absolutelocation (in my computer) 404307, i.e.: relative locations (inmy computer) 30BE:F857 or 4043:0007 evoke the characters youtype, i.e. something like -----------------------------------------------------F855 F856 F857 F858 F859...41 3E first_ready_letter your_1st_letter your_2nd_one...----------------------------------------------------- Inspecting the same prints, you 'll find out that absolutelocation 30C64 (imc) or relative location 30BE:F83E evokes theLAST character you typed in. The relative code line is: CS:0097 MOV AX,[BP-08] where SS:F83E = 00+letter_code Now breakpoint at these locations and investigate what'sgoing on (for instance, the instruction that follows is CS:009A MOV [BX], AX and this means that the code of the letter you just typed in willbe now copied in BX=F85A. What else can you do? Time to use alittle intuition: look for an instruction "CMP AX,000D", whichis the typical "IF the user hits ENTER then" instruction, coz"x1D" its the ENTER keystroke. This must be somewhere around here. Ha! You 'll soon enough find the line CS:0073 3D0D00 CMP AX,000D And now the way is open to the crack. But YOU DO NOT NEED ALLTHIS! Since the password protection schemes are -as I told you-all more or less the same, I would suggest that you use first ofall following trick: in the largest part of the program (usememory map to see where the program dwells) search the "F3A6" sequence, that's instruction REPZ CMPSB. In the case of Lightspd you 'll get as answer FOUR addresseswith this instruction: (pgsg=program main segment) pgsg:C6F9 pgsg:E5CA pgsg:E63E pgsg:EAB0There you are! Only four... have a short look at each of them:you 'll see that the second one (pgsg:E5CA) is the "good" one.The compare mechanism in this program of 1990 it's more or less the same as in 1987'UMS (and do believe me: the same mechanismis still in use to day (1996)!B9FFFF MOV CX,FFFF charge Max in CXF2AE REPNZ SCASB this scans ES:DI (the original password) F7D1 NOT CX so many chars in the original pw2BF9 SUB DI,CX change DI for compareF3A6 REPZ CMPSB compares DS:SI with ES:DI (real pw with user pw) then snaps out at CX=0 or at char_differs See how easy? They all use the same old tricks the lazybastards! Here the section is preceded by a small routine tolowercase the user password, coz the original muster is always lowercased. Now you would like, may be, to breakpoint at one of these locations, in order to stop the program "in the snap area" andinspect the snap mechanism... that WILL NOT DO with a "fixed"breakpoint, coz these locations are called by the snap with adifferent segment:offset numeration as the one you found (that'sold dos magic). So you MUST first set a memory_read/writebreakpoint on these locations, and then get at them at the snap.Now you can find out the segment:offset used by the snap and onlynow you'll be able to set a fixed breakpoint (for instance on theNOT CX instruction). Now run the program and breakpoint in: have a dump of theES:DI and see the original password. How nice! We have now theoriginal password in extenso in our memory dump window. That'sthe "echo". By the way, there is a whole school of crackingdevoted to find and use these echoes... we work on differentpaths, nevertheless password fishing can be interesting: whereare the password stored? From which locations do they come from?A common practice of the protectionists is to hide them indifferent files, far away, or in hooked vectors, or in SMC parts.This is a program of 1990, that differs in respect to UMS: thepasswords are not "hidden" inside a hooked vector, coz that's apretty stupid protection: any hexdump utility would still permityou to see them. Here the passwords are encoded (albeit in a veryprimitive manner): looking for them (with memory rangebreakpoints) you'll quickly find a section of the program codethat looks like this:sg:0118 8C 91 9D 95 9B 8D 00 B8 EC 94 9B 8D 8F 8B 9Bsg:0128 94 9B 8D 00 AE EC 9C 9B 8A 9B 86 00 A9 EC 91This is a typical encoded matrix, with clear 00 fences betweenthe encoded passwords.Ha! If all codes where so easy to crack! This is no better thanchildren's crypt! It's a NEG matrix! And there is directcorrespondence: 91=6F="o"; 92=6E="n"; 93=6D="m" and so on... Ha! Let's now leave the "hidden" passwords and proceed with our cracking... let's follow the snap procedure after the REPZ CMPSBinstruction looking for the "jump to OK" instruction...F3A6 REPZ CMPSB ; compares DS:SI with ES:DI 7405 JZ preserved_AX=0000 <--- Here the first JZ1BC0 SBB AX,AXADFFFF SBB AX,FFFF :preserved_AX=00008BF3 MOV SI,BX8BFA MOV DI,DX5D POP BPCB RETF....83C404 ADD SP,+040BC0 OR AX,AX7509 JNZ 0276 <------ And here it is! Now, remembering the UMS crack, you would probably want tochange the JZ instruction in a JNZ instruction (you tried it onthe fly INSIDE [Soft-Ice] and it did work!), the "74" with a"75" also. And then you would like to change the JNZ instructionin a JZ instruction... Please feel free to try it... it will NOTwork! (You will not even find the second JNZ in the programcode). You should always be aware of the SMC (self modifyingcode) protections: parts of the code my be decrypted "on thefly", as needs arise, by the program. The code you modify whilethe program is running may be different from the code of the"dead" program. Here we have a small "improvement" of the primitive: thesame instruction is used as "muster" for manipulation of otherparts of the program... if you do change it in a JNZ you get anoverlay message and the program pops out with instability! Youcannot easily modify the JNZ instruction either, coz the part after the RETF will be compiled "on the fly" by lightspeed, andyou would therefore have to search the decryption mechanism andmodify the original encrypted byte somewhere... and may be theydo encrypt it twice... and then you must hack all night long...very annoying. So do the following: back to the snap, a sip of martini-Wodka and meditate: loo! The only thing that happens after theJZ, is the setting of the AX register to flag *FALSE* (AX=1...that's what the two SBB instructions do) if the snap went outwith a non-zero flag... i.e. if you did not know the password.So let's nop the 5 bytes of the two SBB instructions, or, moreelegantly, let's have a INC AX, DEC AX, NOP, INC AX, DEC AXsequence instead of the two SBB! There is a good reason to usea sequence of working instructions instead of a series of NOPs:recent protection schemes "smell" patched nops inside the programand trash everything if they find more than -say- threeconsecutive NOPs! You should always try to choose THE LESS INTRUSIVE and MORE "CAMOUFLAGED" solution when you crack! Eliminating the two SBBs we get our crack! No need to botherwith the second JNZ either... the program will work as if you gotthe password if you have it AND if you do not (that's better asthe previous type of crack -seen for UMS- when you crack computeraccesses: hereby the legitimate user will not have any suspects'coz the system will not shut him out... everybody will access:the good guys and the bad ones... that's nice isn't it?). Now let's quickly crack LIGHTSPD: ------------------------------------------------CRACKING LIGHTSPEED.EXE (by +ORC, January 1996)ren lightspd.exe lightspd.dedsymdeb lightspd.ded- s (cs+0000):0 Lffff 2B F9 F3 A6 74xxxx:yyyy (this is the answer of the debugger)- s (cs+1000):0 Lffff 2B F9 F3 A6 74(nothing, but do it nonetheless, just to be sure)- s (cs+2000):0 lffff 2B F9 F3 A6 74 (nothing, just to be sure, now it's enough)- e xxxx:yyyy+6 40 [SPACE] 48 [SP] 90 [SP] 40 [SP] 48- w- qren lightspd.ded lightspd.exe -------------------------------------------------All this CMPSB is very common. Some programs, nevertheless,utilize a password protection scheme that is slightly different,and does not rely on a F3A6 REPZ CMPSB instruction. Let's analyze, for instance, the protection scheme used in the firstversion of Perfect general I from QQP-White wolf, July 1992.When you break in, at the nag screen, you are in the middle ofthe BIOS procedures, coz the program expects your input (yourpassword, that's is). You 'll quickly find out (MAP MEMORYUSAGE!) that [General.exe] dwells in two main areas; Settingbreakpoints on memory write you 'll find out that the memory area"queried" by the protection mechanism is xxxx:1180 to xxxx:11C0where xxxx represents the second of the memory segments where theprogram dwells. Now do the following (a very common crackingprocedure): * Breakpoint on memory range WRITE for the small memory area touched by the program in querying you for the password.* Breakpoint TRACE on the whole memory range of the MAIN CODE.* Run anew everythingIt's already done! Now it's your intuition that should work alittle: Here the last 9 traces (traces [!], not instructionsfollowing on a line) before the calling of the procedure sniffingyour memory area:-9 xxxx:0185 7425 JZ somewhere, not taken -8 xxxx:0187 2D1103 SUB AX,0311-7 xxxx:018A 7430 JZ somewhere, not taken-6 xxxx:018C 2DFD04 SUB AX,04FD-5 xxxx:018F 7443 JZ next_trace, taken-4 xxxx:01D4 E85500 CALL funny_procedure -3 xxxx:022C 803E8F8C11 CMP BYTE PTR[8C8F],11-2 xxxx:0231 750E JNZ somewhere, not taken-1 xxxx:0233 9A0A0AC33E CALL procedure_that_sniffs our_memory_area Well, the call to funny_procedure followed by a byte compare"feels" fishy from very far away, so let's immediately look atthis part of the code of [General.exe]:funny_procedure 803E8F8C11 CMP BYTE PTR[8C8F],11 750E JNZ compare_byte 9A0A0AC333 CALL procedure_that_sniffs 0AC0 OR AL,AL 7405 J2 compare_byte C6068F8C2A MOV BYTE PTR [8C8F],2A:compare_byte 803E8F8C2A CMP BYTE PTR [8C8F],2A 7504 JNZ after_ret B001 MOV AL,01 C3 RET You should be enough crack-able ;=), by this lesson, to noticeimmediately the inconsistency of the two successive instructionsMOV 2A and CMP 2A, coz there would be no sense in comparing the"2A" in order to JNZ to after_ret if you just had the 2A set withthe precedent MOV instruction... but the first JNZ jumps to thecompare WITHOUT putting the "2A" inside. And "2A" is nothing elseas the "*" symbol, commonly used by programmer as "OK"! Thisprotection works in the following way (this is the above codeexplained):- compare holy_location with 11- jump non zero to compare holy_loc with "*"- else call sniffing protection part- or al,al (al must be zero, else)- jump zero to compare holy_loc with "*"- if al was zero mov "*" inside holy_loc- compare holy_loc with "*"- if there is a difference then JNZ beggar_off_ugly_copier- else ret_ahead_nice_buyerNow let's quickly crack it: ------------------------------------------------CRACKING GENERAL.EXE (by +ORC, January 1996)ren general.exe general.dedsymdeb general.ded- s (cs+0000):0 Lffff 8C 11 75 0Exxxx:yyyy (this is the answer of the debugger)- e xxxx:yyyy+2 EB [SPACE] 09 - w- qren general.ded general.exe -------------------------------------------------And in this way you changed the JNZ to the cmp "*" instructionin a JMP to the mov "*" instruction. So no more nag screens, nomore protections... serene, placid, untroubled [general.exe]. Well, that's it for this lesson, reader. Not all lessons of mytutorial are on the Web. You 'll obtain the missing lessons IF AND ONLY IF you mailme back (via anon.penet.fi) with some tricks of the trade I maynot know that YOU discovered. Mostly I'll actually know themalready, but if they are really new you'll be given full credit,and even if they are not, should I judge that you "rediscovered"them with your work, or that you actually did good work on them, I'll send you the remaining lessons nevertheless. Yoursuggestions and critics on the whole crap I wrote are alsowelcomed.