Various Snippets

Just 6 very basic and early tutorials from 1998 that I quickly amalgamated into 1 document, they might be useful for someone, who knows :-).

BS/1 Professional v1.5 http://www.dbsonline.com, FTP File Search - bs1pr15.zip (3.47Mb).
Cache Master 95 v1.06 http://www.offsitelabs.com, FTP File Search - cm32106.zip (393k).
HTMLGate 4 - by RUSKiE http://members.xoom.com/mp_home, FTP File Search - htmlgate4.exe (1,138k).
Signature Program v3.0 http://www.regnoc.com, FTP File Search - sign30.zip (851k).
Wallaby '95 v5.0 http://www.wallaby95.com, Download from their web page (1.33Mb).
Win-eXpose-Registry v1.00 http://www.shetef.com/wxr95-10.zip (1.2Mb).

I first started following Davis Business Systems programs 8 mths or so ago when they released BS/1 Small Business (v1.1 is the earliest I recall), all v1.1x used the same protection, there were a total of 10 options ranging from single user to a 10-user network, registration codes were all 6 digit hard-coded in defaults + the string '04'. Having highlighted previously how appalling the previous scheme was I had hoped v1.5 ($118 worth) would surprise me or at least show some improvement. Sadly the program still relies on the same .ini file although several options have been dispensed with and most legacy ini files do not work.

The serial # routine isn't particularly hard to find using SoftICE but this is truly a program you can crack using just a deadlisting. Without further delay, start the application and select a sample company, then in the Help menu select About and License Upgrade, you'll be confronted with a familiar site, a dialog box begging for your Company Name and Registration Code. We'll naturally use the simple deadlisting approach, firstly enter a bogus code of some description and note down the dialog text "Registration code is invalid", now locate that inside W32Dasm's StringRef's. Here's the only occurrence inside bs1pro.exe.

:004F4583 MOV ECX, 004F48A8 <-- "Registration code is invalid".

Now we'll simply use the backtracing and see "who jumps here".

:004F454E MOV EAX, DWORD PTR [EBP-10] <-- Code entered.
:004F4551 MOV EDX, 004F4894 <-- "c9kk43111" (no comment).
:004F4556 CALL 004036E8 <-- Compare routine.
:004F455B JNZ 004F4578 <-- Jump_invalid_code.

If you just take a quick look at 004036E8 you'll see immediately just from feeling the code that it is a compare routine, you'll also see that its called a lot of times. Evidently this function is a generic string compare which is used for other tasks besides the protection. Naturally several steps higher inside the disassembly would locate you the other valid code, where as a little below gives you /users.ini as the location, note that only the first 6 digits are required in the ini file.

BS/1 Professional v1.5
Single-user license code ($118): b935k5111
Multi-user license ($315): c9kk43111

If I actually cast my mind back I recall that these codes may actually have been used in the previous versions. So legacy ini files which used c9kk43 and b935k5 are probably still valid. I don't think I really need to state what I think of this protection.


In this tutorial I'm going to show you yet another trick I often use when reversing Visual Basic applications. In Cache Master we have a VB4 application (vb40032.dll imported), so lets firstly locate our register option. After trying various VB4 breakpoints (MultiByteToWideChar) etc and getting nowhere I figured there had to be an easier way.

So lets firstly trigger our nag box, you'll find a bpx MessageBoxA works well, you'll locate it at address 0F771820, but still irritatingly inside vb40032.dll. So I thought for a while figuring that tracing through pages of the dll was pointless, and then it occured to maybe the program or OS was using the same memory locations to store my inputs, so lets firstly >bpx MessageBoxA. Once returned back into SoftICE lets do a memory string search for the serial # we entered (remember we are looking in wide character format).

>s 0 l ffffffff 31 00 32 00 31 00 32

You'll actually find probably only 2 memory locations where the string is stored. Mine was found at 0048A7D4 & 004902D4, so what I'm going to do is set a breakpoint on those memory locations.

>bpm 0157:0048A7D4 rw >bpm 0157:004902D4 rw

