to enter SoftIce, and do a search for the
information
you entered...
s ds:0 lffffffff "string you entered"
Now you've found it, so you place a breakpoint on it...
bpr ds:"start of string" ds:"end of string" rw
And F5, let the program run. SoftIce breaks back in when the string
you
entered is being copied to a new location. Now you place a new
breakpoint,
just like you did above, and press F5 again to return to the program.
The
program runs its course, without ever breaking on your string again!
What happened?! You were in a Windows module. When you wern't
looking, the
main program returned, so your breakpoint was invalid. Just re-load the
program, do the steps above again, and when you get to the second
address of
your string, hold down the F8 (trace) button for a few seconds to let
the
program re-gain control. Now do a new search for your string again, set
a
breakpoint on it, and get ready for the fun stuff!
*** :0043BE63 8A00 mov al , [eax] ***
SoftIce will kick back in at the address CS:0043BE63, where you'll be
retrieving the first byte of your input string, and placing it into EAX
for
processing. Now would be a good time to shut down SoftIce, and load
DNSWorkShop into WDASM for dis-assembly. We used SoftIce to quickly find
where this program begins working on our input string, and it's a good
thing
we did because we got to this sub-routine by an indirect call, which
makes
finding this location in a dead listing very tedious.
But now that we know where to start, a dead listing will work just
fine
for the rest of this lesson. If you'll follow this through, using either
SoftIce or a dead listing, here's what you will find...
Eax is cleared, leaving only the first byte from your string. This
byte is
copied to ECX, then checked to see if it's a number, a letter, or a
symbol.
If your character is not one of the above, (if it's a graphics or
control
character) you get kicked out. If your character is a letter, it's
checked
again to see if it's an upper case letter or a lower case letter.
If it's a... Do this...
------------------------------------------
Upper case letter subtract 37
lower case letter subtract 3D
number subtract 30
symbol change to 3F
control character change to 3E
Now save the result in memory (at [00440030]) for later, get the next
byte in the string, and process it the same way. We'll save the result
of
this second byte as the value of EDI, because we're not using EDI for
anything else right now, and our memory location already has the first
byte
stored in it, and we're about to do some math which will require EAX.
Here's
an exerpt from the original lesson I told you about earlier in this
lesson...
MAIN
mov edi, eax ;store result for use after MULTIPLY
mov eax, 00000040 ;the number to multiply by
call MULTIPLY
MULTIPLY
imul edx, [00440030], 08088405 ;EAX * EDX * "KEY" * 08088405
inc edx ;add "1" just for fun
mov [00440030], edx ;save as next "KEY"
mul edx ;EAX * EDX (low bytes * high bytes)
mov eax, edx ;save the high order double word
ret ;to MAIN
MAIN
xor edi, eax ;finish de-crypting the first byte
mov eax, edi ;save the result
Here, we do a signed multiplication. If SBR is your Second Byte
Result,
and FBR is your First byte result, the equation would look like this:
IMUL 40 * SBR * FBR * 08088405
Just in case our result was too small to get a number into EDX, we'll
add a "1" to EDX to be sure we'll have a "key" to use on the next byte.
Then
save this "high order byte + 1" to use as the next "key" value.
The result of our IMUL leaves the result in EDX:EAX, meaning the
biggest
part of the number is in EDX, and the lesser numbers are placed in EAX.
So
the next step multiplies the large part of the number by the low part of
the number. To put this all in perspective, lets say the result of the
IMUL
instruction turned out to be 3031323334 in hex:
EDX would equal 30
So the next step would multiply 31 * 31323334, which, again, leaves
the
result in EDX:EAX. The low order bits (in EAX) are thrown away as we
move
the high order bits (in EDX) into EAX. Anyone concerned with reversing
this
process might find it difficult without the bytes we throw away.
We now XOR the result of this process against the result we got when
we
processed the second byte of our input registration code. Remember, we
saved
that result in EDI just before we started multiplying.
We'll take the result from above and "fix" it depending on it's value
using the same formula from above, but this time ADDING 30, 37, or 3D to
obtain a number, upper case letter, or lower case letter. (Remember, we
subtracted these same values when we began this process) We also get the
options of comming up equal to 3D, or 3E, (which will pass the "ok"
range
of characters), or getting kicked out if we end up with an invalid
character.
If you had entered a bunch of random characters into the input box, AND
if
you got REAL lucky, the character you MIGHT end up with at this point
MIGHT
be the first letter of your name, which is what we would LIKE to see
here!
If we've made it this far, we get a chance to store our first
de-crypted
byte for future use. Again, here's an excerpt from my original lesson...
STORAGE PROCESS
The de-cryption process is now completed for this byte of our
registration code. The storage process takes the byte we have placed
on the stack, and checks for any errors we may have encountered,such
as
an "out of range" byte, etc. If an error is found, a flag is set and
we're sent to the function which processes error codes and, of
course,
get kicked out of the program.
If all goes well, we get an address to store this byte in memory,
then store this byte. If you follow each byte through it's storage
process, you will notice there are many different places in memory
where these bytes are stored, in a seemingly random pattern. Only
one byte of de-crypted code will be stored at each location, but it
will be stored as a double-word. (Each place in memory will have the
bytes "00 00 00 10" when we arive, and we'll replace the "10" with
our
de-crypted byte, so it might look like "00 00 00 41" if our input
character de-crypted to the letter "A".) This address MIGHT get used
again, overwriting the byte we store there with a new byte, or it
MIGHT
NOT. This is important to note for cracking purposes!
When we get a few bytes packed away in memory, we set up a new
address where we'll create a (doubleword sized) partial string,
adding de-crypted bytes as we get them. We will attatch ONLY the
bytes just de-crypted in the steps above, to the end of this partial
string, so our partial string might look like "Hack" in memory when
we're through with it. Once again, if you follow the process through,
you will find these "partial strings" get copied a few times too. The
"partial string" we leave behind MIGHT get over-written, or it MIGHT
be
left alone for processing later.
Eventualy, we'll get an address where we'll place the entire
de-crypted registration string, which will be used to determine
wether or not we've registered properly. If you view the memory
location, it might look like "Hackmore Readrite - 1234", The string
YOU
get will, of course, depend on the input you provide. If you entered
your name as I suggested above, you'll probably end up with a garbled
string of numbers, letters, and symbols.
The storage addresses selected change with the length of the
registration code you type in. If your string is too long, you'll
get to see your de-crypted string stored in memory right below the
original string you typed in. This may be handy for anyone who might
want to compare strings.
After storing this single byte, we get a chance to spend alot of
frustrating time looking up addresses and anything else the author
of this program could think of to slow us down. This takes us through
all kinds of code to NOT check our string against what has been saved
in the registry. It's a very long process dealing with setting up
addresses, checking string length and values, and setting "switch"
values to determine wether or not the machine should enter the
registry
yet. (Has the entire string been processed?, Is the string length
correct?, etc.) Since we're not already registered, a switch will
always
tell the program not to enter the registry yet. This process was
probably placed here to frustrate the average cracker, by making the
process so long you just give up. And remember, it's repeated after
EACH byte we'll de-crypt, and MANY times later as you'll see!
The next two processes are rather boring. The first checks each byte
in
the de-crypted string, and if it is an asterix "*" it will be passed
into
the second process, which will convert it to a space " " character. This
will
check, and repair if nessesary, each byte of the de-crypted string.
Yet another chance to check our de-crypted code against whats stored
in the registry, (remember, we're still UNREGISTERED so there's nothing
to
check against!) along with the normal error checks and clean-up to
finish
up these sub-routines. As usual, if an error is found, we'll be kicked
out of
the program. If everything looks good, we'll set a bunch of bytes in
memory
to tell the program it's alright to go on to the next process. Since
we're
not already registered, a switch will tell the program not to open the
registry yet, but we still have to cruise through all the code
pertaining
to opening, reading, and closing the registry each time we come through
this
"registry check" crap. Basicaly, this is just one more attempt to slow
down
the average cracker, although this time, some of what is done IS
important,
like cleaning up after the sub routine, and setting bytes in memory to
tell
the program it's ok to proceed.
This is the point where we learn that our input string should have
been
24 characters long. So do the steps above 23 more times, and you will
have
de-crypted the entire string. But we're not even close to being done
yet,
unless you just came for the de-cryption lesson. What will we do with
this
de-crypted string in order to determine if you've registered properly?
Read
on to learn more.
*** :0043BEB5 E88AFEFFFF call 0043BD44 ***
Now it's time to DO something with this string we've de-crypted so
nicely.
We'll start at the end, rather than the beginning, because (if you saw
the
MULTIPLY code earlier) the end of the string is where we would be MOST
likely
NOT to succeed. An error EARLY in the process would have a "snowball"
effect
right on down the line, getting larger, and larger as we de-crypted each
byte, because the result of one pass through the MULTIPLY sub-routine
sets
the "key" for the next pass.
Do the math if you are inclined, but to put it simply, from an
incredibly
large number of possible combinations of characters, we only have ten
choices
for the end of our string. The last four characters MUST be NUMBERS (0 -
9)
or we get kicked out of the program.
Assuming YOU were lucky enough to end up with four numbers at the end
of
your de-crypted string, (I sure wasn't), the program copies the last
doubleword of your de-crypted string to a new location in memory. Pour
yourself a tall one for this process because you'll also get to NOT
enter
the registry FOUR more times durring this process, complete with error
checking, address look-ups, etc.
With our doubleword in hand, we'll strip away the first byte, convert
it
to decimal (subtract 30), multiply the "talley" (which is "0" for the
first
character), double the result, and add our decimal number to it. Then do
the same for the remaining three bytes. For an example of this, read
just a
bit further. We'll have to do this one more time, so I've included the
code
and an explanation when we reach that point in this de-cryption scheme.
Just in case we wandered in here with something other than numbers in
our
de-crypted doubleword, we get all kinds of chances to get kicked out of
the
program. And they'll all send us away thinking we've done a good thing,
until much later when the error flag gets tested. Then it's good bye bad
cracker! If we've done a good job, we'll sail through all that registry
crap
again, complete with all the frills, about three more times.
If nothing has gone wrong, we move the result from this last process
back
onto the stack, determine the length of our de-crypted string WITHOUT
the
last four bytes which we just processed above, determine an address to
copy
the shortened de-crypted string to, (without the last four bytes),
determine
if a registration string exists in the registry yet, (only reading it if
it
IS there), or if you have only just typed it in, and finaly, we'll move
the
shortened de-cryped string to a new address, without the last four
bytes. The
original string and the original de-crypted string will remain where
they
have been placed in memory. They will each contain thier entire 18h (24
dec)
bytes of input code, or de-crypted code respectively.
*** :0043BF54 E89B77FCFF call 004036F4 ***
And, after a bit of setup, (getting addresses and updating counters)
we're
ready for the next step, a very simple process of adding each byte of
the
shortened de-crypted string together, to get a sum of the hex values of
each
de-crypted byte. ((H=48) + (a=61) = A9 + (c=63) = 10C + (k=6B) = 177...
etc.
Until we've added all of the remaining 20 bytes, spaces are skipped
though.)
After this 20 byte de-crypted string is tallied, it's added to "3"
just
for kicks, and this doubleword result is saved for a CMP instruction
later.
Ahh... My ears are ringing with the sound of all those happy crackers
out
there thinking "JUST FIX THE CMP INSTRUCTION!" If you've read this far,
you
will know that this program has MANY error checks! One slip and you WILL
get
kicked out.
When registered, this program stores the string you entered into the
registry under:
\HKEY_CURRENT_USER\Software\Info Evolution\DNS WorkShop\Registration
And when it goes there to check up on you, you'll get kicked out
before
you ever reach that CMP instruction. The string is stored in the
registry
exactly as you typed it in, so each time the program is run, the string
goes through this same process again. Fixing the CMP instruction WILL
get
you "registered", and you'll get to see your de-crypted input string in
the
cute little box that say's "Successfuly registered to...", but when you
re-open the program, your "saved" input string will pass through this
same
process again, and you will be UN-registered. There's no "zen" in that!
Now that we have all the work done on our input string and the
resulting
de-crypted string, it's time to check access rights. This is a VERY long
process that jumps to places all over the program just to completely
confuse anyone who has made it this far. All it does is check a two
character string to determine if this is a (%d) demo version, or a (%u)
user
version. Anything other than a "d" or a "u" will get you kicked out of
the
program. Again, the author lets you "play around" awhile before he lets
you
get kicked out. So you'll get to do alot of jumps from a jump table, and
a
lot of checks for "$", " ", "-", "+", "*", etc. You'll also get to check
for
numbers, and capitalize lower case letters. Anything and everything to
confuse the "wanna-be" cracker.
And, just for fun, when we're done with the distraction above, the
author
was kind enough to throw in a few more trips past the registry, with all
the
frills as usual. What a nice guy!
But finaly we return to the task at hand. Just a bit more code to
help
me explain this step. This is the code, and explanation of it, that I
promised you when we were working with the last four bytes of the
de-crypted input string. Here we're working with the doubleword result
derived from adding the first 20 bytes of our de-crypted string. This is
another snippet of code from my original lesson...
NEXT_BYTE
test bl , bl ;do we have a byte to process?
je EXIT ;leave if we don't
sub bl, 30 ;convert to a decimal number
cmp bl, 09 ;is it a number?
ja EXIT ;leave if it's not
cmp eax, edi ;make sure our number hasn't grown too large
;(we put "0CCCCCCC" in EDI earlier in this proc)
ja EXIT ;leave if we got too big
lea eax, [eax + 4*eax] ;use an address as our tally
add eax, eax ;EAX = "0", but it grows as we calculate.
add eax, ebx ;now, add our byte from the doubleword
mov bl , [esi] ;get the next byte
inc esi ;set the byte pointer for the next byte
test bl , bl ;do we have anything?
jne NEXT_BYTE ;if yes, go back to process it
dec ch ;if not, set the flag to leave
je FLAG_CHECK ;then go check it, this is a "3-way" flag
;it can be a good "FF" as we've recieved here
;or a bad "00" or "01" which we would pick up
;if this process fails (if we have a letter
;instead of a number, for instance.)
I'll use 1, 2, 3, & 4 as an example of whats going on here for the
benifit of all those "wanna-be's" who don't quite understand the math.
EAX + (4 * EAX) EAX + EAX EAX + EBX
--------------------------------------------------------------
0 + (4 * 0) = 0 --> 0 + 0 = 0 --> 0 + 1 = 1
1 + (4 * 1) = 5 --> 5 + 5 = 0A --> 0A + 2 = C
C + (4 * C) = 3C --> 3C + 3C = 78 --> 78 + 3 = 7B
7B + (4 * 7B) = 267 --> 267 + 267 = 4CE --> 4CE + 4 = 4D2
As you can see, the end result adds up quickly. And this time, we end
up with four different values describing the first 20 bytes (or last 4
bytes if you've skipped here from above) of our input string...
Our input = XXXXXXXXXXXXXXXXXXXX
De-crypted = Hackmore Readrite -
Sum of Hex values = 1234
Re-calculated = 04D2
We are finaly done with all this crap, so now we can return to the
main
program to use that CMP instruction I spoke of earlier. Of course we
must
do that registry thing several more times first, just because we've come
this far! And as usual we make all three passes (open, read, and close)
and
do all kinds of error checking and clean-up.
So far we've typed in an input string, de-crypted it, stripped off
the
last four bytes and checked to be sure they were numbers, re-calculated
the result to get yet another number, checked the access rights, added
up
the hex values of the first 20 bytes of our string, and re-calculated
that
result to get yet another value. And at last we've reached that
"critical"
instruction which will let you use this program only once if you care to
adjust the values.
*** :0043BF8E 3BD8 cmp ebx, eax ***
This also brings us to the end of my lesson on this de-cryption
technique. Now I will show you two different ways to crack this program.
Using a dead listing and a bit of "zen", it was obvious that the data
address DS:[00440030] was being used for more reasons than just the IMUL
instruction listed earlier in this lesson. It did not take long to
figure
out why after firing up SoftIce.
Load the UNREGISTERED copy of this program into SoftIce, and place a
breakpoint on the memory doubleword used in the multiplication
sub-routine
used for the de-cryption process.
BPMD DS:00440030 RW
Then press F5 (ctrl-d) to return to the program. You will pop back
into
SoftIce very quickly. Press F5 again, and when SoftIce returns dump
DS:ESI.
Hold the "ALT" key down, while pressing the "down" arrow key 14 times.
Here
you will see the following encrypted string...
Tgq'bxGrrsaiper,Ieuutvm+3
After you have registered your program, your registration input
string
will show up here, and the encrypted string above will be gone. You can
follow this through the de-cryption process, (it's a VERY simple
process),
or you can just take my word for it, but either way, it de-crypts to the
following string...
ObjectContainer.Network.1
Sorry, lamers, the de-cryption process used to de-crypt this string
WILL
NOT de-crypt a registration input string! But it WILL give you the name
above, which is the "key" to search for in your registry. Once you've
found
the "key", simply delete it for another FREE 30 DAY TRIAL. This "key"
holds
the information to tell the program how long you've been using it. It
will be
replaced the next time you use the program, so you'll have to delete it
every thirty days.
That's enough "lamer" training, now I'll show you professionals how
to
REALY crack the program.
After dis-assembling the file DNSWorkShop.exe using Wdasm, one of the
first things you'll notice is the message "No Dialog resources in this
aplication." Yet, scanning the dead listing, you'll find several
references
to "string data reference to code object" within the program. So a
simple
search for the string "registered" leads us to...
"Successfuly registered to" at CS:0043C7E3
AND
"This product is registered to" at CS:0043D377
Our good friend SoftIce was kind enough to show us the exact point
where the de-cryption process began. With a little back-tracking from
that point, (that's back-TRACKING, not back-TRACING) through the dead
listing, we find that the sub-routine containing the address CS:0043BE63
begins at CS:0043BE30, which is called from CS:0043BF30. A bit more
back-tracking shows the sub-routine containing the address CS:0043BF30
actualy begins at CS:0043BEE4, which is called from CS:0043C1A0. One
more
time, we back-track to find the sub-routine containing the address
CS:0043C1A0 begins at CS:0043C16C, which is accessed by an indirect call
from somewhere.
Logic, or "zen" would dictate that this is probably the "true"
begining
of the registration process. (Because it's CALLer is a mystery, and it
leads
us right to the de-cryption process) A quick scan of this small
sub-routine
shows us that it happily returns to its caller when finished. As you can
see
by the addresses I've listed above, or better yet by viewing your own
dead
listing, the code below this sub-routine contains all kinds of "string
data"
references, including the ones we are after.
But look closely at the sub-routine itself! Right before your very
eyes,
only four instructions before you call the other sub-routines to get and
de-crypt your registration input string, THERE IT IS! THE switch which
determines if you are registered, or just a bum using this program for
free.
:0043C195 B301 mov bl, 01
Simply changing the "01" to a "00" will crack this program, the "key"
in
your registry called "ObjectContainer.Network.1" will be permantly
removed
from your computers registry, and the registration input string you
typed
will be placed in the "registration" key in your computers registry.
I must confess at this point, I have NOT figured out a way to reverse
the
math used in the de-cryption process. I know what my name is, so there's
no
need for me to see it in print. I'm sure the math COULD be reversed
though.
So when you press the "About this Software" tab, you'll see the message
"This product is registered to", but, unfortunately, your name will not
be
there. If you dis-like this software as much as I do, you'll just throw
it
away as soon as you're finished learning from it anyway.
I hope you have learned something from this lesson. I've tried to
show
you that de-crypting is not that difficult, and also the many "traps" a
programer might set to slow down and frustrate a potential cracker.
There are several REALY GOOD crackers in the +HCU, maybe someday we'll
all
get to be as good as they are. I'm working on it, and YOU should be too!
But
don't let the programers "trick" you into giving up by using methods
like
the ones I've shown you here.
Welcome back +ORC. Thanks to you, fravia+, and all the rest, for your
fine works. We are all islands in a sea of greed, but together we can
form a
continent. Legend has it that intellegent life first apeared on dry
land.
Hackmore Readrite
DataMiners Inc.
(c) Hackmore Readrite 1997. All rights reserved
You are deep inside fravia's page of reverse engineering,
choose your way out:
homepage
links
anonymity
+ORC
students' essays
academy database
tools
cocktails
antismut CGI-scripts
search_forms
mail_fravia
Is reverse engineering illegal?