Paint Shop Pro v6.01 Eval
[Reversing essay]

Subject: Cracking
Target: Paint Shop Pro v6.01 Eval
Author: BlackB
Date: 2000-03-08
Tools used: SoftICE, HIEW
Difficulty (scale 1-5): 2 à 3

Before starting!
This essay is for knowledge purposes only!!
Software developers spend much time in making their programs. They live from the money we give them!
Please buy good software!!
I. Introduction
I'm in my "essay writing" period lately. Be happy! :-) This time on Paintshop Pro. An interesting target as it uses a non-standard nagscreen. Curious? Read on :)
Btw, note that this is not an essay for 100 % newbies!
II. About the protection
30-day trial / nagscreen
III. Cracking it
We'll crack it in two steps:

1.the 30-day trial (fairly easy)
2.the nagscreen (which is a pain in the ass)


We'll do it without w32dasm as disassembling a 7,6 MB .exe file would take a very long time and would make a very huge textfile. Okay let's start cracking the time trial. Run Paintshop Pro (now abreviated: PSP) and note that you can use it for 30 days. When using it more then 30 days it still will work, but it 'll display another message. After 60 days you can't use it anymore.
Let's break on our beloved GetSystemTime. Just after the nagscreen is drawn, SoftICE breaks....hmmm, that's a good sign. Press F12 twice to get back in the PSP main code.

Start partial code

0137:0076C533  MOV     ECX,[ESP+28] <- You land here
0137:0076C537  MOV     EDX,[ESP+64]
0137:0076C53B  PUSH    ECX
0137:0076C53C  PUSH    EDX
0137:0076C53D  CALL    [0098B134]
0137:0076C543  ADD     ESP,0C
0137:0076C546  CALL    00834BCA
0137:0076C54B  MOV     ECX,EAX
0137:0076C54D  MOV     EAX,C22E4507
0137:0076C552  IMUL    ECX
0137:0076C554  ADD     EDX,ECX
0137:0076C556  SAR     EDX,10
0137:0076C559  MOV     EAX,EDX
0137:0076C55B  SHR     EAX,1F
0137:0076C55E  ADD     EDX,EAX
0137:0076C560  LEA     ESI,[EDX+01] <- ESI=days used
0137:0076C563  CMP     ESI,01
0137:0076C566  JGE     0076C56D     <- jump 
0137:0076C568  MOV     ESI,0000005B
0137:0076C56D  MOV     [ESP+44],EBX
0137:0076C571  MOV     DWORD PTR [ESP+40],0087C2D0
0137:0076C579  PUSH    0091DDC0
0137:0076C57E  PUSH    EBX
0137:0076C57F  PUSH    EBX
0137:0076C580  PUSH    EBX
0137:0076C581  PUSH    EBX
0137:0076C582  PUSH    01
0137:0076C584  PUSH    EBX
0137:0076C585  PUSH    EBX
0137:0076C586  PUSH    EBX
0137:0076C587  PUSH    000002BC
0137:0076C58C  PUSH    EBX
0137:0076C58D  PUSH    EBX
0137:0076C58E  PUSH    EBX
0137:0076C58F  PUSH    0E
0137:0076C591  MOV     BYTE PTR [ESP+00000194],07
0137:0076C599  CALL    EDI
0137:0076C59B  PUSH    EAX
0137:0076C59C  LEA     ECX,[ESP+44]
0137:0076C5A0  CALL    0083358E
0137:0076C5A5  LEA     ECX,[ESP+40]
0137:0076C5A9  PUSH    ECX
0137:0076C5AA  LEA     ECX,[ESP+0000008C]
0137:0076C5B1  CALL    00833BB2
0137:0076C5B6  MOV     EBX,[0098B1E8]
0137:0076C5BC  PUSH    009236BC
0137:0076C5C1  MOV     EDI,EAX
0137:0076C5C3  CALL    EBX
0137:0076C5C5  ADD     ESP,04
0137:0076C5C8  CMP     ESI,EAX  <- compare days used to 30
0137:0076C5CA  PUSH    ESI
0137:0076C5CB  JGE     0076C5D9 <- if used longer then 30-days: jump
0137:0076C5CD  LEA     EDX,[ESP+14]
0137:0076C5D1  PUSH    00005CBF
0137:0076C5D6  PUSH    EDX
0137:0076C5D7  JMP     0076C5E3 <- executed when days used < 30
0137:0076C5D9  LEA     EAX,[ESP+14]
0137:0076C5DD  PUSH    00005CC0
0137:0076C5E2  PUSH    EAX
0137:0076C5E3  CALL    00833690
0137:0076C5E8  ADD     ESP,0C
0137:0076C5EB  LEA     ECX,[ESP+1C]
0137:0076C5EF  PUSH    00004F21
0137:0076C5F4  CALL    008334AA
0137:0076C5F9  LEA     ECX,[ESP+5C]
0137:0076C5FD  LEA     EDX,[ESP+58]
0137:0076C601  PUSH    ECX
0137:0076C602  LEA     EAX,[ESP+58]
0137:0076C606  PUSH    EDX
0137:0076C607  MOV     EDX,[ESP+24]
0137:0076C60B  LEA     ECX,[ESP+58]
0137:0076C60F  PUSH    EAX
0137:0076C610  PUSH    ECX
0137:0076C611  PUSH    009216EC
0137:0076C616  PUSH    EDX
0137:0076C617  CALL    [0098B1D4]
0137:0076C61D  ADD     ESP,18
0137:0076C620  CMP     ESI,1E <- double check
0137:0076C623  JLE     0076C66C <- jump if days used < 30
0137:0076C625  LEA     EAX,[ESP+50]
0137:0076C629  PUSH    00
0137:0076C62B  PUSH    EAX
0137:0076C62C  LEA     ECX,[ESP+00000090]

