to enter SoftIce, and do a search for the
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
entered is being copied to a new location. Now you place a new
just like you did above, and press F5 again to return to the program.
program runs its course, without ever breaking on your string again!
What happened?! You were in a Windows module. When you wern't
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
your string, hold down the F8 (trace) button for a few seconds to let
program re-gain control. Now do a new search for your string again, set
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
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
we did because we got to this sub-routine by an indirect call, which
finding this location in a dead listing very tedious.
But now that we know where to start, a dead listing will work just
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
copied to ECX, then checked to see if it's a number, a letter, or a
If your character is not one of the above, (if it's a graphics or
character) you get kicked out. If your character is a letter, it's
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 ) for later, get the next
byte in the string, and process it the same way. We'll save the result
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
stored in it, and we're about to do some math which will require EAX.
an exerpt from the original lesson I told you about earlier in this
mov edi, eax ;store result for use after MULTIPLY
mov eax, 00000040 ;the number to multiply by
imul edx, , 08088405 ;EAX * EDX * "KEY" * 08088405
inc edx ;add "1" just for fun
mov , 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
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
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.
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
part of the number is in EDX, and the lesser numbers are placed in EAX.
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
instruction turned out to be 3031323334 in hex:
EDX would equal 30 <---(then we add "1" to it) EAX would equal 31323334
So the next step would multiply 31 * 31323334, which, again, leaves
result in EDX:EAX. The low order bits (in EAX) are thrown away as we
the high order bits (in EDX) into EAX. Anyone concerned with reversing
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
processed the second byte of our input registration code. Remember, we
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"
of characters), or getting kicked out if we end up with an invalid
If you had entered a bunch of random characters into the input box, AND
you got REAL lucky, the character you MIGHT end up with at this point
be the first letter of your name, which is what we would LIKE to see
If we've made it this far, we get a chance to store our first
byte for future use. Again, here's an excerpt from my original lesson...
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
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
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
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
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
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
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
yet. (Has the entire string been processed?, Is the string length
correct?, etc.) Since we're not already registered, a switch will
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
the de-crypted string, and if it is an asterix "*" it will be passed
the second process, which will convert it to a space " " character. This
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
check against!) along with the normal error checks and clean-up to
up these sub-routines. As usual, if an error is found, we'll be kicked
the program. If everything looks good, we'll set a bunch of bytes in
to tell the program it's alright to go on to the next process. Since
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
to opening, reading, and closing the registry each time we come through
"registry check" crap. Basicaly, this is just one more attempt to slow
the average cracker, although this time, some of what is done IS
like cleaning up after the sub routine, and setting bytes in memory to
the program it's ok to proceed.
This is the point where we learn that our input string should have
24 characters long. So do the steps above 23 more times, and you will
de-crypted the entire string. But we're not even close to being done
unless you just came for the de-cryption lesson. What will we do with
de-crypted string in order to determine if you've registered properly?
on to learn more.
*** :0043BEB5 E88AFEFFFF call 0043BD44 ***
Now it's time to DO something with this string we've de-crypted so
We'll start at the end, rather than the beginning, because (if you saw
MULTIPLY code earlier) the end of the string is where we would be MOST
NOT to succeed. An error EARLY in the process would have a "snowball"
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
the "key" for the next pass.
Do the math if you are inclined, but to put it simply, from an
large number of possible combinations of characters, we only have ten
for the end of our string. The last four characters MUST be NUMBERS (0 -
or we get kicked out of the program.
Assuming YOU were lucky enough to end up with four numbers at the end
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
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
to decimal (subtract 30), multiply the "talley" (which is "0" for the
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
bit further. We'll have to do this one more time, so I've included the
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
de-crypted doubleword, we get all kinds of chances to get kicked out of
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
again, complete with all the frills, about three more times.
If nothing has gone wrong, we move the result from this last process
onto the stack, determine the length of our de-crypted string WITHOUT
last four bytes which we just processed above, determine an address to
the shortened de-crypted string to, (without the last four bytes),
if a registration string exists in the registry yet, (only reading it if
IS there), or if you have only just typed it in, and finaly, we'll move
shortened de-cryped string to a new address, without the last four
original string and the original de-crypted string will remain where
have been placed in memory. They will each contain thier entire 18h (24
bytes of input code, or de-crypted code respectively.
*** :0043BF54 E89B77FCFF call 004036F4 ***
And, after a bit of setup, (getting addresses and updating counters)
ready for the next step, a very simple process of adding each byte of
shortened de-crypted string together, to get a sum of the hex values of
de-crypted byte. ((H=48) + (a=61) = A9 + (c=63) = 10C + (k=6B) = 177...
Until we've added all of the remaining 20 bytes, spaces are skipped
After this 20 byte de-crypted string is tallied, it's added to "3"
for kicks, and this doubleword result is saved for a CMP instruction
Ahh... My ears are ringing with the sound of all those happy crackers
there thinking "JUST FIX THE CMP INSTRUCTION!" If you've read this far,
will know that this program has MANY error checks! One slip and you WILL
When registered, this program stores the string you entered into the
\HKEY_CURRENT_USER\Software\Info Evolution\DNS WorkShop\Registration
And when it goes there to check up on you, you'll get kicked out
you ever reach that CMP instruction. The string is stored in the
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
you "registered", and you'll get to see your de-crypted input string in
cute little box that say's "Successfuly registered to...", but when you
re-open the program, your "saved" input string will pass through this
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
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)
version. Anything other than a "d" or a "u" will get you kicked out of
program. Again, the author lets you "play around" awhile before he lets
get kicked out. So you'll get to do alot of jumps from a jump table, and
lot of checks for "$", " ", "-", "+", "*", etc. You'll also get to check
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
was kind enough to throw in a few more trips past the registry, with all
frills as usual. What a nice guy!
But finaly we return to the task at hand. Just a bit more code to
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...
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
program to use that CMP instruction I spoke of earlier. Of course we
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)
do all kinds of error checking and clean-up.
So far we've typed in an input string, de-crypted it, stripped off
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
the hex values of the first 20 bytes of our string, and re-calculated
result to get yet another value. And at last we've reached that
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: was being used for more reasons than just the IMUL
instruction listed earlier in this lesson. It did not take long to
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
used for the de-cryption process.
BPMD DS:00440030 RW
Then press F5 (ctrl-d) to return to the program. You will pop back
SoftIce very quickly. Press F5 again, and when SoftIce returns dump
Hold the "ALT" key down, while pressing the "down" arrow key 14 times.
you will see the following encrypted string...
After you have registered your program, your registration input
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
or you can just take my word for it, but either way, it de-crypts to the
Sorry, lamers, the de-cryption process used to de-crypt this string
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
the "key", simply delete it for another FREE 30 DAY TRIAL. This "key"
the information to tell the program how long you've been using it. It
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
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
to "string data reference to code object" within the program. So a
search for the string "registered" leads us to...
"Successfuly registered to" at CS:0043C7E3
"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
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
Logic, or "zen" would dictate that this is probably the "true"
of the registration process. (Because it's CALLer is a mystery, and it
us right to the de-cryption process) A quick scan of this small
shows us that it happily returns to its caller when finished. As you can
by the addresses I've listed above, or better yet by viewing your own
listing, the code below this sub-routine contains all kinds of "string
references, including the ones we are after.
But look closely at the sub-routine itself! Right before your very
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
:0043C195 B301 mov bl, 01 <---right HERE! :0043C197 8D4DF8 lea ecx, [ebp-08] :0043C19A 8B5604 mov edx, [esi+04] :0043C19D 8B45FC mov eax, [ebp-04] :0043C1A0 E83FFDFFFF call 0043BEE4 <---get & de-crypt input
Simply changing the "01" to a "00" will crack this program, the "key"
your registry called "ObjectContainer.Network.1" will be permantly
from your computers registry, and the registration input string you
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
math used in the de-cryption process. I know what my name is, so there's
need for me to see it in print. I'm sure the math COULD be reversed
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
there. If you dis-like this software as much as I do, you'll just throw
away as soon as you're finished learning from it anyway.
I hope you have learned something from this lesson. I've tried to
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
get to be as good as they are. I'm working on it, and YOU should be too!
don't let the programers "trick" you into giving up by using methods
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
continent. Legend has it that intellegent life first apeared on dry
(c) Hackmore Readrite 1997. All rights reserved
You are deep inside Fravia's page of reverse engineering,
choose your way out:
Is reverse engineering illegal?