Now lets Ctrl+D out of SoftICE and attempt to re-register, you'll probably break a few times getting back to the Registration screen, just keep using F5 to exit SoftICE. Now when you click OK you should get a break, look at the code you break in, sometimes it will be kernel32, other times oleaut32, just keep pushing F5 until you get a break at this very interesting piece of code inside vb40032.dll. (You may have to repeat this process a few times to get at this code).

:0F79B34C AND AL,10
:0F79B34E MOV ESI,[ESP+0C]
:0F79B352 MOV ECX,[ESP+14]
:0F79B356 XOR EAX,EAX
:0F79B358 REPZ CMPSW <-- Its the old wide-char compare again.
:0F79B35B JZ 0F79B362 <-- You'll break here.

Well lets take a look at the contents of ESI & EDI, you should see your entered code in EDI and the good code in ESI. Note that you are looking at the 2nd character so scroll the data window to view the first, and there you have it, a seemingly tedious VB4 application reversed. Note the good code is written out to the file cm.ini in the program directory.


This tutorial is for HTMLGate 4, an HTML editor. Here's a brief description of the program :

- 32-bit program
- Templates
- Edit more than one document
- Dialog box to all HTML tags
- User defined HTML tags
- JavaScript Editor
- DHTML Samples

And much more.....Lets run the program. A nag box is displayed asking for a name and a password. Type in a name and a password (I used RUSKiE & 1234567890) and click Register. Of course the "wrong password" dialog box is displayed. BPX MessageBoxA and click on Register again. This time we'll enter SoftICE on the MessageBox call. Press F12 three times, remembering to click on the OK button after the first press of F12. This will return you from the original call to MessageBoxA (004A5CE7).

:004A5CA4 MOV EAX,[EBP-04]
:004A5CA7 MOV EDX,004A5D18
:004A5CAC CALL 00403D20 <-- Check password.
:004A5CB1 JNZ 004A5CD4 <-- Bad Guy.
:004A5CB3 PUSH 00
:004A5CB5 MOV ECX,004A5D20 <-- HTMLGate.
:004A5CBA MOV EDX,004A5D2C <-- Thanks! For register HTMLGate 4.
:004A5CBF MOV EAX,[004CA2C4]
:004A5CC4 MOV EAX,[EAX]
:004A5CC6 CALL 0043374C
:004A5CCB MOV EAX,EBX
:004A5CCD CALL 00431468
:004A5CD2 JMP 004A5CEC <-- Good Guy.
:004A5CD4 PUSH 00
:004A5CD6 MOV ECX,004A5D20 <-- HTMLGate.
:004A5CDB MOV EDX,004A5D4C <-- Wrong Password!.
:004A5CE0 MOV EAX,[004CA2C4]
:004A5CE5 MOV EAX,[EAX]

Scroll up through the disassembly until you come across the JNZ instruction at 004A5CB1 which jumps to the bad guy code at 004A5CD4. The call above the JNZ determines if the correct password has been entered or not. Clear the previous breakpoints and BPX 004A5CAC. Re-run the register applet again and SoftICE will break. Press F8 to trace into the call; the code is shown below :-

:00403D20 PUSH EBX
:00403D21 PUSH ESI
:00403D22 PUSH EDI
:00403D23 MOV ESI,EAX <-- ESI = 1234567890
:00403D25 MOV EDI,EDX <-- EDI = pham
:00403D27 CMP EAX,EDX
:00403D29 JZ 00403DBE

Step through the code using F8 and observe the registers. If you look at the above code, 00403D23 moves ESI to our fake password. The next instruction moves EDI to the String 'pham'. I mean, pham? surely that can't be the password?. Re-run the register applet again and change the password to 'pham' (without the quotes). Registered! changing the name of the registered person has *no* effect on the password, it will always be the same. But why pham? Well I realised later, it's the surname of the author: Michael Pham.

This probably goes down as one of the stupidest protections around. Not only a hard-coded password but also one which is easily guessed. After I cracked this with SoftICE I thought I'd have a quick look at a dead listing of the code in W32Dasm. I only wish I initially did this because the password is there for all to see.


