Paint Shop Pro 4.14

Protection: Nagscreen and timelimits
By Indian_trail


In this lessonwe will remove the nagscreen of pain(t)shop pro (PSP) we have in previous essay's used nagscreens to locate parts of the protection scheme in ie a serialnumber check. I'm not as pedagocial as usual in this essay because my readers have reached a somewhat "higher" level in cracking. I don't to tell you step by step how to do different things, cause I don't wanna nag to much about the same old procedures in cracking. If I say stepover or execuet I mean pressing F11 inside Softice. If you are a beginner and you don't understand or you don't land inside the part of code I've landed in, don't despair. It takes time to get the hang of it, besides the other lessons I have online will deal with this more specifically than this essay. At the end of this month I'll publish an essay about general approaches and common misstakes and so on. If any reader of this would like to share his/hers misstakes please email me and explain what misstake you made and how you figured out what you were doing wrong. Email me your misstakes I assume the reader has common experience in dissassembling with win32dasm, if not read some essays at fravias site. Ok on with the show

This program is quite interesting cause it offers three levels of protection, don't ask me why but it does. On startup there is an ugly nagscreen informing you that PSP is shareware and that you are allowed to evaluate it for 30 days, after that you may continue to use it for another 30 days until the locking mechanism snaps. So this obviously means 2 different time checking.

  1. Is it passed 30 days from installation. If so inform user that he has only 30 more days to use it...
  2. Has 60 days passed? If so inform user that he/she has to purchase PSP if he/she wants to continue using it. lock up PSP and exit.

The only reason for this is that they want to show two messages to the user to make the user feel that the programmers are nice guys. I'm however are less interested in their preaching about shareware, also I'm not fond of nagscreens so I naturally want to remove the whole crap. Considering that the programmers have made three level of checking for us, it'd be a pity to waste 'em. So lets crack all of these levels.

The only thing interesting with PSP is the heavily use of Microsofts foundation classes, in this case MFC42.dll. It seems that the programmers has joined the FDG (fucking decadent generation) cause they do not care about learning how to program a computer, no sirs, they are constantly looking for short cuts that will enable them to make more money faster than the speed of light. This is truly sad, because their programs becomes bigger and slower. Programming is no longer an art, it's a business.

Languages like Visual C++, Delphy and (oh dear) Visual Basic are the root of all evil on the software scene. Thanks to them a normal game that would/could be as small as 7*1.44Mb are today 100*.144MB. That is obviously a problem for a modem user on 33K6 /55K6, cause you'll grow old before the download is completed, and it costs alot to download too. So we are in a software declining decade, sad but true. One person who fully enjoys this is Bill Gates who's company is releasing new compilers and new libraries to make programming even easier and SLOWER wich results in largers files. In PSP you'll see alot of references to MFC42.dll and of course they lack sensable names. So dear boyz and girls of tomorrow, please stay away from these languages and instead take pride in programming in real languages wich produce effient code, so the art can survive.

Lets start with dissassembling PSP and look inside the string references for "your 30 day...". You'll find the following snippet of code:

:00406C5A push 004BD2E8
:00406C5F lea ecx, dword ptr [ebp-10]
:00406C62 cmp edi, 0000001E		if edi > 30
:00406C65 jge 00406C8E			jmp to you have exeeded..
* Reference To: MFC42.MFC42:NoName0650, Ord:035Ch			
                                  |
:00406C67 Call 004A7336

* Possible StringData Ref from Data Obj ->"You may use it for 30 days. If "
                                        ->"after your 30 day evaluation"
                                  |
:00406C6C push 004BD2A8
:00406C71 lea ecx, dword ptr [ebp-10]
If edi was greater than 30 we'll get here:
:00406C8E E8A3060A00              Call 004A7336

* Possible StringData Ref from Data Obj ->"You have exceeded your 30 day "
                                        ->"trial period. This program"
                                  |
:00406C93 6850D34B00              push 004BD350
:00406C98 8D4DF0                  lea ecx, dword ptr [ebp-10]

Look at that, " MFC42.MFC42:NoName0650, Ord:035Ch " whatta hell does NoName0650 in MFC do? Lucky us we don't YET need to care much about it, but I guess that these functions will be more and more common in protection schemes and therefore it would be interesting to know what they do. If only microsoft had given these functions more sensable names...Anyway like I said in this scheme they don't play a great role, but we still have to trace the damn MFC42.dll file.

