¦  Cracking M$ Money Demo (v3.00p *FRENCH*)     ¦
¦  by Aitor, 30/08/97                           ¦

****** Excerpt from +ORC lesson 4.2: ****************************************

     This old "trial" demo of MS-Money has THREE levels of protection:

  1) The system date in your computer must be 1994 or 1995
  2) There is a Cinderella 60 days limit (Micro$oft was not yet a "90 days" 
     enterprise... we are watching here the BIRTH of this MS-protection 
     scheme :=) 
  3) Transactions (i.e. fields of this database) can only be entered within
     a 60-days period (this is at the same part the "tricky" part of this 
     crack and a key to the crack :=)


Aurrera !

- Ctrl+D (enter Soft-iCE)
- bpx messagebox (bp#0)       ; bp to catch 1994/1995 limitation messagebox
- g                           ; return to the system
- Run MNYDEMO.EXE             ; Run the program until Soft-iCE break
- bd 0                        ; Again inside Soft-iCE ... disable bp#0
- pret                        ; pret until locate the calling instructions
- pret
- pret
- pret
- Now we are at 0008.1515 (dead list).  Let's take a look a few lines of code
  before our actual position, looking comparing routines ...

: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
:0008.14FE 741C            je 151C
:0008.1500 8A66FF          mov ah, [bp-01]
:0008.1503 80E4FE          and ah, FE
:0008.1506 80FC5E          cmp ah, 5E
:0008.1509 7411            je 151C                 ; Here we got it !
:0008.150B 681709          push 0917
:0008.150E 6A00            push 0000
:0008.1510 9A1AADBB0E      call 0064.AD1A
:0008.1515 33C0            xor ax, ax
:0008.1517 C9              leave
:0008.1518 C20400          ret 0004

- Firstly we'll try the quick way, many programs can be cracked by this
  way ... try it !   Put a BREAKPOiNT at 0008.1509 and go to the program,
  exit the program and run it again ... bypass the first message and
  Soft-iCE breaks at 0008.1509 ... now PATCH the code:

        0008.1509  7411  je 151c  ->  eb11  jmp 151c

  Now return to the program and watch ... eeeepaa!  '1994/1995' check
  has been bypassed ;-).  The other limitation (entering data with dates
  bigger than expiration date (take a look at the 'About' window and note
  that, after patching, expiration date is always the actual date)) can be
  cracked by the same method (search the messagebox calling routine and
  examining the routines above it patching a conditional jump with a JMP),
  but we don't want to crack the program only, we want real cracking
  knowledge ... let's search it !
  One of the KEYS of the protection scheme is the date encryption (the other
  is the expiration date memory location), and it's near us ... can you
  feel it ? ;).  Check the complete routine above the 1994/1995 messagebox:

:0008.14BC C8060000        enter 0006, 00
:0008.14C0 837E0400        cmp word ptr [bp+04], 0000
:0008.14C4 741E            je 14E4
:0008.14C6 8A26D764        mov ah, [64D7]      ; Expiration YEAR encrypted
:0008.14CA 2500FE          and ax, FE00
:0008.14CD 8946FA          mov [bp-06], ax
:0008.14D0 3D005C          cmp ax, 5C00        ; 1994 ?
:0008.14D3 740A            je 14DF
:0008.14D5 3D005E          cmp ax, 5E00        ; 1995 ?
:0008.14D8 7405            je 14DF
:0008.14DA 3D0060          cmp ax, 6000        ; 1996 ?  
:0008.14DD 7505            jne 14E4            
:0008.14DF A1D664          mov ax, [64D6]      ; exp. year in [1994..1996]
:0008.14E2 EB4B            jmp 152F            ; jump to the program
:0008.14E4 8D46FC          lea ax, [bp-04]
:0008.14E7 50              push ax
:0008.14E8 9A52052815      call 0081.0552      ; get/encrypt system date 
:0008.14ED 8BD8            mov bx, ax
:0008.14EF 368B07          mov ax, ss:[bx]     ; encrypted system date
:0008.14F2 8946FE          mov [bp-02], ax     ; store it in the heap 
:0008.14F5 8A66FF          mov ah, [bp-01]     ; encrypted system YEAR
:0008.14F8 80E4FE          and ah, FE
:0008.14FB 80FC5C          cmp ah, 5C          ; 1994 ?
:0008.14FE 741C            je 151C
:0008.1500 8A66FF          mov ah, [bp-01]
:0008.1503 80E4FE          and ah, FE
:0008.1506 80FC5E          cmp ah, 5E          ; 1995 ?
:0008.1509 7411            je 151C             ; OK, jump to the program
:0008.150B 681709          push 0917
:0008.150E 6A00            push 0000
:0008.1510 9A1AADBB0E      call 0064.AD1A      ; Oopss! 1994/1995 messagebox
:0008.1515 33C0            xor ax, ax
:0008.1517 C9              leave
:0008.1518 C20400          ret 0004            ; ret and kick off the program