A key generator tutorial. So without further ado lets launch our target, and select Register from the screen which appears, now you'll need to enter a name, company name and registration code, I'm using CrackZ, Zencrack and 12345678 in that order, you'll find that 3 breaks on GetWindowTextA work well. You should easily trace to the following code, either with F10 or F12.

:00408802 MOV EAX,[EDI] <-- Name.
:00408804 CMP DWORD PTR [EAX-08],05 <-- Check name was at least 5.
:00408808 JGE 0040881E <-- Jump_good_name.
:0040881E MOV EAX,[ESI+64] <-- Code entered.
:00408821 CMP DWORD PTR [EAX-08],01 <-- Check code was at least 1.
:00408825 JGE 0040883B <-- Jump_good_code_length.

So as we have become accustomed, a simple length of name check for 5 characters and a code check for at least 1, we continue at the following code:

:0040883C CALL [00414038] <-- Returns code entered in EAX.
:00408842 ADD ESP,04 <-- Tidy stack.
:00408845 MOV EBX,EAX <-- Place code entered in EBX.
:00408847 PUSH [EDI]
:00408849 CALL 00409010 <-- Calculate real good code.
:0040884E ADD ESP,04 <-- Tidy stack.
:00408851 CMP EAX,EBX <-- Compare good_guy_/_bad_guy.
:00408853 JZ 00408866 <-- Jump_good_code.

Well its easy to type >? EBX in SoftICE and find the good code, however we need to investigate how the program builds this code by tracing into 00409010. Well without highlighting the actual code, the program works as follows. Firstly, the name will be uppercased so in my case we get CRACKZ, then each letter will be squared before the individual results are added together, so I get.

(672 + 822 + 652 + 672 + 752 + 902) = 33,652.

Then we multiply this result by 93h (147 dec) to give the good code (4946844), if you trace the function be sure to also note the use of IsCharAlphaA to identify whether a character is a number or letter.


This program makes for an interesting study because it forces you to use some intuition, you might like to try disassembling, on my system it crashes W32Dasm. So, SoftICE remains our only weapon unless we want to try beating the anti-disassembly tricks it might be using. Start Wallaby and take a look. You'll soon locate the register option and a single dialog box, so lets proceed in our usual fashion and enter a number. Now >bpx Hmemcpy and trace to the code below :-

:00450F4E MOV ECX,00000001 <-- ECX=1.
:00450F53 MOV EDX,00000003 <-- EDX=3.
:00450F58 MOV EAX,[EBP-04] <-- Serial # entered.
:00450F5B CALL 00450B2C <-- Call interesting function.
:00450F60 MOV EAX,[EBP-0C] <-- First 4 digits of code entered loaded in EAX.
:00450F63 MOV EDX,00451110 <-- EDX moved to GMA and a space (20h).
:00450F68 CALL 004011D0 <-- Compare.
:00450F6D JNZ 00451070 <-- Jump_Bad_Code.
.....
:00450F84 CALL 00450B2C <-- Call again.
:00450F89 MOV EAX,[EBP-0C] <-- Next 6 digits of code now in EAX.
:00450F8C MOV EDX,00451110 <-- EDX moved to 17195 and a space (20h).
:00450F91 CALL 004011D0 <-- Compare.
:00450F96 JNZ 00451070 <-- Jump_Bad_Code.

Time to pause here, the program continues after this to make one further check upon the next 5 digits of the entered code checking that they are indeed 3112 + a space. The final check appears here :-

:00450FD6 CALL 00450B2C <-- Function called (again).
:00450FDB MOV EAX,[EBP-0C]
:00450FDE CALL 004011B0 <-- Returns the length of the remaining code in EAX.
:00450FE3 CMP EAX,03 <-- Last part of code must be greater than 3 in length.
:00450FE6 JLE 00451070 <-- Jump_Bad_Code.