Right now you may be dying to try to reverse that jump "jge 00406C8E" into a "jb 00406C8E", go ahead and try it. So set your system date 1 year forward (to make the > 60days snap) and shoot.

As you just experienced it didn't work. That means there's a mirror check let's find it quickly. We can find it by tracing or we can scan the deadlisting for , 0000001E. (1E=30). If we search in the deadlisting we'll find 9 occurences. I've listed them below:

:00406C62 83FF1E                  cmp edi, 0000001E		The first we found
:00406CE7 83FF1E                  cmp edi, 0000001E		Interesting
:0041BDAC 83F81E                  cmp eax, 0000001E
:00429B2A 6A1E                    push 0000001E
:00439DD5 C745FC1E000000          mov [ebp-04], 0000001E
:0044E59E 6A1E                    push 0000001E
:0046A9A7 6A1E                    push 0000001E
:004996C4 C78424DC0100001E000000  mov dword ptr [esp+000001DC], 0000001E
:004A0711 6A1E                    push 0000001E

As you see only three of them are comparing a value with 30 (1Eh). And the second is quite close to the first. Lets trace the code to see if the second one is the trigger. I only showed you the above list cause should we have failed the tracing approach we could have bpx:ed the adresses of the above cmp's. We still can but it will be faster to trace in this case. Alright start anew and prepare to trace after reversing the first jmp, I used nop's (no operations). We also need to find the compare that checks if more than 60 days has passed. 60 is 3Ch, we are looking for a cmp edi,3c, remember that the number of days passed is in edi and will most likely stay in edi. You don't need to trace long before you'll see:

:00406D31 E81C050A00              Call 004A7252
:00406D36 83FF3C                  cmp edi, 0000003C
:00406D39 7E5C                    jle 00406D97

And there you have it. If you reverse these three jumps you'll get PSP to start nomatter how many days that has passed. This is however not a satisfactory solution. It is better in this case to make sure that edi is always 01 for example, that way you'll always be on day 1 of your trial. Lets dig a little deeper to find where edi gets it's value. To do that we will first look inside the routine where the first compare is made. So from :00406C62 scan up (ctrl-uparrow) and see if you find a place where edi is given a value.



And you'll find:
:00406B72 8D7801                  lea edi, dword ptr [eax+01]
:00406B75 83FF01                  cmp edi, 00000001
:00406B78 7D05                    jge 00406B7F	
:00406B7A BF3D000000              mov edi, 0000003D
Ah if edi is set to zero edi will be set to 60, this means that the lowest value edi can have is 01. So change the above routine to:
:00406B72 8D7801                  MOV EDI,01
:00406B75 83FF01                  Nop
:00406B78 7D05                    jmp 00406B7F	
:00406B7A BF3D000000              mov edi, 0000003D
And you have cracked it in a more elegant way :) You'll always be on day 1 of your trial version.

The above approaches is what every newbie should be familiar with (newbie is not the same as beginners in this case), it's not a tough protection, it has alot of weak spots. We will now remove the whole nagscreen. We don't like nagscreens begging us to pay for their software.

To find the entry point of the nag we must first consider what kind of nag screen this is. It's clearly not a messagebox nor a dialog box. That makes it a resource ie a bitmap. You can try to bpx on messageboxA or dialogbox and softice will not break. So let's try a bpx on loadbitmapA. Softice will break inside LoadbitmapA so step out of it (F11) and look at the stack. There's only two PSP references and they are both at the bottom (since they were the last adresses pushed on the "Call stack").

PSP!.text+0029F15 at 0137:0042AF15
PSP!.text+5546 at 0137:406546


Lets look what that code looks like:
U 42af15


:0042AF10 E83BB5FDFF call 00406450
:0042AF15 83C404 add esp, 00000004


Put a breakpoint on 0137:0042AF10. Notice that there is no nag until you execute this call at 42AF10. So that means that we have found the nag caller. Now what. Lets nop the bastard out. Five nop's instead of call 00406450.

Sad but true, you can see the screen for a second and then it exits. Leaving us to our desktop. Hmmn What now? We need to find what went wrong (no kidding) to do that we trace the code until we find something useful. It's now time for you to experience the fat overbloated MFC42.DLL. Nop the call out and continue tracing.

