1748 lines
76 KiB
Plaintext
1748 lines
76 KiB
Plaintext
HOW TO CRACK, A TUTORIAL - LESSON 4
|
||
by +ORC (the old red cracker)
|
||
|
||
How to crack, an approach LESSON 1
|
||
How to crack, tools and tricks of the trade LESSON 2
|
||
How to crack, hands on, paper protections LESSON 3 (1-2)
|
||
-> How to crack, hands on, time limits LESSON 4
|
||
How to crack, hands on, disk-Cdrom access LESSON 5
|
||
How to crack, funny tricks LESSON 6 (1-2)
|
||
How to crack, intuition and luck LESSON 7
|
||
How to crack windows, an approach LESSON 8
|
||
How to crack windows, tools of the trade LESSON 9
|
||
How to crack, advanced cracking LESSON A (1-2)
|
||
How to crack, zen-cracking LESSON B
|
||
How to crack, cracking as an art LESSON C
|
||
How to crack INDEX
|
||
|
||
LESSON 4 - HOW TO CRACK, HANDS ON, Time Limits
|
||
|
||
For 'time protections' we intend a serie of protection schemes
|
||
which are aimed to restrict the use of an application
|
||
ONE
|
||
-to a predetermined amount of days, say 30 days, starting with
|
||
the first day of installation... 'CINDERELLA' TIME PROTECTIONS
|
||
TWO
|
||
-to a predetermined period of time (ending at a specific fixed
|
||
date) independently from the start date... 'BEST_BEFORE' TIME
|
||
PROTECTIONS
|
||
THREE
|
||
-to a predetermined amount of minutes and/or seconds each time
|
||
you fire them... 'COUNTDOWN' TIME PROTECTIONS
|
||
FOUR
|
||
-to a predetermined amount of 'times' you use them, say 30
|
||
times. Strictly speaking these protections are not 'time'
|
||
dependent, but since their schemas are more or less on the
|
||
same lines as in the cases ONE, TWO and THREE, we will examine
|
||
them inside this part of my tutorial. Let's call them 'QUIVER'
|
||
protections since, as with a quiver, you only have a
|
||
predetermined amount of 'arrows' to shoot (and if you never
|
||
went fishing with bow and arrows, on a mountain river, you do
|
||
not know what's real zen... the fish springs out suddendly, but
|
||
you 'knew' it, and your fingers had already reacted... a lot of
|
||
broken arrows on the rocks, though :=)
|
||
|
||
As first example I have chosen a double protected
|
||
application: it has a time protection (of the 'Cinderella' type,
|
||
limited to 90 days) as well as a 'quiver' protection
|
||
scheme, which is the other -not time bounded- current variante
|
||
of the shareware protections... i.e. you should use this program
|
||
only 25 times before a protection lock.
|
||
It's a relatively 'old' windows protection (april 1995). I found
|
||
the program on a cheap cd-rom, which I bought (in a bunch with
|
||
9 others) a month ago: 6000 megabytes of bad protected software
|
||
for the price of a good glass of wine! PCPLUS SUPER CD n<>13,
|
||
originally edited in July 1995. I believe it should be pretty
|
||
easy to find it or to find this program on the Web if you do not
|
||
already have it inside your collection of cheap CD-ROM. Another
|
||
advantage of this program, from our perspective, is that the
|
||
whole PCFILE.EXE represents de facto the protection scheme
|
||
itself... not excessively overbloated: only 8912 bytes, when the
|
||
'real' application works inside the (huge and overbloated)
|
||
pcf.dll, which will be called only if the user passes the
|
||
protection. You can easily print the WHOLE disassembled listing
|
||
of PCFILE.EXE (46 Wordperfect pages), that you'll quickly get
|
||
through wcb (for instance). For once you'll have a COMPLETE and
|
||
COMPLICATED protection scheme under your eyes.
|
||
Basically we'll study here the 'beginning' of more complex
|
||
time protection schemes, the ones we'll crack with our later
|
||
lessons. Some protection elements are here still 'na<6E>v', but the
|
||
protectionists have -at least- worked a little against easy
|
||
cracks... which makes this protection even more interesting for
|
||
us :=)
|
||
This program shows even a 'nasty' behaviour: should you use
|
||
it after the locking snapped, it will obliterate the whole (main)
|
||
pcf.dll from your harddisk, without any warning. This obviously
|
||
does not mean anything at all here, but it's the secret to more
|
||
advanced (and nastier) protection schemes, so you better have a
|
||
look at it too. Nice, enough let's start now.
|
||
[PCFILE] (aka the 'dll counter' method)
|
||
PCFILE, version 8, (PCFILE.EXE, 8912 bytes, 17 apr 1995, Atlantic
|
||
Coast software) is a database program which will be disabled
|
||
after having 90 days from its first use or after having used it
|
||
25 times, whichever comes first.
|
||
We'll begin as usual: just use your wordprocessor search
|
||
capacities to search inside the whole directory (and
|
||
subdirectories) of PCFILE for words like 'demo' 'order' 'contact'
|
||
'expire' 'disabling' 'evaluation' and so on (alternatively, like
|
||
I do, you can write your own little C utility to do it even more
|
||
quickly and automatically on the whole 600 megabytes CD-ROM you
|
||
have inserted on your drive :=)... You'll see immediately that
|
||
only two of the PC-files can interest us: PCFILE.EXE and
|
||
PCFRES.DLL. A quick 'turbodumping' of PCFILE.EXE itself will
|
||
fetch all filenames and nagstrings we need to be happy from the
|
||
end of the file... here they are:
|
||
A) 010C PCF.DAT
|
||
B) 0114 PCF.DLL
|
||
1) 2.011C PC-FIle demo has been disabled...
|
||
2) 2.01A2 The PC-File demo program has reached the maximum
|
||
allowable 25 sessions...
|
||
3) 2.0298 This demo version of PC-File 8 is designed...
|
||
4) 2.035A The PC-File demo program has reached... 90 days
|
||
5) 2.0474 This is the last demo session...
|
||
|
||
When I see something like this I know that the crack is already
|
||
made... it's so easy I can't understand why they don't just give
|
||
their software away for free... money I suppose, people seem to
|
||
be obsessed with this prepuberal problem... how stupid, besides:
|
||
neminem pecunia divitem fecit.
|
||
Beside, snooping inside files can be graet fun! At times you find
|
||
some 'real' info inside them... Have a look at lotus Wordpro,
|
||
for instance, you'll read something like: 'You idiot! Can't flow
|
||
a partial paragraph!'; 'Yow! Need to SetFoundry() on this object!';
|
||
'Dude! I couldn't find myself!'; 'Ain't nothing to pop!' and many
|
||
other amenities which throw a crude light on the life (and possible
|
||
blunders) of commercial programmers and on the well know fact
|
||
that most application are throw out FULL of bugs just in order
|
||
to make money ('bugs for bucks').
|
||
OK, back to our cracking: let's just search for the above NUMBERS
|
||
inside the code of PCFILE:
|
||
1) PC-File has been disabled: 011C
|
||
|
||
1.1100 >C8040100 enter 0104, 00
|
||
1.1104 56 push si
|
||
1.1105 C70632060000 mov word ptr [0632], 0000
|
||
1.110B 6A00 push 0000
|
||
1.110D B81401 mov ax, 0114; THIS is PCF.DLL
|
||
1.1110 8946FE mov [bp-02], ax
|
||
1.1113 50 push ax
|
||
1.1114 9A2E0D0212 call 1:0D2E ;what happens here?
|
||
1.1119 83C404 add sp, 0004
|
||
1.111C 40 inc ax
|
||
1.111D 7532 jne 1151
|
||
1.111F 1E push ds
|
||
1.1120 681C01 push 011C ;HERE****
|
||
1.1123 8D86FCFE lea ax, [bp-0104]
|
||
1.1127 16 push ss
|
||
1.1128 50 push ax
|
||
1.1129 9A6E110000 call USER._WSPRINTF
|
||
|
||
Therefore this target will be disabled after a check at the
|
||
beginning of WinMain (1.1100) if ax, after having been
|
||
incremented is non zero. We should have a look at the routine at
|
||
1:0D2E to see what happens... but let's first check the other
|
||
nagstrings... no point in delving immediatly inside routines.
|
||
|
||
2) The PC-File demo has reached the maximum allowable 25
|
||
sessions... 01A2
|
||
1.11C9 >807EFC66 cmp byte ptr [bp-04], 66
|
||
1.11CD 7C0F jl 11DE
|
||
1.11CF 6AFF push FFFF
|
||
1.11D1 9A36120000 call USER.MESSAGEBEEP
|
||
1.11D6 6A00 push 0000
|
||
1.11D8 1E push ds
|
||
1.11D9 68A201 push 01A2 ; HERE ****
|
||
1.11DC EB62 jmp 1240
|
||
Therefore 25 sessions if byte ptr [bp-04] >= 66 (as you can see,
|
||
the protectionists did not use anything vaguely similar to 25dec,
|
||
which is 19hex).
|
||
|
||
3) This demo version of PC-File 8 is designed... : 0298
|
||
|
||
1.11DE >807EFC4D cmp byte ptr [bp-04], 4D
|
||
1.11E2 7518 jne 11FC
|
||
1.11E4 6A00 push 0000
|
||
1.11E6 1E push ds
|
||
1.11E7 689802 push 0298 ;HERE ****
|
||
1.11EA 1E push ds
|
||
1.11EB FF361000 push word ptr [0010]
|
||
1.11EF 6A00 push 0000
|
||
1.11F1 9A48120000 call USER.MESSAGEBOX
|
||
1.11F6 C70632060100 mov word ptr [0632], 1 ;Flag 632!
|
||
This 'Welcome nagged user' message appears therefore only THE
|
||
FIRST time you run, when our byte ptr [bp-04] has been set to 4D.
|
||
That figures: 66h - 4Dh = 19h, which are the 25 times allowed...
|
||
the programmers from Atlantic Coast must have thought something
|
||
like 'Stupid crackers will not fetch our nice clever protection:
|
||
he'll be searching for byte 19h! Ah!' Note the flag set in
|
||
location [632] if it's the first run :=)
|
||
|
||
4) The PC-File demo program has reached... 90 days : 035A
|
||
1.1211 833E320600 cmp word ptr [0632], 0000
|
||
1.1216 7565 jne 127D
|
||
1.1218 A13406 mov ax, [0634]
|
||
1.121B 8B163606 mov dx, [0636]
|
||
1.121F 2B062C06 sub ax, [062C]
|
||
1.1223 1B162E06 sbb dx, [062E]
|
||
1.1227 83FA76 cmp dx, 0076
|
||
1.122A 7251 jb 127D
|
||
1.122C 7705 ja 1233
|
||
1.122E 3D00A7 cmp ax, A700
|
||
1.1231 764A jbe 127D
|
||
|
||
1.1233 >6AFF push FFFF
|
||
1.1235 9A3C130000 call USER.MESSAGEBEEP
|
||
1.123A 6A00 push 0000
|
||
1.123C 1E push ds
|
||
1.123D 685A03 push 035A ; HERE!
|
||
|
||
There, location [634] in ax and location [636] in dx.
|
||
ax subtracts location [62C] and dx subtracts with carry location
|
||
[62E]. Is it more than 76h? (Which is 118 dec), Tell user he has
|
||
reached 90 days. Is it exactly 76h? Then have a look at ax, if
|
||
it is more than A700 then tell user the same.
|
||
|
||
5) This is the last demo session... : 0474
|
||
|
||
1.132D >56 push si
|
||
1.132E 9AFFFF0000 call KERNEL._LCLOSE
|
||
1.1333 807EFC66 cmp byte ptr [bp-04], 66
|
||
1.1337 7C19 jl 1352
|
||
1.1339 6AFF push FFFF
|
||
1.133B 9AFFFF0000 call USER.MESSAGEBEEP
|
||
1.1340 6A00 push 0000
|
||
1.1342 1E push ds
|
||
1.1343 687404 push 0474 ;HERE****
|
||
1.1346 1E push ds
|
||
1.1347 FF361000 push word ptr [0010]
|
||
1.134B 6A10 push 0010
|
||
1.134D 9AFFFF0000 call USER.MESSAGEBOX
|
||
|
||
1.1352 >1E push ds
|
||
1.1353 681401 push 0114 ;this is PCF.DLL
|
||
1.1356 6A01 push 0001
|
||
1.1358 9AFFFF0000 call KERNEL.WINEXEC ;exec PCF.DLL
|
||
|
||
And here, finally we have our good old [bp-04] -once more-
|
||
compared to 66h. Notice that there is no Jumpequal nor
|
||
jumpgreater check. This means that the program ALREADY KNOWS that
|
||
the user has reached here for the first time the fatidic 66. This
|
||
means (of course) that this code will be examined AFTER having
|
||
incremented the counter of the protection, which must therefore
|
||
happen somewhere between 1.123D and 1.132D (the end of routine
|
||
4 and the beginning of routine 5). If you have printed the whole
|
||
disassembled listing of PCFILE.EXE and if you have read my other
|
||
lessons about dead listing (-> 9.3 and 9.4) you do not need any
|
||
more to read the following part of this lesson. Choose your
|
||
armchair and sit there with a pen, your listing and a good
|
||
cocktail (may I suggest a good Martini-Wodka? Don't use anything
|
||
else but Moskowskaja). The moment to start 'feeling' the code has
|
||
come! You can do everything alone. Write colored arrows on your
|
||
listing! The first (or the fourth) simphony of Mahler on your CD!
|
||
Everything will appear!
|
||
Indeed, if you prefer to follow here, behold: at 1.12B2 we
|
||
have a call KERNEL._LOPEN wich opens the file PCF.DLL (0114):
|
||
|
||
1.12AD 681401 push 0114 ;want pcf.dll
|
||
1.12B0 6A01 push 0001
|
||
1.12B2 9AFFFF0000 call KERNEL._LOPEN ;open it
|
||
|
||
and at 1.12CD we have the exact point where, inside pcf.dll, a
|
||
byte will be modified (at 10AF8):
|
||
|
||
1.12C6 6A01 push 0001
|
||
1.12C8 68F80A push 0AF8
|
||
1.12CB 6A00 push 0000
|
||
1.12CD 9AFFFF0000 call KERNEL._LLSEEK
|
||
|
||
The only modification takes place therefore inside PCF.DLL, a
|
||
monstruosity of 1088832 bytes, where location 10af8 grows WITHOUT
|
||
any change in the date of the dll. You can easily check this:
|
||
* copy pcf.dll pcf.ded
|
||
* (run pcfile a couple of time)
|
||
* fc /b pcf.dll pcf.ded
|
||
fc /b is file compare /binary, good old (and quick) dos, duh?
|
||
And this is what you get...
|
||
|
||
Comparing files PCF.DLL and PCF.DED
|
||
00010AF8: 55 50
|
||
|
||
Et voila mesdames et messieurs, found the other way round, please
|
||
note that this more 'practical' method can also be used *before*
|
||
beginning the dead listing examination of the file (and would
|
||
have given you the '0AF8' string to search for).
|
||
|
||
Well, what did we learn? A lot: an hidden counter grows in
|
||
another file without leaving many traces. The 'quiver'
|
||
protection snaps after growing more than 66h, having started at
|
||
4Dh. The flag for first time user is inside [0632]. [0634] and
|
||
[0636] are used for the current date, [062C] and [062E] are the
|
||
original date against which they are checked in a funny way.
|
||
There are two different protections, therefore we'll need
|
||
two different cracks to deprotect this cram. Let's begin with the
|
||
easiest one.
|
||
Our FIRST crack, must destroy the counter that increases inside
|
||
pcf.dll (the '25' session allowance). This will be made cracking
|
||
following instruction:
|
||
1.12F3 FE46FC inc byte ptr [bp-04]
|
||
which is obviously the increasing instruction we are searching
|
||
for (BECAUSE it's the only 'inc byte ptr' in the whole stupid
|
||
program, AND because it is located short after the _LLSEEK, AND
|
||
because it's incrementing nobody else than our good old [bp-
|
||
04]... what do you want more, a neon green flashing arrow light
|
||
on the top of it?)
|
||
We'll very simply "noop" this instruction, transforming it, for
|
||
instance, in 40 90 48 (inc ax, nop, dec ax = do nothing). Well,
|
||
yes, that was it for the '25 sessions' lock protection, thankyou,
|
||
you may use the program a zillion times now. What now? Ah, yes,
|
||
the DATE lock, let's have a look once more at it:
|
||
1.1218 A13406 mov ax, [0634]
|
||
1.121B 8B163606 mov dx, [0636]
|
||
1.121F 2B062C06 sub ax, [062C]
|
||
1.1223 1B162E06 sbb dx, [062E]
|
||
1.1227 83FA76 cmp dx, 0076 ;118 (-90=1c)
|
||
1.122A 7251 jb 127D
|
||
1.122C 7705 ja 1233
|
||
1.122E 3D00A7 cmp ax, A700 ;(42572)
|
||
1.1231 764A jbe 127D
|
||
|
||
1.1233 >6AFF push FFFF
|
||
1.1235 9A3C130000 call USER.MESSAGEBEEP
|
||
1.123A 6A00 push 0000
|
||
1.123C 1E push ds
|
||
1.123D 685A03 push 035A ;HERE! 90 days!
|
||
|
||
Therefore, if location [636] is > than 76, the nag snaps.
|
||
This 76 is calculated through what SEEMS a simple comparison
|
||
between the actual date and the installation date.
|
||
|
||
1.1218 A13406 mov ax, [0634] ;load date ax
|
||
1.121B 8B163606 mov dx, [0636] ;load date dx
|
||
1.121F 2B062C06 sub ax, [062C] ;subtract first date
|
||
1.1223 1B162E06 sbb dx, [062E] ;subtract first date
|
||
1.1227 83FA76 cmp dx, 0076 ;allowed limit (?)
|
||
1.122A 7251 jb 127D ;ok: you may
|
||
1.122C 7705 ja 1233 ;beggar off
|
||
1.122E 3D00A7 cmp ax, A700 ;well, what's this
|
||
1.1231 764A jbe 127D ;then?
|
||
|
||
In the reality there are various mathematical checkings
|
||
going on here, as the second check on ax = A700 shows. This DOES
|
||
NOT need to concern us much (we'll crack this code, later,
|
||
changing the 'first time user' flag), but it's useful you have
|
||
a rough understanding of what goes on inside these schemes,
|
||
therefore let's delve a little inside it.
|
||
Basically, the good old dos function GetSystemDate (21/2A)
|
||
works like this: On entry: ah = 2a
|
||
On return:
|
||
al = day of the week (0 = Sunday, 1 = Monday...)
|
||
cx = year
|
||
dh = month
|
||
dl = day
|
||
Short before the 90 days check, the protection calls two
|
||
routines:
|
||
1:09B4 (GetSystemDate) and 1:0D64 (FetchInstallationCode)
|
||
The first one fetches the date (1.9D3-1.9D7) and the Time
|
||
(21/2C, at 1.9E2), get's ONCE MORE the system date (1.9F7)
|
||
subtracts the years against 1980 (1.A20: sub cx, 07BC) and then
|
||
makes quite a lot of maniuplation of these data (around 1.C7D,
|
||
where one year LESS than the current year will be stored in
|
||
[SI+03], in order to calculate the total amount of days). The
|
||
second one prepares the numbers for the sub ax and sbb dx of the
|
||
90 days check.
|
||
As I said all this does not need to concern you much, coz
|
||
the protectionists have mad a 'protecion blunder': they have made
|
||
every time snapping depending on a flag, the one in [0632].
|
||
What happens is: THE FIRST THING this program makes, smack
|
||
at the beginning of WinMain, is to set to zero (FALSE) the
|
||
abovementioned flag:
|
||
1.1105 C70632060000 mov word ptr [0632], 0000
|
||
Only in case of first time use, this flag will be set to TRUE at
|
||
1.11F6 C70632060100 mov word ptr [0632], 0001
|
||
knowing that, anyway, as soon as the program runs again this flag
|
||
will be reset to FALSE by Winmain.
|
||
And, as we saw, this flag is checked both for the 90 days snap:
|
||
1.1211 833E320600 cmp word ptr [0632], 0000
|
||
and for the 'This is your last day Cinderella' Warning:
|
||
1.1315 >833E320600 cmp word ptr [0632], 0000
|
||
A good fundamental crack will therefore be the 'automatical'
|
||
setting to TRUE of this flag by our Winmain:
|
||
1.1105 C70632060100 mov word ptr [0632], 0001
|
||
Everytime the program runs it will believe that's the first time
|
||
it does it.
|
||
I know, theoretically, having nooped the increase inside PCF.DLL,
|
||
the counter should remain always at 4D, which would set ANEW the
|
||
flag to true every run... but we do not want the first 'welcome'
|
||
nagscreen either, do we? Therefore:
|
||
****** Crack for PCFILE version 8, by +ORC, march 1997 ***
|
||
psedit pcf.dll
|
||
search 4E 49 44 4D (4D only if you did not run it)
|
||
modify in 4E 49 44 50 (second time run)
|
||
psedit pcfile.exe
|
||
search 83 C4 06 FE 46 FC
|
||
modify in 83 C4 06 40 90 48 (nooped increase)
|
||
search C7 06 32 06 00 00
|
||
modify in C7 06 32 06 01 00 (flag always true)
|
||
*********************************************
|
||
As second example I have chosen a fairly interesting 'CINDERELLA'
|
||
protection scheme of a Window application which can be useful for
|
||
our purposes: Link Check (Version 5.1), an application written
|
||
in august 1996. I'll crack here the Windows 3.1 version, for
|
||
reasons explained in lesson 9.4, but you'll easily find the Win95
|
||
version on the net, whose protection scheme works on the same
|
||
lines.
|
||
Link Check is a suite of three (3) diagnostic programs which
|
||
allows the user to examine different areas of the system.
|
||
1) Link Check (WLCHECK.EXE) enables the user to view the links
|
||
between an executable file and the modules it requires to run on
|
||
the system.
|
||
2) Memory Check (WMCHECK.EXE) allows the user to view, load and
|
||
unload modules currently in memory.
|
||
3) Function Check (WFCHECK.EXE) allows the user to view actual
|
||
function calls inside modules.
|
||
WLCHECK EXE 40400 24/08/96 5:10
|
||
WMCHECK EXE 37104 18/08/96 5:10
|
||
WFCHECK EXE 45424 24/08/96 5:10
|
||
WLCCOMM DLL 46960 18/08/96 5:10
|
||
KSLHOOKS DLL 29568 15/08/96 1:00
|
||
The protection scheme inside this program allows a 21 days use
|
||
of the program, then 'disables' it. Even in the first 21
|
||
'allowed' days there are some functions that are disabled,
|
||
anyway. Another interesting feature of the protection scheme, is
|
||
that once you register, an 'electronic key' will be created and
|
||
sended to you in order to unlock Link Check for the full retail
|
||
version (which, as usual, means that the shareware version you
|
||
are using CAN be unlocked).
|
||
Therefore this application:
|
||
is TIME-LIMITED
|
||
has been CRIPPLED
|
||
has some DISABLED functions
|
||
can be UNLOCKED.
|
||
A wonderful world of cracking possibilities! Let's rub our hands!
|
||
So much to find! So much to learn! Thanks, Karri Software Ltd!
|
||
(100422.3521@compuserve.com)
|
||
For these protection schemes we must use both the 'Winice' live
|
||
approach and the 'dead listing' one. (both described elsewhere
|
||
in my tutorial).
|
||
Let's begin at the beginning, i.e. searching for strings inside
|
||
the WLCHECK.EXE we'll find nothing.
|
||
You'll soon realise that the protection scheme hides inside the
|
||
two *.dll WLCCOMM.DLL & KSLHOOKS.DLL... the real problem, with
|
||
this kind of protections, is that the 'modalities' to unlock it
|
||
are not known, i.e., that you cannot just crack the unlock
|
||
procedure itself, but you must reverse engineer the program long
|
||
enough to find the 'switch' that fires your cracked 'unlock'
|
||
procedure, in order to 'register' this program and in order to
|
||
be able to use it ad libitum.
|
||
What happens with time protections?
|
||
The first problem for the protectionists is the tampering with
|
||
the system date. Even a stupid user could set the system clock
|
||
backwards in order to use a program of the CINDERELLA sort.
|
||
Your target would be easily fooled by any stupid user if it did
|
||
just set a variable [START_DATE] and then simply check the system
|
||
time with something like
|
||
IF SystemTime > [START_DATE+30] then beggar off
|
||
ELSE OK
|
||
Therefore (almost) all this program use some sort of 'diode'
|
||
location. Like diodes, which let current through in only one
|
||
direction, these locations can only grow... i.e, if you set the
|
||
system time to 1 January 2000 and then run the program, it will
|
||
throw you off, as expected, but even when you go back to your
|
||
current year and date this will be 'remembered'...and the
|
||
protection will NOT allow you any more to use the program even
|
||
should you (theoretically) still have some free 'try me' days...
|
||
your setting at year 2000 screwed up your license for ever.
|
||
IF SystemTime > [START_DATE+30] then [MARK_HERE]
|
||
ELSE continue
|
||
If [MARK_HERE] = TRUE then beggar off
|
||
ELSE OK
|
||
Let's try altering the system date on our WLCHECK.EXE target...
|
||
Woa! As I said... it does not work anymore.
|
||
|
||
It's fairly easy to get at this part through Winice: Just bpx
|
||
WritePrivateProfileString (which is a very interesting function
|
||
indeed) and then have a good look at the pointers: You'll quick
|
||
find out that KSLHOOKS (Segment 0B) writes his own xCLSID value
|
||
inside system.ini. The block of KSLHOOKS.DLL's code responsable
|
||
for this is the following:
|
||
11.0569 9AE4013500 call 7:01E4 ;'Value' and 'SYSTEM.INI'
|
||
11.056E 83C408 add sp, 8 ;adjusting stack
|
||
11.0571 8D843901 lea ax, [si+0139]
|
||
11.0575 57 push di
|
||
11.0576 50 push ax ;pushing 'xCLSID'
|
||
11.0577 8D46FA lea ax, [bp-06]
|
||
11.057A 16 push ss
|
||
11.057B 50 push ax ;pushing 'Value'
|
||
11.057C 8D468A lea ax, [bp-76]
|
||
11.057F 16 push ss
|
||
11.0580 50 push ax ;pushing '{6178-0503...}'
|
||
11.0581 8D46EE lea ax, [bp-12]
|
||
11.0584 16 push ss
|
||
11.0585 50 push ax ;pushing 'SYSTEM.INI'
|
||
11.0586 9AFFFF0000 call KERNEL.WRITEPRIVATEPROFILESTRING
|
||
11.058B 33C0 xor ax, ax
|
||
11.058D 5E pop si
|
||
11.058E 5F pop di
|
||
11.058F C9 leave
|
||
11.0590 CB retf
|
||
|
||
The call to 7.01E4 fetches the strings 'Value' and 'SYSTEM.INI'
|
||
which are 'hardwired' there byte by byte, for instance, 'INI' is
|
||
fetched like this:
|
||
7.0234 26C6440749 mov byte ptr es:[si+07], 49 ;I
|
||
7.0239 26C644084E mov byte ptr es:[si+08], 4E ;N
|
||
7.023E 26C6440949 mov byte ptr es:[si+09], 49 ;I
|
||
|
||
What is really interesting in this part of the protection scheme,
|
||
is that the function WritePrivateProfileString is one of the MOST
|
||
COMMON functions used for this kind of protections, being the
|
||
function normally used in order to 'keep track' inside an 'INI'
|
||
file of the particular configuration of an application that the
|
||
user has chosen... as a matter of fact this program creates an
|
||
hidden WLCHECK.SWL file inside c:\windows where it writes its
|
||
data, it also writes, through the above code,
|
||
|
||
[xCLSID]
|
||
Value={0000006236-0017105173-6326000000}
|
||
inside system.ini
|
||
|
||
and then it writes ANOTHER string inside the reg.dat 'register'
|
||
of the windows directory. A short digression, about registrations
|
||
in the reg.dat of the Windows directory. If you never had a look
|
||
at the reg.dat file (wich you should not have only firing
|
||
regedit.exe, but using the switch /v TROUGH THE COMMAND LINE
|
||
run!) you are in for a big surprise. If you are used to install
|
||
and de-install programs as much as I do, you'll be able to see,
|
||
for instance, real BATTLES between big or widespread software
|
||
packages (for instance Coreldraw and PaintShopPro) fought
|
||
there... but you'll also find some cryptic messages like
|
||
WB_10=VMWB20
|
||
FILTER = 000000000e
|
||
OPTION = 0000000005
|
||
TAG = 0000001857
|
||
KEY = 0000184F
|
||
or, even more cryptic:
|
||
VxDSettings = {0000006178-0419758349-4326000000}
|
||
And this is actually our target, as you can see... the first
|
||
thing you should know is that some protection schemes hyde the
|
||
date checking part of their protection inside reg.dat.
|
||
The above value is the 'ID' of our target, and the ciffer in the
|
||
'middle' varies with the date and with the passing of the time.
|
||
As we said, once the protection snaps, there is no 'normal'
|
||
way to reinstall a working copy of the program, even substituting
|
||
ALL the files with fresh ones and deleting the 'secret'
|
||
WLCHECK.SWL will not help... in order to reinstall this program
|
||
or to use it for the eternity (in 21 days chunks) you would have
|
||
to do the following every time the limit snaps:
|
||
A) regedit /v
|
||
delete key VxD
|
||
B) edit system.ini
|
||
manually delete the block
|
||
"[xCLSID]
|
||
Value={0000006236-0017105173-6326000000}"
|
||
C) attrib c:\windows\wlcheck.swl -r -s -h
|
||
del c:\windows\wlcheck.swl
|
||
D) reinstall everything anew and run 21 more days... clearly not
|
||
a satisfactory solution, exspecially given the fact that some
|
||
routines are disabled... therefore let's delve a little more
|
||
inside this protection scheme... we'll find a much neater crack,
|
||
you'll see... :=)
|
||
Since the 'legitimate' user will get 'an electronic key' from the
|
||
protectionists, there must exist, somewhere, a small menu of the
|
||
kind 'Enter your electronic key, legitimate sucker'... we could
|
||
find it searching with a little imagination (and/or zen) inside
|
||
our listings, but in these cases, it's much more quicker a small
|
||
run with WRT (Windows Resource Toolkit) by borland. Since we are
|
||
already inside KSLHOOKS.DLL, let's begin with this one.
|
||
Wrt loads kslhooks.dll and shows you immediatly that there are
|
||
only three dialog items, the last one, tagged as 'dialog 503'
|
||
represents the 'Unlock' little window: ('Please enter your key'),
|
||
which has two buttons: OK (1) and Cancel (2). Let's use WRT
|
||
'ID_tagging' option: we'll immediatly fetch the ID number of the
|
||
'Please enter your key' field: 2035.
|
||
2035 dec is 7F3 hex, therefore we now just need to search 07F3
|
||
inside our listing... and we land immediatly here:
|
||
6.00DE >8B760A mov si, [bp+0A]
|
||
6.00E1 FF760E push word ptr [bp+0E]
|
||
6.00E4 6A08 push 0008
|
||
6.00E6 9AFFFF0000 call USER.GETWINDOWLONG
|
||
6.00EB 8946FC mov [bp-04], ax
|
||
6.00EE 8956FE mov [bp-02], dx
|
||
6.00F1 83FE01 cmp si, 0001
|
||
6.00F4 7556 jne 014C
|
||
6.00F6 FF760E push word ptr [bp+0E]
|
||
6.00F9 68F307 push 07F3 ;HERE! ****
|
||
6.00FC 9AFFFF0000 call USER.GETDLGITEM
|
||
6.0101 50 push ax
|
||
6.0102 8D4698 lea ax, [bp-68]
|
||
6.0105 16 push ss
|
||
6.0106 50 push ax
|
||
6.0107 6A63 push 0063
|
||
6.0109 9AFFFF0000 call USER.GETWINDOWTEXT
|
||
6.010E 8D4698 lea ax, [bp-68]
|
||
6.0111 16 push ss
|
||
|
||
This block of code is part of an Exported function from
|
||
kslhooks.dll: KSLHOOKPROC4 - Ord:0006h
|
||
Here is the whole sequence:
|
||
:CALL_PLEASE_ENTER_ELECTROKEY
|
||
6.00DE >8B760A mov si, [bp+0A]
|
||
...
|
||
6.00F9 68F307 push 07F3 ;HERE ***
|
||
is called (being at 6.00DE) from
|
||
:ENTER 68
|
||
6.0082 C8680000 enter 0068, 00
|
||
...
|
||
6.009B 7441 je 00DE ;HERE ***
|
||
which (being at 6.00082) is called from
|
||
:PUSH_82
|
||
6.000F 68FFFF push selector KSLHOOKPROC4
|
||
6.0012 688200 push 0082 ;HERE ***
|
||
6.0015 FF36200C push word ptr [0C20]
|
||
6.0019 9AFFFF0000 call KERNEL.MAKEPROCINSTANCE
|
||
Much interesting, but we are not yet there...
|
||
let's see if we have other occurrences of our 7F3h instance
|
||
(which, as we saw through WRT, corresponds to the 'Enter your
|
||
Key' field of the 'Unlock' window). Yes, we have one more
|
||
occurrence (always inside KSLHOOKS.DLL):
|
||
|
||
4.030A >81FEF307 cmp si, 07F3 ;HERE ***
|
||
4.030E 7515 jne 0325 ;don't care if not unlock
|
||
4.0310 FF760E push word ptr [bp+0E] ;nID
|
||
4.0313 56 push si ;=7F3, =unlock, =hDlg
|
||
4.0314 9AFFFF0000 call USER.ISDLGBUTTONCHECKED
|
||
4.0319 0BC0 or ax, ax ;mashed button?
|
||
4.031B 7408 je 0325 ;Yeah, jump...
|
||
4.031D C45EFC les bx, [bp-04]
|
||
4.0320 2689B7B104 mov es:[bx+04B1], si
|
||
4.0325 >83FE02 cmp si, 0002 ;...here
|
||
|
||
Now, IsDlgButtonChecked is a 'typical' windows function with
|
||
following structure:
|
||
UINT IsDlgButtonChecked(HWND hFlg, int nID)
|
||
where the handle of the dialog box contaning the button control
|
||
is specified in hDlg. The ID value of the desired button is
|
||
passed in nID. For two-state buttons this function returns zero
|
||
if the button is unchecked and non zero if it is checked, -1 if
|
||
an error occurs.
|
||
What else can we do?
|
||
Let's search for the limit (21 days, that corresponds to 15h)
|
||
inside our code. Well, we'll find two interesting occurrences
|
||
inside the OTHER dll module: WLCCOMM.DLL:
|
||
:OCCURRENCE_1_OF_21_DAYS_LIMIT
|
||
1.3E25 >80BEFFFE15 cmp byte ptr [bp-0101], 15 ;here***
|
||
1.3E2A 7403 je 3E2F ;Please restart...
|
||
1.3E2C E9B900 jmp 3EE8 ;xor ax and retf
|
||
and now, look what we have immediately afterwards...
|
||
1.3E2F >FF760E push word ptr [bp+0E]
|
||
1.3E32 1E push ds
|
||
1.3E33 681306 push 0613 ;Please restart...
|
||
1.3E36 1E push ds
|
||
1.3E37 68EE05 push 05EE ;Retail version...
|
||
1.3E3A 6A40 push 0040
|
||
1.3E3C 9A90080000 call USER.MESSAGEBOX
|
||
1.3E41 FF760E push word ptr [bp+0E]
|
||
1.3E44 6A01 push 0001
|
||
1.3E46 9AE03E0000 call USER.ENDDIALOG
|
||
1.3E4B E99A00 jmp 3EE8 ;xor ax and retf
|
||
|
||
Now, string 0613 is
|
||
"Please restart the program for the reatil version to take
|
||
effect"
|
||
and string 05EE is
|
||
"Retail version successfully unlocked"
|
||
...clearly we have found the part of the code where the user gets
|
||
the appropriate message once he has digited the correct key
|
||
inside the unlock window in KSLHOOKS.
|
||
But let's use a little more our 'new' WRT approach. Examining the
|
||
'dialog' items through WRT, we'll see that inside WLCCOMM.DLL
|
||
there are 'two' About Link check templates, a 'nice' one (for
|
||
registered users) and a 'nag' one (for Cinderella's users).
|
||
The nice one is WLCCOMM.DIALOG 130, and its second part reads
|
||
'This copy of Link check is licensed to'
|
||
FIELD 1 = 603 (25bh)
|
||
FIELD 2 = 604 (25Ch)
|
||
The 'nag' one is WLCCOMM.DIALOG 131 and its second part reads
|
||
'UNREGISTERED Shareware notice...' with two buttons:
|
||
'How do I register' which is 601 (259h) and
|
||
What do I get for it which is 602 (25ah).
|
||
Well... let's have a look around our code... and here is
|
||
(obviously) the relevant part of it inside WLCCOMM.DLL:
|
||
|
||
1.3C60 >8B760E mov si, [bp+0E]
|
||
1.3C63 FF7606 push word ptr [bp+06]
|
||
1.3C66 6AF4 push FFF4
|
||
1.3C68 9A8A1D0000 call USER.GETWINDOWWORD
|
||
1.3C6D 56 push si
|
||
1.3C6E 685B02 push 025B ;here***
|
||
1.3C71 9A803C0000 call USER.GETDLGITEM
|
||
1.3C76 394606 cmp [bp+06], ax
|
||
1.3C79 7421 je 3C9C
|
||
1.3C7B 56 push si
|
||
1.3C7C 685C02 push 025C ;here***
|
||
1.3C7F 9ADA3C0000 call USER.GETDLGITEM
|
||
1.3C84 394606 cmp [bp+06], ax
|
||
1.3C87 7413 je 3C9C
|
||
1.3C89 FF760A push word ptr [bp+0A]
|
||
1.3C8C FF7608 push word ptr [bp+08]
|
||
1.3C8F FF7606 push word ptr [bp+06]
|
||
1.3C92 6A01 push 0001
|
||
1.3C94 9A08039E3D call KSLCONTROLCOLOR
|
||
1.3C99 E94E02 jmp 3EEA
|
||
|
||
Whereby, here is the part for the shareware user:
|
||
1.3EA6 >81FE5902 cmp si, 0259 ;How do I register?
|
||
1.3EAA 7513 jne 3EBF
|
||
1.3EAC FF760E push word ptr [bp+0E]
|
||
1.3EAF 1E push ds
|
||
1.3EB0 688B06 push 068B
|
||
1.3EB3 6A01 push 0001
|
||
1.3EB5 6A00 push 0000
|
||
1.3EB7 687217 push 1772
|
||
1.3EBA 9AD43E0000 call USER.WINHELP
|
||
1.3EBF >81FE5A02 cmp si, 025A ;What do I get for it?
|
||
1.3EC3 7523 jne 3EE8
|
||
1.3EC5 FF760E push word ptr [bp+0E]
|
||
1.3EC8 1E push ds
|
||
1.3EC9 689706 push 0697
|
||
1.3ECC 6A01 push 0001
|
||
1.3ECE 6A00 push 0000
|
||
1.3ED0 687117 push 1771
|
||
1.3ED3 9AFFFF0000 call USER.WINHELP
|
||
1.3ED8 EB0E jmp 3EE8
|
||
|
||
and as you can easily see, here lays the 'working' for the two
|
||
mushbuttons of the shareware version.
|
||
Shareware starts at 1.3EA6 and will be called from here
|
||
1.3DB9 >81FE5802 cmp si, 0258
|
||
1.3DBD 7403 je 3DC2
|
||
1.3DBF E9E400 jmp 3EA6
|
||
|
||
Unlocked version starts at 1.3C60 and will be called from here:
|
||
|
||
1.3C3E C8FE0400 enter 04FE, 00
|
||
1.3C42 57 push di
|
||
1.3C43 56 push si
|
||
1.3C44 1E push ds
|
||
1.3C45 B87938 mov ax, selector 2:0000
|
||
1.3C48 8ED8 mov ds, ax
|
||
1.3C4A 8B460C mov ax, [bp+0C]
|
||
1.3C4D 2D1900 sub ax, 0019
|
||
1.3C50 740E je 3C60 ;***here! UNLOCKED
|
||
1.3C52 2DF700 sub ax, 00F7
|
||
1.3C55 7465 je 3CBC ;copyright, 1st part
|
||
1.3C57 48 dec ax
|
||
1.3C58 7503 jne 3C5D ;(jmp 3EE8) out
|
||
1.3C5A E94901 jmp 3DA6
|
||
|
||
Well... if [bp+0C] is 19 (dec25) then we'll jump to our unlocked
|
||
routine?
|
||
|
||
********************************************
|
||
BELOW IS WORK FROM THE STUDENTS OF THE +HCU
|
||
wlcheck for windows 3.1
|
||
********************************************
|
||
|
||
Starting with the nag screen, here is a silly fix for it that works on many programs
|
||
that use windows resource windows (such as an about box) as the nag screen.
|
||
|
||
Load up the file with the nagscreen in it (as listed above) with WRT (I am using
|
||
borland resource workshop - same program, different version) and delete it.
|
||
I am serious; try it: it works!
|
||
|
||
save the .DLL and it recompiles the binary without the nagscreen.
|
||
(Those borland people scare me sometimes)
|
||
---------------------------------------------------------
|
||
Back to more serious work...
|
||
Since we are learning methods here, this is where I get to go
|
||
after individual parts of the protection and defeat them. I will
|
||
work on finding the flag to register the program later, first I
|
||
want to do a little digging.
|
||
|
||
Looking through our dead listing of kslhooks.dll:
|
||
|
||
Going through our lesson so far, our file included a file reference
|
||
to SYSTEM.INI by means of a byte-at-a-time string creation rather
|
||
than a full data statement
|
||
|
||
(Note: i do this sometimes to make it hard for simpletons to change
|
||
my name in my programming
|
||
---but i at lest jumble the lines around so it isnt so obvious)
|
||
|
||
I will show you two ways of removing this particular hurdle, here is
|
||
the first, and most obvious: (THE NULL TERMINATOR)
|
||
---------------------------------------------------------
|
||
here is the full code from the disassembly:
|
||
---------------------------------------------------------
|
||
:0007.01E3 90 nop
|
||
:0007.01E4 55 push bp
|
||
:0007.01E5 8BEC mov bp, sp
|
||
:0007.01E7 57 push di
|
||
:0007.01E8 56 push si
|
||
:0007.01E9 8B7E06 mov di, [bp+06]
|
||
:0007.01EC 8B760A mov si, [bp+0A]
|
||
:0007.01EF 8E4608 mov es, [bp-08]
|
||
|
||
:0007.01F2 26C60556 mov byte ptr es:[di], 56 ;V
|
||
:0007.01F6 26C6450161 mov byte ptr es:[di+01], 61 ;a
|
||
:0007.01FB 26C645026C mov byte ptr es:[di+02], 6C ;l
|
||
:0007.0200 26C6450375 mov byte ptr es:[di+03], 75 ;u
|
||
:0007.0205 26C6450465 mov byte ptr es:[di+04], 65 ;e
|
||
:0007.020A 26C6450500 mov byte ptr es:[di+05], 00 ; <00> (end of string)
|
||
|
||
:0007.020F 8E460C mov es, [bp-0C]
|
||
|
||
:0007.0212 26C60453 mov byte ptr es:[si], 53 ;S
|
||
:0007.0216 26C6440159 mov byte ptr es:[si+01], 59 ;Y
|
||
:0007.021B 26C6440253 mov byte ptr es:[si+02], 53 ;S
|
||
:0007.0220 26C6440354 mov byte ptr es:[si+03], 54 ;T
|
||
:0007.0225 26C6440445 mov byte ptr es:[si+04], 45 ;E
|
||
:0007.022A 26C644054D mov byte ptr es:[si+05], 4D ;M
|
||
:0007.022F 26C644062E mov byte ptr es:[si+06], 2E ; .
|
||
:0007.0234 26C6440749 mov byte ptr es:[si+07], 49 ;I
|
||
:0007.0239 26C644084E mov byte ptr es:[si+08], 4E ;N
|
||
:0007.023E 26C6440949 mov byte ptr es:[si+09], 49 ;I
|
||
:0007.0243 26C6440A00 mov byte ptr es:[si+0A], 00 ;<00> (end of string)
|
||
|
||
:0007.0248 5E pop si
|
||
:0007.0249 5F pop di
|
||
:0007.024A C9 leave
|
||
:0007.024B CB retf
|
||
|
||
---------------------------------------------------------------------------
|
||
|
||
to me this looks like an easy section to defeat - this because the full
|
||
filename is here, and because it is in a standard string format
|
||
terminating in hex zero (00) a.k.a.: NULL
|
||
|
||
as with programs with unencrypted passwords (yes even some programs
|
||
you may use.. like X-WING have no encryption whatsoever - just try
|
||
scanning FRONTEND.OVL for DANTOOINE with a hex editor, and all the
|
||
passwords are sitting there for you to zero-out)
|
||
|
||
in other words, why bother disabling the function that calls this
|
||
data when you can simply change each character in SYSTEM.INI to a
|
||
hex zero
|
||
|
||
i did and just as i suspected, out of the three places that are
|
||
causing us hassles, SYSTEM.INI, WLCHECK.SWL, and the registry (REG.DAT)
|
||
I no longer have to deal with one of them
|
||
|
||
just run it, you will see: no more added line in system.ini
|
||
|
||
NOW FOR THE OTHER WAY:
|
||
(This one is more useful for a cracker point of view since good
|
||
protections tend to be smarter than letting you view filenames
|
||
like we saw above)
|
||
|
||
This is where we go back to the WRITEPRIVATEPROFILESTRING function
|
||
and check it out.
|
||
|
||
A text search of the dead listing reveals quickly:
|
||
|
||
:0011.0535 90 nop
|
||
:0011.0536 C8760000 enter 0076, 00
|
||
:0011.053A 57 push di
|
||
:0011.053B 56 push si
|
||
:0011.053C 8B7606 mov si, [bp+06]
|
||
:0011.053F 33C0 xor ax, ax
|
||
:0011.0541 B93200 mov cx, 0032
|
||
:0011.0544 8D7E8A lea di, [bp-76]
|
||
.
|
||
.
|
||
.
|
||
|
||
:0011.0584 16 push ss
|
||
:0011.0585 50 push ax
|
||
:0011.0586 9AFFFF0000 call KERNEL.WRITEPRIVATEPROFILESTRING
|
||
:0011.058B 33C0 xor ax, ax
|
||
:0011.058D 5E pop si
|
||
:0011.058E 5F pop di
|
||
:0011.058F C9 leave
|
||
:0011.0590 CB retf
|
||
|
||
notice the end of the function and how it exits...
|
||
|
||
5E POP SI
|
||
5F POP DI
|
||
C9 LEAVE
|
||
CB RETF
|
||
|
||
In order to give the function a little meat to play with but still
|
||
return early, lets insert this code right at the start of the function,
|
||
right after push si.
|
||
|
||
:0011.0536 C8760000 enter 0076, 00
|
||
:0011.053A 57 push di
|
||
:0011.053B 56 push si
|
||
:0011.053C 5E pop si
|
||
:0011.053D 5F pop di
|
||
:0011.053E C9 leave
|
||
:0011.053F CB retf
|
||
|
||
and it really works out, the function gets called, it starts, quits,
|
||
and returns... veni, vidi, crakki.
|
||
|
||
a quick hex edit of the dll to alter this..
|
||
searching for a good string to replace, we get 2 occurrances of:
|
||
|
||
8b760633c0b93200
|
||
|
||
They are GETPRIVATEPROFILESTRING and WRITEPRIVATEPROFILESTRING respectively.
|
||
Go ahead and do the same damage that you did above to both of them. You will notice that
|
||
they are very similar functions, with exactly the same method of beginning
|
||
and ending.
|
||
|
||
so we can change both occurrances toto:
|
||
5e5fc9cbc0b93200
|
||
|
||
NOTE:
|
||
This patch takes care of the system.ini change, so no need to do a
|
||
zero-out of the file.
|
||
It didnt do any good for the .swl file however, because does some
|
||
other method of storing it's data.
|
||
**********************************************
|
||
Here is a little clue in how to find the other filenames that may be
|
||
hidden in the file.
|
||
|
||
From the SYSTEM.INI example, which has a period (hex 2E) and a file
|
||
extension, i knew to look for ", 2E" (COMMA SPACE 2E) in the text
|
||
editor while reading kslhooks.alf
|
||
i decided to give it another whirl and see if there were any other
|
||
surprises
|
||
|
||
Just looking for 2E will work, but you will find many occurrances of
|
||
it in hex data, so it is best to try to differentiate it as much as
|
||
possible for sanity reasons.
|
||
|
||
Apparently it bears fruit...
|
||
--------------------------------------------------------------------------
|
||
Here is the first block of code i landed in:
|
||
--------------------------------------------------------------------------
|
||
:0003.00B0 F3 repz
|
||
:0003.00B1 A5 movsw
|
||
:0003.00B2 13C9 adc cx, cx
|
||
:0003.00B4 F3 repz
|
||
:0003.00B5 A4 movsb
|
||
:0003.00B6 1F pop ds
|
||
:0003.00B7 39460A cmp [bp+0A], ax COMPARE AND JUMP...
|
||
:0003.00BA 7516 jne 00D2
|
||
|
||
:0003.00BC C646FA2E mov byte ptr [bp-06], 2E ; . <----- A .SWL FILENAME EXTENSION
|
||
:0003.00C0 C646FB53 mov byte ptr [bp-05], 53 ;S
|
||
:0003.00C4 C646FC57 mov byte ptr [bp-04], 57 ;W
|
||
:0003.00C8 C646FD4C mov byte ptr [bp-03], 4C ;L
|
||
:0003.00CC 8846FE mov [bp-02], al
|
||
:0003.00CF EB0E jmp 00DF
|
||
|
||
:0003.00D1 90 nop
|
||
:0003.00D2 8D7EFA lea di, [bp-06]
|
||
|
||
* Possible StringData Ref from Data Seg 013 ->".LIC" <---- A NEW FILENAME EXTENSION ".LIC"
|
||
|
|
||
:0003.00D5 BE1800 mov si, 0018
|
||
|
||
--------------------------------------------------------------------------
|
||
what it looks like to me is that WHEN registered, the
|
||
.SWL file extension is replaced by a .LIC file extension
|
||
|
||
though changing the name of the SWL file to LIC
|
||
does not seem to have any beneficial result at this time
|
||
|
||
it may once the other file checks have been disabled
|
||
regardless, it is apparent that there is a file with a .LIC
|
||
extension that gets created upon successfully registering
|
||
this software
|
||
--------------------------------------------------------------------------
|
||
note that because there appears only once a .SWL reference in
|
||
the KSLHOOKS.DLL, my guess is that if i hex-zero the .SWL like i
|
||
did the SYSTEM.INI reference, it would not matter because the file
|
||
write command and file read command apparently use the same
|
||
string for their data. in other words, changing .SWL to anything,
|
||
the file would just have a different name.
|
||
|
||
testing this out, i found that i was correct. hexing out .SWL with
|
||
zeroes resulted in a file in my windows directory called WLCHECK
|
||
with no extension, rather than .SWL (sometimes it would be nice if
|
||
my theories wouldnt be quite so correct)
|
||
|
||
so we are at least in the ballpark, but no real improvements yet.
|
||
|
||
It is still going to take more looking to do anything with this yet
|
||
|
||
----------------------------------------------------------
|
||
|
||
Now let's try for the registry...
|
||
Scan the file for REG, and you will inveitable find quite a few
|
||
registry commands. which are registry key edit functions.
|
||
|
||
|
||
:0011.033A C8300100 enter 0130, 00
|
||
:0011.033E 57 push di
|
||
:0011.033F 56 push si
|
||
|
||
:0011.0340 8B5E06 mov bx, [bp+06]
|
||
:0011.0343 8B4E08 mov cx, [bp+08]
|
||
:0011.0346 81C32D01 add bx, 012D
|
||
:0011.034A 1E push ds
|
||
:0011.034B 8BFB mov di, bx
|
||
.
|
||
.
|
||
:0011.037D 9AFFFF0000 call SHELL.REGCREATEKEY
|
||
.
|
||
.
|
||
and it ends JUST LIKE the previoous functions
|
||
with a:
|
||
|
||
5E POP SI
|
||
5F POP DI
|
||
C9 LEAVE
|
||
CB RETF
|
||
|
||
so we just hexedit the changes...
|
||
|
||
2 occurrances of:
|
||
010057568b5e068b
|
||
|
||
(regopenkey and regcreatekey respectively - feel free to
|
||
look for yourself in the dead listing)
|
||
|
||
it is just fine to change both to:
|
||
010057565e5fc9cb
|
||
|
||
and just like in the case of the writeprivateprofilestring,
|
||
we have cracked the registry.
|
||
|
||
NOW -
|
||
|
||
2 out of 3 of the hoops have been jumped
|
||
Now it is time to test the .SWL file and afterwards we will
|
||
deal with the NAG feature itself.
|
||
|
||
Here is where i get curious to see the differences in the
|
||
before and after... i want to see exactly what i have left
|
||
to conquer, and the resultant file differences in wlcheck.swl
|
||
BEFORE the 21 day date expires, and AFTER it expires.
|
||
|
||
I wrote a program a while back to datecrack stuff like this -
|
||
but as we already know, this program is a little smarter than
|
||
the average 'check today's date' type of protection.
|
||
|
||
The way my program (cdate.exe) works is relatively simple:
|
||
it alters the system date upon program entry, and changes it
|
||
back to normal. The interesting thing about this is that it
|
||
allows future dates to be set as well as past ones since i
|
||
didnt care to put a block on WHICH dates could be set with it.
|
||
|
||
Note that this one works fine past midnight because it has a
|
||
calendar built in, so if you are to write one yourself
|
||
remember that when midnight comes and your calendar strangely
|
||
goes off by a day every time you pass midnight while using a
|
||
datecracked program.
|
||
|
||
CDATE USAGE:
|
||
cdate mm dd yyyy
|
||
|
||
So, since all that is left to crack is the swl file, i can
|
||
delete it with my handy RM command - which like all of
|
||
my little unix tools strips all attribs from the file
|
||
(ignores them really)...
|
||
|
||
rm c:\windows\wlcheck.swl
|
||
|
||
...And i can run wlcheck.exe again (this time with false
|
||
future date)
|
||
|
||
cdate wlcheck 9 9 1999 (it's now 1997 so this works fine)
|
||
|
||
note the result: expired program!!!
|
||
|
||
exit wlcheck and try running it normally (no funky date this time)
|
||
guess what... STILL expired.
|
||
that means it records not only date info, but EXPIRED info as
|
||
well, exactely as +ORC said.
|
||
|
||
Do the little effect of RM C:\WINDOWS\WLCHECK.SWL again and run
|
||
wlcheck
|
||
|
||
It isn't expired now
|
||
|
||
That means that the ONLY recorder for 'expired software' is in that
|
||
file... doing a little dos file compare between a copy of the swl
|
||
file before, and after (the BAD one), here are my results
|
||
again i used CP.EXE to copy the swl file since it strips attribs
|
||
and i dont have to worry about them now.
|
||
-----------------------------------------------------------
|
||
C:\WLCHECK\> FC WLCHECK.SWL WLCHECK.BAD
|
||
|
||
Comparing files wlcheck.swl and wlcheck.bad shows them to be quite
|
||
different (you can try this for yourself if you like)
|
||
------------------------------------------------------------
|
||
|
||
There are a few ways we could go about this.
|
||
We could either try to make it so the 21 day period cannot
|
||
expire, or remove the command that records the info to the
|
||
file. In all honesty, we will probably have to do both in
|
||
order to deprotect it completely.
|
||
**********************************************************
|
||
|
||
maybe we should do a little windows directory listing just
|
||
to see if there are any more surprises
|
||
|
||
dir /a c:\windows\wlc*
|
||
|
||
what do we see:
|
||
wlcheck.ini, wlcheck.ord, and wlcheck.swl
|
||
|
||
that is all fine, no more surprises yet (if you didnt expect
|
||
a wlcheck.ini file: WHY NOT?
|
||
|
||
if you edit wlcheck.ord, it is just your order blank from when
|
||
you filled out the wlcheck form nothing impressive, but at least
|
||
it has the product serial number listed at the bottom - sometimes
|
||
handy
|
||
*********************************************************
|
||
I cannot seem to find any more windows file commands, so i decided
|
||
to see if they had included in the dll their own file access commands
|
||
that means... look for int21
|
||
|
||
(there are a TON of int21 calls in this program! - and to think
|
||
that some people think that dos cracking is dead...)
|
||
|
||
these are the KSL file i/o and system functions, with direct
|
||
access to hardware through DOS.
|
||
|
||
upon searching for int21 calls - specifically int21 with ah=2a
|
||
b42a (mov ah, 2a) = get system date
|
||
|
||
I found 3 instances
|
||
|
||
2 occurrances of:
|
||
008C D89045558BEC1E8ED856 B42A
|
||
|
||
changed to
|
||
00CB D89045558BEC1E8ED856 B42A
|
||
|
||
(CB = retf)
|
||
|
||
an interesting thing happens, on the first run, it works fine,
|
||
writes the .swl file, and goes on it's merry way
|
||
|
||
on any subsequent runs, it says expired
|
||
that tells me that the changes i made, set the date to a nothing value
|
||
in the wlcheck.swl file
|
||
|
||
in easier to understand lingo, i hit the nail on the head.
|
||
i found the date checker - in old int21 style.
|
||
|
||
if you wish to play with this more yourself, go ahead. by all means.
|
||
|
||
i still havent worried with the 3rd date check, which is the hex string:
|
||
9045558BEC1E8ED856 B42A
|
||
|
||
About this time, I begin to think - maybe there is a better way...
|
||
(I have gotten a bit tired of playing around, and I want to fully crack it)
|
||
----------------------------------------------------------
|
||
Now we get down to the nitty gritty.
|
||
|
||
The above is necessary work.. handy for other protection schemes.
|
||
It is, however, not incredibly useful here in this one. If you run wlcheck
|
||
or one of the other executables, you will notice something frustrating:
|
||
you cannot print. Only registered users get that option. That means we
|
||
either have to crack more functions, like above, or just go ahead and
|
||
register the thing and get it over with.
|
||
|
||
So we shall.
|
||
------------------------------------------------------------
|
||
Time to go into the WLCCOMM.DLL...
|
||
|
||
remember how i said +ORC mentioned 2 occurrances of 15 that were interesting?
|
||
i search for " 15" (a space in front so it didn't get every 15 in the
|
||
wsccomm file listing)
|
||
|
||
i didnt find what i wanted other than the original one, so i looked for 0015
|
||
and i found one that looked promising..
|
||
|
||
:0001.3F5D C786E7FB1500 mov word ptr [bp-0419], 0015
|
||
:0001.3F63 B001 mov al, 01
|
||
:0001.3F65 8886CEFB mov [bp+FBCE], al
|
||
:0001.3F69 8886E9FB mov [bp+FBE9], al
|
||
:0001.3F6D 8886EAFB mov [bp+FBEA], al
|
||
:0001.3F71 C68648FC15 mov byte ptr [bp-03B8], 15
|
||
|
||
(I must remember to check for bgoth from now on)
|
||
|
||
just below all that, i saw something strange...
|
||
several 'set value to 1' - in other words, it looks like we see a bunch
|
||
of flags
|
||
|
||
changing the below statement to 00 returns this error: this is an old
|
||
version (and quits) - not extremely useful, but a green light shall we say.
|
||
|
||
:0001.3F63 B001 mov al, 01
|
||
:0001.3F65 8886CEFB mov [bp-0432], al
|
||
:0001.3F69 8886E9FB mov [bp-0417], al
|
||
:0001.3F6D 8886EAFB mov [bp-0416], al
|
||
|
||
going further down...
|
||
we have a comparison (in the form of an 'OR')
|
||
|
||
:0001.3F86 9AFFFF0000 call KSLHOOKS.Ord{0038h}
|
||
|
||
:0001.3F8B 8BF8 mov di, ax <--- backing up ax
|
||
|
||
This program apparently wants to save whatever came out of the strange
|
||
kslhooks call above before making this compare...
|
||
|
||
:0001.3F8D 0BF8 or di, ax <--- COMPARE BOTH
|
||
|
||
Note the special nature of this compare.. since both values are
|
||
the same, it is basically the same as saying if ax is zero, it
|
||
stays zero, if it is not, it becomes a 1 since the result of any
|
||
compare is stored in ax
|
||
|
||
di still has the saved value in it however... for future use by the program
|
||
as you will see below, it is flag containing error codes
|
||
|
||
:0001.3F8F 750F jne 3FA0 <--- FIRST JUMP IF NONZERO
|
||
|
||
This smells to me like a 'beggar off jerk'...
|
||
(i already know what i have here, do you?)
|
||
|
||
:0001.3F91 B80100 mov ax, 0001 <--- SET A FLAG?!?
|
||
|
||
This just gets better and better, but i still look before i try anything,
|
||
I don't want to jump the gun and assume anything without proof...
|
||
|
||
:0001.3F94 C45E06 les bx, [bp+06]
|
||
:0001.3F97 268987A400 mov es:[bx+00A4], ax
|
||
|
||
:0001.3F9C E9D600 jmp 4075 <--- 2nd JMP
|
||
:0001.3F9F 90 nop
|
||
|
||
HERE is where jmp 1 takes me...
|
||
|
||
:0001.3FA0 8B760A mov si, [bp+0A]
|
||
:0001.3FA3 83FF0A cmp di, 000A
|
||
:0001.3FA6 7510 jne 3FB8
|
||
:0001.3FA8 56 push si
|
||
:0001.3FA9 1E push ds
|
||
|
||
* StringData Ref from Data Seg 002 ->"An upgrade is required.
|
||
Continuing as shareware only."
|
||
|
|
||
:0001.3FAA 68CF06 push 06CF
|
||
|
||
AND WOULD YOU LOOK AT THAT EVIL MESSAGE!
|
||
it is very clear that the beggar off guess was correct...
|
||
|
||
just go down a few lines and you will see ALL SORTS of nasty
|
||
error messages, including the shareware expiry message we get
|
||
when we try to run after 21 days (note that it would have been
|
||
much easier had we scanned the text for keywords like shareware,
|
||
reg, exp, or others we could imagine... but that would not work
|
||
with all programs, and we are here to learn how to crack ALSO
|
||
protections that do not do us the favour of carrying their doom
|
||
inside... therefore the approach above is much more solide :-)
|
||
|
||
|
||
paging down a little we see this at the location JMP 2 sent us at 4075...
|
||
|
||
:0001.4075 1F pop ds
|
||
:0001.4076 5E pop si
|
||
:0001.4077 5F pop di
|
||
:0001.4078 C9 leave
|
||
:0001.4079 CA0600 retf 0006
|
||
|
||
it just quits... but if you remember up above, it set a flag before it
|
||
did so!
|
||
|
||
now how do we get it to ignore those nasty error messages and we ALWAYS
|
||
jump to 4075 with the flag set?
|
||
|
||
looking back at our decision code from above:
|
||
|
||
|
||
:0001.3F86 9AFFFF0000 call KSLHOOKS.Ord{0038h}
|
||
|
||
:0001.3F8B 8BF8 mov di, ax
|
||
:0001.3F8D 0BF8 or di, ax
|
||
:0001.3F8F 750F jne 3FA0 <---- evil jump
|
||
|
||
:0001.3F91 B80100 mov ax, 0001
|
||
:0001.3F94 C45E06 les bx, [bp+06]
|
||
:0001.3F97 268987A400 mov es:[bx+00A4], ax
|
||
:0001.3F9C E9D600 jmp 4075 <---- good jump
|
||
|
||
notice the jne? there are quite a few ways of attacking this, but think
|
||
about it, there are a few things that must be done.
|
||
|
||
first, the jne could be changed to a je (or jz) but if we do that, we
|
||
have to WAIT 21 days to be able to use the program, or screw up the date
|
||
at install, or something dumb like that (not a good crack)
|
||
|
||
if AX is set to anything, it is deemed an error by the program and the error
|
||
code is saved in DI. So we need to make sure ax is zero, and it might be
|
||
smart to cover our bases and set di to zero as well (you never know if some
|
||
value had been sitting in it to be confused as an error for our crazy
|
||
program wlcheck to find and complain about)
|
||
|
||
so if we set both to zero, then the jne CANNOT ever jump out and we stay long
|
||
enough for us to set the AX flag and go along happily.
|
||
|
||
it just so happens that there is a simple way to set any variable to zero
|
||
(if you are familiar with assembly, ignore this, i am putting this in
|
||
here for those who havent become as familiar with it as the rest of us -
|
||
this is a tutorial after all isnt it?)
|
||
|
||
xor ax, ax <--- sets ax to zero
|
||
xor di, di <--- sets di to zero
|
||
|
||
if you are lazy like i am, you can search your dead listing for both
|
||
(the listing is so large, that you can probably find examples of many byte
|
||
values that you need)
|
||
|
||
it turns out that the values are:
|
||
|
||
33 C0 xor ax, ax
|
||
33 FF xor di, di
|
||
|
||
and here's how our code will look:
|
||
|
||
|
||
:0001.3F86 9AFFFF0000 call KSLHOOKS.Ord{0038h}
|
||
|
||
:0001.3F8B 33C0 xor ax, ax
|
||
:0001.3F8D 33FF xor di, di
|
||
|
||
:0001.3F8F 750F jne 3FA0
|
||
|
||
:0001.3F91 B80100 mov ax, 0001
|
||
:0001.3F94 C45E06 les bx, [bp+06]
|
||
:0001.3F97 268987A400 mov es:[bx+00A4], ax
|
||
:0001.3F9C E9D600 jmp 4075
|
||
|
||
|
||
simply enough, now we just need to make the changes in the wlccomm.dll
|
||
|
||
*****************************************************
|
||
|
||
Crack for 16-bit wlcheck by +gthorne of the +HCU:
|
||
|
||
pop into your favorite hex editor and load WLCCOMM.DLL
|
||
(File Size: 46,960 bytes)
|
||
|
||
search for byte pattern:
|
||
8BF80BF8750F
|
||
|
||
replace with:
|
||
33C033FF750F
|
||
|
||
and run it...
|
||
it is registered!
|
||
----------------------------------------------------------
|
||
Note for showoffs:
|
||
|
||
If you wish it to say that it is registered to you, go to
|
||
the about box, and run the "registration" part of the program
|
||
BEFORE you crack it, entering data in the order form as you
|
||
want it to be registered.
|
||
|
||
The target stores this info in the windows directory, in
|
||
the file: WLCHECK.ORD.
|
||
After cracking, that info is displayed proudly in the about box.
|
||
*****************************************************
|
||
|
||
None of the many changes listed at the beginning of this
|
||
section are necessary now, not since we have a good, clean
|
||
crack.
|
||
Don't disregard the work though, some programs I've seen are
|
||
defeatable with the kind of work done before the register flag
|
||
was found.
|
||
|
||
If this were a program with no flag to register, it would have
|
||
REQUIRED all that work anyway, and then some.
|
||
|
||
|
||
********************************************
|
||
wlcheck for windows 95
|
||
********************************************
|
||
|
||
Ok, building on my fellow +cracker's good work it was
|
||
pretty easy to defeat the Win'95 protection, which follows
|
||
the same lines as the 16 bit one above... I lost
|
||
some time on a stupid beta version of wlcheck for win 95,
|
||
that I had inside my collection though... how stupid.
|
||
This will teach me to ALWAYS work methodically.
|
||
Therefore:
|
||
FIRST OF ALL
|
||
perform an archie or ftp search for wlck95, you'll find a
|
||
whole bunch of servers carrying it, choose a ftp-server
|
||
near you and get it ftpmailed to you or download it (as
|
||
you prefer).
|
||
You'll soon find all the relevant data:
|
||
WLCHK955.ZIP 213.156 bytes
|
||
|
||
SECOND
|
||
You have it, unzip it and examine it:
|
||
FILE_ID DIZ 438 23/08/96 5:10 FILE_ID.DIZ
|
||
WLCHK95 EXE 70.656 23/08/96 5:10 WLCHK95.EXE
|
||
KSLHKS95 DLL 52.224 21/08/96 1:00 KSLHKS95.DLL
|
||
WMCHK95 EXE 63.488 23/08/96 5:10 WMCHK95.EXE
|
||
WLCHK95 HLP 33.759 23/08/96 5:10 WLCHK95.HLP
|
||
WFCHK95 EXE 77.824 23/08/96 5:10 WFCHK95.EXE
|
||
WMCHK95 HLP 32.463 23/08/96 5:10 WMCHK95.HLP
|
||
WFCHK95 HLP 29.696 23/08/96 5:10 WFCHK95.HLP
|
||
README TXT 8.689 23/08/96 5:10 README.TXT
|
||
WLCCOM95 DLL 73.216 26/03/97 20:11 WLCCOM95.DLL
|
||
|
||
(ignore the date of the last dll, that's just because I tampered
|
||
with it yesterday).
|
||
|
||
THIRD
|
||
Using what we have learned (quite a lot) let's work on
|
||
wlccom95.dll: here the relevant part of the dead listing:
|
||
|
||
* Referenced by a Jump at Address:|:1C005B50(C)
|
||
|
|
||
:1C005B76 C685C3FBFFFF05 mov byte ptr [ebp+FFFFFBC3], 05
|
||
:1C005B7D C685C4FBFFFF01 mov byte ptr [ebp+FFFFFBC4], 01
|
||
:1C005B84 66C785DDFBFFFF1500 mov word ptr [ebp+FFFFFBDD], 0015
|
||
:1C005B8D C685DFFBFFFF01 mov byte ptr [ebp+FFFFFBDF], 01
|
||
:1C005B94 C685E0FBFFFF01 mov byte ptr [ebp+FFFFFBE0], 01
|
||
:1C005B9B C6853EFCFFFF15 mov byte ptr [ebp+FFFFFC3E], 15
|
||
:1C005BA2 8B450C mov eax, [ebp+0C]
|
||
:1C005BA5 66C780A80000000000 mov word ptr [ebx+000000A8], 0000
|
||
:1C005BAE 8D8598FAFFFF lea eax, [ebp+FFFFFA98]
|
||
:1C005BB4 50 push eax
|
||
|
||
* Reference To: kslhks95._KslHookProc1@4, Ord:0000h
|
||
|
|
||
:1C005BB5 E872420000 Call 1C009E2C
|
||
:1C005BBA 66894598 mov [ebp-68], ax
|
||
:1C005BBE 0FBF4598 movsx word ptr eax, [ebp-68]
|
||
:1C005BC2 85C0 test eax, eax
|
||
:1C005BC4 0F8516000000 jne 1C005BE0
|
||
:1C005BCA 8B450C mov eax, [ebp+0C]
|
||
:1C005BCD 66C780A80000000100 mov word ptr [ebx+000000A8], 0001
|
||
:1C005BD6 B801000000 mov eax, 00000001
|
||
:1C005BDB E946010000 jmp 1C005D26
|
||
|
||
* Referenced by a Jump at Address: |:1C005BC4(C)
|
||
|
|
||
:1C005BE0 0FBF4598 movsx word ptr eax, [ebp-68]
|
||
:1C005BE4 83F80A cmp eax, 0000000A
|
||
:1C005BE7 0F8516000000 jne 1C005C03
|
||
:1C005BED 6A40 push 00000040
|
||
|
||
* Possible StringData Ref from Data Obj ->"License Expired"
|
||
|
|
||
:1C005BEF 6828E8001C push 1C00E828
|
||
|
||
* Possible StringData Ref from Data Obj ->"An upgrade is required. Continuing "
|
||
->"as shareware only."
|
||
|
|
||
:1C005BF4 6838E8001C push 1C00E838
|
||
:1C005BF9 8B4508 mov eax, [ebp+08]
|
||
:1C005BFC 50 push eax
|
||
|
||
* Reference To: USER32.MessageBoxA, Ord:0188h
|
||
|
|
||
:1C005BFD FF151C04011C Call dword ptr [1C01041C]
|
||
|
||
* Referenced by a Jump at Address:|:1C005BE7(C)
|
||
|
|
||
:1C005C03 0FBF4598 movsx word ptr eax, [ebp-68]
|
||
:1C005C07 83F807 cmp eax, 00000007
|
||
:1C005C0A 0F8516000000 jne 1C005C26
|
||
:1C005C10 6A40 push 00000040
|
||
|
||
* Possible StringData Ref from Data Obj ->"License Violated"
|
||
|
|
||
:1C005C12 6870E8001C push 1C00E870
|
||
|
||
* Possible StringData Ref from Data Obj ->"The license file has been changed. "
|
||
->"Continuing as shareware only."
|
||
|
|
||
:1C005C17 6884E8001C push 1C00E884
|
||
:1C005C1C 8B4508 mov eax, [ebp+08]
|
||
:1C005C1F 50 push eax
|
||
|
||
* Reference To: USER32.MessageBoxA, Ord:0188h
|
||
|
|
||
:1C005C20 FF151C04011C Call dword ptr [1C01041C]
|
||
|
||
* Referenced by a Jump at Address:|:1C005C0A(C)
|
||
|
|
||
:1C005C26 0FBF4598 movsx word ptr eax, [ebp-68]
|
||
:1C005C2A 83F808 cmp eax, 00000008
|
||
:1C005C2D 0F8516000000 jne 1C005C49
|
||
:1C005C33 6A40 push 00000040
|
||
|
||
* Possible StringData Ref from Data Obj ->"License Violated"
|
||
|
|
||
:1C005C35 68C8E8001C push 1C00E8C8
|
||
|
||
* Possible StringData Ref from Data Obj ->"This seems to be an unlicensed "
|
||
->"copy. Continuing as shareware "
|
||
->"only."
|
||
|
|
||
:1C005C3A 68DCE8001C push 1C00E8DC
|
||
:1C005C3F 8B4508 mov eax, [ebp+08]
|
||
:1C005C42 50 push eax
|
||
|
||
* Reference To: USER32.MessageBoxA, Ord:0188h
|
||
|
|
||
:1C005C43 FF151C04011C Call dword ptr [1C01041C]
|
||
|
||
* Referenced by a Jump at Address:|:1C005C2D(C)
|
||
|
|
||
:1C005C49 8D8598FAFFFF lea eax, [ebp+FFFFFA98]
|
||
:1C005C4F 50 push eax
|
||
|
||
* Reference To: kslhks95._KslHookProc2@4, Ord:0001h
|
||
|
|
||
:1C005C50 E8D1410000 Call 1C009E26
|
||
:1C005C55 66894598 mov [ebp-68], ax
|
||
:1C005C59 33C0 xor eax, eax
|
||
:1C005C5B 8A853EFCFFFF mov al , [ebp+FFFFFC3E]
|
||
:1C005C61 83F80D cmp eax, 0000000D
|
||
:1C005C64 0F8536000000 jne 1C005CA0
|
||
|
||
* Possible StringData Ref from Data Obj ->"Link Check evaluation license "
|
||
->"has expired."
|
||
|
|
||
:1C005C6A 6820E9001C push 1C00E920
|
||
:1C005C6F 8D459C lea eax, [ebp-64]
|
||
:1C005C72 50 push eax
|
||
:1C005C73 E871030000 call 1C005FE9
|
||
:1C005C78 83C408 add esp, 00000008
|
||
:1C005C7B 6A10 push 00000010
|
||
|
||
* Possible StringData Ref from Data Obj ->"License Expiry"
|
||
|
|
||
:1C005C7D 684CE9001C push 1C00E94C
|
||
:1C005C82 8D459C lea eax, [ebp-64]
|
||
:1C005C85 50 push eax
|
||
:1C005C86 8B4508 mov eax, [ebp+08]
|
||
:1C005C89 50 push eax
|
||
|
||
* Reference To: USER32.MessageBoxA, Ord:0188h
|
||
|
|
||
:1C005C8A FF151C04011C Call dword ptr [1C01041C]
|
||
:1C005C90 8B450C mov eax, [ebp+0C]
|
||
:1C005C93 50 push eax
|
||
:1C005C94 E857E3FFFF call 1C003FF0
|
||
:1C005C99 33C0 xor eax, eax
|
||
:1C005C9B E986000000 jmp 1C005D26
|
||
|
||
* Referenced by a Jump at Address:|:1C005C64(C)
|
||
|
|
||
:1C005CA0 0FBF4598 movsx word ptr eax, [ebp-68]
|
||
:1C005CA4 83F804 cmp eax, 00000004
|
||
:1C005CA7 0F8536000000 jne 1C005CE3
|
||
|
||
* Possible StringData Ref from Data Obj ->"This is an old version,"
|
||
|
|
||
:1C005CAD 685CE9001C push 1C00E95C
|
||
:1C005CB2 8D459C lea eax, [ebp-64]
|
||
:1C005CB5 50 push eax
|
||
:1C005CB6 E82E030000 call 1C005FE9
|
||
:1C005CBB 83C408 add esp, 00000008
|
||
:1C005CBE 6A10 push 00000010
|
||
|
||
* Possible StringData Ref from Data Obj ->"License Violation"
|
||
|
|
||
:1C005CC0 6874E9001C push 1C00E974
|
||
:1C005CC5 8D459C lea eax, [ebp-64]
|
||
:1C005CC8 50 push eax
|
||
:1C005CC9 8B4508 mov eax, [ebp+08]
|
||
:1C005CCC 50 push eax
|
||
|
||
* Reference To: USER32.MessageBoxA, Ord:0188h
|
||
|
|
||
:1C005CCD FF151C04011C Call dword ptr [1C01041C]
|
||
:1C005CD3 8B450C mov eax, [ebp+0C]
|
||
:1C005CD6 50 push eax
|
||
:1C005CD7 E814E3FFFF call 1C003FF0
|
||
:1C005CDC 33C0 xor eax, eax
|
||
:1C005CDE E943000000 jmp 1C005D26
|
||
|
||
* Referenced by a Jump at Address:|:1C005CA7(C)
|
||
|
|
||
:1C005CE3 0FBF4598 movsx word ptr eax, [ebp-68]
|
||
:1C005CE7 85C0 test eax, eax
|
||
:1C005CE9 0F8D2D000000 jnl 1C005D1C
|
||
|
||
* Possible StringData Ref from Data Obj ->"An unexpected error has occurred."
|
||
|
|
||
:1C005CEF 6888E9001C push 1C00E988
|
||
:1C005CF4 8D459C lea eax, [ebp-64]
|
||
:1C005CF7 50 push eax
|
||
:1C005CF8 E8EC020000 call 1C005FE9
|
||
:1C005CFD 83C408 add esp, 00000008
|
||
:1C005D00 6A10 push 00000010
|
||
|
||
* Possible StringData Ref from Data Obj ->"System Error"
|
||
|
|
||
:1C005D02 68ACE9001C push 1C00E9AC
|
||
:1C005D07 8D459C lea eax, [ebp-64]
|
||
:1C005D0A 50 push eax
|
||
:1C005D0B 8B4508 mov eax, [ebp+08]
|
||
:1C005D0E 50 push eax
|
||
|
||
* Reference To: USER32.MessageBoxA, Ord:0188h
|
||
|
|
||
:1C005D0F FF151C04011C Call dword ptr [1C01041C]
|
||
:1C005D15 33C0 xor eax, eax
|
||
:1C005D17 E90A000000 jmp 1C005D26
|
||
|
||
* Referenced by a Jump at Address:|:1C005CE9(C)
|
||
|
|
||
:1C005D1C B801000000 mov eax, 00000001
|
||
:1C005D21 E900000000 jmp 1C005D26
|
||
|
||
* Referenced by a Jump at Addresses:|:1C005BDB(U),
|
||
:1C005C9B(U), :1C005CDE(U), :1C005D17(U), :1C005D21(U)
|
||
|
|
||
:1C005D26 5F pop edi
|
||
:1C005D27 5E pop esi
|
||
:1C005D28 5B pop ebx
|
||
:1C005D29 C9 leave
|
||
:1C005D2A C20800 ret 0008
|
||
*******************************************
|
||
OK! let's crack...
|
||
Well it's all pretty obvious:
|
||
After having prepared the call with a lot of parameters
|
||
|
||
:1C005B76 C685C3FBFFFF05 mov byte ptr [ebp+FFFFFBC3], 05
|
||
:1C005B7D C685C4FBFFFF01 mov byte ptr [ebp+FFFFFBC4], 01
|
||
:1C005B84 66C785DDFBFFFF1500 mov word ptr [ebp+FFFFFBDD], 0015
|
||
:1C005B8D C685DFFBFFFF01 mov byte ptr [ebp+FFFFFBDF], 01
|
||
:1C005B94 C685E0FBFFFF01 mov byte ptr [ebp+FFFFFBE0], 01
|
||
:1C005B9B C6853EFCFFFF15 mov byte ptr [ebp+FFFFFC3E], 15
|
||
|
||
note the two x15 parameters... that will of course be the 21
|
||
days limit... well, our target calls the kslhks95._KslHookProc1@4
|
||
function with all its params and upon return the 32 bit version
|
||
uses the SAME protection scheme used in the 16 bit one: it has an
|
||
"evil" and a "good" jump:
|
||
|
||
* Reference To: kslhks95._KslHookProc1@4, Ord:0000h
|
||
|
|
||
:1C005BB5 E872420000 Call 1C009E2C
|
||
:1C005BBA 66894598 mov [ebp-68], ax
|
||
:1C005BBE 0FBF4598 movsx word ptr eax, [ebp-68]
|
||
:1C005BC2 85C0 test eax, eax ;is it zero?
|
||
:1C005BC4 0F8516000000 EVIL jne 1C005BE0 ;not 0: bagger off
|
||
:1C005BCA 8B450C mov eax, [ebp+0C]
|
||
:1C005BCD 66C780A80000000100 mov word ptr [ebx+000000A8], 0001 ;OK, guy
|
||
:1C005BD6 B801000000 mov eax, 00000001 ;eat another good flag
|
||
:1C005BDB E946010000 HOLY jmp 1C005D26 ;and be happy for ever
|
||
|
||
if you throw another look at the listing you'll see all the nasty
|
||
messages following the evil jump
|
||
* Referenced by a Jump at Address: |:1C005BC4(C)
|
||
|
|
||
:1C005BE0 0FBF4598 movsx word ptr eax, [ebp-68]
|
||
:1C005BE4 83F80A cmp eax, 0000000A
|
||
|
||
and the subsequent compare eax ARE intersting, they give
|
||
you an exact look upon the inner working of our target:
|
||
here
|
||
eax=A means "License expired"
|
||
eax=7 means "License violated" (changed)
|
||
eax=8 means "License violated" (unlicensed)
|
||
eax=4 means "old version" etcetera...
|
||
as a matter of fact it may well be that the crack we
|
||
made goes crazy after 21 days (it won't if you push
|
||
the date around, we checked) use... in that case it
|
||
will be only a question of "fine tuning" of this crack,
|
||
and you already know where the relevant protection scheme
|
||
dwells... We do not want to wait 21 days just to be
|
||
absolutely sure that the crack works perfectly... so it
|
||
seems, and so it should be... should it have another
|
||
check somewhere (that I do not see now), I promise you
|
||
that you'll find the crack for it in three weeks time,
|
||
but I'm pretty sure you will not need it :-)
|
||
|
||
Well, we learned a lot:
|
||
Time/Disabling protections may vary a lot, but even in
|
||
apparently very complicated schemes (like the wlcheck one),
|
||
wich do tamper with a lot of more or less hidden files,
|
||
there can be a very simple "hollow" point, where you
|
||
can cut mustard with a neat targeted crack... you need to
|
||
understand and to "feel" a little the program, though, and
|
||
I'm now beginning to understand what +ORC means with his
|
||
zen mystique of "feeling" the code.
|
||
So here is the simple crack for wlcheck 32 bits:
|
||
|
||
search for
|
||
|
||
:1C005BC2 85C0 test eax, eax
|
||
:1C005BC4 0F8516000000 jne 1C005BE0
|
||
:1C005BCA 8B450C mov eax, [ebp+0C]
|
||
:1C005BCD 66C780A80000000100 mov word ptr [ebx+000000A8], 0001
|
||
|
||
85C00F8516000000
|
||
and at the third occurrence of it
|
||
(well, if you want -instead of searching the third occurrence of that
|
||
string- to type a long string... then search directly for the whole set
|
||
85C00F85160000008B450C66C780A80000000100) do as you like, as far as
|
||
you land where you should:
|
||
:1C005BC2 85C0 test eax, eax
|
||
:1C005BC4 0F8516000000 jne 1C005BE0
|
||
it's the time to crack your target! Noop the first 8 bytes out,
|
||
that is from 85C0 until the three subsequent zeros of instruction
|
||
:1C005BC2 ... you may even use the nop=90x instruction like the
|
||
lamers if you fancy... here there is absolutely no checking-protection
|
||
that examine eventual patchings... noop as you like.
|
||
***************************************
|
||
Thinking about it we believe that the aim of this first lesson of
|
||
the "4" series from +ORC was the following: +he found an apparently
|
||
overcomplicated protection only to show us that, hidden behind
|
||
everything, a single neat crack was needed... as the fellow +cracker
|
||
of the 16 bit version observed, +he gave us a single (but decisive)
|
||
hint: he spoke about the second occurrence of the 15x byte, which
|
||
proved decisive -as you already did read- in individuating the
|
||
"hollow" point of our target.
|
||
As this lesson 4.1 was intended as second "+HCU" lesson, we believe
|
||
(and hope) that in finding the neat cracks for the 16 and the 32 bit
|
||
versions of wlcheck (which is a damn useful program in our trade, btw)
|
||
we have accomplished our task.
|
||
Now a question arises:
|
||
Should really all time protections be variations of this scheme?
|
||
(we do not know... we are awaiting the next "4" lesson of +ORC
|
||
like everybody else). In that case there is not a single program
|
||
(now) able to elude us :-)
|
||
Another system: inside win.ini:
|
||
[License]
|
||
Installed=854824551
|
||
Expires=857416551
|
||
LastUsed=854824717
|
||
i.e. calculated in seconds,
|
||
Where 30 days allowance is 857416551 - 854824551 = 2592000
|
||
2592000/30 = 86400 (one day)
|
||
86400/24 = 3600 (one hour)
|
||
3600/60 = 60 (one minute)
|
||
|
||
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 Jimmy Olden 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"
|
||
|
||
+ORC na526164@anon.penet.fi
|
||
|