HOW TO CRACK, by +ORC, A TUTORIAL
Lesson C (3): How to crack Windows, Hands on
[INSTANT ACCESS]
--------------------------------------------------------
LESSON C (3) - How to crack Windows, cracking as anArt:
Web trends, Instant Access (end) and the proximity trick
--------------------------------------------------------
I. [WEB TRENDS]
It's really amazing: I began this tutorial in february 1996...
the year is not yet finished but many things have already
changed, and how! First of all the Web proves to be even more
significant that I would ever have thought: it's -de facto- an
ANTI-ESTABLISHMENT and ANTI-CONSUME "permanent" tool... more than
that: it's an EVOLVING and SHARP tool!
I do not know if you will agree with me, but it seems to me that
it is now NOT ANY MORE NECESSARY to buy any of the following
things (and this is a quite incomplete list:
1) Newspapers Are almost all on the Web for free
2) Magazines Are almost all on the Web for free
3) Software All on the Web for free
4) Books on the Web (even the *images* inside the
books you would have bought are somewhere)
5) Post_stamps e-mail is free and ubiquitous
6) Hard_disks free megabytes everywhere on the Web (for
pages and/or software, quite a lot of
offering (at the moment, middle november
1996 you can get -for free- about 80
megabytes for each email address you have).
Should you do not deem this space enough,
you may multiply them -ad libitum- using one
of the many free "alias e-mail addresses"
generators or, as a brilliant scholar of
mine (re)discovered, you may easily "caper"
(the passwords of) pages established by the
lusers.
I assure you that I used to spend quite a lot of money
buying all the preceding items. The case of the CD-ROM magazines
(and of software in general) seems to me to be the most relevant.
In my earlier lessons I advised you to buy CD-ROM software at
"kilo" prices in second hand shops (obviously never when the
magazines themselves do appear)... even this trick is now
useless: there is NO software that you cannot find on the Web
(I'll bet that the CD-ROM mags are not making any easy money any
more now). This truth may be difficult to slurp until you learn
HOW to search effectively on the Web, a very difficult art -per
se-, that all real crackers should master. A little tip: if you
are in a hurry do your searches using your own search engines
instead of using only the ubiquitous AltaVista, FTP and
Webcrawler (which you SHOULD use, of course, but not alone).
And loo! Good old Internet, made by governments and
universities with public money and no private partecipation
whatsoever reveals itself to be the most striking revolution of
the last years in spite of the continuous blah blah about free
markets and private initiative... quite funny, isn't it?
New promising patterns are emerging: it is clear (to me)
that the future of cracking lays in JavaScript applets: Netscape
has opened quite a Pandora Box... now everybody is scrambling to
close it... TOO LATE! Find the relevant documentation, tutorials,
software, tools, examples... even teachers! Everything is there
for free on the Web! Study it, and when you are ready study it
again... take it easy: we have a long cracking future before
us...
Here is a nice example (by LaDue) of an interesting applet:
this one forges an e-mail from the browsers of your page sending
it to the address contained in the string "toMe". The browser of
your page initiates the mail by connecting (involuntarily) to
port 25 (int mailPort=25).
Now, let's just academically imagine... you would put your
own address (faked email address but working depot when you need
to fetch the messages, as usual) in the string "toMe"... well,
scanning incoming mail you could get the full e-mail address,
including the user name, of many people who have seen your page.
See LaDue example:
here.
JavaScript and Java are two completely different things: The
coincidence in the name is only a stupid marketing move from
Netscape. JavaScript is so easy it's a shame, and this makes it
the ideal weapon for masscracking (Java on the countrary is a
"real" programming language). The implications of easy Javascript
use, of internet growth and of the "on the fly" JavaScript
workings for the drafting of much more interesting applets are
obvious, I'll let them to the intuition (and fantasy) of my
cleverest readers.
II.[INSTANT ACCESS] End
I'll admit it: I am a little deceived: the +HCU strainer
(Instant access protection scheme) has been solved only by very
few (pretty competent) crackers. The amount of people that has
NOT cracked instant access (and that as relentlessy asked for
more "clues") stood in no sound relation to the very few that
solved it. I intended to give my complete solution in this lesson
C3 to allow everybody to have (good) software for free... but too
few worked hard on it to let you all lazy ones deserve a "ready-
made" solution... I will therefore publish here one of the
"incomplete" (albeit very good) solutions.
The solution cracks the scheme but requires a little work
of your part to accomplish it... what I mean is this: studying
the following you'll be able to crack every Instant access
protected code in a couple of hours, not immediatly... this is
good, will make the lazy lurkers work (at least a little :=)
Here it is (C++ code of the solution and admission letter),
I only took off the name of the candidate:
Cracking Instant Access_____________
by xxxxxxxx
Application for 1996 Higher Cracking University
This is my solution to the strainer for admittance into your
HCU. While I was successful in bypassing the protection (and
hence now have a nice collection of software for free) I am the
first to admit that my solution is not the best. However, I am
very proud of the work I have done on this project and it is by
far the most difficult crack I've ever done. In the past I've
traced programs, and when they did something I did not like, I
looked at the jumps immediately before that and reversed them.
Because of idiot programming this worked about 60% of the
time, however in many programs I was just stuck. With the hints
you provided in your tutors I was able to actually disassemble
the program and understand why it did things. Believe me this is
a big jump. Anyway, here is my solution.
I have dozens of handwritten notes and pages of code that
I copied out of soft-ice, and any that are important I will type
into this report, however most turned out to be unimportant. I
have also created a "Magic" number generator and a reverse
generator. I am very proud that I was able to create these,
because the "Magic" number seemed so mysterious at first, and now
I have complete mastery of it, a great feeling of power.
I began the project by following the introductory steps in
lessons C1 and C2. I got lost somewhere in C2, but I kept going.
I got to the end with a vague understanding of what was happening
and decided that I needed to understand this fully before I could
do anything useful towards cracking it.
I left my computer alone and read through the code again,
making notes and explanations for my own use. About the third
time through everything clicked, it was like a light bulb going
off in my head. You mentioned that not everything in Lesson C1
was correct.
Here is a list of what I found to be incorrect.
1. The offsets in the code were not the same. (this is a good
idea to keep people from cheating when pinpointing the correct
code)
2. The pointers to where things are saved in memory were not the
same.
3. You wrote that the 1st digit plus 7 was saved and then you
wrote that the 2nd plus 3 was saved. It is the other way around!
1st plus 3 and 2nd plus 7. (just checking if we are paying
attention huh?)
I think that's all of the one's I found although there were
many specific instances of each one. So here's what I did.
I did a search on the 18 digit code I typed in. I found it
at 30:8xxxxx and did a bpr on it. I let it run, and looked each
time something accessed that area. Eventually I found code that
checked if the digits were between 30 and 39 and copied them to
DS:8CD8. So there lies the code with the "-" 's stripped off of
it. I did a bpr on this area. It copied itself to DS:8CB8, and
I bpr'ed that as well. I discovered that what was going on was,
it copied itself, then that copy was transformed into the "Magic"
number.
So I did a little stack fishing, and found a CALL at offset
5C04 which copies the code from 8CB8 and converts it into the
"Magic" number. At this point I traced into the call and got
really fucking lost, so I stepped back had a sip of Vodka and
thought. I don't care HOW the "magic" gets there, only that it
is there. I figured once I figured out what "magic" I needed I
could trace over the call that put it there, and then put in
whatever "magic" I wanted. So I traced on to see what happened
to the "magic" number that had been produced. I had a bpr on the
"magic" and it stopped on the first line of code below.
The code is copied from my handwritten notes, so not
everything is accurate (I only wrote down what I thought was
important)
2b67:2598 mov al, es:[bx] ; 12th digit of magic
mov [bp-03], al ; ??????
mov al, [bp-03] ; maybe an inefficient compiler
result
add al, d0 ; clean it
mov [bp-04], al ; save it in [8ca6]
les bx, bp+06
add bx, si ; point to 12th again
mov byte ptr es:bx, 30 ; make it a '0'
push then more crap and then
:253d mov al, es:bx ; 1st digit
mov ah, 00 add ax,ffd0 ; clean it
cwd
add [bp-06], ax ; [8c90] is zero to start
this loop repeats 18 times, summing up the "magic" number, with
the 12th set to 0
:256e mov [bp-07], al ; save remainder of sum/a in [8c8f]
cmp [al, bp-05] ; is 12th (in al) save as remainder
of sum/a ? Aha!, this is what you were talking about at the end
of C2, where the remainder doesn't match the 12th number.
I knew I was on the right track. I could feel it.
I traced down farther after the remainder check (I used
8888-8888-8888-8888-88 as my code from then on because it passed
this check and was easy to remember) and I found code which
compared the value at ds:8D00 with the value at ds:8D0C and if
it did not match jumped to beggar off.
Then it checks if ds:8D06 is equal to ds:8D0E and if not
equal jumps to beggar off. So I knew that 8D00 must equal 8D0C
and that 8D06 must equal 8D0E.
All I needed to do was figure out where these came from. I
bpr'ed on 8D0C and found code which wrote the number to it.
I did not copy the ASM down, but this is what I wrote:
move 15th of "Magic" into AX fix it to 0-9 by +- A
put it in SI
mov 16th into AX
mul si by A
add ax to si
mov 17th to AX
mul si by A
add ax to it
put 18th in AX
mul si by A
add AX to it ; This is ds:8D0C !!!!
So now I knew where this came from, the last 4 digits of the
"magic" I bpr'ed on 8D0E and found out quickly that the first
digit of the "magic" was put into ds:8D0E.
Things were looking good. However, I was unable to figure out how
ds:8D06 and ds:8D00 were created. I know they are related to the
product code because they only change when it does. But they are
put there by a MOVSW command and I cannot figure out how to
predict where they are copied from, because it is only done once
and it is never from the same place, so all my attempts to bpr
on the spot they are copied from failed because it copies from
a new spot each time.
I felt dejected. I could not figure it out, even after days
of pointless tracing.
I stepped back and thought, and drank a can of Coke at 2
a.m...
(note from +ORC: Coke is dangerous for your health and your
cracking purposes... drink only Martini-Wodka and use by all
means only russian Wodka)
...I still had not figured out how the "magic" worked. I
decided to do that and come back to the problem of the numbers
generated from the Product Code.
I knew the call at cs:5C04 completely generated the "magic"
so I started there. I traced through it several times and found
that it made a CALL 3517 three times, then looped 6 times. So it
called 3517 a total of 18 times. I also noticed that the CALL
changed the number, but nothing else did, it just set up the
calls.
So I traced into CALL 3517 and came up with this:
mov ax,ss
nop inc bp
push bp
mov bp,sp
push ds
mov ds,ax
xor ax a bunch more unimportant stuff
:356b mov al,es:[bx} ; al = 18th digit
cbw push ax
mov ax, A
sub ax,[5dad] ; subtract 6 from a to get 4
imul [5db1] pop dx ; 18th digit
add dx,ax add dx, -30 ;clean it
mov [5db5], dx ;save it then fix [5db5] to be
between 0 and 9
mov al, es:[bx] ; load 18th again
cbw push ax
mov ax,a
sub ax,[5dad]
imul [5db3]
pop dx ; 18th digit
add dx, ax
add dx, -30 ;clean it
:35bb mov [5db7], dx ;save it.
:35d9 mov bx,[5dad]
mov es, bp+1a
add bx,[bp+18]
mov al,es:[bx-1] ; al = 6th digit
mov [5dc3], al ; save it
mov bx,[5dad]
mov es,[bp+1e]
add bx,[bp+1c]
mov al,es:[bx-1] ; 12th digit
mov [5dc4], al ; save it more junk then
3605: mov bx,[5dbf] ; this is the beginning of a loop
mov es,[bp+1a]
add bx,[bp+18]
mov al,es:[bx-1] ; 5th digit
push ax ; save it
mov ax,[5db5] ; [5db5] created above using 18th digit
mov dx,A
imul dx ;[5db] *A
les bx,[bp+0c]
add bx,ax
add bx,[5db7] ; created using 18th
pop ax ;5th digit
sub al,es:[bx};subtract a value from the lookup table
les bx add bx,[5dbf]
mov es:[bx],al ; Put new value in 6th spot fix it
so that it's between 0 and 9 by +- A
:3656 mov bx,[5dbf]
mov es,[bp+1e]
add bx,[bp+1c]
mov al,es:[bx-1] ; 11th digit
push ax mov ax,[5db5]
mov dx,a
imul dx
les bx
add bx,ax
add bx,[5db7]
pop ax ;11th digit
sub al,es:[bx] ; subtract a value from lookup
table
les bx, [bp+1c]
add bx,[5db7]
mov es:[bx],al ;put it in 12th spot fix it to be
between 0 and 9 The loop above repeats doing the same thing,
changing 2 numbers, but not always the same two. The next time
through it changes 5th and 11th, after that the 4th and 10th, 3rd
and 9th then the 2nd and 8th using this same pattern. After the
loop it changes the 1st and 7th using the values of the original
6th and 12th which were saved in [5dc3] and [5dc4] using the same
pattern. I quickly wrote a program in C which would produce this
number, and it worked fine.
I traced into the second call of 3517 and found that the
parameters passed to it changed which values where used to create
[5db5] and [5db7], whether they increment or decrement, whether
you add 0 or 64 to your index for the lookup and the digits which
are changed. All three calls to 3517 have a different
arrangement, but the their arrangement is the same each time they
are called. For instance, the three calls are looped over 6
times, on each instance that the 1st call is executed it will
change the 6th,12th,5th, 11th, etc. So I modified my C program
to mimic the behaviour of each call and looped it six times,
expecting this to be the "magic" number. To my surprise it was
not right.
So I followed the code until after the 3 CALL 3517's had
been made, this was the number my generator had given me, so it
must do something more afterwards.
I found the following code, still within the cs:5c04 call
:44C1 mov al,es:[bx+si-2] ; 17th digit
add al,d0 ;clean it
mov [5dc1], al ;save it
les bx
mov al,es:[bx+si-2] ; 18th digit
add al,d0 ;clean it
mov [5dc2],al ;save it
mov [5dbf],0
jmp 455f :44df
les bx
add bx,[5dbf]
mov al,[5dc1] ;17th cleaned
sub es:[bx],al ;1st digit has 17th cleaned
subtracted from it fix it between 0 and 9
mov al,[5dc2] ;18th cleaned 4520
sub es:[bx],al ;7th - 18th cleaned is put in 7th
spot fix it between 0 and 9
:455b inc word ptr [5dbf]
mov ax,[5dbf]
cmp ax,[5dad] ; run six times
jge 456b
jmp 44df 456b: blah blah continue on.
This loop executes six times each time incrementing the digit to
be changed by one so that the first change changes the 1st digit,
and the next time through the loop the 2nd then the 3rd.....till
the sixth. The second change alters the 7th through the 12th
digits. I added code to do this at the end of my Generator, and
I now had a "Magic" number generator. However this did not do me
much good in itself. The breakthrough was reversing this program
(it wasn't hard, but getting all the bugs out was really tough)
so that it takes a "magic" number as input and tells you what
registration number will produce it. I have included the source
code for both programs to prove that they are my own work. The
coding is not the best, they are my own crude tools, and they do
the job I need them for. But now I am home free. Even without
knowing how the product code is manipulated to come up with
ds:8D00 and ds:8d06 I can crack it. Here's what I did.
The product code given me was 3850-0118-6260-1057-23 I
traced to where ds:8D00 and ds:8D06 are placed they were:
ds:8D00 = E03 ds:8D06 = 3 I knew the last 4 digits when added,
and multiplied as explained above must be E03 so this is what I
wrote down, using my calculator
DFC + 7 =E03
This is the final answer, but I need to work backwards from here
166 * A = DFC
15E + 8 = 166
23 * A = 15E
1E +5 = 23
3 * A = 1E
Just working things backwards from the way the program did it I
figured out the last 4 digits of the magic code need to be 3587
in order for it to produce E03 as a result. I also know that the
first digit must be equal to ds:8d06 which is 3 so I now have:
3___-____-____-__35-87
as a "magic" number and I fill it in with 1's
3111-1111-111X-1135-87
I left the 12th number as an X because I remember that the
remainder of the sum of all the digits except the 12th must be
equal to the 12th.
3+1+1+1+1+1+1+1+1+1+1+1+1+3+5+8+7 = 26 26/A
26 26/A = 3 with a remainder of 8,
so the 12th digit is an 8!
My "magic" number should be 3111-1111-1118-1135-87
So I run my UNINSTAN program, which tells me that in order to get
that "magic" I need to enter the following registration code:
4798-8540-6989-6899-53 I enter this in, the "Retrieve" button is
enabled and I install Norton Utilities without a hassle! I used
the same method to install Wine Select (I've been interested in
wine since reading about your Pomerol), Labels Unlimited (which
I use for what else? Barcodes!), Harvard Graphics, and Lotus Ami
Pro, which I'm using to write this report on!
Well, that's it. That is how I cracked Instant Access. As
I mentioned above it is not the best way, but I gave everything
I had and it's the best I could do.
I have succeeded because I have beaten the protection, and
because I taught myself a lot along the way. I'm sure you already
have a "magic" number generator of your own, but I included mine
so you could see it. If I just knew how the product code produces
those 2 numbers I could create a product code to registration
number converter, which I assume is what the operators at Instant
Access have when you call them to buy stuff.
One last note about this assignment. I know that you have
realized that Instant Access was hard to find. I want to tell you
how I got it, a bit a social engineering in itself. After
searching every library and book/magazine store in the city I got
on the Internet and asked. Nobody had it.
So I found the Instant Access homepage. ...
(this will not be published, coz I, +ORC, do not want to expose
my crackers, but the way this guy got hold of the protection
scheme is in itself worth is access to the +HCU)
...So as you can see, I have gone to great lengths for admittance
into your University, and I hope I have earned it. I am proud to
wear my +
...address follows
And here are the two C++ programs:
INSTANT.CPP-----------------------------------
// Template for byte patch files
#include
#include
#include
#include
#include
void main()
{
char fix(char x);
char *t; //*stopstring
int save1, save2,fdbf,fdbs, i;
static int table[208] = {1,3,3,1,9,2,3,0, 9,0,4,3,8,7,4,4,
5,2,9,0,2,4,1,5, 6,6,3,2,0,8,5,6,
8,9,5,0,4,6,7,7, 2,0,8,0,6,2,4,7,
4,4,9,5,9,6,0,6, 8,7,0,3,5,9,0,8,
3,7,7,6,8,9,1,5, 7,4,6,1,4,2,7,1,
3,1,8,1,5,3,3,1, 2,8,2,1,6,5,7,2,
5,9,9,8,2,9,3,0, 0,4,5,1,1,3,8,6,
1,1,9,0,2,5,5,5, 1,7,1,5,8,7,1,9,
8,7,7,4,4,8,3,0, 6,1,9,8,8,4,9,9,
0,7,5,2,3,1,3,8, 6,5,7,6,3,7,6,7,
4,2,2,5,2,4,6,2, 6,9,9,1,5,2,3,4,
4,0,3,5,0,3,8,7, 6,4,8,8,2,0,3,6,
9,0,0,6,9,4,7,2, 0,1,1,1,1,0,1} ;
//_clearscreen(_GCLEARSCREEN);
printf("Enter the 18 digit Reg code: ");
gets(t);
for (i=1; i<=6 ; i++)
{
save1 = t[5]; // save the sixth digit
save2 = t[11]; // save the twelfth digit
fdbf = 0xFFC+t[17]-0x1000-0x30 ; // create [5db5]
if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = fdbf; // and [5db7]
t[5] = t[4] - table[fdbf*0xA+fdbs] ; // sixth number
t[5] = fix(t[5]);
t[11] = t[10] - table[fdbf*0xA+fdbs+0x64]; // 12th
number
t[11] = fix(t[11]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[4] = t[3] - table[fdbf*0xA+fdbs] ; // 5th number
t[4] = fix(t[4]);
t[10] = t[9] - table[fdbf*0xA+fdbs+0x64]; // 11th
number
t[10] = fix(t[10]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[3] = t[2] - table[fdbf*0xA+fdbs] ; // 4th number
t[3] = fix(t[3]);
t[9] = t[8] - table[fdbf*0xA+fdbs+0x64]; // 10th number
t[9] = fix(t[9]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[2] = t[1] - table[fdbf*0xA+fdbs] ; // 3rd number
t[2] = fix(t[2]);
t[8] = t[7] - table[fdbf*0xA+fdbs+0x64]; // 9th number
t[8] = fix(t[8]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[1] = t[0] - table[fdbf*0xA+fdbs] ; // 2nd number
t[1] = fix(t[1]);
t[7] = t[6] - table[fdbf*0xA+fdbs+0x64]; // 8th number
t[7] = fix(t[7]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[0] = save1 - table[fdbf*0xA+fdbs]; // first digit
t[0] = fix(t[0]);
t[6] = save2 - table[fdbf*0xA+fdbs+0x64]; // 7th digit
t[6] = fix(t[6]);
//puts(t);
// end of first call
////////////////////////////////////////////////
save1 = t[5]; // save the sixth digit
save2 = t[17]; // save the 18th digit
fdbf = t[10]+0x4-0x30 ; // create [5db5]
if (fdbf <0X0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = t[9]+0x4-0x30; // and [5db7]
if (fdbs <0X0)
fdbs += 0xA; // fix it if necessary
else if (fdbs >= 0xA)
fdbs -= 0xA;
t[5] = t[4] - table[fdbf*0xA+fdbs] ; // sixth number
t[5] = fix(t[5]);
t[17] = t[16] - table[fdbf*0xA+fdbs+0x64]; // 18th
number
t[17] = fix(t[17]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[4] = t[3] - table[fdbf*0xA+fdbs] ; // 5th number
t[4] = fix(t[4]);
t[16] = t[15] - table[fdbf*0xA+fdbs+0x64]; // 17th
number
t[16] = fix(t[16]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[3] = t[2] - table[fdbf*0xA+fdbs] ; // 4th number
t[3] = fix(t[3]);
t[15] = t[14] - table[fdbf*0xA+fdbs+0x64]; // 16th
number
t[15] = fix(t[15]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[2] = t[1] - table[fdbf*0xA+fdbs] ; // 3rd number
t[2] = fix(t[2]);
t[14] = t[13] - table[fdbf*0xA+fdbs+0x64]; // 15th
number
t[14] = fix(t[14]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[1] = t[0] - table[fdbf*0xA+fdbs] ; // 2nd number
t[1] = fix(t[1]);
t[13] = t[12] - table[fdbf*0xA+fdbs+0x64]; // 14th
number
t[13] = fix(t[13]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[0] = save1 - table[fdbf*0xA+fdbs]; // first digit
t[0] = fix(t[0]);
t[12] = save2 - table[fdbf*0xA+fdbs+0x64]; // 13th
digit
t[12] = fix(t[12]);
//puts(t);
// end of second call
////////////////////////////////////////////////
save1 = t[11]; // save the 12th digit
save2 = t[17]; // save the 18th digit
fdbf = t[1]+0x4-0x30 ; // create [5db5]
if (fdbf <0X0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = t[2]+0x4-0x30; // and [5db7]
if (fdbs <0X0)
fdbs += 0xA; // fix it if necessary
else if (fdbs >= 0xA)
fdbs -= 0xA;
t[17] = t[16] - table[fdbf*0xA+fdbs] ; // 18th number
t[17] = fix(t[17]);
t[11] = t[10] - table[fdbf*0xA+fdbs+0x64]; // 12th
number
t[11] = fix(t[11]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[16] = t[15] - table[fdbf*0xA+fdbs] ; // 17th number
t[16] = fix(t[16]);
t[10] = t[9] - table[fdbf*0xA+fdbs+0x64]; // 11th
number
t[10] = fix(t[10]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[15] = t[14] - table[fdbf*0xA+fdbs] ; // 16th number
t[15] = fix(t[15]);
t[9] = t[8] - table[fdbf*0xA+fdbs+0x64]; // 10th number
t[9] = fix(t[9]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[14] = t[13] - table[fdbf*0xA+fdbs] ; // 15th number
t[14] = fix(t[14]);
t[8] = t[7] - table[fdbf*0xA+fdbs+0x64]; // 9th number
t[8] = fix(t[8]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[13] = t[12] - table[fdbf*0xA+fdbs] ; // 14th number
t[13] = fix(t[13]);
t[7] = t[6] - table[fdbf*0xA+fdbs+0x64]; // 8th number
t[7] = fix(t[7]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[12] = save2 - table[fdbf*0xA+fdbs]; // 13th digit
t[12] = fix(t[12]);
t[6] = save1 - table[fdbf*0xA+fdbs+0x64]; // 7th digit
t[6] = fix(t[6]);
// end of third call
////////////////////////////////////////////////
} // end of for loop
// Now we finish it up
save1 = t[16] + 0xD0 - 0x100; // [5dc1]
save2 = t[17] + 0xD0 - 0x100; // [5dc2]
for (i=0; i<6; i++)
{
t[i] = t[i] - save1;
t[i] = fix(t[i]);
t[i+6] = t[i+6] - save2;
t[i+6] = fix(t[i+6]);
}
printf("'Magic' code is: ");
for (i=0; i<18 ;i++) // output the string (only first 18)
putc(t[i], stdout);
printf("\n\n Created by xxxxx for +Orc's HCU 1996");
} // end of main()
char fix(char x)
{
if (x < '0')
x = x+0xA;
else if (x > 0x39)
x -= 0xA;
return x;
}
---------------------------------------------------
UNINSTANT.CPP
#include
#include
#include
#include
#include
void main()
{
char fix(char x);
char *t;
int save1, save2,fdbf,fdbs, i,q, fdbssave,fdbfsave;
static int table[208] = {1,3,3,1,9,2,3,0, 9,0,4,3,8,7,4,4,
5,2,9,0,2,4,1,5, 6,6,3,2,0,8,5,6,
8,9,5,0,4,6,7,7, 2,0,8,0,6,2,4,7,
4,4,9,5,9,6,0,6, 8,7,0,3,5,9,0,8,
3,7,7,6,8,9,1,5, 7,4,6,1,4,2,7,1,
3,1,8,1,5,3,3,1, 2,8,2,1,6,5,7,2,
5,9,9,8,2,9,3,0, 0,4,5,1,1,3,8,6,
1,1,9,0,2,5,5,5, 1,7,1,5,8,7,1,9,
8,7,7,4,4,8,3,0, 6,1,9,8,8,4,9,9,
0,7,5,2,3,1,3,8, 6,5,7,6,3,7,6,7,
4,2,2,5,2,4,6,2, 6,9,9,1,5,2,3,4,
4,0,3,5,0,3,8,7, 6,4,8,8,2,0,3,6,
9,0,0,6,9,4,7,2, 0,1,1,1,1,0,1} ;
printf("Enter the 18 digit 'Magic' code: ");
gets(t);
save1 = t[16] + 0xD0 - 0x100; // [5dc1]
save2 = t[17] + 0xD0 - 0x100; // [5dc2]
for (i=5; i>=0 ; i--) // fix it before main loop
{
t[i] = t[i] +save1;
t[i] = fix(t[i]);
t[i+6] = t[i+6] + save2;
t[i+6] = fix(t[i+6]);
}
for (i=1; i<=6 ; i++)
{
// begin third call
fdbf = 0x4+t[1]-0x30 ; // create [5db5]
if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = 0x4+t[2]-0x30 ; // create [5db7]
if (fdbs <0X0)
fdbs += 0xA; // fix it if necessary
else if (fdbs >= 0xA)
fdbs -= 0xA;
save1 = t[6]; //save 7th
save2 = t[12]; // and 13th
for (q=1; q<=5; q++) // put [ ]'s where they were at end
of loop
{
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
}
fdbssave = fdbs;
fdbfsave = fdbf;
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[6] = t[7] + table[fdbf*0xA+fdbs+0x64]; // 7th digit
t[6] = fix(t[6]);
t[12] = t[13] + table[fdbf*0xA+fdbs]; // 13th digit
t[12] = fix(t[12]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[7] = t[8] + table[fdbf*0xA+fdbs+0x64]; // 8th digit
t[7] = fix(t[7]);
t[13] = t[14] + table[fdbf*0xA+fdbs]; // 14th digit
t[13] = fix(t[13]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[8] = t[9] + table[fdbf*0xA+fdbs+0x64]; // 9th digit
t[8] = fix(t[8]);
t[14] = t[15] + table[fdbf*0xA+fdbs]; // 15th digit
t[14] = fix(t[14]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[9] = t[10] + table[fdbf*0xA+fdbs+0x64]; // 10th digit
t[9] = fix(t[9]);
t[15] = t[16] + table[fdbf*0xA+fdbs]; // 16th digit
t[15] = fix(t[15]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[10] = t[11] + table[fdbf*0xA+fdbs+0x64]; // 11th
digit
t[10] = fix(t[10]);
t[16] = t[17] + table[fdbf*0xA+fdbs]; // 17th digit
t[16] = fix(t[16]);
t[11] = save1 + table[fdbfsave*0xA+fdbssave+0x64]; //
12th digit
t[11] = fix(t[11]);
t[17] = save2 + table[fdbfsave*0xA+fdbssave]; // 18th digit
t[17] = fix(t[17]);
// end of third call
// begin second call
fdbf = 0x4+t[10]-0x30 ; // create [5db5]
if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = 0x4+t[9]-0x30 ; // create [5db7]
if (fdbs <0X0)
fdbs += 0xA; // fix it if necessary
else if (fdbs >= 0xA)
fdbs -= 0xA;
save1 = t[0]; //save first
save2 = t[12]; // and 13th
for (q=1; q<=5; q++) // put [ ]'s where they were at end
of loop
{
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
}
fdbssave = fdbs;
fdbfsave = fdbf;
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[0] = t[1] + table[fdbf*0xA+fdbs]; // 1st digit
t[0] = fix(t[0]);
t[12] = t[13] + table[fdbf*0xA+fdbs+0x64]; // 13th digit
t[12] = fix(t[12]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[1] = t[2] + table[fdbf*0xA+fdbs]; // 2nd digit
t[1] = fix(t[1]);
t[13] = t[14] + table[fdbf*0xA+fdbs+0x64]; // 14th digit
t[13] = fix(t[13]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[2] = t[3] + table[fdbf*0xA+fdbs]; // 3rd digit
t[2] = fix(t[2]);
t[14] = t[15] + table[fdbf*0xA+fdbs+0x64]; // 15th digit
t[14] = fix(t[14]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[3] = t[4] + table[fdbf*0xA+fdbs]; // 4th digit
t[3] = fix(t[3]);
t[15] = t[16] + table[fdbf*0xA+fdbs+0x64]; // 16th digit
t[15] = fix(t[15]);
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
t[4] = t[5] + table[fdbf*0xA+fdbs]; // 5th digit
t[4] = fix(t[4]);
t[16] = t[17] + table[fdbf*0xA+fdbs+0x64]; // 17th digit
t[16] = fix(t[16]);
t[5] = save1 + table[fdbfsave*0xA+fdbssave]; // 6th
digit
t[5] = fix(t[5]);
t[17] = save2 + table[fdbfsave*0xA+fdbssave+0x64]; // 18th
digit
t[17] = fix(t[17]);
// end of second call
// begin first call
fdbf = 0xFFC+t[17]-0x1000-0x30 ; // create [5db5]
if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = fdbf; // and [5db7]
save1 = t[0]; //save first
save2 = t[6]; // and 7th
for (q=1; q<=5; q++) // put [ ]'s where they were at end
of loop
{
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
}
fdbssave = fdbs;
fdbfsave = fdbf;
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[0] = t[1] + table[fdbf*0xA+fdbs]; // 1st digit
t[0] = fix(t[0]);
t[6] = t[7] + table[fdbf*0xA+fdbs+0x64]; // 7th digit
t[6] = fix(t[6]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[1] = t[2] + table[fdbf*0xA+fdbs]; // 2nd digit
t[1] = fix(t[1]);
t[7] = t[8] + table[fdbf*0xA+fdbs+0x64]; // 8th digit
t[7] = fix(t[7]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[2] = t[3] + table[fdbf*0xA+fdbs]; // 3rd digit
t[2] = fix(t[2]);
t[8] = t[9] + table[fdbf*0xA+fdbs+0x64]; // 9th digit
t[8] = fix(t[8]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[3] = t[4] + table[fdbf*0xA+fdbs]; // 4th digit
t[3] = fix(t[3]);
t[9] = t[10] + table[fdbf*0xA+fdbs+0x64]; // 10th digit
t[9] = fix(t[9]);
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
t[4] = t[5] + table[fdbf*0xA+fdbs]; // 5th digit
t[4] = fix(t[4]);
t[10] = t[11] + table[fdbf*0xA+fdbs+0x64]; // 11th digit
t[10] = fix(t[10]);
t[5] = save1 + table[fdbfsave*0xA+fdbssave]; // 6th
digit
t[5] = fix(t[5]);
t[11] = save2 + table[fdbfsave*0xA+fdbssave+0x64]; // 12th
digit
t[11] = fix(t[11]);
// end of first call
} // end for loop
printf("\nTo Get That 'Magic' Use: ");
for (i=0; i<18 ;i++) // output the string (only first 18)
putc(t[i], stdout);
printf("\n\n Created by +xxxxx for +Orc's HCU 1996");
} // end of main()
char fix(char x)
// fixes chars to between 0 and 9
{
if (x < '0')
x = x+0xA;
else if (x > 0x39)
x -= 0xA;
return x;
}
III. THE [DATADUMP_WINDOW] TRICK & HOW TO SEARCH THE WEB.
[WINFORMANT 4 HOW TO FIND IT]
I have chosen (as usual) an older windows application for
Win 3.1. (Version 1.10, by Joseph B. Albanese), in order to
terminate completely the "password lessons" and at the same time
show you a nice little trick that can be very useful in cracking
*ALL* protected programs (password protected or time protected
or function disabled): memory windows_dumping. There is in almost
all protection routines, as you have already learned, a moment
when on the stack appears the ECHO of the real, "correct"
passnumber or password, in order to compare the input of the user
with it.
The location of this ECHO varies, but it will be most of the
time in a range of +- 0x90 bytes from the user input. This is due
to datadump windows restraints inside the tools used by the
protectionists I'll not delve inside here, and this use is bound
to diminish (especially after this lesson :=).
You'll find the files that I use in this lesson searching
the web with the usual search_tools and search_strategies: These
are names, lengths and dates of the relevant files... this will
allow you to FTPMAIL them after having located them through an
ARCHIE_search:
CTL3D DLL 20976 17/08/93 4:36
README WRI 2688 08/05/94 1:54
SS3D2 VBX 88096 11/06/92 18:42
STDLL DLL 10880 06/05/94 22:57
THREED VBX 64432 17/07/93 0:00
WIN4MANT EXE 562271 07/06/96 17:51
WIN4MANT HLP 190608 08/05/94 0:36
XLIST VBX 15248 15/02/93 0:00
Please do not underestimate the importance of *EXACT NAMES*
on the Web (be it of people, of subjects or of software)... as
a matter of fact the Web corroborates (every day more). The old
intuition from Persio: NOMEN ATQUE OMEN: how true! Think a moment
about it, the importance of the NAMES on the Web is astonishing
(and growing)!
1) It is true for http://... addresses: domains must be
unique and registered (and the Web registration burocrats will
get from you 100 dollars per year just to keep them registered);
2) It is true for programs (you must know BEFOREHAND the name of
a file to find it quickly on the Web); 3) It's even true for your
own site denomination (try searching for "Bill's" page instead
than for "WIKKY_WAKKY's" page... that's (reversing this approach)
one of the reason I have a "+" inside my handle, this confuses
the search engines just enough to give me a little more anonymity
(search for me! You'll get quite a lot of Warcraft stuff :=).
Enough! If you do not know neither why all this happen nor
how to search the Web, but are interested in these matters (as
you should), study the web search engines themselves and read the
relevant help files (search AltaVista and WebCrawler for
"FTPMAIL", "WWW via e-mail", "AGORA", "search strategies" etc).
It's amazing how few crackers (not to mention the lusers)
do actually read the help files of the search engines they are
using, which should be your bible (or the coran, or some other
crap, for all I care about religions), your alpha and omega! The
(growing) amount of junk on the Web makes your ability to search
effectively the little grains of interesting truths that are
escaping the growing heavy censorship of our enemies even more
important.
Back to our [Winformant] cracking now, and back to our
stackdump window trick... here you are:
[WINFORMANT CRACKING]
This application is -per se- absolutely crap, I doubt you'll
ever use it: this program is so primitive it must have been one
of the first crappy visual basic experiments made by his
programmer... but this [Winformant] program is nevertheless very
interesting for us coz it possesses a curious (and pretty rare)
"deactivate" mode, i.e. you can "unregister" it on the fly if you
feel the need to... it beats me why the programmer wanted such
a feature inside... he was just probably collecting little
routines and mixing them without sound reasons.
This feature is as rare as useless, but it is worth for
cracking scholars that (should) investigate password algorithms
with valid and invalid codes without having to reinstall
everything only in order to delete previous valid codes.
For your cracking exercises you should therefore choose
programs that have "REVERSIBLE" protections (like this
Winformant... very rare) or that can be re-registered a billion
times (that's a more frequent protection pattern). Programs that
keep the valid registration on *.ini or special files can also
be useful... you just need to change a couple of lines in these
files to restore the "unregistered" mode.
The trick we'll use in this lesson: "password proximity",
bases on the fact that the protectionists need to keep an eye on
their protection when they "build" it and have to *see* closely
the relationships between
1) USER INPUT PASSNUMBER (i.e. the input registration number
that the user should have bought, but could be a fake bad guy
input)
2) USER INPUT TRANSFORMED (i.e. the result of the working of
the protectionist's algorithm on the user input passnumber)
and the
3) CORRECT PASSNUMBER ANSWER (The BINGO!) i.e., the Passnumber
calculated with some algorithm on the bases of the USER INPUT
NAME (the name of the user, eventually transformed in USER INPUT
TRANSFORMED).
In order to clear bugs these relationships must be
constantly checked when they prepare the protection... i.e. when
they are writing the protection code.
Most of the time all these data will therefore dwell inside
a small stack... that means they will be "visible" in the SAME
"watchwindow" inside the protectionist's debugger... and they use
the same turbodebugger (or Winice) YOU are using!
This means that most of the time the "ECHO" will swell not
very far away from the USER INPUT. Therefore proceed as follows:
Fire Winice
Fire Winformant
Choose HELP
Choose REGISTRATION
Fill the registration fields
this is mine: "+ORC+ORC" as "Registrant"
and "12121212" as "Activation" code
CTRL+D ;switch to Winice
task ;let's see the names
:task
TaskName SS:SP StackTop StackBot StackLow TaskDB hQueue Events
WINWORD 1AD7:85F2 4A52 8670 7532 1247 122F 0000
PROGMAN 1737:200A 0936 2070 1392 066F 07F7 0000
DISKOMAT *2C5F:6634 1D3C 6AC6 5192 2CB7 2C9F 0000
hwnd DISKOMAT ;which window is getting the input?
:hwnd diskomat
WinHandle Hqueue QOwner Class Name Window Procedure
0EB4(0) 2C9F DISKOMAT #32769 04A7:9E6B
0F34(1) 2C9F DISKOMAT #32768 USER!BEAR306
365C(1) 2C9F DISKOMAT #32770 2C3F:0BC6
36BC(2) 2C9F DISKOMAT Button 2C3F:1CEA
3710(2) 2C9F DISKOMAT Edit 2C3F:24BE
3758(2) 2C9F DISKOMAT Edit 2C3F:24BE
37A0(2) 2C9F DISKOMAT Button 2C3F:1CEA
37E4(2) 2C9F DISKOMAT Button 2C3F:1CEA
... and many more irrelevant windows.
bmsg relevant_window wm_gettext ;let's pinpoint the code, here
;the relevant window is the first "edit" one (obviously),
;i.e. wHnd 3710 you could also use GetWindowsText or
;GetDlgItmText to locate the relevant routines
:bmsg 3710 wm_gettext ;set breakpoint
CTRL+D ;run the babe
Break Due to BMSG 3710 WM_GETTEXT C=01
Hwnd=3710 wParam=0050 lParam=2C5F629A msg=000D WM_GETTEXT
2C3F:000024BE B82F2C MOV AX,2C2F
So! Now that we have pinpointed the code... let's snoop around
a little: first thing to do is a good stack command which, here,
will work OK (in other cracking sessions it may not -magic
involved- but do not worry: if it does not work immediately, just
pinpoint a little more... for instance on GetWindowText() (always
good) or do a BPRW diskomat (also very useful), and then try and
retry the stack... should this too fail to work, do search for
your input in memory (in the 30:0 lffffffff selector, as usual)
and breakpoint range on it with ReadWrite, and then stack, stack,
stack... till you get the "real" list of calls coming from your
babe's protection (in our example the babe's name is "DISKOMAT").
:stack
USER(19) at 073F:124C [?] through 073F:1239
CTL3D(02) at 2C3F:0D53 [?] through 2C3F:0D53
DISKOMAT(01) at 2C97:20B9 [?] through 2C97:20B9
DISKOMAT(01) at 2C97:3D94 [?] through 2C97:3D94
DISKOMAT(01) at 2C97:49E2 [?] through 2C97:4918
DISKOMAT(04) at 2C7F:EA20 [?] through 2C7F:EA20
USER(01) at 04A7:19BE [?] through USER!GETWINDOWTEXT
=> CTL3D(02) at 2C3F:24BE [?] through 04A7:3A3Cë
Beautiful stack picture! Immediately BPX on 2C7F:EA20 (on your
computer the segment will differ, the offset will be the SAME).
2C7F:EA20 9A25ABA704 CALL USER!GETWINDOWTEXT
2C7F:EA25 8E4608 MOV ES,[BP+08]
2C7F:EA28 26FFB42C02 PUSH WORD PTR ES:[SI+022C]
2C7F:EA2D 8D865CFF LEA AX,[BP+FF5C]
2C7F:EA31 16 PUSH SS
2C7F:EA32 50 PUSH AX
2C7F:EA33 6A50 PUSH 50
2C7F:EA35 9A25ABA704 CALL USER!GETWINDOWTEXT
2C7F:EA3A 8D46AE LEA AX,[BP-52] ;load ptr "+ORC+ORC"
2C7F:EA3D 16 PUSH SS ;save pointer segment
2C7F:EA3E 50 PUSH AX ;save pointer offset
2C7F:EA3F 9A768D872C CALL 2C87:8D76 ;strlen "ORC+ORC"
2C7F:EA44 83C404 ADD SP,+04
2C7F:EA47 3D2800 CMP AX,0028
2C7F:EA4A 762C JBE EA78
...
2C7F:EA78 8D442C LEA AX,[SI+2C]
2C7F:EA7B FF7608 PUSH WORD PTR [BP+08]
2C7F:EA7B FF7608 PUSH WORD PTR [BP+08]
2C7F:EA7E 50 PUSH AX
2C7F:EA7F 9AE002772C CALL 2C77:02E0
2C7F:EA84 0BC0 OR AX,AX
2C7F:EA86 740F JZ EA97
2C7F:EA88 687F2C PUSH 2C7F
2C7F:EA8B 68E4ED PUSH EDE4
2C7F:EA8E 6A00 PUSH 00
2C7F:EA90 6A00 PUSH 00
2C7F:EA92 6A00 PUSH 00
2C7F:EA94 E94501 JMP EBDC
2C7F:EA97 8D46AE LEA AX,[BP-52] ;load ptr "+ORC+ORC"
2C7F:EA9A 16 PUSH SS ;various algor on input
2C7F:EA9B 50 PUSH AX ;we do not care
2C7F:EA9C 8D860AFF LEA AX,[BP+FF0A]
2C7F:EAA0 16 PUSH SS
2C7F:EAA1 50 PUSH AX
2C7F:EAA2 6A51 PUSH 51
2C7F:EAA4 8D442C LEA AX,[SI+2C]
2C7F:EAA7 FF7608 PUSH WORD PTR [BP+08]
2C7F:EAAA 50 PUSH AX
2C7F:EAAB 9ABA00772C CALL 2C77:00BA
2C7F:EAB0 0BC0 OR AX,AX
2C7F:EAB2 0F851101 JNE EBC7
2C7F:EAB6 8D8E5CFF LEA CX,[BP+FF5C] ;ptr "12121212"
2C7F:EABA 16 PUSH SS
2C7F:EABB 51 PUSH CX
2C7F:EABC 9A768D872C CALL 2C87:8D76 ;strlen "12121212"
2C7F:EAC1 83C404 ADD SP,+04
2C7F:EAC4 50 PUSH AX
2C7F:EAC5 8D865CFF LEA AX,[BP+FF5C] ;ptr "12121212"
2C7F:EAC9 16 PUSH SS
2C7F:EACA 50 PUSH AX
2C7F:EACB 8D860AFF LEA AX,[BP+FF0A] ...etc
OK, it's enough: now what obviously follows is to "algorithmize"
this second string, and somewhere, then, you'll have a compare
that checks and divides good guys from bad fellows.
BUT NOW IT'S ALSO THE MAGIC MOMENT OF THE ECHO! We know it, we
feel it: The echo is somewhere... what can we do to find it?
Should we search "12121212" in memory? No, look how many
locations we would find...
:s 30:0 lffffffff '12121212'
Pattern Found at 0030:0005AD6A
Pattern Found at 0030:0048AD6A
Pattern Found at 0030:007DED98
Pattern Found at 0030:007E25F8
Pattern Found at 0030:008E0FE1
Pattern Found at 0030:008E1433
Pattern Found at 0030:008E186F
Pattern Found at 0030:008E1904
Pattern Found at 0030:008E601A
Pattern Found at 0030:80509D6A
Pattern Found at 0030:8145AD6A
Pattern Not Found
And now...should we look for all occurrences of this string
and get a memory dump of +- 0x90 around it till we find the
echo... that's not zen... that's boring, even if we know that the
relevant ones will ALWAYS be the ones that have MORE than
80000000 in their "offset", i.e., in this case, only two:
Pattern Found at 0030:80509D6A
Pattern Found at 0030:8145AD6A
But this procedure is not always true, and in other
protection there will be a proliferation of locations with the
aim of deterring casual crackers... clearly the above method is
no good... there must be some other way... YES THERE IS!
THE LAST loading of the numeric input string in the code
(the one after the strlen count) is most of the time (exspecially
in Visual Basic and Delphy programs) the "right" one for our
cracking purposes, coz the protections follow (most of the time)
this pattern (remember that we are here inside a stack "heavy"
section of the code... if you want to crack higher I suggest you
read some good literature about stack working and stack magics
inside the 80386/80486/80586 processors).
This is the usual sequence:
LOAD NAME
COUNT NAMELENGTH
LOAD NAME_AGAIN
TRANSFORM NAME
LOAD PASSCODE
COUNT PASSCODE_LENGTH
LOAD PASSCODE_AGAIN
E-mail +ORC
+ORC an526164@anon.penet.fi