SPSS Systat 10.0
http://www.spssscience.com/SYSTAT/index.cfm
Flying Raichu, 3/23/01
This is a pretty descent gui-dominant statistics program (retails $1300).
From web page:
"Visualize Your Data With More Graphing Capabilities. SYSTAT offers more
scientific and technical graphing options than any other desktop statistics
package... YouÆll never have to worry about finding the right statistic.
Robust algorithms from leading statisticians give meaningful resultsûeven
with extreme data...."
Dedicated to my new friends in the Science Division at the Forum.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
Okay, so i spent 5 or so hours a month ago trying to open this app and
almost had it, but then moved on to other more pressing things.
Decided yesterday to go back and have another look.
But this time decided to take a look at an older crack for Systat 9 done
by Replugge a member of those friends of ours at Phrozen Crew.
Seeing what Replugge did to the new code it was very clear what to do
to fix the new version, at least half of it. Turns out that a
critical element of the crack was not done by Replugge, though i
don't know if this was only an issue with version 10 or if in fact
the version 9 crack had flaws. Regardless, Replugge deserves *at least*
half the credit for this crack, maybe much more depending on your view.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
PART 1 - FINDING THE ANALOGUES OF THE SYSTAT 9 CRACK IN SYSTAT 10
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
Systat 9 Crack is very simple. It makes two changes:
-----------------------------------------------------------------------------
...
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0046BC0E(U), :0046BF6C(U)
:0046BD95 6800002240 push 40220000
:0046BD9A 6A00 push 00000000
:0046BD9C 8B8DDCFEFFFF mov ecx, dword ptr [ebp+FFFFFEDC]
:0046BDA2 51 push ecx
:0046BDA3 E848890100 call 004846F0
:0046BDA8 83C40C add esp, 0000000C
:0046BDAB 8D95B0FAFFFF lea edx, dword ptr [ebp+FFFFFAB0]
:0046BDB1 52 push edx
:0046BDB2 8D45F0 lea eax, dword ptr [ebp-10]
:0046BDB5 50 push eax
:0046BDB6 6A00 push 00000000
:0046BDB8 E8838B0100 call 00484940
:0046BDBD 83C40C add esp, 0000000C
:0046BDC0 85C0 test eax, eax // first change is here, crack forces the next jump
:0046BDC2 0F8532030000 jne 0046C0FA
:0046BDC8 8B4DF0 mov ecx, dword ptr [ebp-10]
:0046BDCB 898D48F6FFFF mov dword ptr [ebp+FFFFF648], ecx
:0046BDD1 8B9548F6FFFF mov edx, dword ptr [ebp+FFFFF648]
:0046BDD7 83EA01 sub edx, 00000001
:0046BDDA 899548F6FFFF mov dword ptr [ebp+FFFFF648], edx
:0046BDE0 83BD48F6FFFF17 cmp dword ptr [ebp+FFFFF648], 00000017
...
* Possible StringData Ref from Data Obj ->" SYSTAT: License server is down. "
->" Please try later"
:0046BE29 68682B6100 push 00612B68
:0046BE2E E8B0E71000 call 0057A5E3
:0046BE33 C785FCF6FFFF00000000 mov dword ptr [ebp+FFFFF6FC], 00000000
:0046BE3D C645FC00 mov [ebp-04], 00
:0046BE41 8D8DCCFCFFFF lea ecx, dword ptr [ebp+FFFFFCCC]
:0046BE47 E82F3A1000 call 0056F87B
:0046BE4C C745FCFFFFFFFF mov [ebp-04], FFFFFFFF
:0046BE53 8D8DB8FAFFFF lea ecx, dword ptr [ebp+FFFFFAB8]
:0046BE59 E8029A0000 call 00475860
:0046BE5E 8B85FCF6FFFF mov eax, dword ptr [ebp+FFFFF6FC]
:0046BE64 E9D9080000 jmp 0046C742
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0046BE23(C)
:0046BE69 6A00 push 00000000
:0046BE6B 6A00 push 00000000
* Possible StringData Ref from Data Obj ->" SYSTAT: Your license number is "
->"not correct. Please enter valid "
->"license"
:0046BE6D 689C2B6100 push 00612B9C
...
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0046BDC2(C)
:0046C0FA 8D8D60FBFFFF lea ecx, dword ptr [ebp+FFFFFB60]
:0046C100 51 push ecx
:0046C101 6A00 push 00000000
:0046C103 E878890100 call 00484A80
:0046C108 83C408 add esp, 00000008
:0046C10B 83BD94FBFFFF00 cmp dword ptr [ebp+FFFFFB94], 00000000
:0046C112 0F8EF3000000 jle 0046C20B // second change is here, crack forces jump
* Possible StringData Ref from Data Obj ->" You have "
:0046C118 68782D6100 push 00612D78
:0046C11D 8D8D64F7FFFF lea ecx, dword ptr [ebp+FFFFF764]
:0046C123 E8C1371000 call 0056F8E9
:0046C128 C645FC1D mov [ebp-04], 1D
* Possible Reference to String Resource ID=00010: "SYSTAT Data File"
:0046C12C 6A0A push 0000000A
:0046C12E 8D954CF7FFFF lea edx, dword ptr [ebp+FFFFF74C]
:0046C134 52 push edx
:0046C135 8B8598FBFFFF mov eax, dword ptr [ebp+FFFFFB98]
:0046C13B 2B8594FBFFFF sub eax, dword ptr [ebp+FFFFFB94]
:0046C141 50 push eax
:0046C142 E83E1C0300 call 0049DD85
:0046C147 83C40C add esp, 0000000C
* Possible StringData Ref from Data Obj ->" day(s) of license left"
:0046C14A 68842D6100 push 00612D84
...
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
Now we want to find the analogues of these changes in Systat 10.
Well, we run into an immediate problem.
W32dasm crashes if you try to dissassemble Systat10.exe right out of the box.
Sucks 'cause as you know i am head-over-heels in love with w32dasm, and i only
jump ship after the program is well sinking...
Luckily, in this case we can kludge the systat10.exe enought to make w32dasm eat it.
I *think* that w32dasm just runs out of internal memory trying to dissassemble the
big file. This happens some times, and the way i fix this in these cases
(happens occassionally), is make a copy of the exe, load it into peeditor, and
start chopping stuff that isn't critical for debugging. in this case, i just
removed the entire resource section of the exe. so i lost the dialog references
but that wasn't the critical part. SO anyway, then it can be disassembled with
w32dasm. whew.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// Let's start with second patch first, since it's easy
:00474D06 8D954CFBFFFF lea edx, dword ptr [ebp+FFFFFB4C]
:00474D0C 52 push edx
:00474D0D 6A00 push 00000000
:00474D0F E860B10100 call 0048FE74 // ?
:00474D14 83C408 add esp, 00000008
:00474D17 83BD80FBFFFF00 cmp dword ptr [ebp+FFFFFB80], 00000000 // this may be # of days used [file 074d17]
// such that we don't display on first day.
:00474D1E 0F8EF3000000 jle 00474E17 // force the jump here [file 074D1E]
* Possible StringData Ref from Data Obj ->" You have "
:00474D24 68F4696300 push 006369F4
:00474D29 8D8D44F7FFFF lea ecx, dword ptr [ebp+FFFFF744]
:00474D2F E8BC971100 call 0058E4F0
:00474D34 C645FC1D mov [ebp-04], 1D
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// the first change that pc does in systat9 is handled quite differently in 10
// here's where the text is in systat 10.
// systat 10 doesn't have these error text messages adjacent to the code,
// instead they are indirectly reference. so we need to be more clever
// about locating the analagous code.
* Possible StringData Ref from Data Obj ->"Unable to find a required SYSTAT "
->"component."
:004741F3 C78558F8FFFF00676300 mov dword ptr [ebp+FFFFF858], 00636700
* Possible StringData Ref from Data Obj ->" SYSTAT: License server is down. "
->" Please try later"
:004741FD C785B8FBFFFF2C676300 mov dword ptr [ebp+FFFFFBB8], 0063672C
* Possible StringData Ref from Data Obj ->" SYSTAT: Your license number is "
->"not correct. Please enter valid "
->"license"
:00474207 C745F060676300 mov [ebp-10], 00636760
* Possible StringData Ref from Data Obj ->"Start ".\SYSTAT Demo Expiration "
->"Message.wri""
:0047420E C785BCFBFFFFAC676300 mov dword ptr [ebp+FFFFFBBC], 006367AC
* Possible StringData Ref from Data Obj ->" SYSTAT: Your license number is "
->"expired."
:00474218 C7856CF8FFFFDC676300 mov dword ptr [ebp+FFFFF86C], 006367DC
* Possible StringData Ref from Data Obj ->" SYSTAT: Your license number is "
->"expired. Please enter a new license."
:00474222 C785ACFBFFFF08686300 mov dword ptr [ebp+FFFFFBAC], 00636808
* Possible StringData Ref from Data Obj ->" SYSTAT: Too many network users. "
->" Please try later."
:0047422C C785C0FBFFFF50686300 mov dword ptr [ebp+FFFFFBC0], 00636850
* Possible StringData Ref from Data Obj ->" SYSTAT: Missing or incorrect "
->"dongle."
:00474236 C78598FAFFFF84686300 mov dword ptr [ebp+FFFFFA98], 00636884
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// Ok so we just have to use our 3am caffeine drenched brain for a *strategy*
// just like michael corleone in the godfather, we just need to have
// sneaky thoughts, then everything is simple and we follow the path
// of least resistance.
// If you look at the first fix in systat 9, look where it jumps...
// oh, what a surprise, it jumps almost directly above the
// the second check (which we *have* located the analagous section of).
// So, we take advantage of w32dasms generosity w.r.t. crossreferencing
// jumps and we look at the place which jumps just about our systat 10
// second check.
// Sure enough this is the analagous code for change number one.
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0047480E(U), :00474B77(U)
|
:00474995 6800002440 push 40240000
:0047499A 6A00 push 00000000
:0047499C 8B95D8FEFFFF mov edx, dword ptr [ebp+FFFFFED8]
:004749A2 52 push edx
:004749A3 E828B10100 call 0048FAD0
:004749A8 83C40C add esp, 0000000C
:004749AB 8D859CFAFFFF lea eax, dword ptr [ebp+FFFFFA9C]
:004749B1 50 push eax
:004749B2 8D4DEC lea ecx, dword ptr [ebp-14]
:004749B5 51 push ecx
:004749B6 6A00 push 00000000
:004749B8 E854B30100 call 0048FD11 // the call we wonder about below
:004749BD 83C40C add esp, 0000000C
:004749C0 85C0 test eax, eax
:004749C2 0F853E030000 jne 00474D06 // here is the jump to section 2, which we want to force [file 04749C2]
:004749C8 8B55EC mov edx, dword ptr [ebp-14] // in order to be analogue of systat 9 crack part 1
:004749CB 899510F6FFFF mov dword ptr [ebp+FFFFF610], edx
:004749D1 8B8510F6FFFF mov eax, dword ptr [ebp+FFFFF610]
:004749D7 83E801 sub eax, 00000001
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
PART 2 - BUT ARE WE REALLY DONE?
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// if you apply these cracks, all looks well until it expires, then it
// freaks and tell you the program is corrupt. Not Good.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// Let's look more closely in the vicinity of the cracks, which have the
// flavour of being right, but are just not quite making it.
// Look at the above patch, it fixes a jump which is dependent on a
// call to 0048fd11. and presumably this is the call which makes some
// decision about the trial/dongle/corruptness of program, etc.
//
// If you check out the routine at 0048fd11, here is what you see:
* Referenced by a CALL at Addresses:
|:004749B8 , :0048FD76 , :0048FD8F , :0048FDAD // 4 callers!
|
:0048FD11 55 push ebp // [file 08FD11]
:0048FD12 8BEC mov ebp, esp
:0048FD14 83EC08 sub esp, 00000008
:0048FD17 C745FC01000000 mov [ebp-04], 00000001
:0048FD1E 8B450C mov eax, dword ptr [ebp+0C]
:0048FD21 C70000000000 mov dword ptr [eax], 00000000
:0048FD27 8B4D10 mov ecx, dword ptr [ebp+10]
:0048FD2A C70100000000 mov dword ptr [ecx], 00000000
:0048FD30 8B5510 mov edx, dword ptr [ebp+10]
:0048FD33 52 push edx
:0048FD34 8B450C mov eax, dword ptr [ebp+0C]
:0048FD37 50 push eax
:0048FD38 8B4D08 mov ecx, dword ptr [ebp+08]
:0048FD3B 51 push ecx
:0048FD3C E8D1080000 call 00490612
:0048FD41 83C40C add esp, 0000000C
:0048FD44 8945F8 mov dword ptr [ebp-08], eax
:0048FD47 837DF800 cmp dword ptr [ebp-08], 00000000
:0048FD4B 7413 je 0048FD60 // [file 08FD48]
:0048FD4D 8B5510 mov edx, dword ptr [ebp+10]
:0048FD50 52 push edx
:0048FD51 8B450C mov eax, dword ptr [ebp+0C]
:0048FD54 50 push eax
:0048FD55 E8F2060000 call 0049044C
:0048FD5A 83C408 add esp, 00000008
:0048FD5D 8945F8 mov dword ptr [ebp-08], eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048FD4B(C)
:0048FD60 8B45F8 mov eax, dword ptr [ebp-08] // [file 08fd60]
:0048FD63 8BE5 mov esp, ebp
:0048FD65 5D pop ebp
:0048FD66 C3 ret
// The most important thing here is that there are 4 callers to this procedure.
// all the time i see cracks which are incomplete because they patch 1 return
// call check, and miss some hidden checks. and always the best solution is
// to patch the called check function to return a value that says all is well.
// However, we need to find out how this function is used first before we can
// say for sure. It might not be nesc. Or in fact it might be critical
// to leave the called function alone if it tells whether this is a trial
// or dongle version and if we say it is dongle then other things get messed
// up.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// Let's look at the callers (we'll see lots of symmetry)
* Referenced by a CALL at Addresses:
|:004749B8 , :0048FD76 , :0048FD8F , :0048FDAD
004749B8 this is our initial check that we patch (ie we pretend that eax!=0)
0048FD76 this itself is a routine with two callers (0042FA28,0048FDF6)
0042FA28 is Exported fn(): KernelCheck - Ord:003Ah (eax is moved into [ebp-0c]
but also a call to 0049037B is SKIPPED if eax!=0
0048FDf6 is called from a suspicious 'orphaned' routine starting at 0048FDE2
which sets [ebp-08] to 0 if eax==0 or 1 if eax!=0
0048FD8F this itself is a routine with two callers (0048B1C1,0048FE3F)
004B1C11 is Exported fn(): SygraphCheck - Ord:0060h (eax moved into [ebp-0c]
but also a call to 0049037B is SKIPPED if eax!=0 (see below)
0048FE3F is called from a suspicious 'orphaned' routine starting at 0048FE2B
which sets [ebp-08] to 0 if eax==0 or 1 if eax!=0
0048FDAD also called from a suspicious 'orphaned' routine starting at 0048fd99
which sets [ebp-08] to 0 if eax==0 or 1 if eax!=0
-----------------------------------------------------------------------------
// Here is the exported suspicious SygraphCheck, which we hope will illuminate the desired
// return valued from the procedure at 0048FD11
Exported fn(): SygraphCheck - Ord:0060h
:0048B1AA 55 push ebp
:0048B1AB 8BEC mov ebp, esp
:0048B1AD 83EC0C sub esp, 0000000C
:0048B1B0 C745F401000000 mov [ebp-0C], 00000001
:0048B1B7 8D45F8 lea eax, dword ptr [ebp-08]
:0048B1BA 50 push eax
:0048B1BB 8D4DFC lea ecx, dword ptr [ebp-04]
:0048B1BE 51 push ecx
:0048B1BF 6A00 push 00000000
:0048B1C1 E8BA4B0000 call 0048FD80 // call winds up in 0048fd11
:0048B1C6 83C40C add esp, 0000000C
:0048B1C9 8945F4 mov dword ptr [ebp-0C], eax // set [ebp-0c]
:0048B1CC 837DF400 cmp dword ptr [ebp-0C], 00000000
:0048B1D0 7505 jne 0048B1D7
:0048B1D2 E8A4510000 call 0049037B // only call if eax==0
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048B1D0(C)
:0048B1D7 8B45F4 mov eax, dword ptr [ebp-0C]
:0048B1DA 8BE5 mov esp, ebp
:0048B1DC 5D pop ebp
:0048B1DD C3 ret
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// if you check for references to the exported fn checks
// you will see they are called from sygraph.dll and kernsys.dll
// SO, we need to make sure that those won't get upset at an expired program.
// which i suspect they might...
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// SURE ENOUGH, look at this call from sygraph.dll
* Reference To: SYSTAT.SygraphCheck, Ord:0048h
:100084BD FF15E8B10C10 Call dword ptr [100CB1E8]
:100084C3 85C0 test eax, eax
:100084C5 7520 jne 100084E7 // if eax==0 then it drops down with error
:100084C7 6A10 push 00000010
* Possible StringData Ref from Data Obj ->"SYSTAT"
:100084C9 6824190D10 push 100D1924
* Possible StringData Ref from Data Obj ->"Unable to properly run SYSTAT. " // ie it detects you are expired or missing dongle or bad serial
->" Please reinstall the product "
->"from the original media."
:100084CE 682C190D10 push 100D192C
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// what does this mean?
// i'll tell you. it means that if we went with the obvious fix (the one used in systat 9),
// then systat might run fine sometimes, until sysytat10::0048FD11 is called by a dll or other code (ole link?)
// in which case, if systat was expired, the error will crash you.
// SO, we need to force a return of eax=1 in the call to 0048FD11.
// This is critical, and it's a good lesson - always fix the CALLED function, not the CALLER.
//
// Note: Once we force the routine at 0048FD11 to return with eax==1, we don't need the first patch
//
// We test, it works. all done. whew, fingers are tired.
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
SUMMARY OF PATCHES
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// PATCH #1 - THIS IS NO LONGER NEEDED, BECAUSE PATCH 3 TAKES CARE OF IT
:004749B8 E854B30100 call 0048FD11 // the call we wonder about below
:004749BD 83C40C add esp, 0000000C
:004749C0 85C0 test eax, eax
...
:004749C2 0F853E030000 jne 00474D06 // [file 749C2] force this jump to section 2
CHANGE TO
E93F030000 jmp 00474D06 (Thank you to cool mccool's opcode generator)
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// PATCH #2
:00474D0F E860B10100 call 0048FE74
:00474D14 83C408 add esp, 00000008
:00474D17 83BD80FBFFFF00 cmp dword ptr [ebp+FFFFFB80], 00000000 // [file 074d17] this may be # of days used
...
:00474D1E 0F8EF3000000 jle 00474E17 // [file 074D1E] force the jump here
CHANGE TO
E9F4000000 jmp 00474E17 (Thank you to cool mccool's opcode generator)
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// PATCH #3
:0048FD11 55 push ebp
...
:0048FD60 8B45F8 mov eax, dword ptr [ebp-08] // [file 08fd60]
CHANGE TO
33C0 xor eax,eax
40 inc eax
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// PATCH #4 (aesthetics)
// Used exescope to extract, modify, and replace the small and tasteful systat splash screen
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
// PATCH #5 (Do-It-Yourself User Customization of About Box)
//
// File SITE.TXT has text saying "Demonstration Version"
// which is displayed in the About Box
// You can change that to whatever you want after crack is applied
-----------------------------------------------------------------------------