482 lines
18 KiB
Plaintext
482 lines
18 KiB
Plaintext
![]() |
|
|||
|
odin's_________ _______ ______ _____________
|
|||
|
____\ /____\ /________\ /____| /_____/_______ _________
|
|||
|
/ _____/ _____/ __ ___/ '____/ / | \ _____/___
|
|||
|
/ | \ || | | | \ . \ | | | \__ /
|
|||
|
\_____ \___| \____ |____ \___| \___|____| |_____ |
|
|||
|
|_______/ <hook> `----' |_____/ |______/ |____| |_____|
|
|||
|
tutorial v1.51
|
|||
|
|
|||
|
TOPIC: CRACKING/PATCHING SOFTART'S DESKEY v1.02.010
|
|||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
|
|||
|
|
|||
|
X. TABLE OF CONTENTS
|
|||
|
~~~~~~~~~~~~~~~~~~~~
|
|||
|
1. FOREWARDS
|
|||
|
2. INTRODUCTION
|
|||
|
3. TOOLS USED FOR THIS
|
|||
|
4. THE CRACKING STARTS
|
|||
|
5. MAKING A PATCH
|
|||
|
6. THE URL'S
|
|||
|
|
|||
|
1. FOREWARDS
|
|||
|
~~~~~~~~~~~~
|
|||
|
Welcome. So how come you're interested in reading this tutorial?
|
|||
|
Perhaps you think cracking is cool and seems easy, and that cracking
|
|||
|
is a way to be famous on the internet today. Well, if you think
|
|||
|
like this please stop reading now. Why? Mainly because most crackers
|
|||
|
don't crack because they think it's "cool." and want to be famous.
|
|||
|
Cracking is something they actually do because they think its a great
|
|||
|
thing to spend their precious time on, believe it or not. Most crackers,
|
|||
|
not to say all, also code in one or several computer languages.
|
|||
|
On the other hand if you're very interested in how computers work
|
|||
|
internally, and you like to program in languages like Pascal, C++ and
|
|||
|
Assembler, then I believe this tutorial is worth reading for people
|
|||
|
such as you, and you might even learn something from it.
|
|||
|
If you're the third category, you've been learning cracking for
|
|||
|
some time now and read every little article about cracking you
|
|||
|
can get, then this tutorial also is very good to read. You can always
|
|||
|
learn something that you didn't know before. Even I can learn things
|
|||
|
I didn't know by listening to others and reading various text files.
|
|||
|
|
|||
|
To become a cracker will take several years. And to become a good
|
|||
|
cracker will take even longer. The key to success is practice and, in
|
|||
|
my point of view, learning and listening to other crackers.
|
|||
|
|
|||
|
I'll skip the most things about how SoftICE works because there
|
|||
|
are several good tutorials out about that. One is Exact's SoftICE
|
|||
|
tutorial, very good and recommended reading.
|
|||
|
|
|||
|
|
|||
|
2. INTRODUCTION
|
|||
|
~~~~~~~~~~~~~~~
|
|||
|
This text files purpose is to show and hopefully learn
|
|||
|
you how to patch away a time limit of a program. The program we will
|
|||
|
use is SoftArt's Deskey. It isn't necessary to patch this program
|
|||
|
because you can also enter a registration code in the registry to
|
|||
|
get the program to work fully, but then you have to write a keymaker
|
|||
|
because the code depends on the Windows name and company (the one
|
|||
|
you enter when you installed Windows 95). So we're going to do it
|
|||
|
the lazy way and patch it. There are of course other ways to
|
|||
|
do this crack.
|
|||
|
|
|||
|
3. TOOLS YOU WILL NEED FOR THIS
|
|||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
(1) SoftICE 2.0/3.0, of course, our beloved debugger.
|
|||
|
(2) Ultra Edit or another good hex editor.
|
|||
|
(3) A patch generator, or if you write the patch yourself
|
|||
|
as I do.
|
|||
|
|
|||
|
4. THE CRACKING STARTS
|
|||
|
~~~~~~~~~~~~~~~~~~~~~~
|
|||
|
Ok, let's begin with removing the semicolon from the user32.dll
|
|||
|
and kernel32.dll lines in SOFTICE.DAT if you haven't done so already.
|
|||
|
|
|||
|
Now let's do some detective work, by checking the Deskey help
|
|||
|
file. You'll notice that this program will stop working after
|
|||
|
60 minutes. This limit is what we're going to remove. There
|
|||
|
are a few possible solutions for the programmer to obtain this
|
|||
|
limit. To check which functions the program use, let's test the
|
|||
|
approach Qapla used in his tutorial:
|
|||
|
Start the explorer and press the right mouse button on the
|
|||
|
Deskey exe file. Now choose Quick-View. You'll notice all the
|
|||
|
calls the program uses and which dll's store the code for
|
|||
|
the calls. When you look at them, you'll notice some interesting
|
|||
|
functions.
|
|||
|
|
|||
|
Import Table
|
|||
|
------------
|
|||
|
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
KERNEL32.dll
|
|||
|
Ordinal Function Name
|
|||
|
------- -------------
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
008f FreeLibrary
|
|||
|
0188 MultiByteToWideChar
|
|||
|
011d GetSystemTime <----- Interesting
|
|||
|
00e4 GetLocalTime <----- Interesting
|
|||
|
025d lstrcmpiA
|
|||
|
00ca GetDateFormatA
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
USER32.dll
|
|||
|
Ordinal Function Name
|
|||
|
------- -------------
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
00ec GetDlgItemTextA
|
|||
|
007d DefWindowProcA
|
|||
|
01fe SetTimer <----- Interesting
|
|||
|
01a2 PostMessageA
|
|||
|
0224 TrackPopupMenu
|
|||
|
01b8 RemoveMenu
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
|
|||
|
Ok, as you see I'm interested in 3 different calls. We can try
|
|||
|
to see if the program uses KERNEL32!GetSystemTime(); and
|
|||
|
KERNEL32!GetLocalTime();. Enter SoftICE and put a breakpoint
|
|||
|
on these two. Enable them just when you're about to start
|
|||
|
the program. If you do it before, you risc to break on these
|
|||
|
calls used by another program. So just before you start
|
|||
|
Deskey, enable these. Ok, now you started it and program pops
|
|||
|
up in the traybar. Nothing happens. Oh well, then we can
|
|||
|
exclude these ones. Actually a cracker might have excluded them
|
|||
|
from the beginning and tried some other calls first. Why?
|
|||
|
Probably because a programmer usually uses these calls if the
|
|||
|
program has a 30-day limit, not a 60-minutes one. Ok, now
|
|||
|
we have one left to test, USER32!SetTimer();. Exit Deskey and
|
|||
|
put a breakpoint on SetTimer(); just before you start Deskey.
|
|||
|
Finally, SoftICE detected the use of this function by Deskey.
|
|||
|
Press F11. It should look something like this now:
|
|||
|
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
0137:0040397F 833D1890400000 CMP DWORD PTR [00409018], 00
|
|||
|
0137:00403986 7409 JZ 00403991
|
|||
|
0137:00403988 833D1C90400000 CMP DWORD PTR [0040901C], 00
|
|||
|
0137:0040398F 7421 JZ 004039B2
|
|||
|
0137:00403991 6A00 PUSH 00
|
|||
|
0137:00403993 A128904000 MOV EAX,[00409028]
|
|||
|
0137:00403998 6880EE3600 PUSH 0036EE80
|
|||
|
0137:0040399D 6834120000 PUSH 00001234
|
|||
|
0137:004039A2 50 PUSH EAX
|
|||
|
0137:004039A3 FF158CB44000 CALL [USER32!SetTimerA] <-- you're here
|
|||
|
0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
|
|||
|
0137:004039B0 EB12 JMP 004039C4
|
|||
|
0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
|
|||
|
0137:004039B0 EB09 JMP 004039C4
|
|||
|
0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
|
|||
|
0137:004039B0 EB07 JMP 004039CB
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
|
|||
|
Let's check the SetTimerA function in our we-cant-be-without-it
|
|||
|
API guide:
|
|||
|
|
|||
|
The SetTimer function creates a timer with the specified time-out value.
|
|||
|
|
|||
|
UINT SetTimer(
|
|||
|
HWND hwnd, // handle of window for timer messages
|
|||
|
UINT idTimer, // timer identifier
|
|||
|
UINT uTimeout, // time-out value
|
|||
|
TIMERPROC tmprc // address of timer procedure
|
|||
|
);
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
uTimeout
|
|||
|
Specifies the time-out value, in milliseconds.
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
|
|||
|
Aha, let's check on the code again:
|
|||
|
|
|||
|
0137:00403991 6A00 PUSH 00 <-- tmprc
|
|||
|
0137:00403993 A128904000 MOV EAX,[00409028] <-- pushed later
|
|||
|
0137:00403998 6880EE3600 PUSH 0036EE80 <-- uTimeout
|
|||
|
0137:0040399D 6834120000 PUSH 00001234 <-- idTimer
|
|||
|
0137:004039A2 50 PUSH EAX <-- HWND
|
|||
|
0137:004039A3 FF158CB44000 CALL [USER32!SetTimerA] <-- you're here
|
|||
|
|
|||
|
Hmm, very interesting indeed, let's check the value 0036EE80 in
|
|||
|
the SoftICE debugger:
|
|||
|
|
|||
|
:? 36ee80
|
|||
|
0036EE80 0003600000 "6<><36>"
|
|||
|
|
|||
|
An even and nice value. And if you read further in the API help
|
|||
|
file you'll notice that the uTimeout should be in milliseconds.
|
|||
|
1 second is 1000 milliseconds. Let's do some calculating:
|
|||
|
|
|||
|
3600000/1000=3600 seconds.
|
|||
|
|
|||
|
60 seconds*60 minutes=3600 seconds, which is 1 hour
|
|||
|
|
|||
|
We've found the right one! This call creates a timer which will be
|
|||
|
checked when the program process the WM_TIMER message from Windows.
|
|||
|
The WM_TIMER message is sent when 1 hour has past. Let's check
|
|||
|
the API reference once more:
|
|||
|
|
|||
|
WM_TIMER
|
|||
|
|
|||
|
wTimerID = wParam; // timer identifier
|
|||
|
tmprc = (TIMERPROC *) lParam; // address of timer callback
|
|||
|
|
|||
|
The WM_TIMER message is posted to the installing thread's message
|
|||
|
queue or sent to the appropriate TimerProc callback function after
|
|||
|
each interval specified in the SetTimer function used to install a
|
|||
|
timer.
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
|
|||
|
So now we know where he creates the timer. If you remove this
|
|||
|
SetTimer(); call the WM_TIMER message will never be sent,
|
|||
|
resulting in that the 60 minute limit will be REMOVED!! Let's
|
|||
|
take a look at this example code below:
|
|||
|
|
|||
|
SetTimer(hwnd, idTimer, 0x36EE80, tmprc);
|
|||
|
^-- hex value
|
|||
|
|
|||
|
WM_TIMER: { <-- this structure is reached when
|
|||
|
PostQuitMessage(0); the hex value above reach 0. If
|
|||
|
^-- will exit the program the timer never is set this
|
|||
|
} structure wont be reached.
|
|||
|
|
|||
|
This is very simple to understand, I hope :-).
|
|||
|
So perhaps you think, "hey, let's NOP away the whole structure"
|
|||
|
|
|||
|
(for those of you not familiar with NOP: it means NO OPERATION
|
|||
|
and are very commonly used when patching. The computer will
|
|||
|
do nothing when it executes this instruction.)
|
|||
|
|
|||
|
Nono stop! Don't NOP away the whole call. Well first of all
|
|||
|
a good rule when patching is that, never alter the code more
|
|||
|
then you actually need. It looks nice (who'll notice anyway), and
|
|||
|
it decreases the chance of program crash due to doing something
|
|||
|
stupid. So how should we do instead? Well let's check that code
|
|||
|
once more:
|
|||
|
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
0137:0040397F 833D1890400000 CMP DWORD PTR [00409018], 00
|
|||
|
0137:00403986 7409 JZ 00403991
|
|||
|
0137:00403988 833D1C90400000 CMP DWORD PTR [0040901C], 00
|
|||
|
0137:0040398F 7421 JZ 004039B2
|
|||
|
0137:00403991 6A00 PUSH 00
|
|||
|
0137:00403993 A128904000 MOV EAX,[00409028]
|
|||
|
0137:00403998 6880EE3600 PUSH 0036EE80
|
|||
|
0137:0040399D 6834120000 PUSH 00001234
|
|||
|
0137:004039A2 50 PUSH EAX
|
|||
|
0137:004039A3 FF158CB44000 CALL [USER32!SetTimerA] <-- you're here
|
|||
|
0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
|
|||
|
0137:004039B0 EB12 JMP 004039C4
|
|||
|
0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
|
|||
|
0137:004039B0 EB09 JMP 004039C4
|
|||
|
0137:004039A9 8BBC24AC060000 MOV EDI,[ESP+000006AC]
|
|||
|
0137:004039B0 EB07 JMP 004039CB
|
|||
|
.
|
|||
|
.
|
|||
|
.
|
|||
|
|
|||
|
The CMP (compare) instructions above seems very interesting.
|
|||
|
As you might notice, the one at 00403986 will jump to 00403991
|
|||
|
and start the timer. If you check the JZ at 0040398F it will go
|
|||
|
to 004039B2 and therefor jump over the timer, resulting in
|
|||
|
that there will be no time limit. So to solve this simple
|
|||
|
problem just change the JZ 00403991 at 00403986 to JMP 004039B2
|
|||
|
instead. Like this:
|
|||
|
|
|||
|
0137:00403986 7409 JZ 00403991
|
|||
|
---> to --->
|
|||
|
0137:00403986 EB2A JMP 004039B2
|
|||
|
|
|||
|
Now let's apply the patch to the exe file. Load up your favorite
|
|||
|
hex editor. In this case I'll use Ultra Edit. Now load the exe file.
|
|||
|
Choose search and enter the following bytes: 68 80 EE 36 00.
|
|||
|
So why do we search after these? Well that's very easy. Check the
|
|||
|
code once again:
|
|||
|
|
|||
|
0137:00403993 A128904000 MOV EAX,[00409028]
|
|||
|
0137:00403998 6880EE3600 PUSH 0036EE80 <--- this one
|
|||
|
0137:0040399D 6834120000 PUSH 00001234
|
|||
|
|
|||
|
As you see these bytes stands for the instruction PUSH 0036EE80.
|
|||
|
"Uhu, I don't have those cryptic numbers to the left of my
|
|||
|
instructions!!". Well that's easy to fix. Just write 'code on'
|
|||
|
and you'll see these cryptic numbers, also known as OPerand codes.
|
|||
|
"Why didn't you search 83 3D 18 90 40 00 00 for example?". Well
|
|||
|
that's because I know the ones we searched for only exists one
|
|||
|
time in the exe file. The one mentioned above (83 3D...) exists
|
|||
|
several times, so you cannot actually know which of those to use,
|
|||
|
if you don't check the surrounding bytes that is. Always do
|
|||
|
"search next" so you are sure that that byte combination doesn't
|
|||
|
exist somewhere else in the file.
|
|||
|
|
|||
|
Now let's change the bytes needed. Some bytes above '68 80 EE 36 00'
|
|||
|
you will find '74 09' which is the JZ 00403991 instruction. This
|
|||
|
is the two bytes we want to change. So how do you know which numbers
|
|||
|
to actually change to? That's also easy. In the debugger when you're
|
|||
|
looking at the code just use the 'a' command. Like This:
|
|||
|
|
|||
|
0137:0040397F 833D1890400000 CMP DWORD PTR [00409018], 00
|
|||
|
0137:00403986 7409 JZ 00403991
|
|||
|
0137:00403988 833D1C90400000 CMP DWORD PTR [0040901C], 00
|
|||
|
----------------------------------------^ code window ^ -----
|
|||
|
:a 00403986 JMP 004039B2
|
|||
|
----------------------------------------^ prompt ^-----------
|
|||
|
|
|||
|
This will change the instruction at 00403986 and a new code will
|
|||
|
pop up, EB2A. So this is the code you want to change for the 7409
|
|||
|
one. Remember, that if you use the 'a' command it will not change
|
|||
|
the code permanently, only temporary. That's why we have to use
|
|||
|
a hex editor. So go to the '74 09' bytes and change it to 'EB 2A'.
|
|||
|
Now save the exe file, voila! That's it. Now start the program
|
|||
|
up and test if it works. If SoftICE doesn't break on SetTimer();
|
|||
|
it probably worked. If it does, read this all again :-).
|
|||
|
|
|||
|
One thing has to be said also. If you for example want to change
|
|||
|
a instruction with the opcode 'C1 E1 10' (3 bytes) to a instruction
|
|||
|
that only has a 2 byte opcode, for example '0B D1', you have to NOP
|
|||
|
away the last byte. NOP has the hex value 90.
|
|||
|
Like this:
|
|||
|
|
|||
|
C1 E1 10 becomes ---> 0B D1 90
|
|||
|
|
|||
|
SHL ECX, 10 becomes ---> OR EDX, ECX <- 0B D1
|
|||
|
NOP <- 90
|
|||
|
|
|||
|
As you see I change the F3 to 90 and therefore put the instruction
|
|||
|
NOP there. If you didn't do this the chance of a program crash
|
|||
|
would be 98%.
|
|||
|
|
|||
|
That's all. To patch is very simple, but to find the bytes to
|
|||
|
change is harder. Remember that the byte combination can exist
|
|||
|
somewhere else so check the surrounding bytes.
|
|||
|
|
|||
|
5. MAKING THE PATCH
|
|||
|
~~~~~~~~~~~~~~~~~~~
|
|||
|
Now it's time to make this patch available to the public. To
|
|||
|
write something like "uhu change the bytes at blabla to blabla"
|
|||
|
doesn't look that good, does it? So now it's time to make
|
|||
|
a exe file that changes those bytes asap so the user don't have
|
|||
|
to use Ultra Edit every time. I've included a program in Pascal
|
|||
|
done for this task. There are also several good patch generators.
|
|||
|
One for Windows 95, that I strongly recommend, is Qapla's
|
|||
|
PatchIt '97. It's fast and nice interface (happy now Qapla :-)
|
|||
|
To convert this program to C++ should be easy. You have to know
|
|||
|
one more thing to make a patch, where the bytes are located in
|
|||
|
the file. This is called "offset.", to check the offset just
|
|||
|
go to the bytes you changed, and look at the status bar in Ultra
|
|||
|
Edit, it should say the offset (pos) in hex.
|
|||
|
|
|||
|
I did the patch in Turbo Pascal 7, most would probably do it in
|
|||
|
Asm :). Anyway, here is the patch:
|
|||
|
|
|||
|
----------------------------------------------------------------------
|
|||
|
----------------------------------------------------------------------
|
|||
|
|
|||
|
Program Patcher;
|
|||
|
|
|||
|
Uses Crt;
|
|||
|
|
|||
|
Const offset : Longint = $2D86; { $ means a hex value }
|
|||
|
bytes : Byte = 2;
|
|||
|
len : Longint = 51200; { file length }
|
|||
|
orgbytes : Array[1..2] Of Byte = ($74, $09);
|
|||
|
newbytes : Array[1..2] Of Byte = ($EB, $2A);
|
|||
|
{---------------------------------------------------------}
|
|||
|
filename : String[12] = 'DESKEY.EXE';
|
|||
|
errnof : String[43] = ' ERROR: File DESKEY.EXE was not found.';
|
|||
|
errver : String[36] = ' ERROR: File size is not correct.';
|
|||
|
errpch : String[36] = ' ERROR: File seems to be patched.';
|
|||
|
msgdon : String[21] = ' Patch successful!';
|
|||
|
ask : String[26] = ' Continue anyway? (Y/N)';
|
|||
|
|
|||
|
Procedure message(message : String);
|
|||
|
Begin
|
|||
|
|
|||
|
WriteLn;
|
|||
|
WriteLn(message);
|
|||
|
Halt;
|
|||
|
|
|||
|
End;
|
|||
|
|
|||
|
Procedure patchfile;
|
|||
|
Var fil : File Of Byte;
|
|||
|
teck : Byte;
|
|||
|
n : Byte;
|
|||
|
ch : Char;
|
|||
|
Begin
|
|||
|
|
|||
|
Assign(fil, filename);
|
|||
|
|
|||
|
{$I-}
|
|||
|
Reset(fil);
|
|||
|
{$I+}
|
|||
|
|
|||
|
If (Not(IOResult=0)) Then message(errnof);
|
|||
|
If (Not(FileSize(fil)=len)) Then
|
|||
|
Begin
|
|||
|
|
|||
|
WriteLn;
|
|||
|
WriteLn(errver);
|
|||
|
WriteLn(ask);
|
|||
|
Repeat Until Keypressed;
|
|||
|
|
|||
|
ch:=ReadKey;
|
|||
|
|
|||
|
If Upcase(ch)='N' Then Halt;
|
|||
|
|
|||
|
End;
|
|||
|
|
|||
|
Seek(fil, offset);
|
|||
|
|
|||
|
For n:=1 To bytes Do
|
|||
|
Begin
|
|||
|
|
|||
|
Read(fil, teck);
|
|||
|
If (Not(teck=orgbytes[n])) Then message(errpch);
|
|||
|
|
|||
|
End;
|
|||
|
|
|||
|
Seek(fil, offset);
|
|||
|
For n:=1 To bytes Do Write(fil, newbytes[n]);
|
|||
|
Close(fil);
|
|||
|
|
|||
|
WriteLn;
|
|||
|
WriteLn(msgdon);
|
|||
|
|
|||
|
Halt;
|
|||
|
|
|||
|
End;
|
|||
|
|
|||
|
Begin
|
|||
|
|
|||
|
WriteLn;
|
|||
|
WriteLn(' SoftArts Deskey v1.02.010 Patch');
|
|||
|
WriteLn(' By ODIN / RBS^TFT^PIE in 1997');
|
|||
|
patchfile;
|
|||
|
|
|||
|
End.
|
|||
|
|
|||
|
----------------------------------------------------------------------
|
|||
|
----------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
Some final words. Take some programs and play with patching them
|
|||
|
in various ways. This gives you experience, and hopefully you'll
|
|||
|
become a better cracker.
|
|||
|
|
|||
|
Thanks to Qapla, kOUGER, Hook and Tgunner for help while making this
|
|||
|
tutorial.
|
|||
|
|
|||
|
A special greeting goes to ED!SON.
|
|||
|
|
|||
|
6. THE URL'S
|
|||
|
~~~~~~~~~~~~
|
|||
|
--
|
|||
|
My E-Mail
|
|||
|
cracking@usa.net
|
|||
|
--
|
|||
|
SoftArts Deskey v1.02.010
|
|||
|
http://www.spiresoft.com
|
|||
|
--
|
|||
|
Ultra Edit vX
|
|||
|
http://www.windows95.com/apps/
|
|||
|
--
|