........

0137:0076C6D1  CMP     ESI,EAX  <- days used > 60?
0137:0076C6D3  JLE     0076C763 <- if days used > 60 don't jump

End partial code

Yea, we _could_ patch all the conditional jumps but......there is an easier way: just set ESI==1. That way our program 'll believe we're still at our first day of trial, no matter how long we used it.
To do so change:
:0076C560 LEA ESI,[EDX+01]
:0076C563 CMP ESI,01
:0076C566 JGE 0076C56D
into:
:0076C560 MOV ESI,00000001
:0076C565 NOP
:0076C566 JMP 0076C56D

Make the changes in HIEW, start PSP and see it working, no matter what day.

Next thing to do: the nagscreen. As I said in the beginning: a pain in the ass. Why? You'll find out soon :)
Set a breakpoint on UpdateWindow, run PSP, SoftICE breaks. Press CTRL-D until the nagscreen appears (should be 10 times, incluis the one when sice breaks for the first time!). Clear the breakpoint, exit PSP, set breakpoint again, run PSP again. Now let SoftICE break 9 times. We're now in the middle of the nagscreen call:

Start partial code

0137:0076B853  CALL    [USER32!UpdateWindow]
0137:0076B859  PUSH    EDI
0137:0076B85A  PUSH    EDI
0137:0076B85B  PUSH    00020000
0137:0076B860  MOV     ECX,ESI
0137:0076B862  CALL    00833F9C
0137:0076B867  PUSH    00923690
0137:0076B86C  CALL    EBX
0137:0076B86E  MOV     ECX,[00930B2C]
0137:0076B874  ADD     ESP,04
0137:0076B877  MOV     EDX,[ECX+20]
0137:0076B87A  PUSH    EDI
0137:0076B87B  PUSH    EAX
0137:0076B87C  PUSH    07
0137:0076B87E  PUSH    EDX
0137:0076B87F  CALL    [USER32!SetTimer] <- Timer to delay OK-button click
0137:0076B885  MOV     ECX,[00930B2C]
0137:0076B88B  MOV     [ECX+74],EAX
0137:0076B88E  CALL    [KERNEL32!GetTickCount]
0137:0076B894  MOV     ECX,[ESP+10]
0137:0076B898  POP     ESI
0137:0076B899  MOV     [00930B20],EAX
0137:0076B89E  POP     EBX
0137:0076B89F  MOV     EAX,00000001
0137:0076B8A4  POP     EDI
0137:0076B8A5  MOV     FS:[00000000],ECX
0137:0076B8AC  ADD     ESP,10
0137:0076B8AF  RET

End partial code

After the 'ret' instruction you can set a breakpoint on the call that let appear the nagscreen, and you could (when restarting psp) trace into that call and try about everything that's possible to disable it.......it won't be sucessfull. Well, you _can_ let the nagscreen disappear, but PSP will give fatal errors when for example: you try to open a file. So forget this call, we can't do anything with it.
Now _how_ for god's sake can we remove the nag??! Idea: make a splashscreen of the nag. Therefore we gotta know where the nagscreen is destroyed.
Re-run PSP, when everything is loaded set a breakpoint on DestroyWindow. Click the 'OK' button, SoftICE breaks. Press F12 (about two times I guess) until you see this:

Start partial code

