http://www.hippie98.com - Webpage.
In this tutorial I'm looking at another fairly competent HTML editor and I'm also writing this document somewhat blindly, as I'm unsure quite how difficult this protection might be, I think it will help many reversers to actually see how I approach a given target. Lets start Hippie and see what we are up against.
Starting Hippie produces our nag box and also a friendly register option, 4 registration boxes now stand between you and registered status, the important ones are obviously the ID and Registration Code. Well, I'm an impatient reverser so I quickly set a bpx GetWindowTextA and allowed the necessary breaks, tracing from there took me briefly through mfc42.dll several times before I traced over a function which displayed the message box.
At this stage I'm still trying to pinpoint the precise protection code, and you could maybe just bpm your input strings and re-trace in SoftICE, but I disassembled hippie.exe next and sure enough User *ID* jumped out at me. You'll find 3 occurences of ID, addresses 0041944C, 0041952B and 0042A916. Fishing around further also unearths some interesting code.
:00419553 CALL 0042A8F0 <-- Interesting function call which is actually StringRef 0042A916.
:00419558 TEST EAX,EAX <-- Check EAX for 0.
:0041955A JZ 00419587 <-- "Cool Dude!" - nice buyer perhaps.
:0041955C MOV ECX, DWORD PTR [ESI+68] <-- String length of ID.
:00419563 CMP DWORD PTR [ECX-08], 00000007 <-- Check ID's length for 7.
:00419567 JNZ 004194A8 <-- No jump and the ID is only valid for Windows 3.1
So, it looks as if our protection dwells somewhere beneath function 0042A8F0.
We know also that 0042A8F0 has to return EAX=0, the registration ID musn't be
of length 7 (although should we chose to patch this won't matter), and also
that the registry is where our information is being stored. I thought next about
trying to intercept the registry reading, don't waste your time with any bpx's,
I gave up pretty quickly with that but I'll show you later how to SoftICE to
the precise code with minimal effort. Inside the disassembly you'll see our
call is referenced in 4 other places.
Address 00401416 is the first instance of call 0042A760 and looks very much like a startup check. Here's the relevant code.
:0040141B TEST EAX,EAX <-- Check EAX for 0 as before.
:0040141D JNZ 0040146B <-- No jump means Registered To, etc,etc.
This is fairly obvious from the disassembly, jumping here is going to call
our nag box and run-time check, just look at the StringRef's, where as no jump
looks as if it will read all of our *bogus* registry values and accept
them as being valid. So lets make a preliminary patch and change the
TEST EAX,EAX to XOR EAX,EAX and NOP away the bad jump.
Our next incidence of 0042A8F0 is at address 00419553, this is the check which we've seen before (again its a very simple patch to ensure that the code jumps). The other 2 references are at 00428A8C and 0042910D, however both of these locations present us with potential problems.
:00428A8C CALL 0042A8F0 <-- Our call again.
:00428A91 CMP EAX,EBX <-- Compare against EBX (which is unknown).
:00428A93 JNZ 0042902C <-- Which way to jump (Problem 1).
:0042902C CMP EAX,1 <-- Check for a bad result.
:0042902F JNZ 004290D9 <-- Another check.
:0042910D CALL 0042A8F0 <-- Good return means EAX = 0.
:00429112 MOV ESI,EAX <-- Moves EAX into ESI (Problem 2).
.....
As you can see, Problem 1 occurs because we have no way of knowing what EBX's
value is and therefore no way of knowing which way the code should jump.
At 0042910D we encounter Problem 2, not a conditional jump in site and EAX
(which must be 0) moved into ESI, there simply isn't enough room to XOR EAX and
ESI as we would like and its eminently possible this result could be checked or
called somewhere else in the protection.
In fact Problem 1 isn't that hard to solve with some thought, note that JNZ 0042902C jumping results in a another check at 0042902C which then conditionally jumps to another check EAX=2 (feels like window error handling), the alternative seems to be our ToolTips box and a call to IsIconic (an API call used to check for minimised Windows), the *jump* therefore looks like a quick exit and is probably not desirable, so we can patch by XOR EAX,EAX then XOR EBX,EBX and CMP EAX,EBX + appropriate NOP's (2).
Examining problem 2 in greater detail reveals that we should be able to safely XOR ESI,ESI instead of MOV ESI,EAX and not worry about EAX, the reason?, well after the MOV, function 0045C308 gets called 6 times with no conditional jumps in sight, and you should remember this function as being the length checker when you first used SoftICE, recalling of course that the length was always returned in EAX which suggests that the value of EAX therefore doesn't matter.
After making all of these modifications, running Hippie proves that our conclusions were correct and registered status is now ours, but lets turn our attention to finding a possible good code. We know that call 0042A8F0 is our protection and that it must return EAX=0 (verified above), but lets see if we can examine the scheme using SoftICE. Launch the SoftICE loader and Open Module hippie.exe, this new version causes a crash, but you can always bpx for the protection routine anyhow.
Hippie doesn't have a bad protection at all in fact, however you should keep in mind that EAX must be returned = 0 with your ID, keep a careful watch on [ESP+1C], or simply XOR EAX,EAX at this code.
:0042ADA0 MOV EAX, DWORD PTR [ESP+1C] <-- Here's the bad/good guy move.