- And now the date encryption ... trace the program a little from 0008.14e8
  and you'll come here:

:0081.0552 8CD8            mov ax, ds
:0081.0554 90              nop
:0081.0555 45              inc bp
:0081.0556 55              push bp
:0081.0557 8BEC            mov bp, sp
:0081.0559 1E              push ds
:0081.055A 8ED8            mov ds, ax
:0081.055C 83EC0A          sub sp, 000A
:0081.055F 8D46F6          lea ax, [bp-0A]
:0081.0562 50              push ax
:0081.0563 9AC008FFFF      call 0010.08C0      ; get system date


  :0010.08C0 8CD8               mov ax, ds
  :0010.08C2 90                 nop
  :0010.08C3 45                 inc bp
  :0010.08C4 55                 push bp
  :0010.08C5 8BEC               mov bp, sp
  :0010.08C7 1E                 push ds
  :0010.08C8 8ED8               mov ds, ax
  :0010.08CA B42A               mov ah, 2A
  :0010.08CC 2EF70610000100     test word ptr cs:[0010], 0001
  :0010.08D3 7407               je 08DC
  :0010.08D5 9AB5030000         call KERNEL.DOS3CALL   ; get system date
  :0010.08DA EB02               jmp 08DE 
  :0010.08DC CD21               int 21                 ;int 21, ah=2a (same)
  :0010.08DE 8B5E06             mov bx, [bp+06]
  :0010.08E1 894F02             mov [bx+02], cx        ; system YEAR
  :0010.08E4 887701             mov [bx+01], dh        ;        MONTH
  :0010.08E7 8817               mov [bx], dl           ;        DAY
  :0010.08E9 884704             mov [bx+04], al        ;        DAY OF WEEK
  :0010.08EC 33C0               xor ax, ax
  :0010.08EE 83ED02             sub bp, 0002
  :0010.08F1 8BE5               mov sp, bp
  :0010.08F3 1F                 pop ds
  :0010.08F4 5D                 pop bp
  :0010.08F5 4D                 dec bp
  :0010.08F6 CB                 retf                   


