This is not cracking, it's just simple reversing or modifying an
application, you know those programs where you wait five minutes for
it to kill it's "splash" screen (or "company logo"), or when you have
to click it to get rid of it. The one in this essay is a nag, it's
Paint Shop Pro's.
When your confronted with a nag, you don't really have to crack it,
sometimes it can be too much trouble to crack the nag out of an application,
it could be hard work, but I'm sure if your really capable--you'll do it!
You see if we make the nag, stop nagging, as long as it doesn't bother
you, you'll be able to "evaluate" the application properly. Oh yeah, a
nag that doesn't nag isn't a nag, right? :-). Also I think it's stupid
to nag your potential buyers, you'll put 'em off, so 'stop nagging me will
ya!' and protect you apps or disable some stuff (that's fun to crack ;-).
I'm using Win98, version 6.01 of PSP, psp.exe with a huge size of
7782400 bytes!
If you use the "Evaluation Version" of PSP then you have certainly
noticed the nag screen that presents itself at startup. This nag is
comprised of a huge bitmap (or a couple, who cares?), a little text
(including the "Evaluation" text and notice), and two buttons. You
can't immediately kill the nag by clicking the 'Ok' button, OH! NO! to
piss you off even more the coders decided to rub a little salt on
the wounds that the nag created and add a timer that lets you click
the nag away after a specified amount of time. If you examine the
window procedure of the nag you'll notice that, if you click the nag,
it first checks where you clicked by obtaining the co-ords of the
mouse (uses GetCursorPos, then PtInRect if you clicked in the correct
places -a button- it then continues), then it sees whether the click
is allowed, if so it kills the nag for you. Oh yeah, it's written in
M$ Vi$ual C++, you'll land in the libraries quite a lot, which is to
be expected for this type of application (given the size and speed
'n' all).
I could now go on explaining what I found, taking this approach -the
window procedure one- but after a while I decided to take a different
approach, because removing the nag would be nice but it isn't really
necessary.
So, the approach, well when d'you think would be the right.time and
place to fix this nag, of course, your thinking when it's created and
your right. Firstly we'll have to find where the nag is created and
then we can worry about what to do.
When you launch PSP -after a while of loading- you see the nag screen,
you see it but you don't see anything else around do you. What this
tells us is that the nag is created before the main GUI is loaded (or
updated). Where can we go from here? We certainly should think how
this nag is shown to us. Well the program obviously uses the API
UpdateWindow to "update" the nag to the screen, so our next port of
call is to investigate the area of code that shows us the nag, so
'bpx updatewindow do "p ret;rs"' in SoftICE until you see the nag on
the screen and, you'll be here:
loc_76B84A: ; CODE XREF: .text:0076B82Fj mov eax, dword_930B2C mov ecx, [eax+20h] push ecx ; hNag call ds:UpdateWindow ; UpdateWindow: <--- HERE YOU GO! loc_76B859: ; CODE XREF: .text:0076B848j push edi push edi push 20000h ; Style (WS_MINIMIZEBOX) mov ecx, esi call j_MFC42_4284 ; ?ModifyStyle@CWnd@@QAEHKKI@Z: push offset str5000 ; "5000" call ebx ; atoi -> ASCII to INT mov ecx, dword_930B2C add esp, 4 mov edx, [ecx+20h] push edi push eax push 7 push edx ; hNag call ds:SetTimer ; SetTimer, set the button timer mov ecx, dword_930B2C mov [ecx+74h], eax call ds:GetTickCount ; GetTickCount mov ecx, [esp+10h] pop esi mov dword_930B20, eax pop ebx mov eax, 1 pop edi mov large fs:0, ecx add esp, 10h retnThis is from IDA of course. IDA helps us (a lot!) because if you look at the 'call j_MFC42_4284' you'll see it's a call to 'ModifyStyle'. (By the way, I didn't disassemble PSP straight away, with IDA or anything, but I noticed that WS_MINIMIZEBOX was being pushed (20000h, from coding and stuff), I changed it to null and it worked so I had to have a look, I couldn't help myself :)
0076B859 57 PUSH EDI 0076B85A 57 PUSH EDI 0076B85B 6800000200 PUSH 00020000 ; WS_MINIMIZEBOX 0076B860 8BCE MOV ECX,ESI 0076B862 E835870C00 CALL 00833F9C ; ModifyStyleswitches to this
0076B859 57 PUSH EDI 0076B85A 57 PUSH EDI 0076B85B 6800000000 PUSH 00000000 ; NOTHING! 0076B860 8BCE MOV ECX,ESI 0076B862 E835870C00 CALL 00833F9C ; ModifyStyleYou could also change it to 6A00909090 (push 0, nop, nop, nop--because the stack is aligned to a dword boundary in 32 bits).
0076B8A5 64890D00000000 MOV FS:[00000000],ECX 0076B8AC 83C410 ADD ESP,10 0076B8AF C3 RETbecomes
0076B8A5 64890D00000000 MOV FS:[00000000],ECX 0076B8AC A12C0B9300 MOV EAX,[00930B2C] 0076B8B1 8B4820 MOV ECX,[EAX+20] ; Get hNag 0076B8B4 6A00 PUSH 00 0076B8B6 6A00 PUSH 00 0076B8B8 6A10 PUSH 10 ; WM_CLOSE 0076B8BA 51 PUSH ECX ; hNag 0076B8BB FF1590B59800 CALL [USER32!SendMessageA] ; Kill the nag 0076B8C1 83C410 ADD ESP,10 0076B8C4 B801000000 MOV EAX,00000001 ; Just to be safe 0076B8C9 C3 RETYou'll need to set a breakpoint on SendMessageA to check how it's called inside PSP, because if you assemble this in SoftICE you'll be calling straight to User32 and not through the import table, it'll be Ok on your PC if you don't but may not work on others, which probably won't bother you. The WM_CLOSE message is used because that's the one that didn't make PSP scream like a baby.
loc_76BF17: ; CODE XREF: .text:0076BF12j push 0 push 0 push eax push edx ; height push ecx ; width push 0 push 0 push 90000000h push 0 push 0 push 0 push 0 push 0 call j_MFC42_1233 ; ?AfxRegisterWndClass@@YGPBDIPAUHICON__@@PAUHBRUSH__@@0@Z: push eax push 0 mov ecx, ebx call j_MFC42_2152 ; ?CreateEx@CWnd@@QAEHKPBD0KHHHHPAUHWND__@@PAUHMENU__@@PAX@Z: pop edi pop esi pop ebx pop ecx retn 4Here we go then, this is where the nag is created. The only two args I've outlined are the height and width (the rest are hInst, Style and mostly nulls) which is all we need, we'll change the height and width to 1x1 so you'll only see 1 pixel in the center of the screen.
0076BF17 6A00 PUSH 00 0076BF19 6A00 PUSH 00 0076BF1B 50 PUSH EAX 0076BF1C 52 PUSH EDX ; height 0076BF1D 51 PUSH ECX ; widthto this
0076BF17 6A00 PUSH 00 0076BF19 6A00 PUSH 00 0076BF1B 50 PUSH EAX 0076BF1C EB42 JMP 0076BF60; jump to fixand don't forget to put this little piece in place
0076BF5C C20400 RET 0004 0076BF5F 90 NOP 0076BF60 6A01 PUSH 01 ; height (1 pixel) 0076BF62 6A01 PUSH 01 ; width (1 pixel) 0076BF64 EBB8 JMP 0076BF1E; jump back 0076BF66 CC INT 3 ; <-FillerNow, run PSP and see what happens. Yeah, the nag's hardly visible. I think we can finish now, but I know that some of you may be wondering why we kill the nag even though it's only 1 pixel in size now, well it's taking up memory and it could get in the way of things, that's it really. I think the WM_CLOSE message worked here because the nag didn't process the WM_CLOSE message, this results in it sending the message to DefWindowProc which in turn uses the DestroyWindow API to kill the nag. So this message is pretty useful if your app doesn't process it.
There's a problem (big problem) with nags that are totally
integrated with the 'real' code, it's a bitch getting rid of them.
Just examining the surrounding code isn't enough when your in this
situation, but remember kids "a nag that doesn't nag isn't a nag"
and you can do this with any sort of window--modify it to suit your
own needs!
So your all going to modify all those "startup", "splash", "nag" or
whatever screens that you were once forced to see everytime you
started an application now, aren't you?
Reed