0137:0076BC65  CALL    00833888 <- You land here
0137:0076BC6A  TEST    EAX,EAX
0137:0076BC6C  JZ      0076BC77
0137:0076BC6E  MOV     EDX,[EAX]
0137:0076BC70  MOV     ECX,EAX
0137:0076BC72  CALL    [EDX+7C]
0137:0076BC75  JMP     0076BC79
0137:0076BC77  XOR     EAX,EAX
0137:0076BC79  MOV     EAX,[EAX+20]
0137:0076BC7C  PUSH    EAX
0137:0076BC7D  CALL    [USER32!UpdateWindow] <- Removes nagscreen

End partial code

Press F12 to leave to execute the call until 'ret'. If you look 1 instruction above, you now see the call that takes care of destroying the nagscreen. Set a breakpoint on it. Trace into that call. .I'll comment the call as it would be executed when removing the nagscreen. Btw, to find out what jumps are made, what registers are loaded etc.... to remove the nag, just compare this call when removing the nag with the same call is it processes other stuff (this call is called very very often, not only for the nagscreen)

Start partial code

0137:0076BA40  MOV     EAX,FS:[00000000]
0137:0076BA46  PUSH    FF
0137:0076BA48  PUSH    00870648
0137:0076BA4D  PUSH    EAX
0137:0076BA4E  MOV     EAX,[00930B2C] <- Move "event-happened" in mem location
0137:0076BA53  MOV     FS:[00000000],ESP
0137:0076BA5A  SUB     ESP,2C
0137:0076BA5D  TEST    EAX,EAX                      <- Event happened??           
0137:0076BA5F  PUSH    EBP
0137:0076BA60  PUSH    ESI
0137:0076BA61  PUSH    EDI
0137:0076BA62  JZ      0076BCE0                     <- Don't jump if an event happened
0137:0076BA68  CALL    008334B0
0137:0076BA6D  LEA     ECX,[ESP+0C]
0137:0076BA71  CALL    0083341A
0137:0076BA76  PUSH    00004F1D
0137:0076BA7B  LEA     ECX,[ESP+10]
0137:0076BA7F  MOV     DWORD PTR [ESP+44],00000000
0137:0076BA87  CALL    008334AA
0137:0076BA8C  MOV     ESI,[0098B1D4]
0137:0076BA92  LEA     EAX,[ESP+24]
0137:0076BA96  LEA     ECX,[ESP+20]
0137:0076BA9A  PUSH    EAX
0137:0076BA9B  LEA     EDX,[ESP+20]
0137:0076BA9F  PUSH    ECX
0137:0076BAA0  MOV     ECX,[ESP+14]
0137:0076BAA4  LEA     EAX,[ESP+20]
0137:0076BAA8  PUSH    EDX
0137:0076BAA9  PUSH    EAX
0137:0076BAAA  PUSH    009216EC
0137:0076BAAF  PUSH    ECX
0137:0076BAB0  CALL    ESI
0137:0076BAB2  ADD     ESP,18
0137:0076BAB5  LEA     ECX,[ESP+0C]
0137:0076BAB9  PUSH    00004F1E
0137:0076BABE  CALL    008334AA
0137:0076BAC3  LEA     EDX,[ESP+34]
0137:0076BAC7  LEA     EAX,[ESP+30]
0137:0076BACB  PUSH    EDX
0137:0076BACC  LEA     ECX,[ESP+30]
0137:0076BAD0  PUSH    EAX
0137:0076BAD1  MOV     EAX,[ESP+14]
0137:0076BAD5  LEA     EDX,[ESP+30]
0137:0076BAD9  PUSH    ECX
0137:0076BADA  PUSH    EDX
0137:0076BADB  PUSH    009216EC
0137:0076BAE0  PUSH    EAX
0137:0076BAE1  CALL    ESI
0137:0076BAE3  MOV     EAX,[ESP+60]
0137:0076BAE7  ADD     ESP,18
0137:0076BAEA  CMP     DWORD PTR [EAX+04],00000201        <- Button clicked?
0137:0076BAF1  JNZ     0076BCCF                           <- If not then jump
0137:0076BAF7  MOV     ESI,[EAX+0C]
0137:0076BAFA  MOV     EBP,[USER32!PtInRect]
0137:0076BB00  XOR     EDI,EDI
0137:0076BB02  LEA     ECX,[ESP+18]
0137:0076BB06  MOV     DI,[EAX+0C]
0137:0076BB0A  SHR     ESI,10
0137:0076BB0D  PUSH    ESI
0137:0076BB0E  PUSH    EDI
0137:0076BB0F  PUSH    ECX
0137:0076BB10  CALL    EBP
0137:0076BB12  TEST    EAX,EAX                             <- Is it the help button?
0137:0076BB14  JZ      0076BBFE                            <- Jump if not help button 
0137:0076BB1A  LEA     ECX,[ESP+48]
0137:0076BB1E  CALL    0083341A
0137:0076BB23  MOV     BYTE PTR [ESP+40],01
0137:0076BB28  CALL    008334B0
0137:0076BB2D  MOV     EAX,[EAX+04]
0137:0076BB30  LEA     ECX,[ESP+48]
0137:0076BB34  MOV     EDX,[EAX+00000090]
0137:0076BB3A  PUSH    EDX
0137:0076BB3B  CALL    00833414
0137:0076BB40  PUSH    009236B0
0137:0076BB45  LEA     ECX,[ESP+4C]
0137:0076BB49  CALL    00833996
0137:0076BB4E  PUSH    EAX
0137:0076BB4F  LEA     EAX,[ESP+14]
0137:0076BB53  PUSH    EAX
0137:0076BB54  LEA     ECX,[ESP+50]
0137:0076BB58  CALL    008336EA
0137:0076BB5D  PUSH    EAX
0137:0076BB5E  LEA     ECX,[ESP+4C]
0137:0076BB62  MOV     BYTE PTR [ESP+44],02
0137:0076BB67  CALL    008334BC
0137:0076BB6C  LEA     ECX,[ESP+10]
0137:0076BB70  MOV     BYTE PTR [ESP+40],01
0137:0076BB75  CALL    00833402
0137:0076BB7A  PUSH    ECX
0137:0076BB7B  LEA     EDX,[ESP+4C]
0137:0076BB7F  MOV     ECX,ESP
0137:0076BB81  MOV     [ESP+18],ESP
0137:0076BB85  PUSH    EDX
0137:0076BB86  CALL    0083368A
0137:0076BB8B  CALL    004073E2
0137:0076BB90  ADD     ESP,04
0137:0076BB93  TEST    EAX,EAX
0137:0076BB95  JZ      0076BBBA
0137:0076BB97  MOV     EAX,[00930B2C]
0137:0076BB9C  TEST    EAX,EAX
0137:0076BB9E  JZ      0076BBA3
0137:0076BBA0  MOV     EAX,[EAX+20]
0137:0076BBA3  MOV     ECX,[ESP+48]
0137:0076BBA7  PUSH    00027530
0137:0076BBAC  PUSH    01
0137:0076BBAE  PUSH    ECX
0137:0076BBAF  PUSH    EAX
0137:0076BBB0  CALL    [USER32!WinHelpA]
0137:0076BBB6  TEST    EAX,EAX
0137:0076BBB8  JNZ     0076BBC8
0137:0076BBBA  PUSH    FF
0137:0076BBBC  PUSH    00
0137:0076BBBE  PUSH    00005DB6
0137:0076BBC3  CALL    008336CC
0137:0076BBC8  LEA     ECX,[ESP+48]
0137:0076BBCC  MOV     BYTE PTR [ESP+40],00
0137:0076BBD1  CALL    00833402
0137:0076BBD6  LEA     ECX,[ESP+0C]
0137:0076BBDA  MOV     DWORD PTR [ESP+40],FFFFFFFF
0137:0076BBE2  CALL    00833402
0137:0076BBE7  MOV     EAX,00000001
0137:0076BBEC  MOV     ECX,[ESP+38]
0137:0076BBF0  MOV     FS:[00000000],ECX
0137:0076BBF7  POP     EDI
0137:0076BBF8  POP     ESI
0137:0076BBF9  POP     EBP
0137:0076BBFA  ADD     ESP,38
0137:0076BBFD  RET
0137:0076BBFE  PUSH    ESI
0137:0076BBFF  LEA     EDX,[ESP+2C]
0137:0076BC03  PUSH    EDI
0137:0076BC04  PUSH    EDX
0137:0076BC05  CALL    EBP
0137:0076BC07  TEST    EAX,EAX   <- checking routine if really okay button                     
0137:0076BC09  JZ      0076BCCF  <- if not real, jump and do funny stuff                    
0137:0076BC0F  MOV     EAX,[00930B24]<- OK-button pressed flag in eax
0137:0076BC14  TEST    EAX,EAX
0137:0076BC16  JZ      0076BCA7      <- If OK-button pressed, don't jump 
0137:0076BC1C  MOV     ESI,[00930B2C]
0137:0076BC22  CALL    008334B0
0137:0076BC27  MOV     EDI,[EAX+04]
0137:0076BC2A  TEST    ESI,ESI
0137:0076BC2C  JZ      0076BCA7      <- don't jump
0137:0076BC2E  MOV     EAX,[ESI+20]
0137:0076BC31  PUSH    EAX
0137:0076BC32  CALL    [USER32!GetParent]
0137:0076BC38  PUSH    EAX
0137:0076BC39  CALL    008334EC
0137:0076BC3E  PUSH    00
0137:0076BC40  PUSH    00020000
0137:0076BC45  PUSH    00
0137:0076BC47  MOV     ECX,EAX
0137:0076BC49  CALL    00833F9C
0137:0076BC4E  MOV     EAX,[00930B24] <-move OK-button-pressed in mem location
0137:0076BC53  TEST    EAX,EAX        
0137:0076BC55  JNZ     0076BC5E       <- jump if ok pressed
0137:0076BC57  MOV     EDX,[EDI]
0137:0076BC59  MOV     ECX,EDI
0137:0076BC5B  CALL    [EDX+70]
0137:0076BC5E  MOV     EAX,[ESI]
0137:0076BC60  MOV     ECX,ESI
0137:0076BC62  CALL    [EAX+60]
0137:0076BC65  CALL    00833888
0137:0076BC6A  TEST    EAX,EAX
0137:0076BC6C  JZ      0076BC77       <- don't jump
0137:0076BC6E  MOV     EDX,[EAX]
0137:0076BC70  MOV     ECX,EAX
0137:0076BC72  CALL    [EDX+7C]
0137:0076BC75  JMP     0076BC79
0137:0076BC77  XOR     EAX,EAX
0137:0076BC79  MOV     EAX,[EAX+20]
0137:0076BC7C  PUSH    EAX
0137:0076BC7D  CALL    [USER32!UpdateWindow] <- delete the nag!!
0137:0076BC83  MOV     ECX,EDI
0137:0076BC85  CALL    0040FBFA
0137:0076BC8A  CALL    [KERNEL32!GetTickCount]
0137:0076BC90  MOV     ECX,[00930B18]
0137:0076BC96  ADD     ECX,00001194
0137:0076BC9C  CMP     EAX,ECX
0137:0076BC9E  JAE     0076BCA7
0137:0076BCA0  MOV     ECX,EDI
0137:0076BCA2  CALL    00402A9F
0137:0076BCA7  LEA     ECX,[ESP+0C]
0137:0076BCAB  MOV     DWORD PTR [ESP+40],FFFFFFFF
0137:0076BCB3  CALL    00833402
0137:0076BCB8  MOV     EAX,00000001
0137:0076BCBD  MOV     ECX,[ESP+38]
0137:0076BCC1  MOV     FS:[00000000],ECX
0137:0076BCC8  POP     EDI
0137:0076BCC9  POP     ESI
0137:0076BCCA  POP     EBP
0137:0076BCCB  ADD     ESP,38
0137:0076BCCE  RET
0137:0076BCCF  LEA     ECX,[ESP+0C]
0137:0076BCD3  MOV     DWORD PTR [ESP+40],FFFFFFFF
0137:0076BCDB  CALL    00833402
0137:0076BCE0  MOV     ECX,[ESP+38]
0137:0076BCE4  POP     EDI
0137:0076BCE5  POP     ESI
0137:0076BCE6  XOR     EAX,EAX
0137:0076BCE8  MOV     FS:[00000000],ECX
0137:0076BCEF  POP     EBP
0137:0076BCF0  ADD     ESP,38
0137:0076BCF3  RET