:0081.0568 83C402            add sp, 0002              ; encryption begins
:0081.056B 8A46F7            mov al , [bp-09]          ; MONTH
:0081.056E 2AE4              sub ah, ah
:0081.0570 48                dec ax                    ; MONTH -1
:0081.0571 C1E005            shl ax, 05                
:0081.0574 3346FC            xor ax, [bp-04]
:0081.0577 25E001            and ax, 01E0
:0081.057A 3146FC            xor [bp-04], ax
:0081.057D 8A46FC            mov al , [bp-04]
:0081.0580 8A4EF6            mov cl , [bp-0A]          ; DAY
:0081.0583 2AED              sub ch, ch
:0081.0585 49                dec cx                    ; DAY-1
:0081.0586 32C1              xor al , cl 
:0081.0588 251F00            and ax, 001F
:0081.058B 3146FC            xor [bp-04], ax
:0081.058E 8B46F8            mov ax, [bp-08]           ; YEAR
:0081.0591 2D9C07            sub ax, 079C              ; YEAR - 1948
:0081.0594 3D7F00            cmp ax, 007F              ; difference > 127 ?
:0081.0597 760F              jbe 05A8
:0081.0599 836EF864          sub word ptr [bp-08],64   ; YEAR - 100
:0081.059D 8B46F8            mov ax, [bp-08]
:0081.05A0 2D9C07            sub ax, 079C
:0081.05A3 3D7F00            cmp ax, 007F
:0081.05A6 77F1              ja 0599                   ; until YEAR <= 2075
:0081.05A8 8B46F8            mov ax, [bp-08]           ; YEAR
:0081.05AB 2D1C00            sub ax, 001C              ; YEAR - 28
:0081.05AE C1E009            shl ax, 09
:0081.05B1 8B4EF8            mov cx, [bp-08]
:0081.05B4 C1E109            shl cx, 09
:0081.05B7 334EFC            xor cx, [bp-04]
:0081.05BA 80E501            and ch, 01
:0081.05BD 33C8              xor cx, ax
:0081.05BF 894EFC            mov [bp-04], cx
:0081.05C2 8BC1              mov ax, cx        
:0081.05C4 8B5E06            mov bx, [bp+06]
:0081.05C7 368907            mov ss:[bx], ax         ; encrypted system date
:0081.05CA 8BC3              mov ax, bx
:0081.05CC 8CD2              mov dx, ss
:0081.05CE 8D66FE            lea sp, [bp-02]
:0081.05D1 1F                pop ds
:0081.05D2 5D                pop bp
:0081.05D3 4D                dec bp
:0081.05D4 CA0200            retf 0002

- With this code "dates.class" tppabs="http://www.fravia.org/solutions/dates.class" are encrypted and you'll get, eg:

        0000 = 01/01/1948
        5c00 = 01/01/1994
        633d = 30/10/1997
  try it yourself ...

  Ripping the encryption code we can write a little program to do the job 
  (it may help in future Micro$oft cracking sessions :)) ... here you got
  the TP/BASM code (with a few little modifications you can get the C 

{----- begin of the program ------------------------------------------------}

Program MS_Money_Date_Encryption;


  Str4 = String[4];

Function Word2Hex(W:Word):Str4;
  Hex : Array [0..$f] of Char = '0123456789ABCDEF';
    les di,@Result; mov al,4; stosb; mov bx,W; mov dx,bx; mov bl,bh;
    xor bh,bh; mov cl,4; shr bx,cl; mov al,byte ptr Hex[bx]; mov bl,dh
    and bx,$f; mov ah,byte ptr Hex[bx]; stosw; mov bl,dl; xor bh,bh;
    mov cl,4; shr bx,cl; mov al,byte ptr Hex[bx]; mov bl,dl; and bx,$f;
    mov ah,byte ptr Hex[bx]; stosw
End; {Word2Hex}

  Day,Month     : Byte;
  Year,CrypDate : Word;

  WriteLn('¦  MS Money v3.0 date encryption  ¦');
  WriteLn('¦  by Aitor, 30/8/97 (62FD :))    ¦');
  Write('Enter DAY .... : '); ReadLn(Day);
  Write('Enter MONTH .. : '); ReadLn(Month);
  Write('Enter YEAR ... : '); ReadLn(Year);
    xor ax,ax
    mov al,Month
    dec ax
    shl ax,5
    and ax,$1e0
    xor CrypDate,ax
    mov ax,CrypDate
    xor cx,cx
    mov cl,Day
    dec cx
    xor al,cl
    and ax,$1f
    xor CrypDate,ax
    mov ax,Year
    sub ax,$79c
    cmp ax,$7f
    jbe @2
    sub Year,$64
    mov ax,Year
    sub ax,$79c
    cmp ax,$7f
    ja @1
    mov ax,Year
    sub ax,$1c
    shl ax,9
    mov cx,Year
    shl cx,9
    xor cx,CrypDate
    and ch,1
    xor cx,ax
    mov CrypDate,cx
  WriteLn(#13#10+'Encrypted Date : '+Word2Hex(CrypDate));
End. {MS_Money_Date_Encryption}

{----- end of the program --------------------------------------------------}

  If you want to go a little deeper into this protection (more knowledge
  for possible future cracking works ;-) ...
      - Run the program, click in the 'About ... ' option and write on a
        paper the expiration date, suppose it is (e.g.) 29/10/95.
      - Create a new M$Money file (let's call it DUMMY.MNY, save it and
        exit the program.

      - Fire your little encryption program and process this date, you'll
        get:  29/10/95 = 5F3C

      - Take an hex editor (e.g. Hacker´s View), load your just created
        DUMMY.MNY and search for 3C5F (remember! words are stored 
        inverted ... low_byte/high_byte) ... wait a little and you´ll be
        located at offset 224h.

      - Try the same with other *.MNY files you want ... yes, encrypted
        expiration date is stored at offset 224h in EVERY *.MNY file !!


- With the first patch we have cracked the first two levels of protection,
  but the third is still (not for many time :)) uncracked ...
  The 3rd level: we cannot enter transaction data with dates beyond the
  expiration date ...
  Reading the dead listing transcripted before (0008.14bc ...) we have
  noted that (encrypted) expiration date (word) is located at DS:64d6 ...
  ... to crack the 3rd level we have to do a memory read breakpoint at this
  position, and see what happens ... lastly we land here:

:0014.2B63 A1D664       mov ax, [64D6]     ; encrypted expiration date
:0014.2B66 3906D870     cmp [70D8], ax     ; exp. date < transaction date ?
:0014.2B6A 7203         jb 2B6F            ; ooppsss! limitation messagebox
:0014.2B6C E9970A       jmp 3606           ; OK, jump and store entered data

  We can patch it with an unconditional jump like this:

        :0014.2B6A  7203  jb 2B6F  ->  eb03  jmp 2B6F

- Complete patch:

          Program : Micro$oft Money v3.00p (Demo) *FRENCH*  (thanx Reverser!)
          File    : MNYDEMO.EXE, 1.205.888 bytes
          Search  : 74 11 68 17 09
          Replace : eb -- -- -- --

          Search  : 72 03 e9 97 0a
          Replace : eb -- -- -- --

- That's all.  Hope you understand all I wrote, sorry for my English :).
¦  Cracking M$ Money Trial (v5.0 *ENGLiSH*)  ¦
¦  by Aitor, 30/08/97                        ¦

- To follow this document a previous reading of the v3.0 cracking doc is
  suitable (el que avisa ... ;)).

- Protection scheme is mostly the same (same date encryption, expiration
  date, entering dates between a range, etc.), but this time we'll follow 
  another approach ... may be a little tricky, but surely more funny 8-) ...
  ... aurrera with it !