From 42AF10:
You'll return to 5F4018C6 in MFC42.dll
After tracing that for some time you'll get to Kernel!_FREQASM. Keep on and you'll get to Kernel, user and FINALLY back to PSP at adress 4363XX. In this procedure there is some calls that sets up PSP's screen. At 4364CD there is a call to "updatewindow". You better place a breakpoint on 4364CD or any nearby adress so you don't have to trace on next time. Anyway executing Updatewindow and you'll see PSP's screen.
Here is the path we take:

:004364CD FF1560324C00 Call dword ptr [004C3260]


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0043648E(C)
|

:004364D3 8B4DE8                  mov ecx, dword ptr [ebp-18]
:004364D6 E8754AFFFF call 0042AF50
:004364DB 85C0 test eax, eax
:004364DD 7576 jne 00436555 we have eax=0
:004364DF C645FC00 mov [ebp-04], 00
:004364E3 E83B020000 call 00436723
:004364E8 E99AFAFFFF jmp 00435F87 therefore we jump here


We have 0 in eax and therefore we will jump at :004364E8 to 435F87 and we will then end up at :

:00435F87 C745FCFFFFFFFF          mov [ebp-04], FFFFFFFF
:00435F8E E8AA070000 call 0043673D
:00435F93 33C0 xor eax, eax
:00435F95 8B4DF4 mov ecx, dword ptr [ebp-0C]
:00435F98 5F pop edi
:00435F99 64890D00000000 mov dword ptr fs:[00000000], ecx
:00435FA0 5E pop esi
:00435FA1 5B pop ebx
:00435FA2 8BE5 mov esp, ebp
:00435FA4 5D pop ebp
:00435FA5 C3 ret


The ret will take us to a nasty place in MFC42.dll

:5F407EAB 85C0                    test eax, eax
:5F407EAD 7415 je 5F407EC4
:5F407EAF 8B06 mov eax, dword ptr [esi]
:5F407EB1 8BCE mov ecx, esi
:5F407EB3 FF505C call [eax+5C]
:5F407EB6 8BF8 mov edi, eax
:5F407EB8 E81D990000 call 5F4117DA
:5F407EBD 8BC7 mov eax, edi
:5F407EBF 5F pop edi
:5F407EC0 5E pop esi
:5F407EC1 C21000 ret 0010


AND WE'LL CONTINUE


:5F407EC4 8B4E20 mov ecx, dword ptr [esi+20]
:5F407EC7 85C9 test ecx, ecx
:5F407EC9 0F8575440100 jne 5F41C344 Here we jump


:5F41C344 8B01 mov eax, dword ptr [ecx]
:5F41C346 FF5060 call [eax+60]
:5F41C349 E981BBFEFF jmp 5F407ECF
:5F407ECF 8B06 mov eax, dword ptr [esi]
:5F407ED1 8BCE mov ecx, esi
:5F407ED3 FF5070 call [eax+70] killer!!!!
:5F407ED6 EBDE jmp 5F407EB6


The call to [eax+70] kills the window, how rude of them to exit before we even had the chance to draw a single pixel.


You, dear reader have of course already spotted the jump that needs to be changed and you may be wondering why I included all this MFC code. However there's a reason why I'm showing you all this code of MFC42.dll and that's because there is a good chance that you'll miss the *important* code among the overbloated MFC dlls. And if you do so you'll end up patching the MFC42 code instead of your targets call.

Where where where is the important code, well if you change al from 0 to 1 at :004364DB 85C0 test eax, eax The whole bazar will start. But as I said before should you miss this spot you'll end up changing:

:5F407EAB 85C0 test eax, eax
:5F407EAD 7415 je 5F407EC4
Inside MFC42.dll wich IS NOT a good idea, since other programs may use this particular function.



This will be the last essay on selfexpainary cracks. I want to move on to more complex cracks. What I mean by that is that only protections that donot use the common API calls will be written down and that goes for any contributor too. I'm well aware of the prideness one feel when one has succeed in cracking by oneself for the first time, but there's too many essay's on the web explaining the same sort of protections. What I wont to cover is:




They don't have to be tough or hard to crack, the important thing is that they offer some new schemes like this PSP essay who deals with a nagscreen that is a bitmaps.

/Indian_Trail


(Saddle all the horses far on the indian trail, 'til it's time to change key and jump into a different scale)