(Hic sunt tabulae: Best viewed with good old Courier 10) In this lesson I'll teach you another cracking technique known as "dead listing" approach, in opposition to the "live" cracking (through Softice/Winice) that we have used (and we'll use) most of the time. Since this approach requires a good Hexeditor and a good disassembler (and a good Wordprocessor), it suits us well to begin the 'hands on' part cracking what we need: a good Hexeditor. I'll crack here the nagscreens out of Hexworkshop, Version 2.10 (32 bit version). A good and relatively quick (for Windoze's standards) application by Breakpoint software. Many among you will already have this hexeditor inside their Software collection, if not find it on the Web through an Archie search and download it through ftpmail... searching through the archies will give you something like this: Host ftp.loria.fr (152.81.10.10) Last updated 11:25 23 Oct 1996 Location: /pub1/pc/win95/programr FILE -r--r--r-- 707906 bytes 02:00 13 Aug 1995 hworks32.zip The exact NAME of this hexediting program is HWORKS32.EXE, it is 524288 bytes LONG, and its DATED 2 February 1996. This program has many little nag annoyances: - shows a nagscreen reminding you how many days you have used the program; - keeps a nag_string "unregistered version" on the main screen of the program; - has, inside help, a "registration serial number form"... this is the number you could get registering... and should digit inside the HELP/ABOUT HEX WORKSHOP window form. Elsewhere in this tutorial we have already learned how to defeat this type of protection: through Winice breakpoints. Basically we would type a fake registration number (say '121212121212') and then look for the occurrences of our string in memory, and then search and investigate the manipulations undertaken by the protection scheme. In this way we would finally be able to crack the nagscreen procedure. Fine, fine... this would indeed work, but I want to teach you through this lesson ANOTHER, completely different approach to cracking, which is and will be especially useful for 'nagscreen' and 'time-limit' cracking... i.e. the "dead listing" approach. This approach is a much more "relaxed" sort of crack, which will work flawlessly most of the time. This approach is particularly easy with Windows programs, since -as I have already told you a hundred times- the modularity of this overbloated atrocity makes it particularly easy for us little crackers to track back the -mostly primitive- protection methods utilized by the commercial programmers. I remember older times, when programming was still an art for intelligent (not mercantile) beings, cracking the old (and sometime beautifully crafted) Z-80, CP/M and DOS programs. In those time 'a byte was a byte'! And good programmers found funny tricks in order to write 'tight' code. We old crackers used the 'dead listing' approach sitting (or snoozing) in pleasant (albeit a little battered) armchairs, inside a huge university library, drinking very good Martini Wodka (you would be well advised to use only Moskowskaja, coz non Russian Wodkas are repugnant). Four of us at a time, each one just looking at his paper listings. You cannot imagine how many little (unrelated) tricks we found inside the code cracking in that way! A hacker, a cracker (me), a 'real' programmer and an encryption specialist, all four sitting in the same room, exchanging pretty clever findings and sipping (much too many) good cocktails... it's long ago, those times (and societies) are gone for ever! Microsoft's abomination has unfortunately created this overbloated world of huge 'programs' which perform more slowly (and much more awkwardly) what the old programs did quickly and flawlessly. You don't believe me? Why don't you just install Linux on your harddisk and see for yourself the difference between a good OS and Windoze? Just try it... you'll be amazed and you'll never go back... well, you'll actually do... only in order to crack the hell out of Windows: We'll never damage enough Microsoft's interests to compensate for this moronic situation: millions of stupid users have to wait hours (and this with microprocessors that are 1000 times quicker than the old 8086) to perform with MS_Word -slowly- what they could have done immediately with an old copy of Wordperfect for Dos. Anyway, the huge dimension of all Windows' programs forces us to abandon the printed "dead listing" approach... printing in extenso the listing of a Windows program would consume a couple of ink cartridges and could easily take ages... therefore we can indeed still crack with the "dead listing" method, and we can indeed still drink our Martinis (and we do, Oh Yessir), but we must keep the overbloated listings off page, on our PC, printing only the small part of them that are relevant to our crack. As I said at the beginning, for this art of cracking you'll need basically only two programs (and you will NOT need Softice/Winice). 1) A disassembler like W32DASM (or another good one) in order to find the protection scheme. You will probably already possess it (else how did you crack until now?)... if not find the last version on the Web -through an Archie search- and download it -through ftpmail-, Searching the archies will give you something like this: Host ftp.funet.fi (128.214.248.6) Last updated 07:57 1 Jan 1997 Location: /pub/mirrors/ftp.cdrom.com/pub/simtelnet/win3/prog FILE -rwxrwxr-x 650327 bytes 23:25 28 Oct 1996 w32dasm6.zip 2) An hexeditor (Use Hexworkshop version 2.10 itself, since we are already cracking it :=) in order to defeat the protection scheme as soon as you have found it. OK, enough, let's crack. Here is how the "dead listing" approach works: 1) Run the program you want to crack, in this case Hexworkshop, look at all the nag_strings and write them down (I mean snap them down -automatically- from screen... see elsewhere in my tutorial how to get and crack snap32); 2) Wdasm the file (that means: 'open' it inside the disassembler in order to get the listing). 3) Transfer the listing to your favorite wordprocessor (we will not need Wdasm any more, bye) 4) Search (Find) inside your wordprocessor the nag_references, say, in our case, the string "unregistered version" You'll immediately land inside following piece of code: :MAIN_NAG_ROUTINE :00415732 CC int 03 :00415733 CC int 03 :00415734 CC int 03 :00415735 CC int 03 :00415736 CC int 03 :00415737 CC int 03 :00415738 CC int 03 :00415739 CC int 03 :0041573A CC int 03 :0041573B CC int 03 :0041573C CC int 03 :0041573D CC int 03 :0041573E CC int 03 :0041573F CC int 03 :00415740 55 push ebp :00415741 8BEC mov ebp, esp :00415743 6AFF push FFFFFFFF :00415745 6873584100 push 00415873 :0041574A 64A100000000 mov eax, fs:[00000000] :00415750 50 push eax :00415751 64892500000000 mov fs:[00000000], esp :00415758 81EC0C020000 sub esp, 0000020C :0041575E 53 push ebx :0041575F 56 push esi :00415760 57 push edi :00415761 898DE8FDFFFF mov [ebp-00000218], ecx :00415767 8B450C mov eax, [ebp+0C] :0041576A 50 push eax :0041576B 6A73 push 00000073 :0041576D 8B8DE8FDFFFF mov ecx, [ebp-00000218] :00415773 E87EFC0100 call 004353F6 :00415778 C745FC00000000 mov [ebp-04], 00000000 :0041577F 8B8DE8FDFFFF mov ecx, [ebp-00000218] :00415785 83C144 add ecx, 00000044 :00415788 E84EF40100 call 00434BDB :0041578D C645FC01 mov [ebp-04], 01 :00415791 8B85E8FDFFFF mov eax, [ebp-00000218] :00415797 C70028AE4500 mov dword ptr [eax], 0045AE28 *StringData Ref from Data Obj->"An unregistered version of Hex" ->"Workshop has been on" | :0041579D 68085B4600 push 00465B08 :004157A2 8D85F4FDFFFF lea eax, [ebp-0000020C] Good, we immediately see that the above routine starts at instruction :00415740 55 push ebp Therefore now we'll search our listing for following string: call 00415740 (that is: who calls here?). The reason we must search for the caller is very simple: there is no conditional jump inside the piece of code above... and therefore it'll very unlikely hide a protection and/or a check time or nag routine. If we do perform our search for the caller we'll immediately land inside following routine: : CALL_NAG_ROUTINE :00415DAC 55 push ebp ;pusha lotta values :00415DAD 8BEC mov ebp, esp :00415DAF 6AFF push FFFFFFFF :00415DB1 68045E4100 push 00415E04 :00415DB6 64A100000000 mov eax, fs:[00000000] :00415DBC 50 push eax :00415DBD 64892500000000 mov fs:[00000000], esp :00415DC4 83EC54 sub esp, 00000054 :00415DC7 53 push ebx :00415DC8 56 push esi :00415DC9 57 push edi :00415DCA 894DA0 mov [ebp-60], ecx :00415DCD 6A00 push 00000000 :00415DCF 8B4508 mov eax, [ebp+08] :00415DD2 50 push eax :00415DD3 8D4DA4 lea ecx, [ebp-5C] ;for the call :00415DD6 E865F9FFFF call 00415740 ;*** HERE !!! *** :00415DDB C745FC00000000 mov [ebp-04], 00000000 :00415DE2 8D4DA4 lea ecx, [ebp-5C] :00415DE5 E804F70100 call 004354EE :00415DEA C745FCFFFFFFFF mov [ebp-04], FFFFFFFF :00415DF1 E805000000 call 00415DFB :00415DF6 E913000000 jmp 00415E0E :00415DFB 8D4DA4 lea ecx, [ebp-5C] :00415DFE E8FD000000 call 00415F00 :00415E03 C3 ret Good, OK. Now -once more- who calls this function? As -here too- we don't have any conditional jumps, we are compelled to look further inside the green branches of our code_tree. Let's go on: searching for call 00415DAC (the beginning of the above function) we will land inside following code: :WILL _I_CALL_THE_CALL_NAG_ROUTINE_? :0040254C 6808414500 push 00454108 :00402551 8D8568FEFFFF lea eax, [ebp-198] :00402557 50 push eax :00402558 E893460200 call 00426BF0 :0040255D 83C408 add esp, 8 :00402560 0FBF0508414500 movsx word ptr eax, [00454108] :00402567 85C0 test eax, eax :00402569 0F8586000000 jne 004025F5 ;jump 1 over CALL_NAG :0040256F 8B8D40FEFFFF mov ecx, [ebp-1C0] :00402575 E8D3350100 call 00415B4D :0040257A 85C0 test eax, eax :0040257C 0F841B000000 je 0040259D :00402582 8B8D40FEFFFF mov ecx, [ebp-1C0] :00402588 E866360100 call 00415BF3 :0040258D 8B8D40FEFFFF mov ecx, [ebp-1C0] :00402593 E8DF360100 call 00415C77 :00402598 E953000000 jmp 004025F0 ;jump 2 over CALL_NAG :0040259D 8B8D40FEFFFF mov ecx, [ebp-1C0] :004025A3 E83D370100 call 00415CE5 ;(month year routine) :004025A8 898570FFFFFF mov [ebp-90], eax :004025AE 83BD70FFFFFF00 cmp dword ptr [ebp-90], 0 :004025B5 0F8417000000 je 004025D2 ;jump 3 over CALL_NAG :004025BB 8B8570FFFFFF mov eax, [ebp-90] :004025C1 50 push eax :004025C2 8B8D40FEFFFF mov ecx, [ebp-1C0] :004025C8 E8DF370100 call 00415DAC ;HERE! CALL_NAG! * :004025CD E91E000000 jmp 004025F0 :004025D2 8D8D7CFFFFFF lea ecx, [ebp-84];jump 3 lands here :004025D8 E88C420200 call 00426869 :004025DD 85C0 test eax, eax :004025DF 0F840B000000 je 004025F0 :004025E5 8D8D7CFFFFFF lea ecx, [ebp-84] :004025EB E8FE2E0300 call 004354EE :004025F0 E91E000000 jmp 00402613 ;jump 2 lands here :004025F5 8D8D7CFFFFFF lea ecx, [ebp-84];jump 1 lands here :004025FB E869420200 call 00426869 Now have a good look at the code above: As you can see there are only three possible jumps which will NOT call the CALL_NAG routine. The one at :00402598 E953000000 jmp 004025F0 (Jump 2) is not conditional, and therefore very rarely used for nagscreens protections. Besides, it links to another unconditional jump and it's most probably a "Quick_out" way... let's eliminate it, at least for now. We remain with only two jumps over the NAG_SCREEN call routine: 00402569 0F8586000000 jne 004025F5 (jump 1) and 004025B5 0F8417000000 je 004025D2 (jump 3) You may investigate both of them, but, hey, you could eliminate one more jump, again, just using a little Zen code feeling): see how the jump condition for jump_3 is a base pointer value [ebp-90], while the one for jump_1 is a memory fixed location [00454108]... this sort of condition is usually a green light, for compiler reasons I'll not delve inside here. Therefore let's have a closer look at it and let's forget jump 3, at least for now. :JUMP_1_UNDER_THE_LUPE :0040254C 6808414500 push 00454108 ;values for :00402551 8D8568FEFFFF lea eax, [ebp-198] :00402557 50 push eax ;the following :00402558 E893460200 call 00426BF0 ;call :0040255D 83C408 add esp, 8 ;modify stack :00402560 0FBF0508414500 movsx word ptr eax, [00454108] ;HERE :00402567 85C0 test eax, eax ;conditional test :00402569 0F8586000000 jne 004025F5 ;jump over CALL_NAG What will then this mysterious [00454108] location be? Don't you feel it? It's the ACTIVATOR! The location with the flag, which sets the whole nag screen galore for Hexworkshop! Our cracking job is already finished! We don't need anything more: we don't need any fiddling with breakpoints, nor to examine hundreds of irrelevant calls... with Windows this kind of "dead listing" cracks works so smooth I could shriek! But, hey, OK, we will continue our snooping, for the sake of it and just in order to be completely sure... it's not necessary, but let's do it anyway... check a little more around... search, inside your huge listing, all the other occurrences of the same [00454108] location... you'll get no more than 5 hits. The most striking one from our cracking point of view being the following occurrence: :00402770 898574FFFFFF mov [ebp-8C], eax ;save old eax :00402776 0FBF0508414500 movsx word ptr eax, [00454108];FLAG* :0040277D 85C0 test eax, eax ;flag is zero? :0040277F 0F8528000000 jne 004027AD ;nope, so we won't :00402785 8B4DEC mov ecx, [ebp-14] :00402788 E883280000 call 00405010 ;call this, nor :0040278D 898574FFFFFF mov [ebp-8C], eax ;write * Possible StringData Ref from Data Obj ->"Unregistered Version" | :00402793 6854494600 push 00464954 ;on the screen :00402798 685C800000 push 0000805C ;& we'll jump over :0040279D 6800400000 push 00004000 ;these pushes :004027A2 8B8D74FFFFFF mov ecx, [ebp-8C] :004027A8 E823280000 call 00404FD0 ;and this call * Possible StringData Ref from Data Obj ->"ControlBars" | :004027AD 686C494600 push 0046496C ;directly here Well, yes, now it's more than enough, thanks... location [00454108] seems indeed to be the flag we are searching. Confirmed. Struck and sunk! Now let's quickly crack Hexworkshop: *** CRACK FOR HEXWORKSHOP VERSION 2.10 by +ORC (January 1997) ** Use hexworkshop itself (no more debug/symdeb, coz we are working with the overbloated Microsoft monstrosity) and search inside the code of the copy on your harddisk for the hex sequence: 08414500 that's the code for our flag_location, duh? ****(a short digression): BE CAREFUL SEARCHING FOR BYTES ***** Be careful with instructions you try to search for. You should only search for instructions that don't change the bytes they assemble to, depending on their location in memory. For example, searching for the following instructions presents no problem: PUSH DX POP [DI+4] ADD AX, 100 but searching for the following instructions CAN cause unpredictable results: JE 123 CALL MYFUNC LOOP 100 **** (end) ********************************* **** **** **** Searching for the byte sequence 08 41 45 00 you will obviously find the several occurrences of it we have seen before... you have to modify only one location though, the one followed by the two bytes 0F85... (jne after CALL_NAG) at the FIFTH (and sixth) position after the search string, because that's the location we are looking for. Once you found it, write over the byte 85 the byte 84 and now you'll have modified the jne in a (je after CALL_NAG). We'll now jump if equal (as all men should be, by the way)... Look!... no more nagscreens to annoy our proven aesthetic perception, no more silly protections to blemish our suave future hexediting around :=) I almost forgot... that's obviously not enough... you must as well modify the location at :0040277F :0040277F 0F8528000000 jne 004027AD ;jump over 'unregistered' to :0040277F 0F8428000000 je 004027AD ;jump equal! in order to have a well cracked copy of our target. [PSP 32] Can we apply this 'dead listing' approach to other programs? Can we use the same strategies for other protection schemes? Sure! Let's remain a little more inside the nagscreens protections. A logical step, after the invention of the nagscreen itself, has been the "mingling" of the nagscreen calling routine. In this kind of protection the nagscreen routines are 'amalgamated' with other routines, which cannot be skipped as they are essential for the working of the program. The main disadvantage of this approach, for the mercantile protectionists, is that they have therefore to prepare TWO different versions of their programs: a 'nagscreened' one and a 'clean' one, since else we would immediately be able to transform the crippled program in a fully functional one using the same approach they would use to 'uncripple' it. Such mingling is therefore only used by major programs which are well established on the market and can afford the 'doubled' approach. This is the case of the last versions of PaintShopPro (PSP). Even in this case, though, we can crack nice enough, as I will now demonstrate you with PaintShopPro version 3.2 (a 32 bit program for Windows 95). You will probably already possess it, if not find the last version on the Web -through an Archie search- and download it -through ftpmail-, Searching the archies will give you something like this: Host ftp.mds.mdh.se (130.238.252.239) Last updated 08:10 4 Dec 1996 Location: /pub/windows/win95/graphic_utils/paintshop FILE -rw-r--r-- 311542 bytes 15:11 27 Jul 1996 psp32bit.zip We have seen in the preceding lesson (-> lesson 9.2) how to disrupt, through the usual Winice 'live' approach, the PaintShopPro nagscreens for Windows 3.1., cracking the older versions of this program. Instead we will now try our 'dead listing' approach for PSP 32 and PSP Version 4.1 (both 32 bit programs). Let's fire PSP32 (I am using here the shareware version with a PSP.EXE of 1.042.944 bytes, dated 27 December 1995). Let's have a good look at the nagscreen (snapping it), OK, that's enough. Now load the target inside Wdasm32 (I am using here version 5 of Wdasm, you'll find cracked versions of it everywhere on the Web). As soon as you have the complete (huge) listing of PSP.EXE use the option "Save disassembly to text file"... you'll get a huge text file (with 12.590.025 bytes, gosh). Load it inside a (good and quick, i.e. not Microsoft's) Wordprocessor and let's first of all have a look at the code preceding and following our nagscreen (at this point -if you are not completely imbecile- you should already have grasped the foundation techniques of my "dead listing" cracking approach). You will see that in the code of PSP we have a lot of USER calls. Therefore we cannot use the same easy 'find the caller' approach used before (more about code mingling later). Have a look at the following piece of code (the Stringdata for the Shareware notice has landed us there) there is a GetDlgItem(), which is User32.EB and a EnableWindow(), which is User32.AB. GetDlgItem(), as you should know, returns the handle of the specified ID control (or zero if error). The ID number is the parameter passed, the returned value is the hdlg (handle of the dialog box of ID). :0041DB69 891D38A04B00 mov [004BA038], ebx ;ebx in here ** :0041DB6F 6A6C push 6C :0041DB71 881DF4134C00 mov [004C13F4], bl ;bl in here ** :0041DB77 56 push esi * Reference To: GetDlgItem, Ord:00EBh in USER32.dll | :0041DB78 FF154C5A4C00 call dword ptr [004C5A4C] ;callnag-1 :0041DB7E 50 push eax * Reference To: EnableWindow, Ord:00ABh in USER32.dll ;callnag-2 | :0041DB7F FF15DC594C00 call dword ptr [004C59DC] *StringData Ref from Data Obj->"Paint Shop Pro Shareware Notice" | :0041DB85 6820174C00 push 004C1720 :0041DB8A 56 push esi Now follow me closely: 1) Since the following code pushes two locations (one with bx and the other with bl) just before calling the GetDlgItem and EnableWindow routines for the "PaintShopPro Shareware Notice" Window... 2) ...we just need to search these locations ELSEWHERE, "around" the above section of the code. Let's do it... Searching the STRING "[004BA038]" we'll fetch inside our wordprocessed listing two more occurrences: Let's look at the first one: this piece of code compares to 1 our location just after enabling a Window: :REFERENCE_1_OF_OUR_[004BA038] * Reference To: EnableWindow, Ord:00ABh in USER32.dll | :0041DA41 FF15DC594C00 call dword ptr [004C59DC] :0041DA47 C605F4134C0002 mov byte ptr [004C13F4],2 :0041DA4E 833D38A04B0001 cmp dword ptr [004BA038],1 ;HERE!! ** :0041DA55 7510 jne 0041DA67 ;and the conditional jump! :0041DA57 6A00 push 00000000 ;If equal (Zero flag), :0041DA59 6A6C push 0000006C ;push these parameters :0041DA5B 6811010000 push 00000111 ;for the PostMessage :0041DA60 56 push esi ;function... * Reference To: PostMessageA, Ord:01A3h in USER32.dll | :0041DA61 FF155C594C00 call dword ptr [004C595C] ;...call) :0041DA67 B801000000 mov eax, 1 ;our jump here: flag=1 :0041DA6C E9EE030000 jmp 0041DE5F ;end of code snippet, this jumps to the "popping away" part of the code... :0041DE5F 5D pop ebp :0041DE60 5F pop edi :0041DE61 5E pop esi :0041DE62 5B pop ebx :0041DE63 81C434050000 add esp, 00000534 :0041DE69 C21000 ret 0010 AhHa! The value 111! (at :0041DA5B). You know what that means, don't you? For the newbyes among you that don't, learn it here (the others can skip): ************ THE 111 WM_COMMAND RELEVANCE, by +ORC ******** The function PostMessage() has following structure: PostMessage(HWND hWnd, UINT uMsg, WPARAM wMsgParam1, LPARAM lMsgParam2)Where hWnd is the receiving Window, UINT is TRUE or FALSE WPARAM is a 16 bit value and LPARAM a 32 bit one! Windows' applications use PostMessage() to deliver WM_Message requests... and parameter 111 is WM_COMMAND! Write it on your cracking notes and underline it! 1 is IDOK, 2 is IDCANCEL and 111 is WM_COMMAND. WM_COMMAND is extremely important for understanding the behaviour of the application you want to crack, because the handler for WM_COMMAND is where that application deals with user commands, such as menu selctions, dialog push button clicks, etcetera. In other words all what makes the 'guts' of an application. An application can tell wich command a user gives through the wParam parameter to the WM_COMMAND message. These values are (almost) always part of the application's menu resources, and it is easy to get the menu ID values through any utility for resources dumping. ************ (end) ************** OK, so the above listed piece of code has a jump over the PostMessage routine which (probably) disables the nag screen (6C is the same ID, for both pieces of code we have seen)...let's try a "weak" crack on it: ***** WEAK CRACK FOR PSP32, by +ORC, January 1997 ******** 1) Use Hexworks32 2) Load PSP.EXE 3) Search for the bytes sequences of the instructions :0041DA4E 833D38A04B0001 cmp dword ptr [004BA038],1 :0041DA55 7510 jne 0041DA67 which are followed by the pushes: :0041DA57 6A00 push 00000000 ;zero :0041DA59 6A6C push 0000006C ;ID :0041DA5B 6811010000 push 00000111 ;WM_COMMAND And as a quick crack (but there are more elegant ways) we can 4) substitute the byte '75' at :0041DA55 with a 74, transforming the jne in a je, as usual, inverting the jumps. Jump if equal! Since I have been (blandly) critized by fellow scholars for speaking all the time of more elegant ways and yet presenting only simple ways, here IS a more elegant crack for this code: 4) Substitute with a new ONE the first TWO instructions: :0041DA4E 66C70538A04B000100 mov word ptr [004BA038],1 and leave all the rest unchanged: :0041DA57 6A00 push 00000000 ;zero :0041DA59 6A6C push 0000006C ;ID :0041DA5B 6811010000 push 00000111 ;WM_COMMAND ***************************** As you can see, we have just moved the flag '1' inside our location, instead of comparing and jumping away as in the original code and in the quickly cracked one. Estilo muchissimo elegante. Since this lesson was thought as +HCU material, here is the result of the work on it made by (some of) my students: JANUARY 1997: THIS PART OF LESSON 9.3 HAS BEEN MODIFIED (OR ADDED) BY THE +HCU STUDENTS OF UNIT 4 Let's finish our cracking of the nagscreens of the whole PaintShopPro family with version 4.1, which is the most recentwe know of. I am using here PSP.EXE 1.151.488 bytes from 1 Sep 1996, fetch it through the archies. We will crack this shareware program BETTER than the registered version, since we will completely eliminate any nagscreen and we'll not ever have the welcome screen that REMAINS inside the registered version. We'll do this 'in a hurry', since it is not +ORC speaking, but some of his students... you already know enough about the 'dead listing' method to be able to follow. No Winice in our hands, Ladies and Gentleman, We never used it on this program. (Well... we actually did, before reading 9.3, but it brought us nowhere, for this crack we (almost) DID NOT, following +his instructions) 1) Get the 'dead listing' of psp.exe (it's huge) 2) Load it inside a fast wordprocessor 3) Find the string 'Purchasing' at :00406710 4) short after 'Purchasing' the only location compared and loaded is location [004BC218]. Let's call it 'BINGO' and let's hope it'll work. 5) this location is handled inside a small part of the code :00406290 to :004067B5, this reduces the more than one million bytes to 1317 bytes we'll have to examine, not bad. 6) Let's print this nagging part of the code and let's feel it a little 7) Let's see the possible cracks we could think of (we repeat, here is not +ORC's but his students at work, we are not perfect). You'll see this piece of code :FIRST_ATTEMPT (NOT SO GOOD) :004065D0 50 push eax :004065D1 64892500000000 mov fs:[00000000], esp :004065D8 81ECB4000000 sub esp, 000000B4 :004065DE 833D18C24B0000 cmp dword ptr [004BC218], 0 ;Is BINGO zero? :004065E5 56 push esi :004065E6 57 push edi :004065E7 0F85A0010000 jne 0040678D ;not really this is 'pentium optimised' code, with a couple of pushes 'inside' the two logically consecutive instructions following the double 80586 fetching... on a 80486 you would have had: push esi; push edi; cmp dword ptr [004BC218], 0; jne 0040678D We may just try substituting a 0F84 at :004065E7 (that is a jump equal instead of the jne) and BOUM! We get an 'inamovible' nagscreen, No way to click it away, it covers the main program PaintShopPro for the eternity. This confirms that we are on the right track (it's a green light). Uncrack the code (or reload the original nagged program). Now look here: :SECOND_ATTEMPT (NOT SO GOOD) :00406495 E95AEA0900 jmp 004A4EF4 :0040649A 33F6 xor esi, esi :0040649C C745FCFFFFFFFF mov [ebp-04], FFFFFFFF :004064A3 893518C24B00 mov [004BC218], esi ;load esi in BINGO Since :00406495 jumps away, it would be interesting to know who the cuckoos lands at :0040649A. You'll quickly discover that there are two jumps in this area. One 'xores' the esi before loading it in our location, the other one does not: :0040641C 747C je 0040649A ;xores esi :0040646F EB2B jmp 0040649C ;does not xore esi So you may be tempted to try '‡a passe ou ‡a casse' following cracks: :0040641C 747E je 0040649C ;no xoring even if it should (THIS DOES NOT CHANGE ANYTHING) :0040646F EB19 jmp 0040649A ; xoring even if it should not (THIS CRASHES) Bad score: a frozen nagscreen, a nothing and a crash. Three to zero for our enemies. Let's look a little more around our 1317 bytes listing. Well, what else? The following code refers THREE TIMES to our location, that's a lot, let's hope it does not suck: :THREE_SISTER_BINGOS :00406547 33C0 xor eax, eax ;xor :00406549 85C0 test eax, eax ;test ax :0040654B 7513 jne 00406560 ;don't move in cx :0040654D 8B0D18C24B00 1! mov ecx, [004BC218] ;move in cx :00406553 85C9 test ecx, ecx ;test cx :00406555 7418 je 0040656F ;don't call Updatewin :00406557 6A01 push 1 :00406559 8B01 mov eax, [ecx] ;move cx in ax :0040655B FF5004 call [eax+04] ;and call here :0040655E EB0F jmp 0040656F ;don't call Updatewin :00406560 A118C24B00 2! mov eax, [004BC218] ;move in ax soon :00406565 8B4820 mov ecx, [eax+20] :00406568 51 push ecx :00406569 FF15C4014C00 call dword ptr [004C01C4] ;call Updatewindow :0040656F 6A00 push 0 :00406571 A118C24B00 3! mov eax, [004BC218] ;move in ax later Well, something fishy here, don't you feel it? Who comes in here? From where? Let's have a GOOD look at the 'preamble', i.e. the part of the code that 'switches' to our THREE_SISTER_BINGOS block above: :PREAMBLE_TO_THREE_SISTER_BINGOS :004064DD FF15BCF24B00 call dword ptr [004BF2BC] ;check this loc :004064E3 85C0 test eax, eax ;test :004064E5 744E je 00406535 ;zero, go 6535 :004064E7 B896000000 mov eax, 96 ;load par 96 :004064EC 3945E0 cmp [ebp-20], eax ;compare this :004064EF 7C44 jl 00406535 ;lower, go 6535 :004064F1 3945E4 cmp [ebp-1C], eax ;compare that :004064F4 7C3F jl 00406535 ;lower, go 6535 :004064F6 8B4508 mov eax, [ebp+08] ;load this :004064F9 85C0 test eax, eax ;test it :004064FB 7504 jne 00406501 ;do not xor and... :004064FD 33C0 xor eax, eax ;xor and :004064FF EB03 jmp 00406504 ;do not :00406501 8B4020 mov eax, [eax+20] ;...load this :00406504 6A00 push 0 ;push :00406506 8B4DE0 mov ecx, [ebp-20] ;load ecx :00406509 6A00 push 0 ;push Let's have a look at the 6535 routine of the switch PREAMBLE: :00406535 E836560100 call 0041BB70 and :41BB70 A118C34B00 mov eax, [004BC318] :41BB75 85C0 test eax, eax :41BB77 7407 je 0041BB80 :41BB79 50 push eax :41BB7A FF1530F54B00 call dword ptr [004BF530] ;globalFree :41BB80 C70518C34B00 mov dword ptr [004BC318], 0 :41BB8A C3 ret Well, let's try along, what happen if we substitute a ret at :00406535? :00406535 C390909090 ret and nops Nothing at all. And what if we substitute here :004064F6 8B4508 mov eax, [ebp+08] :004064F9 85C0 test eax, eax :004064FB 7504 jne 00406501 :004064FD 33C0 xor eax, eax :004064FF EB03 jmp 00406504 :00406501 8B4020 mov eax, [eax+20] :00406504 6A00 push 00000000 ... the instruction :004064FB 7504 jne 00406501 with the instruction 7500 (or 90 90)? MOST BRILLIANT! Now we XOR ANYWAY THIS AX without caring for ax+20. The nagscreen is defeated? Not really... the nagscreen has been passed ON THE BACKGROUND, where it still remains when you shut the 'main' window of the program... the nag protection is somewhere there, looking at us square in the faces... but where? +gthorne here: since i had already seen the production version of paint shop pro, i realized that it also had a nag screen - not per se, but a splash screen (the very same screen without the buttons to push and the 'number of days elapsed' warning). what this means is that it is very possible that the screen (regardless of what version we are running) could be intermingled with the rest of the code, and not fully existing within a call. This does not proved it, just allowed the possibility. Poking around, and being playful, i fired up snap32 and grabbed the nagscreen window and saved it for future reference. The next thing i did was check into the help screen area of Paint Shop Pro. Often in shareware programs there is a HELP ABOUT, or a HELP REGISTER section. Sometimes those places give away good info needed (or just plain useful) in the crack routine. Something that stood out in the help area was the paint shop pro version statement. It seemed to be identical to the printed version as seen on the nag screen. That means one of two things: either the version number string was just typed in twice, or more likely, just another call to a function: PSP_VERSION() or somesuch. What that means for the crackist should be pretty clearly a way to locate the protection routine. Since the word SHAREWARE shows up in both version calls, it can be scanned for pretty easily with either that or the word VERSION itself. Then, once i felt i had done enough scouting the territory, I ran WDASM and grabbed myself a dead listing. Scanning for SHAREWARE, I found a couple easy references to it... one being a data string that I promptly blanked out and the other being in the text that comes up on the nagscreen itself. WELL WELL... This is the nagscreen result here: * StringData Ref from Data Obj ->"This is a shareware version of "Paint Shop Pro." | :00406B64 6810A34B00 push 004BA310 :00406B69 8D4DEC lea ecx, [ebp-14] Okay, running the program again, and firing softice (old friend) i immediately saw that the version checking routine no longer tacked on the word SHAREWARE in either the nagscreen or in the help box.. thus proving the version call to be just that.. a call (as suspected). Immediately, something else came up that I was not expecting, the location of most of the program in memory was exactly the same as seen with softice that it was hardcoded into the disassembly. What i mean by that is that where softice was reporting 0137:0043FAD1 for a location in memory, identical data was reported at location :0043FAD1 on the disassembly. Now, talk about convenient! Simply enough, i breakpointed in softice with a few locations i had located in the disassembly, and voila... landed smack in the middle of the nagscreen data. It was do-able with soft-ice alone, but tracing into the maze of nested calls in PSP really wasn't worth my time. Line-by-line'ing it, it was simple to watch the nagscreen build itself call by call, and NOP or alter JZ's & JNZ's to JMP's (74's and 75's become EB's) so that the nagscreen lost more and more functionality. Then came a little work - not too much, but some things were a little funny. Notice the BITBLT in the nagscreen creation code. I had tried to scan for some of the standard SHOWWINDOW calls with softice and in the disassembly, but not one was to be found where it needed to be. Apparently PSP was using some other method of showing the screen... and a simple graphics memory copy (known to those who follow Micro$oft as a BitBlt) was apparently the modus operandi. Some of the text was already in place before the BitBlt, so here is our reason that some of the nagscreen was not being done as we watched with the debugger... it was being written to a backbuffer before being copied as a whole window before being blitted to the screen. This, for those of you new to graphics programming, is how people make smooth animation that does not flicker... all of the animating is done in the background and a whole screen is blitted at one time rather than by bits and pieces (you can tell which programs do not do this very easily since they have images that seem to disappear or flicker wrong in odd places on the screen) There were not many calls in that area, and only the ones that referenced string data or the bitblt itself could be effectively nop'ed out. Here is where i basically stopped the work, since i was having trouble locating what CALLED the nagscreen area. The reason we are getting the ghost window in the back (notice it's size is EXACTLY the same as the nagscreen, is that windows is being instructed by some window create command to block off the rectangular space for the screen even though the graphic interior does not get written. The backgrounding code is invaluable here since the ghost window does not have a way to be removed without paint shop pro closing (which cleans up nicely for itself on exit). Now we need to locate the call that creates the window in the first place and nop it or whatever... there is probably a nicer way to do all this (if you work at it, you can probably jmp past all the functions i nop'd - taking care not to leave unmatched pushes or pops which ruin the flow of the program - at some point in the nagscreen area The funny part of all this is that our cracked version will be better than the registered version since the registered version has a splash screen anyway - and ours does not :) Using all of this knowledge later can actually benefit us in a different way... we can actually use all of the techniques (since we already know where the nagscreen is) on the executable of the full version as well. Since it has no nag functions, it is a smaller executable and cracking it will give is a nagless, splashless (eg. screenless) version of paint shop pro that is smaller (i.e. better and more functional) than by just cracking the shareware version. I find that funny somehow :) So here is all the rest you need: Let's have a look at the VERSION subroutine that is called both in the nagscreen and the HELP screen: * StringData Ref from Data Obj ->"4" ;FIRST DIGIT OF VERSION 4.01 | :004350E4 6874AE4B00 push 004BAE74 :004350E9 8B3D90004C00 mov edi, [004C0090] :004350EF C645FC07 mov [ebp-04], 07 :004350F3 C706F0A54A00 mov dword ptr [esi], 004AA5F0 :004350F9 FFD7 call edi :004350FB 83C404 add esp, 00000004 :004350FE 8BD8 mov ebx, eax :00435100 C1E310 shl ebx, 10 * StringData Ref from Data Obj ->"0" ;SECOND DIGIT OF 4.01 | :00435103 6860A64B00 push 004BA660 :00435108 FFD7 call edi :0043510A 83C404 add esp, 00000004 :0043510D 0BD8 or ebx, eax :0043510F C1E308 shl ebx, 08 * StringData Ref from Data Obj ->"1" ;THIRD DIGIT OF 4.01 | :00435112 685CA64B00 push 004BA65C :00435117 FFD7 call edi :00435119 C1E010 shl eax, 10 :0043511C 83C404 add esp, 00000004 :0043511F 0BD8 or ebx, eax * Possible StringData Ref from Data Obj ->"2" | :00435121 68C4A14B00 push 004BA1C4 :00435126 FFD7 call edi :00435128 83C404 add esp, 00000004 :0043512B 0BD8 or ebx, eax :0043512D 899ED4000000 mov [esi-000000D4], ebx * Possible StringData Ref from Data Obj ->"0" | :00435133 6860A64B00 push 004BA660 :00435138 FFD7 call edi :0043513A 83C404 add esp, 00000004 :0043513D 50 push eax * Possible StringData Ref from Data Obj ->"1" | :0043513E 685CA64B00 push 004BA65C :00435143 FFD7 call edi :00435145 83C404 add esp, 00000004 :00435148 50 push eax * Possible StringData Ref from Data Obj ->"4" | :00435149 6874AE4B00 push 004BAE74 :0043514E FFD7 call edi :00435150 83C404 add esp, 00000004 :00435153 50 push eax * Ref from Data Obj ->"%i.%i%i" ;PRINT 3 INTEGERS: N.NN (4.01) | :00435154 686CAE4B00 push 004BAE6C :00435159 8D86CC000000 lea eax, [esi-000000CC] :0043515F 50 push eax * Reference To: n/a, Ord:09A7h in MFC40.DLL | :00435160 E815FF0600 call 004A507A :00435165 83C414 add esp, 00000014 :00435168 8D8ECC000000 lea ecx, [esi-000000CC] * StringData Ref from Data Obj ->" Shareware" ;PRINT SHAREWARE | :0043516E 6860AE4B00 push 004BAE60 The first BitBlt routine of the program puts the screen on! it is at: * Reference To: BitBlt, Ord:000Ah in GDI32.dll | :00406917 FF15B4F24B00 call dword ptr [004BF2B4] :0040691D B800000000 mov eax, 00000000 :00406922 85FF test edi, edi :00406924 7403 je 00406929 :00406926 8B4704 mov eax, [edi+04] :00406929 50 push eax :0040692A 8B45B4 mov eax, [ebp-4C] :0040692D 50 push eax and here some other annoying pieces of code: The red bar as soon as you use the program more than 30 days... * Reference To: n/a, Ord:0970h in MFC40.DLL | :00406BE3 E836E60900 call 004A521E ;DRAW RED BAR :00406BE8 6801080000 push 00000801 :00406BED 8D45A0 lea eax, [ebp-60] :00406BF0 50 push eax :00406BF1 8B4DEC mov ecx, [ebp-14] :00406BF4 8B853CFFFFFF mov eax, [ebp-000000C4] :00406BFA 8B51F8 mov edx, [ecx-08] :00406BFD 52 push edx :00406BFE 51 push ecx :00406BFF 8D8D3CFFFFFF lea ecx, [ebp-000000C4] :00406C05 FF5070 call [eax+70] ;BOTTOM WINDOW TXT+RED BAR :00406C08 53 push ebx :00406C09 8D8D3CFFFFFF lea ecx, [ebp-000000C4] Once found all the above, the rest is pretty obvious... here all the necessary crackcodes: bytes to find and change. This is a weird, non-elegant crack, but kinda funny, so i had to write it down until i discover a better one (+gthorne speaking) note: i gave good search strings so lamers don't get confused with similar patterns in the software: 8B450885C07504 to 8B450885C07500 - screen backgrounding 3CFFFFFFFF5070 to 3CFFFFFF750090 - do not draw lower text in box 3CFFFFFFFF5064 to 3CFFFFFFEB0090 - do not report version number 83FF1E7E1E to 83FF1EEB1E - do not draw red bar 000083FFC07403 to 000083FFC0EB03 - turn nagscreen invisible 53686172657761726500 to 20202020202020202000 - disable shareware notice writing phisycally some spaces over it final note: since psp closes the nagscreen when the program exits, all is now cleaned up. FF15B4F24B00 to 750090750090 (bitblt) seems to not do anything the above cracks dont do. Time to explain BitBlt... isn 't it? BitBlt copies a bitmap from the device context sopecified by hdcSource to the device context specified by hdcTarget performing a block copy. On success the function returns not zero. It is called with the handle hdcTarget, int nTargetX and nTArgetY (upper left coordinates of the point at which the bitmap will be copied... a 'pixel point' locator may be very useful in our trade) int nWidth and nHeight of the region, the handle hdcSource and then, finally the upper left coordinates IN the bitmap, the two int nSourceX and nSourcey. Is it all? NO! The final parameter, DWORD dwRaster determines HOW the bit-by-bit contents of the bitmap will actually be copied (black, inverted, ANDed, ORed, XOred...etc.). Lotta things to learn if you want to crack a lot... THE STUDENTS OF UNIT 4 (+HCU, January 1997) ******************************************* As a matter of fact both cracks here, mine for PSPS32 and my student's VERY smart one for PSP41 are 'weak', though: they will not eliminate the nagscreen (you should search for the remaining occurrences of our locations and work from them inwards, if you really want to crack completely this scheme, but in this case it would be better to work more with Winice95, in my opinion. But I hope I have made the point about "dead listing" cracking: It works! Quick and placid! In the PSP32 case the protection will still show you the nagscreen, which will "automatically" disappear, though, leaving you with no annoyance (in nuce: you cracked the return button), in the other case you have physically eliminated all possible annoyances. The nagscreen is still there, but it does not 'harm' you any more. Anyway I wanted only to show you the POWER and the CHILD'S PLAY working of this "dead listing" approach (that you may combine with some quick winice probes if you really think you need it anytime). You'll agree with me, though, that this quick "weak" crack, made with the "dead listing" method is far less tiresome than a 'live' crack with our beloved SoftIce/WinIce. Now, in life, I believe, you should always search to obtain the maximum giving the minimum. There is no point in being altruistic or excessively honest in a society where the tiny minority that profits most keeps getting richer and richer and the overwhelming majority that lives with meager earnings keeps getting poorer and poorer (and -moronized by TV-watching and other Pavlovian propagandistic sources of misinformation- keeps voting the same rich bastards that keep it enslaved under the whips of publicity, as if the slaves of ancient Egypt would happily vote for their Pharaohs). I abhor and despise the society I am compelled to live in... but this does not mean that I renounce to anything. I am (pretty) rich, (yet do not exploit anybody), eat very well, have a big nice house with all the useless objects and cars and garages and terraces and futile gadgets you are supposed to enjoy in this moronic society (I enjoy foremost my spacious library) and I drink my regular bottle of (Moskowskaja) Wodka every week. My liver (and my nice family) do not seem to complain :=) Well, that's it for this lesson, reader. Not all lessons of my tutorial are or will be on the Web. You'll obtain the missing lessons IF AND ONLY IF you mail me back (via anon.penet.fi) with some tricks of the trade I may not know that YOU discovered. Mostly I'll actually know them already, but if they are really new you'll be given full credit, and even if they are not, should I judge that you "rediscovered" them with your work, or that you actually did good work on them, I'll send you the remaining lessons nevertheless. Your suggestions and critics on the whole crap I wrote are also welcomed. Do not annoy me with requests for warez, everything is on the Web, learn how to search, for goddess sake. "If you give a man a crack he'll be hungry again tomorrow, but if you teach him how to crack, he'll never be hungry again"