Application for +HCU98

by swann (


This session deals with the French version of ms money trial 3.00p, 
1.205.888 bytes, of 02/08/94 which reverser+ kindly provided on his web 

I'm not dogmatic, and so I usually employ a mixed approach to my cracks, 
get a general orientation and strategy from the disassembly, and use 
winice for local tactics and operations. 

The task at hand is spelled out by +orc in lesson 4.2: get rid of the 
check for the year, get rid of the check for the 60 days limit, get 
rid of the transaction limit. Plus disabling a couple of nag screens 
as a gimme.

So you run the program and the first thing you encounter after the 
startup nag is the message that informs you that your system date 
should be between 1994 and 1995. Let's tackle that first. 

In this program, most problems we encounter are signified by such 
message boxes. It turned out to be pretty efficient to bpr on the 
location of the message text once the box appears, and then after the 
breakpoint get back to the offending instruction and defeat it. They're 
mostly conveniently located right before the call to the message box.  
In the case of the system year check, we end up in the code segment 8:  

:0008.14E4 8D46FC                 lea ax, [bp-04]
:0008.14E7 50                     push ax
:0008.14E8 9A52052815             call 0081.0552
:0008.14ED 8BD8                   mov bx, ax
:0008.14EF 368B07                 mov ax, ss:[bx]
:0008.14F2 8946FE                 mov [bp-02], ax
:0008.14F5 8A66FF                 mov ah, [bp-01]
:0008.14F8 80E4FE                 and ah, FE
:0008.14FB 80FC5C                 cmp ah, 5C;             check if 92
:0008.14FE 741C                   je 151C
:0008.1500 8A66FF                 mov ah, [bp-01]
:0008.1503 80E4FE                 and ah, FE
:0008.1506 80FC5E                 cmp ah, 5E;             check if 94
:0008.1509 7411                   je 151C ;               let's screw some more
:0008.150B 681709                 push 0917
:0008.150E 6A00                   push 0000
:0008.1510 9A1AADBB0E             call 0064.AD1A;  you got bad breath
:0008.1515 33C0                   xor ax, ax
:0008.1517 C9                     leave 

 So obviously we want to jump at 8.1509, so we'll patch "EB11" for "7411." 
And jump we do and that was that.

On my system, this jump fix takes care of a lot. For some reason, 
I don't even get an expiration notice, no matter how I change my system 
date back and forth.

So the next part can probably be skipped and I only add it because our 
diva asked us to "DELVE DEEP". When I first tried this crack, I changed 
the system date to 1995, and then I encountered the further protection 
parts. If you do this, change your system date to 1995 and then change 
the date beyond the 60 days limit, you'll get the next error message telling 
you the trial period is over.  With the same tactics mentioned before 
you'll land here:

:0008.17E2 8B46F4                 mov ax, [bp-0C]
0008.17E5 3946F0                 cmp [bp-10], ax; has it been 60 dayz yet?
:0008.17E8 7246                   jb 1830 ; let's screw some more

* Possible Reference to Dialog: DialogID_0494 
:0008.17EA 689404                 push 0494 ; buy the registered version
:0008.17ED 686D05                 push SEG ADDR of Segment 0028
:0008.17F0 68C015                 push 15C0   

This obviously is one of the three locations +orc mentioned in 4.2, 
only the address being different because it's the French version. 
+orc suggested we nop this jump at 8.17e8 out.  I don't know whom he is 
kidding, but certainly noone who's studied his tutorials. Obviously, 
we _do_ want to take that jump, and therefore patch "EB46" for "7246" 
at 8.17e8.

This may lead to a problem here:

:0008.1830 50                     push ax
:0008.1831 9AE6083E18             call 0081.08E6
:0008.1836 FF76F0                 push word ptr [bp-10]
:0008.1839 8BF0                   mov si, ax
:0008.183B 9AE608EB14             call 0081.08E6 ;   date check call
:0008.1840 2BF0                   sub si, ax
:0008.1842 8976FE                 mov [bp-02], si
:0008.1845 83FE07                 cmp si, 0007
:0008.1848 7F22                   jg 186C;       let's screw some more
:0008.184A 8A46FE                 mov al , [bp-02]
:0008.184D 0430                   add al, 30
:0008.184F 8846EE                 mov [bp-12], al 
:0008.1852 C646EF00               mov byte ptr [bp-11], 00
:0008.1856 681949                 push 4919
:0008.1859 68D207                 push 07D2
:0008.185C 8D46EE                 lea ax, [bp-12]
:0008.185F 16                     push ss
:0008.1860 50                     push ax
:0008.1861 6A00                   push 0000
:0008.1863 6A00                   push 0000
:0008.1865 6A40                   push 0040
:0008.1867 9A44B11315             call 0064.B144

We want to jump at 8.1848, and that's why we patch "eb22" for "7f22". 
After that, we'll get to the program without much of a problem, except 
for two standard nag screens we'll take care of later.

Now in the program, you create an account and do some transactions. If 
the transaction date you use is beyond the registration year, you'll 
get another error message.  Same procedure, bpr on message string, pop 
into winice, get back into the program, find the call and take the jump 
with which you could have avoided the call. 

* Referenced by a Jump at Address:0014.2B5E(C)
:0014.2B63 A1D664                 mov ax, [64D6]
:0014.2B66 3906D870               cmp [70D8], ax
:0014.2B6A 7203                   jb 2B6F; hey honey - make money
:0014.2B6C E9970A                 jmp 3606; bad breath 

If your transaction date is beyond the valid period, you don't take the 
jump at 14.2b6a (in softice it's 0e.2b6a but you did know that didn't 
you?) So you'll patch "eb03" for "7203" and then you can record 
transactions for all future generations. >Insert generic anti-capitalist 
flame here <.

The program is functional now, all that's left to do is kick those nag 
screens out. 
There are two of them, the general trial one, and a - so I assume-  
specifically French one informing you that the minitel features are not 
available in the trial version. Same procedure:

:0002.0EAE 837E0601               cmp word ptr [bp+06], 0001
:0002.0EB2 7406                   je 0EBA;  patch here
:0002.0EB4 837E0609               cmp word ptr [bp+06], 0009
:0002.0EB8 7530                   jne 0EEA 

* Referenced by a Jump at Address:0002.0EB2(C)
:0002.0EBA FF36540B               push word ptr [0B54]
:0002.0EBE 833E720B01             cmp word ptr [0B72], 0001
:0002.0EC3 1BC0                   sbb ax, ax
:0002.0EC5 24FE                   and al, FE
:0002.0EC7 050300                 add ax, 0003
:0002.0ECA 50                     push ax
:0002.0ECB 9AF20E0000             call USER.SHOWWINDOW
:0002.0ED0 689304                 push 0493
:0002.0ED3 68FFFF                 push SEG ADDR of Segment 0028
:0002.0ED6 68C015                 push 15C0
:0002.0ED9 FF36540B               push word ptr [0B54]
:0002.0EDD 6A00                   push 0000
:0002.0EDF 6A00                   push 0000
:0002.0EE1 6A00                   push 0000
:0002.0EE3 9A3A01FFFF             call 0005.013A; EVIL
:0002.0EE8 EB0C                   jmp 0EF6

You patch the location 2.0eb2:  "EB36" (jmp 0eea) for "7406" and you'll 
never see that nag screen again.

And here goes minitel:

:0002.1455 7508                   jne 145F; patch here
:0002.1457 68E666                 push 66E6
:0002.145A 9A7A287C15             call 0002.287A; 666 <<

* Referenced by a Jump at Address:0002.1455(C)
:0002.145F 9A520AFFFF             call 0030.0A52
:0002.1464 0BC0                   or ax, ax
:0002.1466 7503                   jne 146B
:0002.1468 E9CB00                 jmp 1536

So our last patch is at location 2.1455: "EB0d" (jmp 1464) for "7508". 
Nuff said about this truly ZEN crack of an intrinsically useless 
program. Don't ask me why I've done this. I don't know.

MSMONEY97 trial

Well, having worked on the old version does help a bit for cracking 
this disgrace of a program, since it uses the same protectionist 
structure. The version I'm working on is msmoney.exe 4.929.536 bytes 
of 09/10/96.  

This time we'll do it in the order in which the annoyances occur. First 
the nag screen. "Welcome to Microsoft Money, which will transform the 
way you manage your finances." You bet that it won't. BPR on the message 
text, and you'll land in the program after cs:46bfbf. This section is 
called from cs:4a74fb. No useful conditional jumps before that section. 
There are some conditional jumps 4a75ee but they correspond to startup 
errors, so you don't want to take these. It looks like whenever you 
start the program you're supposed to get the nag screen. 

* Reference To: USER32.RegisterClassA, Ord:01ABh
:004A74CC FF15D00A6200            Call dword ptr [00620AD0]
:004A74D2 6685C0                  test ax, ax
:004A74D5 0F8413010000            je 004A75EE;not enough memory
:004A74DB E8401A0000              call 004A8F20
:004A74E0 85C0                    test eax, eax
:004A74E2 0F8406010000            je 004A75EE
:004A74E8 56                      push esi
:004A74E9 56                      push esi

* Reference To: USER32.GetDesktopWindow, Ord:00E8h
:004A74EA FF150C0B6200            Call dword ptr [00620B0C]
:004A74F0 50                      push eax
:004A74F1 6810F54C00              push 004CF510
:004A74F6 685E2F0000              push 00002F5E
:004A74FB E8104AFCFF              call 0046BF10; call to nag

So let's see what happens if we nop the whole call out. Insert any 5 
bytes that don't do anything at cs:4a74fb. In this case, simply inserting 
5 nops works just fine. And now the program starts without a nag screen. 
Hurdle 1 taken. 

Next thing you do is advance your system time and, as expected, you'll 
get a notice of expiration screen. You bpx on the text again, which 
leads you to our friend  cs:46bfbf again and this time it's called 
from cs:470e2a. So let's take a look at the code "before.class" tppabs="" this 

* Referenced by a Jump at Address:00470E81(C)
:00470E07 668B442414             mov ax, word ptr [esp + 14]
:00470E0C 6639842478010000    cmp word ptr [esp + 00000178], ax
:00470E14 721C                    jb 00470E32; good guy
:00470E16 6A00                    push 00000000
:00470E18 A1F03F6100              mov eax, [00613FF0]
:00470E1D 6A00                    push 00000000
:00470E1F 50                      push eax
:00470E20 6810F54C00              push 004CF510
:00470E25 685F2F0000              push 00002F5F
:00470E2A E8E1B0FFFF              call 0046BF10; call to expir

cs:470e0c compares system date and expiration date. If ax is not lower, the 
program calls the note of expiration. So it might be a good idea to change 
the conditional jump into an unconditional jump: eb1c.

In case you have tampered your system time (moved it forward and back again), 
you won't even get there.  Note the conditional jump that leads to the above 
quoted section. 

* Referenced by a  Jump at Addresses:00470C17(C), :00470C21(C), :00470C2B(C)
:00470E63 8B44246C                mov eax, dword ptr [esp + 6C]
:00470E67 6A5A                    push 0000005A
:00470E69 50                      push eax
:00470E6A E8017CFFFF              call 00468A70
:00470E6F 6689442474              mov word ptr [esp + 74], ax
:00470E74 83C408                  add esp, 00000008
:00470E77 668B442414              mov ax, word ptr [esp + 14]
:00470E7C 663944246C              cmp word ptr [esp + 6C], ax
:00470E81 7384                    jnb 00470E07; here
:00470E83 6A00                    push 00000000
:00470E85 6A00                    push 00000000
:00470E87 6A00                    push 00000000
:00470E89 6A00                    push 00000000
:00470E8B 6A00                    push 00000000
:00470E8D 680F090000              push 0000090F
:00470E92 E8A9330000              call 00474240; bad guy

cs:470e7c compares the system date and the installation date. If the former is 
earlier than the latter, the program sends you to the "get your system clock 
right, lamer" screen. So in case you have played around with your system time, 
you might want to make the conditional jump at cs:470e81 an unconditional jump: 

So let's take a look at the transaction limit, shall we? You enter a date beyond 
the registration period in the account manager, and the program gives you a 
screen: "The date you just entered is beyond ... blabla."  Back in the program 
you get to a couple of locations with not much going on. You hit F12 until you 
find something more interesting. After 5 or so times you'll find:

* Referenced by a  Jump at Address:005B5525(C)
:005B622D 6A00                    push 00000000
:005B622F 680B090000              push 0000090B
:005B6234 E867E9EBFF              call 00474BA0; call to transaction limit
:005B6239 83C408                  add esp, 00000008

Which leads us to this location:

:005B550D 668B81A9010000          mov ax, word ptr [ecx+01A9]
:005B5514 663DFFFF                cmp ax, FFFF
:005B5518 0F84F60C0000            je 005B6214
:005B551E 66390544926100          cmp word ptr [00619244], ax; beyond hope?
:005B5525 0F86020D0000            jbe 005B622D; jump to transaction limit

Here, at cs:5b551e the transaction date is being compared to the expiration 
date. If the expiration date is below or equal, we take that jump we don't 
want to take.  So it might be a good idea to nop out that jump at cs:5b5525. 
Let's make it inc eax, dec eax, inc ax, dec ax for a change. 

It's not like I've ever used that program but playing around with it I found 
another restriction: on creating new files. This is actually the major difference 
between the old demo and the new trial version: an additional check on the 
creation of new files. The usual procedure takes you here: 

* Referenced by a Jump at Addresses:00470648(C), :00470664(C)

:0047067C E84F83FFFF              call 004689D0
:00470681 6689442402              mov word ptr [esp + 02], ax
:00470686 662500FE                and ax, FE00
:0047068A 663D0060                cmp ax, 6000
:0047068E 7428                    je 004706B8;good guy 
:00470690 663D0062                cmp ax, 6200
:00470694 7422                    je 004706B8;good guy
:00470696 6A00                    push 00000000
:00470698 A1F03F6100              mov eax, [00613FF0]
:0047069D 6A00                    push 00000000
:0047069F 50                      push eax
:004706A0 6810F54C00              push 004CF510
:004706A5 68DC2F0000              push 00002FDC
:004706AA E861B8FFFF              call 0046BF10; call to expir
:004706AF 83C414                  add esp, 00000014
:004706B2 33C0                    xor eax, eax
:004706B4 83C404                  add esp, 00000004
:004706B7 C3                      ret

As you can see, ax is compared to 6000 and 6200 consecutively, and if it matches 
either of them, you will skip the call to the expiration notice. Looks like we 
better have one of these values in ax. So we can make either the jump at cs:47068e 
or the one at cs:470694 unconditional.  For instance EB28 at the former location.

So what is the date format anyway? What's all this  6000, 6200, etc. stuff about? 
It's the result of a date transformation routine starting with a call to 
getlocaltime  at cs:4689d8 

These are the restrictions I've encountered and how they can be overcome. 
There might be some more somewhere but I didn't want to spend too much time 
with this program. So there.


The question was: Why does patching the location at cs:5168015 not work?

Well, it seems pretty obvious just from looking at the code fragments in the 

we jump to "badflag" at cs:5167f97
don't patch something related to that "badflag"

the comparison at cs:5167fdc and the consecutive jump at cs:5167fe1
will kick us out before we even get to the location cs:5168015.

The patch at cs:5168015 doesn't work because, if we're expired and don't patch 
something else, we don't even get to that location. Duh.


Ok. Hope this is enough to qualify for +HCU98. I've learnt a lot about 
cracking during the last year but I know I'm far from being a good cracker. 
I'm a little unsatisfied because mostly I've used the same approach for all of 
this. Break at the text of the error message and kill the instruction that
sends you there. This wouldn't have worked as well if the offending instructions 
had been hidden better. But it works sufficiently well in this case. And that 
should be enough. Minimalism is not a bad thing.