+ORC Tutorials

default


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  3.2
How to crack, hands on, time limits LESSON 4.1  4.2
How to crack, hands on, disk-CDrom access LESSON 5
How to crack, funny tricks LESSON 6
How to crack, intuition and luck LESSON 7
How to crack windows, an approach LESSON 8.1  8.2
How to crack windows, tools of the trade LESSON 9.1  9.2  9.3  9.4
How to crack, advanced cracking LESSON A
How to crack, zen-cracking LESSON B
How to crack, cracking as an art LESSON C.1  C.2  C.3
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‹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

+ORC contents
default