So you should see how to register this software and circumvent the necessary checks. Its quite an interesting scheme although not overly complex, in some respects calling the same 2 functions on each check is weak, however I like the use of spaces in the code and the subtle final check. This program writes the registration information out to a registry key interestingly only containing the first 3 parts of the code check.

Wallaby '95 Version 5.0
Registration Code: GMA 17195 3112 xxxx


This next program is a very useful tool of our trade , I therefore believe it makes a good program to analyse. Although you will eventually find out that the program can be tricked by manipulating several critical jumps be sure to look further than just the crack. Start the program, you'll locate a registration option in the Help menu and be confronted by a Win-eXpose Registry screen, so lets enter some details in the dialog boxes, (you should enter something in every box to avoid any "did user enter anything" checks), I'll also advise you now that short is best.

For your information the password I've entered is 1313131313. So lets start using SoftICE, with 6 dialog boxes to be copied into memory I advise you use >bpx Hmemcpy and allow the necessary returns (6 in total). Now you could be forgiven for believing that the program checks both the Serial Number: and Password: but this will prove not to be the case, the program will actually work out whether the password is correct with respect to the Serial Number. Lets use SoftICE and trace to this code :-

:004023ED MOV EAX,[EBP-1C] <-- Dialog box contents.
:004023F0 PUSH EAX <-- Save on stack.
:004023F1 CALL EDI <-- Gets length of stack save.
:004023F3 ADD ESP,08 <-- Tidy stack.
:004023F6 TEST EAX,EAX
:004023F8 JZ 0040273F <-- Jump_Nothing_Entered.

This code above you'll see several times over, if you've done as I've said you'll pass all of these checks without a problem. The next section of our code is critical.

:00402448 TEST EBX,EBX
:0040244C JLE 004024B0 <-- Another length check.
:0040244E CALL [006D7B28] <-- Function call and start of loop.
.....
:004024AE JL 0040244E <-- End of loop reached using ESI as a counter.

If your live in SoftICE prepare to be bored, just keep your finger on F10 and watch the loop count variable in ESI until it reaches something close to EBX (it will loop the length of the Serial Number entered). At the end you'll drop out of the JL 0040244E at the most critical routine.

:004024C6 LEA EAX,[EBP-0134] <-- Real password.
:004024CC LEA ECX,[EBP-0234] <-- Password you entered.
:004024D2 MOV DL,[EAX] <-- First letter of good password.
:004D24D4 CMP DL,[ECX] <-- Compare good pwd with yours.
:004D24D6 JNZ 004024F2 <-- Jump_Bad_Password.
:004D24D8 OR DL,DL <-- Good result.
:004D24DA JZ 004024EE
:004D24DC MOV DL,[EAX+01] <-- 2nd letter.
:004D24DF CMP DL,[ECX+01] <-- Check it.
:004D24E2 JNZ 004024F2 <-- Jump_Bad_Password_Again.
:004D24E4 ADD EAX,02 <-- Shift EAX along to next chars.
:004D24E7 ADD ECX,02 <-- Same with ECX.
:004D24EA OR DL,DL <-- Good result.
:004D24EC JNZ 004D24D2 <-- Loop until end of compare.

So the code performs a step by step comparison of your password with the good password, in my case thats f401e1ac, eventually you'll drop out of the loop at the end. Now, you don't actually have to continue tracing, although there is some pretty interesting looping a little later on, I didn't try this but I would suspect that just fixing the 2 JNZ's so that they never happen (no-opping maybe) would be sufficient.

You should find that the information, along with a KEY is written out to the file wxr95.ini (in the /WINDOWS directory), I've pasted a copy of my example below, note also that this program seems to resist disassembly. You might like to also download Win-eXpose-IO also from the tools page as its system is virtually identical to the one I've discussed here.

[Win-eXpose-Registry 95]
Name=CrackZ
Company=Zencrack
AddrLine1=N/A
AddrLine2=N/A
SerialNumber=1212121212
Key=EXPREF0631BC


© 1998, 1999, 2000 CrackZ. 21st December 2000.