- Three levels of protection, but we'll solve them in one step ;-).
  The KEY to solve this scheme is the cracking of the (encrypted) expiration
  date ... once we got it, all the scheme will come down ...

  We could try the same approach used to crack version 3.0, but here you got
  what I call the 'happy idea' method (I think it's far from +ORC's
  ZEN-cracking, but ... :)):

    When we click the 'About' option from the main menu to know the
    expiration date the program reads its encrypted value (located somewhere
    in the memory) to transform it in a 'dd/mm/yy' string ... uhmmm ?
    All we need to do is locate the memory position where the encrypted
    date is stored and 'bpm' it ...

  Process MSMONEY.EXE with a good disassembler (eg. W32Dasm ;)) and get a
  dead listing.  Load it with a good word processor or viewer (I use Lister
  from Windows Commander ... surely quicker than WinWord v8.0 ;-)), search
  for the string 'This copy will expire' and we get this:

    017 - ControlID:0423, Control Class:"" Control Text:
            "This copy will expire on:" 

:004CF252 6823040000       push 00000423               ; our string
:004CF257 51               push ecx
:004CF258 E843DAF9FF       call 0046CCA0
:004CF25D 83C40C           add esp, 0000000C
:004CF260 8B4D08           mov ecx, dword ptr [ebp+08]
:004CF263 6A01             push 00000001
:004CF265 6824040000       push 00000424
:004CF26A 51               push ecx
:004CF26B E830DAF9FF       call 0046CCA0
:004CF270 83C40C           add esp, 0000000C
:004CF273 668B0D44926100   mov cx, word ptr [00619244] ; expiration date !!
:004CF27A 51               push ecx
:004CF27B 8B5508           mov edx, dword ptr [ebp+08]
:004CF27E 6824040000       push 00000424
:004CF283 52               push edx
:004CF284 FF15C8086200     Call dword ptr [006208C8]
:004CF28A 50               push eax
:004CF28B E8C0A0F9FF       call 00469350               ; 'dd/mm/yy' conversion
:004CF290 83C408           add esp, 00000008
:004CF293 B801000000       mov eax, 00000001
:004CF298 E904020000       jmp 004CF4A1
:004CF29D B890FE5F00       mov eax, 005FFE90
:004CF2A2 E915AD1000       Jmp 005D9FBC

