How to crack ANY program that uses the TL32V2.DLL! (An addition to Harwi's essay)
Courtesy of Fravia's page of reverse engineering
Slightly edited by fravia+, 3 May 1998


Greetings +Fravia,

I enclose a txt copy
of my essay which goes into quite some depth the how's and why's I did
what I did and more importantly, builds upon an essay written by Harwi
called: BoundsChecker time limit ("Persistent file protection").

In Harwi's essay he spoke of Bounds Checker V5.1 and the relationship of
a file called TL32V2.DLL but while he was able to show how to patch this
DLL so that Bounds Checker  
would run as a registered program afterwards he missed a vital section
about this DLL file which everyone should know about..

In brief, Bounds Checker uses the TL32V20.DLL file for its entire
protection system (nothing new here) but what if I could show you a way
to *crack* Bounds Checker in just a few minutes or less using just one
Softice BPX breakpoint and NO patching of the code and THEN use this
knowledge to *crack* EVERY program thereafter that uses this same
protection system in just a minute or two!!.

A draft copy of my essay has been pasted below, a copy of this draft is
also on my newly created web page at:
http://www.proweb.co.uk/~greenway/Es4.html


Program Details Program Name: Bounds Checker V5.02 Program Type: Code Analyser/Debugger Program Location: ftp://ftp.kgb.ru/NTUtil/NuMega/BC5_VC/bc502sp_v.exe Program Size: 8.37 megs Tools Required: Softice v3.2 How to crack Bounds Checker V5.02 ( And ANY program using TL32V2.DLL! ) Written by The Sandman Introduction:- ------------- Having read Harwi's essay on: Bounds Checker Time limit (Persistent file Protection) I immediately decided to locate a copy of Bounds Checker from the Web and try and follow Harwi's steps in the hope of learning something new about reverse code engineering and besides, Bounds Checker sounds like an ideal tool to learn how programs really operate under windoze '95!. This *crack* represents my first MAJOR crack to date, having only cracked three other simple shareware programs before this, all of which took me many hours to figure out. This crack however took me LESS than five minutes to figure out and if I'm honest here it didn't require much knowledge on Assembler since I don't know much at all!. So what's the deal here!. Harwi's approach to cracking Bounds Checker is based on his experiance and knowledge in reverse engineering and as expected, the protection system was written and designed on how experienced crackers would try and de-code it's hidden secrets. Fair enough, nothing wrong here but what-if someone, like me who has little experience or knowledge tried to 'attack' this same code, would not my approach be one based on 'gut feeling' or perhaps based on a little Zen?. Have you ever noticed that when someone is being taught (say a new card game ) that they seem to win more times than say someone who has played the game many times and knows the game quite well?. We would put this down to 'Beginners Luck'. The reason why this happens is because the novice player isn't bogged down with the rules of the game, nor is he able to draw upon past experience of the game so he relies purely on the scraps of information he has so far managed to get on the game and then uses 'educated guesses' to work out what card to play next.. So how does this tie into how I cracked Bounds Checker, patience, I'm getting there.. My knowledge of Assembler is very sketchy, I know the basics and that's it so like the person learning a new card game I too have to rely on Educational Guesses' to find my way round this new game of cracking. Can you see where I'm leading you to?. If we now change the words:- 'Educational Guesses' to simply 'Zen' ( +ORC goes to great lengths to teaching us that Zen is not just based on great knowledge or experience, but how 'we feel' about the code itself! ). As our knowledge and experience in reverse engineering increases we tend to start to rely more on this and less on the true 'Zen' we once possessed as newbies!. We might now see that newbies to cracking have in many ways, a clearer insight into cracking an unfamiliar protection system when compared to some of the more "experienced" crackers simply because we can't be mis-lead by fake routines or bogged down in routines we know nothing about since we have only 'Zen' to help us through this jungle of code. Ever heard the saying: 'Can't see the wood for the trees?'. Harwi's essay was based on Bounds Checker V5.1, while the copy I found was V5.2 so rather than waste anytime on trying to patch my copy of Bounds Checker (the addresses I thought would be different to the ones Harwi used) I decided to see if I could somehow find another, much easier way to accomplish the same thing. What I found by accident was a way to crack Bounds Checker V5.2 AND ANY OTHER PROGRAM THAT USES THE SAME PROTECTION SYSTEM and that it requires just one Softice BPX command and NO patching of any files!!. A newbie's dream crack!. touches on one aspect of the protection system used in Bounds Checker and I'm sure if he had pursued this further he would have discovered that here lies a most interesting flaw in the TL32V2.DLL file that CONTROLS the whole of this protection system!. About this protection system ---------------------------- The whole of this protection system is housed in a single DLL file called TL32V2.DLL (TimeLock32) and in the case of Bounds Checker V5.2 it can be found in the C:\Windows directory, not as you would expect in the C:\Windows\System directory. This DLL file is 91648 bytes long. (Don't get this confused with the one installShield Express V2 uses which is 130,560 bytes long and which also uses the same filename. ) This DLL file is configured as a self contained 'TimeLOCK Purchase Wizard' and is made by Preview Software Inc so that it can be used by anyone who has a licence to use it in their programs ( just as Installshield is used by many different programs and companies today. ) The Essay --------- After installing Bounds Checker using: Name: The Sandman Company:- Keycode: *leave this blank for now* I started up Bounds Checker and went directly to the Purchase Screen in Bounds Checker by loading in the example program: C:\BChecker\EXAMPLE\BUGBENCH\Bugbench.exe and then attempted to run bugbench which resulted in the 14 Day trial screen popping up. I selected the Purchase button and for the Keycode I typed in: 12345 You should have now:- For the User Name: The Sandman For the Company Name: - For the Keycode: 12345 Harwi mentions in his essay that Bounds Checker expects 16 characters here but we don't really need to know this nor do we need to enter all 16 characters..:) At this point I pressed Ctrl-D to get into Softice and typed: BPX getwindowtext then pressed x to leave softice. Now I Press the OK button and wham, Softice breaks as expected in the getwindowtext routine, so from here I pressed F12 then F12 again which now placed me in the main TL32V20.DLL code (TL32v20!text+1859) at address: 014f:10003e81 * Possible Reference to Dialog: DialogID_0070, CONTROL_ID:2334, "" :10003E81 6834230000 push 00002334 ;We land here :10003E86 56 push esi :10003E87 FFD7 call edi :10003E89 50 push eax :10003E8A 8BD8 mov ebx, eax * Reference To: USER32.GetWindowTextLengthA, Ord:0140h :10003E8C FF15D4630110 Call dword ptr [100163D4] :10003E92 83F802 cmp eax, 00000002 ;Check for a valid Name :10003E95 7F1C jg 10003EB3 :10003E97 6800200000 push 00002000 :10003E9C 68193B0110 push 10013B19 :10003EA1 6829400110 push 10014029 :10003EA6 6A00 push 00000000 * Reference To: USER32.MessageBoxA, Ord:0195h | :10003EA8 FF15A8630110 Call dword ptr [100163A8] ;Show 'invalid :10003EAE E939010000 jmp 10003FEC ;Name' Msgbox * Referenced by a Jump at Address: :10003E95(C) :10003EB3 6A27 push 00000027 :10003EB5 8D4584 lea eax, dword ptr [ebp-7C] :10003EB8 50 push eax :10003EB9 53 push ebx * Reference To: USER32.GetWindowTextA, Ord:013Fh | :10003EBA FF15DC630110 Call dword ptr [100163DC] * Possible Reference to Dialog: DialogID_0070, CONTROL_ID:2335, "" | :10003EC0 6835230000 push 00002335 :10003EC5 56 push esi :10003EC6 FFD7 call edi :10003EC8 6A31 push 00000031 :10003ECA 68A0440110 push 100144A0 :10003ECF 50 push eax * Reference To: USER32.GetWindowTextA, Ord:013Fh | :10003ED0 FF15DC630110 Call dword ptr [100163DC] :10003ED6 8D45D8 lea eax, dword ptr [ebp-28] :10003ED9 50 push eax :10003EDA E885E9FFFF call 10002864 ; CHECK REGKEY CODE HERE! From looking at the source code that Softice was showing me I noticed that: 1. I was not in the actual Bounds Checker code but in fact in the TIMELOCK32 DLL file which Harwi mentioned that he had managed to patch in several places to get Bounds Checker to run as a fully registered program. 2. Scrolling down the listing a little more that there were a few Pushes of information onto the stack and a few system Call's with a liberal dose of conditional Jumps but nothing that showed the classical:- Cmp instruction conditional jump/Call statement. While there are many other ways that Bounds Checker could test to see if the Keycode that I had typed was correct, I knew of only the above method so decided to follow this hunch through. At this point I typed:- BD 00 to clear away my breakpoint and began to start to pressing the F10 key and watched what each Call instruction did until the actual 'Wrong Keycode' message popped up on my screen, which told me that one of the Call instructions I had by-passed dealt with the verification of my fake Keycode. Since I had only pressed the F10 key a few times before the 'Wrong Keycode' message appeared helped me narrow down the possible Call statements to just a small handful. I exited out of softice and re-ran the purchase screen again, and once again Softice broke into the Bounds Checker code at the getwindowtext routine and once more pressed the F12 key TWICE to land back into the TL32V2.DLL code. At this point I first dis-counted any Calls or Jumps to any of the system routines since I knew these wouldn't handle the process of actually creating a Keycode based on the User's entered text and then choose the FIRST Call I found that went into the actual TL32V2.DLL code which was found at: :10003EDA E885E9FFFF call 10002864 At this point I moved the cursor on this line and told Softice to run the code normally from where I was until it reached THIS line. I typed: here Now instead of pressing F10 I pressed P so that I could trace into this call statement. I then arrived to this routine:- * Referenced by a CALL at Addresses: 10002B25 , :10003EDA :10002864 55 push ebp ;We Land here :10002865 33C0 xor eax, eax :10002867 8BEC mov ebp, esp :10002869 81ECB0000000 sub esp, 000000B0 :1000286F C68550FFFFFF00 mov byte ptr [ebp+FFFFFF50], 00 :10002876 56 push esi :10002877 57 push edi :10002878 8DBD51FFFFFF lea edi, dword ptr [ebp+FFFFFF51] :1000287E 33F6 xor esi, esi :10002880 AB stosd :10002881 AB stosd :10002882 AB stosd :10002883 AB stosd * Referenced by a Jump at Address:100028C2(C) :10002884 6870100110 push 10011070 :10002889 8D45FC lea eax, dword ptr [ebp-04] :1000288C 50 push eax :1000288D 46 inc esi :1000288E E8ED250000 call 10004E80 :10002893 83C408 add esp, 00000008 :10002896 8D4DFC lea ecx, dword ptr [ebp-04] :10002899 0FBE8632430110 movsx eax, byte ptr [esi+10014332] :100028A0 50 push eax * Possible StringData Ref from Data Obj ->"%c" | :100028A1 68B8140110 push 100114B8 :100028A6 51 push ecx :100028A7 E864250000 call 10004E10 :100028AC 83C40C add esp, 0000000C :100028AF 8D4DFC lea ecx, dword ptr [ebp-04] :100028B2 51 push ecx :100028B3 E848250000 call 10004E00 :100028B8 83C404 add esp, 00000004 :100028BB 8944B5A0 mov dword ptr [ebp+4*esi-60], eax :100028BF 83FE06 cmp esi, 00000006 :100028C2 72C0 jb 10002884 :100028C4 33F6 xor esi, esi * Referenced by a Jump at Address:10002904(C) :100028C6 6870100110 push 10011070 :100028CB 8D45FC lea eax, dword ptr [ebp-04] :100028CE 50 push eax :100028CF 46 inc esi :100028D0 E8AB250000 call 10004E80 :100028D5 83C408 add esp, 00000008 :100028D8 8D4DFC lea ecx, dword ptr [ebp-04] :100028DB 0FBE86DF440110 movsx eax, byte ptr [esi+100144DF] :100028E2 50 push eax | :100028E3 68B8140110 push 100114B8 :100028E8 51 push ecx :100028E9 E822250000 call 10004E10 :100028EE 83C40C add esp, 0000000C :100028F1 8D4DFC lea ecx, dword ptr [ebp-04] :100028F4 51 push ecx :100028F5 E806250000 call 10004E00 :100028FA 83C404 add esp, 00000004 :100028FD 8944B5B8 mov dword ptr [ebp+4*esi-48], eax :10002901 83FE10 cmp esi, 00000010 :10002904 72C0 jb 100028C6 :10002906 FF75CC push [ebp-34] :10002909 FF75F8 push [ebp-08] :1000290C FF75A4 push [ebp-5C] :1000290F FF75D8 push [ebp-28] :10002912 FF75BC push [ebp-44] :10002915 E861FCFFFF call 1000257B :1000291A 83C414 add esp, 00000014 :1000291D 898564FFFFFF mov dword ptr [ebp+FFFFFF64], eax :10002923 FF75D0 push [ebp-30] :10002926 FF75F4 push [ebp-0C] :10002929 FF75A8 push [ebp-58] :1000292C FF75D4 push [ebp-2C] :1000292F FF75C0 push [ebp-40] :10002932 E844FCFFFF call 1000257B :10002937 83C414 add esp, 00000014 :1000293A 898568FFFFFF mov dword ptr [ebp+FFFFFF68], eax :10002940 FF75D4 push [ebp-2C] :10002943 FF75F0 push [ebp-10] :10002946 FF75AC push [ebp-54] :10002949 FF75D0 push [ebp-30] :1000294C FF75C4 push [ebp-3C] :1000294F E827FCFFFF call 1000257B :10002954 83C414 add esp, 00000014 :10002957 89856CFFFFFF mov dword ptr [ebp+FFFFFF6C], eax :1000295D FF75D8 push [ebp-28] :10002960 FF75EC push [ebp-14] :10002963 FF75B0 push [ebp-50] :10002966 FF75CC push [ebp-34] :10002969 FF75C8 push [ebp-38] :1000296C E80AFCFFFF call 1000257B :10002971 83C414 add esp, 00000014 :10002974 898570FFFFFF mov dword ptr [ebp+FFFFFF70], eax :1000297A FF75DC push [ebp-24] :1000297D FF75E8 push [ebp-18] :10002980 FF75B4 push [ebp-4C] :10002983 FF75C8 push [ebp-38] :10002986 FF75CC push [ebp-34] :10002989 E8EDFBFFFF call 1000257B :1000298E 83C414 add esp, 00000014 :10002991 898574FFFFFF mov dword ptr [ebp+FFFFFF74], eax :10002997 FF75E0 push [ebp-20] :1000299A FF75E4 push [ebp-1C] :1000299D FF75B8 push [ebp-48] :100029A0 FF75C4 push [ebp-3C] :100029A3 FF75D0 push [ebp-30] :100029A6 E8D0FBFFFF call 1000257B :100029AB 83C414 add esp, 00000014 :100029AE 898578FFFFFF mov dword ptr [ebp+FFFFFF78], eax :100029B4 FF75E4 push [ebp-1C] :100029B7 FF75E0 push [ebp-20] :100029BA FF75A4 push [ebp-5C] :100029BD FF75C0 push [ebp-40] :100029C0 FF75D4 push [ebp-2C] :100029C3 E8B3FBFFFF call 1000257B :100029C8 83C414 add esp, 00000014 :100029CB 89857CFFFFFF mov dword ptr [ebp+FFFFFF7C], eax :100029D1 FF75E8 push [ebp-18] :100029D4 FF75DC push [ebp-24] :100029D7 FF75A8 push [ebp-58] :100029DA FF75BC push [ebp-44] :100029DD FF75D8 push [ebp-28] :100029E0 E896FBFFFF call 1000257B :100029E5 83C414 add esp, 00000014 :100029E8 894580 mov dword ptr [ebp-80], eax :100029EB FF75E8 push [ebp-18] :100029EE FF75F8 push [ebp-08] :100029F1 FF75AC push [ebp-54] :100029F4 FF75F8 push [ebp-08] :100029F7 FF75DC push [ebp-24] :100029FA E87CFBFFFF call 1000257B :100029FF 83C414 add esp, 00000014 :10002A02 894584 mov dword ptr [ebp-7C], eax :10002A05 FF75EC push [ebp-14] :10002A08 FF75F4 push [ebp-0C] :10002A0B FF75B0 push [ebp-50] :10002A0E FF75F4 push [ebp-0C] :10002A11 FF75E0 push [ebp-20] :10002A14 E862FBFFFF call 1000257B :10002A19 83C414 add esp, 00000014 :10002A1C 894588 mov dword ptr [ebp-78], eax :10002A1F FF75F0 push [ebp-10] :10002A22 FF75F0 push [ebp-10] :10002A25 FF75B4 push [ebp-4C] :10002A28 FF75F0 push [ebp-10] :10002A2B FF75E4 push [ebp-1C] :10002A2E E848FBFFFF call 1000257B :10002A33 83C414 add esp, 00000014 :10002A36 89458C mov dword ptr [ebp-74], eax :10002A39 FF75F4 push [ebp-0C] :10002A3C FF75EC push [ebp-14] :10002A3F FF75B8 push [ebp-48] :10002A42 FF75EC push [ebp-14] :10002A45 FF75E8 push [ebp-18] :10002A48 E82EFBFFFF call 1000257B :10002A4D 83C414 add esp, 00000014 :10002A50 894590 mov dword ptr [ebp-70], eax :10002A53 FF75F8 push [ebp-08] :10002A56 FF75E8 push [ebp-18] :10002A59 FF75A4 push [ebp-5C] :10002A5C FF75E8 push [ebp-18] :10002A5F FF75EC push [ebp-14] :10002A62 E814FBFFFF call 1000257B :10002A67 83C414 add esp, 00000014 :10002A6A 894594 mov dword ptr [ebp-6C], eax :10002A6D FF75CC push [ebp-34] :10002A70 FF75E4 push [ebp-1C] :10002A73 FF75A8 push [ebp-58] :10002A76 FF75E4 push [ebp-1C] :10002A79 FF75F0 push [ebp-10] :10002A7C E8FAFAFFFF call 1000257B :10002A81 83C414 add esp, 00000014 :10002A84 894598 mov dword ptr [ebp-68], eax :10002A87 FF75D0 push [ebp-30] :10002A8A FF75E0 push [ebp-20] :10002A8D FF75AC push [ebp-54] :10002A90 FF75E0 push [ebp-20] :10002A93 FF75F4 push [ebp-0C] :10002A96 E8E0FAFFFF call 1000257B :10002A9B 83C414 add esp, 00000014 :10002A9E 89459C mov dword ptr [ebp-64], eax :10002AA1 FF75D4 push [ebp-2C] :10002AA4 FF75DC push [ebp-24] :10002AA7 FF75B0 push [ebp-50] :10002AAA FF75DC push [ebp-24] :10002AAD FF75F8 push [ebp-08] :10002AB0 E8C6FAFFFF call 1000257B :10002AB5 83C414 add esp, 00000014 :10002AB8 8DB564FFFFFF lea esi, dword ptr [ebp+FFFFFF64] :10002ABE 8945A0 mov dword ptr [ebp-60], eax * Referenced by a Jump at Address:10002AFE(C) | :10002AC1 6870100110 push 10011070 :10002AC6 8D45FC lea eax, dword ptr [ebp-04] :10002AC9 50 push eax :10002ACA E8B1230000 call 10004E80 :10002ACF 83C408 add esp, 00000008 :10002AD2 8D4DFC lea ecx, dword ptr [ebp-04] :10002AD5 FF36 push dword ptr [esi] | :10002AD7 68B4140110 push 100114B4 :10002ADC 51 push ecx :10002ADD 83C604 add esi, 00000004 :10002AE0 E82B230000 call 10004E10 :10002AE5 83C40C add esp, 0000000C :10002AE8 8D4DFC lea ecx, dword ptr [ebp-04] :10002AEB 8D9550FFFFFF lea edx, dword ptr [ebp+FFFFFF50] :10002AF1 51 push ecx :10002AF2 52 push edx | :10002AF3 FF158C620110 Call dword ptr [1001628C] :10002AF9 8D4DA4 lea ecx, dword ptr [ebp-5C] :10002AFC 3BF1 cmp esi, ecx :10002AFE 72C1 jb 10002AC1 :10002B00 8D8550FFFFFF lea eax, dword ptr [ebp+FFFFFF50] :10002B06 50 push eax :10002B07 FF7508 push [ebp+08] :10002B0A E871230000 call 10004E80 :10002B0F 83C408 add esp, 00000008 :10002B12 B801000000 mov eax, 00000001 :10002B17 5F pop edi :10002B18 5E pop esi :10002B19 8BE5 mov esp, ebp :10002B1B 5D pop ebp :10002B1C C3 ret I have shown this routine in full because as anyone who is new to reverse engineering might do I scrolled down Softice's window until I found a RET instruction, signify the end of this particular routine and noticed a set of instructions that kept repeating themselves... now comes the really interesting question: *can you feel it?* :10002A4D 83C414 add esp, 00000014 :10002A50 894590 mov dword ptr [ebp-70], eax :10002A53 FF75F8 push [ebp-08] :10002A56 FF75E8 push [ebp-18] :10002A59 FF75A4 push [ebp-5C] :10002A5C FF75E8 push [ebp-18] :10002A5F FF75EC push [ebp-14] :10002A62 E814FBFFFF call 1000257B I counted out of curiosity the number of times this pattern repeated and it came to 16 and since each 'Call' went to the same address this made me think of what Harwi said about there being 16 characters in the KeyReg code!. Very interesting... I guessed here that the registration key was being processed individually letter by letter ( 16 times) so again, I choose the FIRST Call instruction I found that came AFTER these 16 letter checks and placed my cursor on this line and then told Softice to run the code as normal UNTIL it came to the line with my cursor on it:- :10002AC9 50 push eax :10002ACA E8B1230000 call 10004E80 ;I stopped here Remembering that the program had to somehow compare our fake Key registration with one that the program had generated and used to check the registration code I typed: D eax to see what was being pushed onto the stack and BINGO!, I saw a 16 character code that looked like a key registration code! 5905135905135905 I cleared Softice's breakpoints with BC * and exited Softice with x and now typed in this new Registration Key. Job done. Final Notes:- ------------- Using the above procedure will not only defeat the protection system employed in Bounds Checker it will ALSO defeat any other programs using it!. Because no patching of code is required anyone can defeat this protection system in just a few minutes using just ONE BPX statement and a few F10's.