--------------------------------------------------------
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 at:
     http://www.math.gatech.edu/~mladue/PenPal.java

     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 f***!ing 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
                    <- ECHO CHECK here
     TRANSFORM PASSCODE
                    <- ECHO CHECK here
     COMPARE TRANSFORMED_NAME WITH TRANSFORMED_PASSCODE

     So... what does this mean? This means that at line
2C7F:EAC5 8D865CFF   LEA  AX,[BP+FF5C]  ;ptr "12121212"
you'll already have your echo somewhere... just dump the memory
around the pointer [BP+FF5C]:

:d 2c5f:61e8

2C5F:61E8 
02 62 2F 06 02 00 26 2E-A3 4E A3 4E 01 00 38 30  .b/...&..N.N..80
33 37 2D 36 34 36 2D 33-38 33 36 00 01 06 02 00  37-646-3836.....
2F 06 75 62 C3 2E B7 04-F2 24 2F 06 CE 6E 2F 06  /.ub.....$/..n/.
49 00 5A 00 00 00 01 00-04 2C 2F 06 AE 24 36 62  I.Z......,/..$6b
74 62 7A 2E B7 04 36 62-01 00 C2 62 2F 2C 26 2E  tbz...6b...b/,&.
03 01 BA 0F AE 24 5F 02-C9 01 5E 02 BA 01 5F 02  .....$_...^..._.
31 32 31 32 31 32 31 32-00 00 0C 00 BC 02 00 00  12121212........
00 00 00 00 49 00 BA 0F-AE 24 F2 24 2F 06 00 00  ....I....$.$/...
AF 17 00 00 00 00 E2 5F-7A 62 FE FF 79 1B BA 0F  ......._zb..y...
96 0B 01 00 02 4E 00 00-37 01 8A 62 D2 0F 8F 17  .....N..7..b....
2F 06 00 00 00 00 37 01-98 62 20 10 16 03 2F 06  /.....7..b .../.
C2 62 2B 4F 52 43 2B 4F-52 43 00 0D AE 24 2F 06  .b+ORC+ORC...$/.
                                          2C5F:62A7 

and look... everybody is there! The stack pointers points in the
middle of this dump, at the string "12121212". 0x50 bytes before
is our good old ECHO (i.e. the CORRECT passnumber) and 0x50 bytes
afterwards is my beautiful input name "+ORC+ORC". 
     Therefore the "right" code for "+ORC+ORC" is 8037-646-3836.
It cannot be so easy! You'll protest. It is: this crap protection
is already cracked and hunderts of Visual Basic/Delphy schemes
are absolutely identical. 
     Now begins the hard work: if you really want to learn,
accomplish the following tasks:
-    First of all "Unregister" and find anew your own code for
     your own handle. *DO NOT* use serial numbers with any other
     name that your own handle.
-    Study the two coding algorithms, the one for the input name
     and the one for the input passnumber, this will be useful
     for ALL your future cracking sessions.
-    Find the compare locations, i.e. the code block that sets
     the two usual flags "good guy, you may move on" and "bad
     cracker, beggar off", and create a patch crack for this
     protection, that will allow anybody, with any name and any
     password number to get through.

Please accomplish all of the preceding tasks: once you do it
you'll have FINISHED the password protection schemes part of my
tutorial and you'll be able to pass over to the (very
interesting) world of disabled and crippled functions (all these
"demos" that do not save and do not print... I'll teach you how
to do it, starting in Februar 1997).

Well, that's it for this lesson, reader. Not all lessons of my
tutorial are on the Web.
     You 'll obtain the missing lessons IF AND ONLY IF you mail
me back (via anon.penet.fi) with some tricks of the trade I may
not know that YOU discovered. Mostly I'll actually know them
already, but if they are really new you'll be given full credit,
and even if they are not, should I judge that you "rediscovered"
them with your work, or that you actually did good work on them,
I'll send you the remaining lessons nevertheless. Your
suggestions and critics on the whole crap I wrote are also
welcomed.

     "If you give a man a crack he'll be hungry again
     tomorrow, but if you teach him how to crack, he'll
     never be hungry again"

+ORC  526164@anon.penet.fi