End partial code

Woehoew! Lots of instructions man. I suggest you trace them 10 times with SoftICE and try to understand what the instructions do (even I don't understand 'em all). After quite some time I finally managed to get the nag away without PSP giving errors:

1. NOP out the :0076BAF1 JNZ 0076BCCF
2. change following instructions:
0137:0076BC07 TEST EAX,EAX
0137:0076BC09 JZ 0076BCCF
0137:0076BC0F MOV EAX,[00930B24]
into:
0137:0076BC07 MOV EAX, 00000001
0137:0076BC0C MOV [00930B24], EAX
0137:0076BC11 NOP
0137:0076BC12 NOP
0137:0076BC13 NOP

What does this do? It equals EAX to 1. Then it moves 1 into memory location 00930B24 which is needed to make the program believe the okay button is pressed and that it can remove the nagscreen. How can you know? By experimenting. That's my only advice! Trace through the code and try to understand. If you have enough cracking feeling or knowledge this should be no problem.

IV. In the end

Another essay finished :-) Hope (again) that you enjoyed it.
Hmmmm, who should I greet? Heh, well.....greets to all crackers reading this and to all crackers on #cracking4newbies.

Greets

BlackB

Endnote:
Essay written by The Blackbird © 1999-2000
This essay can be freely distributed/ published/ printed etc... as long as no modifications are made.