- Once you got the memory location of the exp. date, put a memory breakpoint
  on it:

     - bpm ds:619244
     - g

  Now try to create a new file (demo limitation beyond the exp. date), and
  again program is broken by Soft-iCE getting this:

:00470640 83EC04          sub esp, 00000004
:00470643 837C240C00      cmp dword ptr [esp + 0C], 00000000
:00470648 7432            je 0047067C
:0047064A 66A144926100    mov ax, [00619244]      ; read expiration date
:00470650 662500FE        and ax, FE00            ; and extract the year
:00470654 663D0060        cmp ax, 6000            ; 1996 ?
:00470658 740C            je 00470666
:0047065A 663D0062        cmp ax, 6200            ; 1997 ?
:0047065E 7406            je 00470666
:00470660 663D0064        cmp ax, 6400            ; 1998 ?
:00470664 7516            jne 0047067C            ; expired trial version
:00470666 66A144926100    mov ax, [00619244]      ; OK, read again exp. date
:0047066C 8B4C2408        mov ecx, dword ptr [esp + 08]
:00470670 668901          mov word ptr [ecx], ax
:00470673 B801000000      mov eax, 00000001
:00470678 83C404          add esp, 00000004
:0047067B C3              ret

  This is a good place to our PATCH:

:0047064A 66B8FFFF        mov ax, FFFF            ; New expiration date
:0047064E EB1C            jmp 0047066C            ; Follow the good way

  And now test the patch ...  
  Expiration message has been removed, OK.
  Test now the 'New/Open file' limitations ...  I got 4 .MNY files: 
  AITOR1 to AITOR4.MNY.  1 and 2 were created just before installing
  M$-Money, 3 and 4 were created after PATCHing ...  When I try to load
  1 and 2, the expiration message appears, but when I do the same with
  3 and 4 I see nothing ...
     ... yes!  Do you remember what I told you about expiration date storing
  inside MNY files (read v3.0 doc) ? ... take your hex editor and check the
  files:  nothing at offset 224h (only zeros), but there is something 
  familiar at 228h ... in files 1 and 2 (old files) appears
        5B63 -> 635B = 28/11/1997

  yes, my old expiration date.  Check it now the files created after patching
  (3 and 4) ...

        FFFF -> my new expiration date !!

  But wait a moment, let's see if we're right ... take one of the old files,
  change the 5B63 for FFFF (or other right encrypted date) at offset 228h 
  and run the program ... now it loads withouth problem !!

  Concluding:  Expiration date is stored in the MNY files.  When you install
  the program expiration date is save inside SAMPLE.MNY file.  When you run 
  the program the expiration date is loaded in memory from this file, and all
  the files you create will be stamped with this date ...  Now you see the
  reason for the 'File required' message window, eh ?

  And now the final test, entered dates between a valid range ...
  Just before saving new data our breakpoint at ds:619244 (exp. date) brings
  us Soft-iCE again, getting the following:

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

  Here it is the kernel of the last level of protection, a simple comparation
  between transaction date and expiration date ... our expiration date will 
  be always FFFF (remember the PATCH), i.e. we can enter any date we want, no
  more patching needed here ;-).

- Complete patch:

          Program : Micro$oft Money v5.0 (Trial version) *ENGLiSH*  
          File    : MSMONEY.EXE, 4.929.536 bytes
          Search  : a1 44 92 61 00
          Replace : b8 ff ff eb 1c

- That's all.  Hope you understand all I wrote, sorry for my English :).

----- EOF -------------------------------------------------------------------
----- EOF -------------------------------------------------------------------