Unfortunately, this site has restricted functionality as this browser does not support the HTML button formaction attribute.
Unfortunately, this site has restricted functionality as this browser has HTML web storage turned off.

How To Crack, by +ORK, A Tutorial. by Independent (IND)

1 of 1 file ork
A very thorough tutorial on how to crack software titles from the late 1980s and early 1990s.
  • TXT / Text   How to
  • 292 kB   DOWNLOAD   SHARE
hide RetroTxt from Defacto2   The open source WebExtension to view many ANSI, ASCII and NFO files in a browser. Available for Chrome Firefox Brave Edge.
[+] Configuration Select all


(Htocrk10.txt) Lesson 1: an approach

(Htocrk20.txt) Lesson 2: tools and tricks of the trade

(Htocrk31.txt) Lesson 3.1: hands on, paper protections (1)

(Htocrk32.txt) Lesson 3.2: hands on, paper protections (2)

(Htocrk51.txt) Lesson 5.1: disk & CD-Rom access (basics)

(Htocrk61.txt) Lesson 6.1: funny tricks

(Htocrk81.txt) Lesson 8.1: how to crack Windows, an approach

(Htocrk82.txt) Lesson 8.2: how to crack Windows, a deeper approach

(Htocrk91.txt) Lesson 9.1: how to crack Windows, hands on

(Htocrka1.txt) Lesson A.1: advanced cracking: internet cracking (Unix)

(Htocrkc1.txt) Lesson C.1: how to crack, cracking as an art

(Htocrkc2.txt) Lesson C.2: how to crack, cracking as an art                     HOW TO CRACK, by +ORC, A TUTORIAL


                           Lesson 1: an approach




     The best way to learn cracking (i.e. understanding, broadly

individuating, locating exactly and eliminating or suspending or

deferring one or more protection schemes inside a software

application you do not possess the source code of) is to begin

your tampering experiments using OLDER applications which have

OLDER protection schemes.

     In this way you 'll quickly grasp the base techniques of the

trade. Do not forget that the evolution of the protection schemes

has not been a one way road... strictly speaking it's not even

an evolution: you'll eventually find some very clever new tricks,

but most of the time you 'll unearth only various trite

repetitions of past (and well known) tricks. This is no wonder:

the REAL knowledge of the "commercial" programmers themselves

(the "protectionists") is often very limited indeed: they are

inclined to use the old methods (albeit somehow changed,

sometimes even improved) instead of conceiving new methods. This

typical "commercial" degeneration happens every time people act

for money instead of doing things for the sake of it or for

pleasure. This "commercial" trend is blindly encouraged by the

stupid, money-oriented society we are coerced to live in.

     So I'll begin the "hands on" part (-> starting from lesson

3), using as examples, some "old" applications and some "old"

tricks. We'll be able to come later over to the newest protection

schemes in order to understand them, and you 'll learn how to

defeat this kind of junk too. I'll also explain WHERE you can

find a lot of programs to crack for next to no money at all, and

HOW 'grossomodo', you should proceed in your work.

     This tutorial is for people who are getting started with

cracking. Maybe you are just contemplating doing some cracking,

maybe you have tried it with mixed success. If you are here to

get aimed in the right direction, to get off to a good start with

the cracking tricks and procedures, then you have come for the

right reason. I can't promise you'll get what you want, but I'll

do my best. On the other hand, if you have already turned out

some working cracking code in assembler and already cracked many

different protection schemes, then this tutorial is likely to be

on the elementary side for you. (If you want to review a few

basics and have no where else pressing to go, then by all means


     In order to crack successfully you need four basic things:

*    A passing knowledge of assembler language (the more you

     know, the better and quicker you crack)

*    Some intuition

*    Some help from more experienced cracker

*    A non mercantile mind (more about this later)

The applications you'll use to learn with can be divided into:

1    - Password crippled applications (the easiest to crack)

2    - applications crippled on how many times, or how many

     days, you use them (fairly easy to crack)

3    - applications crippled on which date you use them before

     (easy to crack)

4    - applications that have some functions present but

     disabled (sometimes easy, sometimes difficult)

5    - applications crippled on Disk access (protections schemes

     that are now defined as "obsolete") and applications

crippled on

     CD-ROM presence (more or less the same methods, but -

     somehow- not defined as "obsolete") (very easy to crack)

6    - CRYPTOGRAFED ADDS ON (i.e. one of the previous protection

     schemes, but with some scrambled or self modifying code

     (XORring and SHRLing codes) (fairly easy to crack)

7    - None of the above (sometimes difficult to crack)


     The recent widespread appearance of "Demo"-CDROM on magazine

covers is a treasure for all crackers! A short time after their

release you 'll get all the copies that remain unsold for next

to free. The demos on CD-ROMs will permit you to gather quickly

a lot of applications -old and new- that have somehow been

crippled (at times with interesting schemes). Truly a wonderful

world of cracking possibilities! Gee! For next to no money you

can secure on one CDROM the whole of LOTUS applications (or

Microsoft or Wordperfect, or you name them) on "trial for 30

days" or "try it 20 times" editions. You'll really enjoy to crack

them, to use them for ever and ever and/or graciously donate them

on the Web to the poor lamers that have no money and no brain.

     GAMES are definitely not to be frowned upon! They are

very interesting from a cracker prospective coz they are often

"overprotected". With this I mean that they possess protection

schemes of a relatively HIGH level hidden inside files that are

relatively small. Now, see, it is much more easy, and simple, to

track down and eliminate protection schemes inside a single

35.000 bytes long executable file than to locate them inside a

collection of many lengthy DLLs and overlaids that could have

swollen as long as 2.000.000 bytes each. The lazy bunch of

"modern" programmers relies systematically for protection schemes

on this "hide the sting in the wide desert" logic. As a matter

of fact they are no longer able to program in assembler: they

bank more and more on overbloated "fatty" atrocities like Visual

Basic, Delphy or Visual C++. (Don't worry... I'll nevertheless

teach you how to crack -and quickly- those huge applications


     There is another reason for employing games instead of

applications as study material: often EXACTLY THE SAME protection

schemes that you find in a simple (and short) shareware game will

be used -without much improving- a little later in order to

"protect" some huge and extremely expensive graphic application.

     For this reason in my tutorial we'll often crack games

protection schemes, even if we'll later apply what we learn

mainly in order to crack the protection schemes of commercial

applications, or to crack the access protection routines to

remote servers, or BBS, or even ATM (cash dispensers).

     Here follows an example cracking session, that will show you

-I hope- the dos and donts of our art: let's crack together as

introductory example a time crippled application. We'll learn

later (-> LESSON 4) that all applications that are crippled on

time (i.e. "how many times" you use them or "how long" you use

them) rely on analogous protection schemes (albeit with a huge

palette of small variations):

1-   they may have a counter which "clicks" every so often: FIND


2-   they may fetch the time_clock interrupts in your machine:


3-   they may compare a random_seed with a variable: NOOP IT!

4-   they may check randomly the date of your other, unrelated,

     files on the hard disk: find this verification routine and

     INVERT the JUMPS!

I wanted to start with a modern example of this "counter clicks"

protection type, just to give you a feeling for cracking, and I

have chosen a widely published demo: you should be able to find

it pretty easily. In order to show you some of the problems you

may encounter we'll crack this example "wrongly" (you'll learn

how to crack effectively in the "HANDS ON" lessons).

     EXAMPLE: ARCADE POOL, Demonstration version, PC Conversion

by East Point Software Ltd, (c) Team 17 Software Ltd 1994. This

demo has been published by many magazines on their CDRom covers

throughout 1995.

     What follows will be useful even if you do not have our

example; nevertheless you should get a copy of this widespread

demo in order to better grasp some of the following points.

     This nice demo of a billiard game is time-crippled. It is

crippled on how long you use it: i.e., you can only play 2

minutes, afterwards a "nag" reminder of where and how you can buy

the real version snaps: protectionist squalor at its best.

     So, how do you proceed? Where does the beginning begin?

Here is what you could (but not necessarily should) do:

     Get [Soft-ice] and load it in your config.sys. See the TOOLS

OF THE TRADE lesson (-> LESSON 2) about this debugger. Version

2.6 of [Soft-Ice] has been cracked by MARQUIS DE SOIREE and can

be found on the Web for free.

-    vecs s (save all the vectors before loading the babe)

-    start [pooldemo.exe]

-    vecs c (vector compare, save a printing of all hooked


-    enter and leave Soft-ice a few times to understand what's

     going on and where in [pooldemo.exe] are we roaming around

     (you should always check MORE THAN ONCE your findings when

     you snoop around: nothing moves and confuses pointers in a

     more frenzied way than good old "inactive" DOS).

-    have a good look at the map of memory usage ("map")

-    now "snap_save" the main memory regions where

     [pooldemo.exe] dwells... snapping saves "photographs" of

     memory areas.

-    do not do anything, let just the seconds go by.

-    "snap_compare" every two or three seconds without moving

     anything at all on the game board (no mouse_clicking,

     NOTHING), so that the only changes are (hopefully) the

     changes caused by the time counters.

-    snap_compare twice in a second.

-    snap_compare at second 00:59 and at second 1:01.

-    snap_compare just before and just after the time limit and

     the snapping of the nag screen.

-    Now collect carefully your printed "snaps" data: write

     clearly on the various sheets the occurrences of the snaps.

-    now comes the graceful "zen-cracking" moment: Sit down with

     a dry Martini and Wodka (obviously only russian Wodka will

     do) and contemplate the printing of the various mutant

     locations. Feel, perceive, empathize! Look closely at the

     locations that have changed in the snap compares. Analyze,

     interpretate, evaluate.

-    Mmm! Hey! Something fishy is changing there, and there, and

     there! (you are lucky, few do actually change in this case:

     only two dozen)

-    breakpoint on execute at the location that you believe act

     as a "continuous" counter, i.e. the location that triggers

     the "a second went by" event when it zeroes.

-    Now set the occurrence counter of BPX in order to break at

     the moment where the location "refills" and restarts from

     the beginning (the equivalent of "one second" went by,

     let's start anew). Use the occurrence counter in order not

     to single-step through the program your life long!

-    IN THIS CASE you 'll quickly locate the refill at location

     3DD0. Here follows the "refill" line:

     xxxx:3DCC C706F1013C00   MOV  WORD PTR [01F1], 003C

The "3C" byte at xxxx:3DD0 represents a counter_byte... i.e. the

program "charges" 3C in this location and then DECs it step by

step to 3B, 3A, 39, 38 etc... till 0. When it reaches 0: bingo!

Sucker user has lost one second more of his precious two minutes.

     Now, you would get a first wizard level if you searched

further on for the exact point where you get the "nag screen" in

order to eliminate the whole witless protection, but you may

think you got it already and you remember anyway that the first

principle in cracking is the following: "once you can eliminate

the effects of a protection, do not look further!"

     Most of the time this is true: you do not always need to

eliminate a "whole" protection scheme (unless you are just

studying it for the joy of it). It's normally easier (and

quicker) to eliminate the "effects" of a given protection scheme.

Unfortunately this is not true in this case.

     Here you believe that you have already found the way: you

got the counter that charges the reverse clock that triggers the

particular protection scheme of [pooldemo.exe]. Now you may think

that if you could modify the refill_value... say changing "3C"

to "EE" (Yeah, the maximum would be FF... but it's always good

practice to avoid such extreme values when cracking) you should

get four times more playtime for your game... more than enough

in order to make the protection scheme useless.

     So you change location xxxx:3DD0 from "3C" to "EE". To work

on bytes you should use a good Hexeditor like PSEDIT (Parity

solutions, [Psedit.exe], brilliant shareware: see the "tool of

the trade" section) but you could also work with simpler

debuggers like [debug] or [symdeb] (-> see lesson 2). If you do,

remember to work on a "dead" copy of your crippled [*.exe] file,



     symdeb POOLDEMO.DED

     -s (cs+0000):0 Lffff C7 06 F1 01 C3 <-  this string

                                             corresponds to the

                                             refill line).

     cs:3E85   <- symdeb gives you two locations as answer


     -e cs:3E85+4 EE     <- refill changed from C3 to EE



Now you run your tampered pooldemo. You think you cracked it, you

glee with satisfaction... but loo! Nothing at all has changed,

everything's as lame as before, you still have only 2 minutes

playtime. How disappointing: how comez it didn't work?

     Well, for a start you have not been attentive enough! The

search in debug gave you TWO locations, you moron, and not just

the one you just tampered with. Check and you 'll see that the

second location (cs:3EEA) is a MIRROR/CONTROL location (more on

this later). Some times there exist "double" locations... coz at

times it's quicker to use a double routine than to use a

branching if or switch structure... some times the second

locations do mirror the first ones and correct them on the fly

if need be.

     So you need to modify this too... you act as said above but

this time you enter in debug a

     -e cs:3EEA+4 EE

before writing back the dead file and then renaming it to exe and

then running it... and loo! Hoow sloow! THERE YOU ARE! Your

crippled POOLDEMO.EXE is now (sort of) unprotected: You think

that you can now play the stupid game up to 12 minutes real time,

even if the protection scheme (and the counter) "believes" that

it is playing only two minutes.

     So you begin to play, and the seconds look veeery sloow, and

everything seems OK, but -alas- NO! At screen second 28 you get

the irritating "two minutes are over" nag screen! Obviously you

were dead wrong: the program "knows" the time directly from the

timer... you only modified the stupid counter ON THE SCREEN.

     So it's back to cracking, and now you are angry, and forget

the quiet ways of the zen-analyze and begin the heavy cracking

you should reserve -if ever- for really complicated schemes. You

now start to check the hooked vectors (you did your routinely

VECS_save before loading pooldemo in [Soft-ice] and your

VECS_compare afterwards) and you see some findings that you

believe interesting:

          vecs c

          08   1EFD:84C6 0CD1:17AC <- the clock

          09   1EFD:85EC 136A:069C <- the keyboard

          22   0BCE:02B1 0BCE:017E <- the terminate

     That's more like it -you think. Smack at the beginning: the

first hooked vector does it! It's good old interrupt_08: the


     Some basics for those of you that do not know anything:

INT_08 controls indirectly the INT_1C timer interrupt. The 8253

clock chip generates an IRQ_0 hardware interrupt at a rate of

18.2 interrupts per second. This gives control to the ISR

(Interrupt Service Routine) that the INT_08 points to... and this

should be at 0CD1:17AC, but has been hooked here, by pooldemo,

to 1EFD:84C6.

     One of the actions taken by the INT_08 ISR within the BIOS

is to issue a software interrupt call to INT_1C, just in case any

software modules within the system have established an intercept.

If no intercepts have been established, the default contents of

the INT_1C vector point to an iret instruction within the BIOS,

so that a null action results.

     Normally a protectionist would intercept INT_1C, coz at

every ISR from INT_08 the CPU would fetch the contents of the

corresponding interrupt vector and make an interrupt style call

to the code at that address (which should contain the iret at

address F000:9876 but can contain any trick they could think of).

     So -you think- the protectionist hooked here INT_08 directly

(a pretty infrequently used protection scheme by the way): What


     A rather drastic measure would be, in such circumstances,


disable the IRQ_0 level timer interrupt, which is controlled by

bit 0 of the mask register, at address I/O 0021h. When bit 0

within the mask register is set to 1, no further interrupts will

be recognized for this IRQ level. This unfortunately won't work

here, but it's an interesting technique per se, so you better

learn it anyway, just in case you should need it elsewhere:

--- Trick to disable the timer ("IRQ_0 masking" by +ORC) ---

*    prompt $t and hit ENTER a few times, see how the dos_clock

     is merrily ticking along?

*    enter DEBUG.COM

*    Assemble using the command 'a'

- a

in al,21

or al,1

out 21,al



RETURN    <- twice to exit immediate assembler

- g 100   <- to run the tiny program.

- q       <- to quit debug.

prompt $t is still on: hit ENTER a few times:

whoa! The clock has stopped advancing!

     Compliments: you loaded the current mask register's contents

into AL, you set the mask bit in the bit 0 position (which

corresponds to IRQ_0) at then updated the value back to the mask


When you are ready to activate IRQ_0 events again, reenter DEBUG,

run the following and then reset the clock you stopped with DOS

TIME command:

- a

in al,21

and al,fe

out 21,al


RETURN twice

- g 100

- q

A word of caution: with the timer click disabled some processes

will not operate correctly: once you access the diskette drive,

the motor will continue to run indefinitely afterwards, etcetera.


     Unfortunately the above technique cannot work with our

[pooldemo.exe], where you now are looking closely to the INT_08

hook you found, believing that it hides the protection scheme:

herein you find immediately the EoI (End_of_interrupt: MOV

AL,20h... OUT 20h,AL). Both controllers have a second port

address at 20h (or 0a0h), from which the instructions are given.

The most important is the EoI command (20h). This instruction

indicates the end of the interrupt handler and frees up the

corresponding controller for the next interrupt. If somebody

writes a new custom interrupt handler (as many protectionists

do), it's up to him to see to it that at the end of the handler

the EoI command (20h) is written to either port 20h or port 0a0h.

     After the EoI follow the usual pushes, then some CALLS then

a call that issues some OUT 40,AL that look like timer refreshing

(OUT transfers data to an output port and ports 40-42 correspond

to the Timer/counter). Some do_maintenance follows, then a double

CALL, one more conditional CALL and then a "mysterious" call FAR

CS:[AA91] on which depends a byte PTR[970C] that decides another

final CALL... then the routine pops all registers and irets away.

     Ah! You say, and begin disassembling, reverse engineering

and looking inside each suspect call (the quicker method in

these cases is to breakpoint calls on entrance and see if you

find the one that's only called at the awakening of the time

limit protection).

     You work, and work, and work... and eventually find nothing

at all, coz the protection of this program is NOT HERE!

     Back to the zen-analyze of the snap printings... we forsake

it too soon, as you will see.

     If you watch with more attention the compare locations for

the range DS:0 DS:FFFF you 'll notice that one of them changes

relatively slowly from 0 to 1 to 2 to 3 and so on... the

precedent location changes very quickly, and runs the complete

cycle 0...FF. That's a counter, at locations DS:0009 and DS:000A!

How long will it tick along? Well, we saw above that the "charge"

every second is 3C, so it will be x3C*x78=x1C20, coz x78 is 120

seconds, i.e. the two minutes time limit.

     Now search this 1C20 value around inside the code

(protections are most of the time at the beginning of the

CS:offset section), and you 'll find quickly what follows:

The protection in [pooldemo.exe] is at code_locations

CS:0A8A   813E20A7201C   CMP  WORD PTR [A720], 1C20

                         compare location A720 with limit 1C20

CS:0A90   7C07           JL   okay_play_a_little_more

CS:0A92   E834FD         CALL beggar_off_time_is_up


Now let's quickly crack it:



ren pooldemo.exe pooldemo.ded

symdeb pooldemo.ded

-    s cs:0 Lffff 81 3E 20 A7 20 1C

xxxx:yyyy           <- this is the answer of the debugger

-    e xxxx:yyyy+5 4C  <- this time limit is much better

-    w

-    q

ren pooldemo.ded pooldemo.exe


     We have done here a "weak" crack: we limited ourselves to

accept a (better) time limit, changing it from 1C20 to 4C20 (4

minutes instead of two). We could obviously have done a more

radical crack if we had changed the JL (jump lower) instruction

in a JMP (jump anyway) instruction. In this case it would have

worked, but for reasons that will be explained in lesson 4, you

should choose a rather delicate approach in cracking when you

deal with time-limit protection schemes.

     As you have seen, in this artificial cracking session we

found the protection scheme after a little snooping around. But,

as you will see in the hands on part, there are always MANY ways

to crack a single protection scheme. You could -for instance-

have found this protection the other way round: set a trace on

memory range for the program, restricting the trace to the first

part of it (say CS:0 to CS:1000, if you do not fetch anything you

can always try the other blocks). Breakpoint at the nag screen,

have a look at the last 300-400 backtraced instructions, if you

did not move anything, everything will follow a repetitive

pattern, until the protection snaps on:


       JL 0A99

       CMP BYTE PTR [A72A],01


       JL 0A99

       CMP BYTE PTR [A72A],01


       for ages and ages and then...


       JL 0A99

E834FD CALL 0759           <- BINGO! (CALL beggar_off_time_is_up)

... there it is, found the other way round. (But this apparently

better method is unfortunately very unstable: it depends on your

timing of the breaking in and on the distance between protection

and nag screen, therefore the somehow more complicated, but more

sure previous one should be favoured).

     The reason why "minimal" approaches in cracking are often

more successful than heavy vector_cracking, is that the programs

are hardly ever "overprotected", and therefore the protections

are seldom difficult to find (and those that are really worth

cracking for study reasons).

     Sometime you don't even need to crack anything at all! Some

applications are fully functional -per se-, but have been

crippled in a hurry in order to release them as demos. The

commercial programmers want only money, do not even try to

understand our zen ways, and do not care at all for a well done

job. That means, among other things, that the hard disk of the

user will be cluttered with files that the main program module

never calls. A typical example of this sloppy method is the demo

of [Panzer General] from SSI that appeared in the summer '95.

This was in reality no less than the complete beta version of the

game: you just had to substitute to one of the two "allowed"

scenarios one of the 20 or more scenarios of the beta version in

order to play them freely... you didn't ever need to crack!

     The pooldemo crack example above should not discourage you

from cracking intuitively. Be careful! Perform a thoroughly

zen_analyze before attempting deeper methods: do remember that

you want to crack the protection scheme SOMEHOW, and not

necessarily following the same line of thought that the

programmer eventually WANTED YOU TO CRACK IT with.

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


                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


                  Lesson 2: tools and tricks of the trade





     When you break into a program you end up in portions of code

that are unfamiliar to you. It is also not uncommon for the

breakpoints to occur outside of the confines of the program you

want to crack. Getting your bearings is, in these cases, very


     One of the handiest utilities is the memory dump tool -it

tells you where all the device drivers and TSR are loaded, in

which memory locations the program you are cracking dwells, how

much memory is left and what the next program load point is. The

tools you use should report on the following:

-    the contents of interrupt vectors

-    the state of the BIOS data area, beginning at address 40:0

-    internal structures within DOS, such as the MCB chain, the

     SFT (System File Table) chain, the chain of installed

     device drivers, the PSPs and memory allocations associated

     with installed TSRs

-    memory allocation statistic from XMS and EMS drivers

     When seeking to understand a section of foreign code, you

must be especially careful to seek the real intent of the code.

Consider using a profiler prior to undertaking an analysis of an

unfamiliar program. This will help you by ensuring that you don't

waste time studying sections of the program that aren't even

involved in the protection scheme you are chasing down.

     Using a utility that charts a program's calling hierarchy

can give you an important perspective on how your babe conducts

its internal operations.


     First and foremost, your debugger must be designed for use

with resident modules (or must be itself a resident module).

Trying to crack with simplistic [debug.com] is a sure way to get

absolutely nowhere. We recommend Softice.exe from Nu-Mega

technologies (Version 2.6 [S-Ice.exe] has been cracked by MARQUIS

DE SOIREE and its vastly available on the Web). You could also

use [Periscope] or [Codeview] or Borland's Turbodebugger... all

these programs have been boldly cracked and/or distributed and

are now on the Web for free... learn how to use YAHOO and find

them. In emergency cases you could fix some quick crack using

[debug] or [symdeb], but, as said above, most of the time these

older debuggers won't do. I'll nevertheless ALWAYS give the final

crack procedure for [debug.com], in order to permit even lusers

to crack programs.

     When you first smell a protection, it can be tempting to

immediately begin your crack using invasive types of techniques.

While there is certainly nothing wrong with this approach,

provided that you are fairly familiar with the protection scheme

used, going in too deep too soon can be a problem when you don't

have a strong hunch. Most of the time you'll end up missing

important details. So first of all sit down and ponder... that's

the zen-way, the only one that really works.

     Single-stepping is expensive, not only because of the time

it requires but also because of the amount of detail with which

you must contend. Your immediate goal is to home in on the

protection scheme through a series of successively refined traps,

your broader aim is to get an overview idea of the program's

action... the wise use of breakpoints will condense these

minutiae into an understandable form.

     The first step is to try to identify the section of the

program where the protection scheme is snapping.

     Once you are able to isolate a certain section of a program,

breakpoints can be used to gather a trace history of the

program's execution. If your debugger sports a backtrace buffer,

logging window, or similar feature, by all means learn how to use

it. The debugger it's your best weapon, you must know all the

possibilities it offers and all the capabilities it possesses.

Having a debugger's display output echoed to a printer is another


     Using breakpoints is beneficial for two basic reasons: speed

and reduction of detail. Manual single-stepping is invaluable

when you are close to the protection scheme, but too much of it

will bore you to death.

     When selecting breakpoint locations and the types of

breakpoint to use, it is important to step back once more, drink

a cool Martini-Wodka (use only Moskovskaja: non-russian Wodkas

are appalling) and ask yourself: "What is this going to tell me?"

and "What else will I need to know once the break occurs?". MOST

IMPORTANT OF ALL: "Is my current cracking approach the simplest

and most direct?", coz you do not want to waste precious cracking


     When devising a set of breakpoints it is wise to consider

how "a trail of bread crumbs" can be left. Not allowing for an

execution chronicle from the start can mean having to restart a

cracking session.

     Setting breakpoints on certain software interrupt calls is

an excellent way to get an overview of a program's operations.

The INT_21 DOS services interrupt is probably the most universal

useful of these, with BIOS interrupts such as the INT_13 (BIOS

Disk services) and INT_16 (BIOS keyboard services) useful for

specific cracking.

     When working with a debugger, evaluative breakpoints are

usually your best shot. To avoid having to deal with a plethora

of calls, you would want to have a debugger capable of being told

to "break on any INT_21 call except where AH == 2C or AH == 0B".

     A real understanding of the working of a program is surely

important, but don't overdo it! To reverse-engineer even a small

program can involve many hours of analysis and documentation

work. If you'll not be able to use the zen-cracking techniques

described in this tutorial (sadly not everybody can) pace

yourself and make sure your chair is comfortable: you'll be

sitting for quite a spell.

     Much of the work involved in reverse-engineering consist of

chasing down tentacles. In order to understand the operations of

one function, you must understand what happens within each of the

functions it calls- its child functions. To understand these

child functions you must study their children; and so on down the

calling hierarchy tree. Then there is the data. Tracing tentacles

based on a program's calling hierarchy is a directed process.

Each function you encounter is basically a list of other

functions you must reckon with. When it comes to analyzing a

function's interrelationship with the program's data structure,

no such list is provided. You must have instinct, feeling and


     Data analysis requires more of a broad-based inquisition.

For each memory variable you are interested in, you must survey

all functions to determine which ones read and write that

variable. The use of memory conditional breakpoints and of a

disassembler that builds a cross-reference table can make this

task a lot easier. (Use Sourcer! It's a fairly good tool and

version 4.08 of [sr.exe] has been long ago cracked and

distributed on the Web).


     Remember that if the program you are cracking was written

in assembler in the first place (very unlikely knowing the

laziness of to_days programmers), system calls are probably made

directly from the functions which need them. But when a program

is developed in a high-level language, it is more likely that

common library functions will be used for many operations

involving system calls. When a program makes all of its INT_21

calls from the same location, you know that this is certainly the


     Now, what happens sometimes is that the programmers write

the whole application in a overbloated language like C++, but are

afterwards compelled to "speed up" critical sections of the code

writing them in assembler. And loo! A section where you

repeatedly find assembler crafted patches is precisely the

protection scheme! So you could have a program with all INT_21

calls from the same location but for one or two calls which are

coming out of the section where the morons have "hidden" their

protection strategy. By just "looking" at the dead code of a

program, you should be capable to tell wich parts have been

"added on" in a later phase. They presents themselves as

unevenness and irregularities, especially if you use an utility

that represents graphicallly the code of a program. Protections

are often added on at the end of the development.

     Should you determine that the system calls relevant to your

cracking are made from common library functions, all is not lost.

The specific function from which these library calls were made,

the function you are seeking to locate, is executing at some

point in between these calls. Break in with your debugger at the

end of the first system call, just where it is returning to the

point of call. From there, trace through the remainder of the

common library routine until it returns to its caller. In short

order, you should find yourself in the function you need to see.

The trick is to be able to identify it for what it is.


     In the interest of gaining an overall familiarity with the

program you want to crack, it can be enlightening to use a hex

dump utility to examine the message strings contained within the

program's binary modules. If the program happens to load its

message strings from separate files, your search has just been


     Your debugger's memory-dumping feature is one tool that can

be useful for this type of exploration. You could also construct

a filtering program, which would read a binary file and output

all sequences of bytes that are comprised of displayable

characters and are over a certain minimum length (the best

cracker tools are often the ones you write yourself).

     When a protection scheme is marked by the issuance of a

specific message on the screen, you could go into the program and

locate the code that emits this message, and then determine what

triggers it. A good way to start the location process is to see

if a system call is used to display the string. Interrupt INT_21,

INT_10 or INT_29 are usually used to display text messages to the


     When the message's display is not a result of one of these

system calls, direct video writing is probably being used. If you

know the screen location used, and if that part of video memory

is not used for anything else at the time (a big if), a memory

write breakpoint could be set on the video buffer address

corresponding to the first character's position. If this won't

work, use the step-over/step-around tracing technique while

watching for the message to appear.

     Now you found it: from a disassembled listing, you locate

the address of the message string and then survey the reminder

of the file for any instructions that reference this address.

[Sourcer] can generate labels for specific memory locations and

a cross-reference table showing where these labelled locations

are referenced. Otherwise, load the disassembled listing file

into your editor and use its search capabilities. Manually

searching for such things in a listing will make you old before

your time.


     When stepping through code at the assembler level, watch out

for interrupt calls that are followed by data. Sometimes you will

find an interrupt call, typically within the range INT_34 to

INT_3F, where several bytes immediately following the interrupt

instruction will be data rather than code.

     Be especially suspicious of this type of code-and-data

mixture when your debugger's disassembly output of the

instructions immediately following an interrupt call doesn't make

sense. Sometimes you  can determine the offset of the next true

instruction by inspecting the following code and data. In other

cases, you will have to trace through the interrupt call to see

how it accesses the data following the interrupt call instruction

and how it manipulates the return address on the stack.


     Seeing what interrupt intercepts already exist within a

system before running the program you want to crack, as well as

what interrupt handlers are established by the target program,

can provide useful clues. For example, if a protection

establishes an INT_09 intercept just before the snapping of a

keyboard verification routine, your range of suspects has just

been narrowed significantly.

     To study the interrupt vector activities of an application,

a vector dump map utility is useless. It can't be run while

running the application you want to crack. One solution is to run

the program under a debugger and watch for system calls to INT_21

functions 25h (set interrupt vector) and 35h (get interrupt

vector), but in the event that the program  reads and writes

interrupt vectors directly, this method will not give you a

complete picture. Normally you'll use a spy, trace or "step"



TO THE ENTIRE TABLE is another way to deal with this.

     Note that some sort of direct vector writing must be

occurring if a vector change is detected between system calls.

     If a vector change is detected during a system call but it

isn't function 25h of INT_21, suspect that an IRQ handler may be

effecting the change.


*    determining interrupt vector addresses ****************

     How do you determine the interrupt vector addresses? As

example let's find the address of the INT_21 interrupt vector.

Since the interrupt vector table starts at address 0000:0000

(easy to remember, isn't it?) and there are four bytes per

vector, the basic process is to multiply the interrupt number

four times and use the result at the offset (on segment zero).

21h + 21h = 42h                         42h + 42h = 84h

The int_21 vector is located at address 0000:0084

You could also use a calculator, for instance, the address of

INT_63 is 63h*4=18ch               ->   0000:018C

* address conversion ***************************************

     After a painstaking cracking session, you have finally

determined that a byte of memory at address 6049:891C is the

trigger. But when you isolate the offending instruction, you find

that the address it is generating when the protection occur is

different, being 6109:7D1C instead! How can this be?

     An 80x86 type CPU, when running in real or VM86 mode, uses

what is known as segment:offset type addressing. One side effect

of this addressing method is that one physical address can be

equivalent to many different segment:offset addresses.

     To find the PHYSICAL ADDRESS for a given segment:offset do

the following:

- convert the segment portion of the address to a 1-based number

by multiplying it by 16 (x10)... it's easy: add 0 at the right

end of the number!...

     6049 -> 60490

     6109 -> 61090

now all you have to do is to add this value to the offset value

     60490+891C  -> 68DAC

     61090+7D1C  -> 68DAC          <-   Got it?

And the other way round? If you have a physical address, say

19AC3, and you want to obtain a segment:offset address you must

first of all decide in which segment you want the address... if,

say, you choose segment 16CC, you proceed as follows:

     16CC           -> 16CC0

     19AC3-16CC0    =  2E03 (offset)

     address for 19AC3 in segment 16CC = 16CC:2E03


Before starting this section, for those of you that do not know

anything, here is the ARCHIE way you get all the program that do

EXIST on the planet: e-mail following

1) (address)   archie@archie.univ-rennes1.fr

I use this french archie, but you can get a worldwide list using

the metacommand "servers"

2) (text)      set search sub      <- anywhere in string

               set maxhits 140     <- (100-1000)

               set maxhitspm 15    <- not just 1 file all over

               find stepdos        <- search e.g. this file

Wait two hours, get your post and ftp the file you wanted (and

YES!, you 'll find also EVERYTHING else for free on the Web).

You could, instead of using archie, also learn how to use YAHOO.


     One of the most fascinating tools that I have ever seen is

a (very old) program: MEMSCAN.EXE.

This program was originally written in 1988 by Scott A. Mebust,

running in CGA. It's a "visual" utility: it enables you to see

graphically the 1-meg of PC memory in 8 kbyte chunks. It's a

powerful tool in order to locate quickly bit mapped graphics and

other 'objects' in memory, like program data tables, stack areas,

code areas, available RAM, etc. I used this great idea to create

(in C) my own tools: a "dead_programs scanner" and an ameliorate

version of Memscan itself. Looking at the VISUAL STRUCTURE of a

program it's a great help when you'll crack higher levels.


     A very good tool by James W.Birdsall, tracks memory usage

of programs (EMS, XMS, conventional).


     "THE" scancode lister, by the code_masters from clockwork

software. The must utility for crackers that do not learn all

scancodes by heart.


     Actually "MAP2", THE memory mapper from the code_masters at

clockwork software. It's a very good tool and an interesting one

too, coz you get it with the "Nigel" nag screens. They are not

difficult to remove (a "passletter" protection scheme, you'll

learn how to find and remove it from [Map.exe] in LESSON 3.2).


     There are hundred of file dump utilities, coz file dumping

is one of the first exercise they learn you at C-school.

Hexdump.com is 558 bytes long, Tdump.exe 120.704, pick the one

you like better or write your own (even better). Filedump.com,

by Daniel M.O'Brien, 1046 bytes long, it's nice.


     That's a good crack utility indeed! This 1989 program by

Daniel M.O'Brien gives you a "post-mortem" picture of your

memory. You redirect it to <myfile> and study it at ease. It's

difficult to say how many hours of cracking it did spare me (you

should study the program, only 252 bytes long, and will have to

modify it a bit, coz it's pretty primitive, in the original

version, for instance, the redirection to the printer works only

if there is NO SPACE between "spray" and ">").


     A good EXE files analyzer, useful for windows programs too

(see --> LESSON 7). Some of its functions are present in

TDUMP.EXE too. This 1991 program by S.Krupa it's sometimes very




     A must to study the "calling hierarchy" of an unknown

program. KGB.EXE, a 1992 program by Petr Hor…k could easily be

the best one, and comes with source code(!). I'll teach you how

to crack without any of them (you do not need them if you zen-

crack), but they can nevertheless be very useful in some

situations. Stepdos.exe, by Mike Parker, is a excellent program:

a pleasure to crack in order to use it for slightly different

purposes :=)


     SR.EXE can be used for sourcering unknown programs. It's a

fairly good sourcering tool. Version 4.08 has been cracked (it's

a "ORIGINAL NUMBERCODE" protected program) and distributed on the

Web, so you should easily find it. This said, you should NEVER

use such a brute force approach, unless you are really desperate:

I'll teach you how to crack without sourcering (you don't need

to sourcer if you zen-crack).


Every idiot has written at least one hexeditor, and you can find

very bad tools everywhere (the SIMTEL collection, on the Web,

lists at least 35 hexeditors). I suggest you write your own and

contribute to the flood, or (better) get PSEDIT.EXE, a good 1990

program by Gary C. Crider (Parity Solutions, 1903 Pavia Ct.

Arlington, TX 76006... sometimes even americans can write good

programs). If you do use it (as you should) disapt the nag screen

as small exercise in cracking.


     Your best friend in cracking, your weapon, your hidecloak...

I suggest [Softice.exe] from Nu-Mega technologies (Version 2.6

has been cracked by MARQUIS DE SOIREE and its vastly available

on the Web). You could also use [Periscope] or [Codeview] or

Borland's Turbodebugger... all these programs have been boldly

cracked and/or distributed and are now on the Web for free...

learn how to use ARCHIE and YAHOO in order to find them. Your

debugger is the only tool you 'll REALLY need, believe me. So

choose your weapon wisely and learn how to use backtrace ranges

and (FOREMOST!) breakpoint on user written qualifications

routines. You 'll be able to crack almost EVERYTHING using these

features in the right way.

     You should get all the programs mentioned above (all the

programs that EXIST for that matter) for free on the Web. Use

them, but also modify them recklessly! REMEMBER THAT YOU ARE

(GOING TO BE) A CRACKER! The first programs you should crack and

modify are therefore your very tools! So steal the code of the

best tools you find! Snatch the best routines and change them for

the better! That's the whole point in cracking: a mission to

IMPROVE the best accomplishments of humanity's genius :=)


     You 'll learn, beginning with next lesson, how to crack

systematically the different protection schemes: paper & password

protections, time protections, access protections. At the end of

the "methodolocical" part, you'll be able to deprotect programs,

but you still wont be a cracker. In order to crack higher you

must use what I call (lacking a better definition) "zen-

cracking". I 'll give you right now an example of this, so that

you know what I'm talking about, but -unless you are already

capable- you'll have to finish this tutorial part for "normal"

cracking before attempting this techniques. Let's zen-crack

together a password protection scheme (aka "paper protection",

coz you need the original manual of the program in order to

answer). This protection is based on the typing, at the nag

screen, of the correct sequence of numbers. Our example is a game

for the reasons explained in lesson 1, but you 'll find the SAME

protection scheme in the access protection procedure of some old

Tapestry networks... so do not frown upon games protections.

INDIANAPOLIS 500, Papyrus software & Electronic Arts, 1989

It's a rather widespread program, you should therefore find it

pretty easily. The nag screen asks for data based on the

historical performances of race cars... that means that the

answers will consist in two to three digits.

     Now, the normal way to crack such a program (described in

-> lesson 3.1) embodyes following steps:

-    snap save program memory areas before typing your answer

-    snap compare after typing, say, "666"

-    search for the sequence 36,36,36 (i.e. 666)

-    breakpoint on memory range for reading

-    look at the program part fetching your data

-    find the snap procedure

-    disable it.

     The above crack it's relatively quick and should be most of

the time fairly effective, but there is a better way: the "zen

way", the only one that can really enable you to crack high

protection schemes.

-    Run the program and break in at the nag screen

-    Answer consist of 2-3 digits? Search for "AC" (i.e. the

instruction LODSB, load digit of answer in AL) in the area 500

bytes BEFORE and 500 bytes AFTER your position. You'll get some

locations. (In the case of INDY 500 you get 6 such locations).

-    "feel" the locations (that's the tricky part).

-    OK, you already made it! Here is the protection strategy:

  8BBF28A5     MOV  DI,[BX+A528]<-- DI points to coded data area


  AC      LODSB          <-- load first digit of answer in AL

  B4FF    MOV  AH,FF     <-- load mask in AH

  2A25    SUB  AH,[DI]   <-- sub coded data from mask and get

                         real answer

  47      INC  DI        <-- ready to get next coded data

  3AC4    CMP  AL,AH     <-- user answer = real answer ?

  751A    JNZ  beggar_off_coz_false_answer

  0AC0    OR   AL,AL     <-- more numbers?

  75F2    JNZ  compare_loop

  59      POP  CX        <-- all OK, go on, nice guy


And if the protection scheme had been more far away? And if you

cannot "feel" the right one? And if my grandma had wheels? You'll

learn it, believe me.

Now let's quickly crack this crap.


CRACKING INDY.EXE (by +ORC, January 1996)

ren indy.exe indy.ded

symdeb indy.ded

-    s (cs+0000):0 Lffff B4 FF 2A 25 47 3A C4 75 1A

xxxx:yyyy           <-- this is the answer of the debugger

-    s (cs+1000):0 Lffff B4 FF 2A 25 47 3A C4 75 1A

(nothing, but you must be sure there isn't a mirror)

-    e xxxx:yyyy+8 00    <-- "JNZ 1A ahead" changes to "JNZ 0"

-    w

-    q

ren indy.ded indy.exe


Cracked: you just changed the JNZ beggar_off instruction in a JNZ

go_ahead_anyway. Nice, isnt'it?


     Strange as it may seem, the reasons for cracking are very

important for the success of our task. We (at least we old

crackers) crack AGAINST society, and OPPOSING laws and

conventions. We usually DO NOT crack for money or for other

"commercial" reasons (just sometimes, and we are expensive: I

have plenty of money already and my services are VERY expensive

if you need an aimed deprotection). But in general we don't care

much for money and -as you can see- I am giving away the basis

of what I know for free with this tutorial. The programs we crack

should be made free for everybody, even if we spent some of our

time deprotecting them. We could not care less of the commercial

value of a given program, not to mention the holy work of the

ethical programmers... we program ourselves, but only because we

LIKE it... if somebody does something only in order to gain

money, he does not deserve anything. It's the mind challenge that

counts, NEVER the profit! (Even if you can make good use of the

cracked programs and even if -as I said- there is at times a

personal profit).

     This is an indispensable attitude! Only a non-mercantile

mind can leap forward to the "satori" knowledge that you

desperately need if you want to crack quickly and elegantly huge

iperbloated monstruosities that somebody else wrote and

protected, or if you want to gain access to some hidden

information, data that you would like to snoop but that somebody

declared "off limits", coz a stupid government, or useless

industry sector, or money oriented programmer or dirty lobby of

interest decided it.

     If you do accept the society where we are compelled to live,

its awfully egoistic way of life and its dirty "profit" values,

you may eventually learn how to disable some simple protections,

but you'll never be able to crack in the "right" way. You must

learn to despise money, governments, televisions, trends,

opinion-makers, public opinion, newspapers and all this

preposterous, asinine shit if you want to grasp the noble art,

coz in order to be emphatic with the code you must be free from

all trivial and petty conventions, strange as it may sound. So

you better take a good look around you... you'll find plenty of

reasons to hate society and act against it, plenty of sparks to

crackle programs in the right way... Hope all this did not sound

too cretin.

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


                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


                Lesson 3.1: hands on, paper protections (1)


                   [UMS.EXE] [LIGHTSPD.EXE] [GENERAL.EXE]



The INT instruction is the source of a great deal of the

flexibility in the PC architecture, because the ability to get

and set interrupt vectors means that system services (included

DOS itself) are infinitely extensible, replaceable and

MONITORABLE. Yet the Int instruction is also remarkably

inflexible in two key ways:

-    an interrupt handler DOES NOT KNOW which interrupt number

     invoked it.

-    the int instruction itself expects an IMMEDIATE operand:

     you cannot write MOV AX,x21, and then INT AX; you must

     write INT x21.

That would be very good indeed for us cracker... unfortunately

many high level language compilers compile interrupts into PUSHF

and FAR CALL instruction sequences, rather than do an actual INT.

Another method is to PUSH the address of the handler on the stack

and do RETF to it.

     Some protection schemes attempt to disguise interrupt calls,

1) camouflaging the code, 2) putting in substitute interrupt

instructions which look harmless and modifying them "on the fly"

or 3) replicating whole interrupt routines inside the code. This

is particularly frequent in the various "disk access" protection

schemes that utilize INT_13 (the "disk" interrupt) and will

therefore be thoroughly explained in -> lesson 5.


In order to understand the protection schemes and to defeat them,

you must acquire a passing knowledge of assembler, the "machine

language" code. You can find a lot of good, well explained code

for free: viruses are one of the best sources for good "tight and

tricky" assembler code. You can find the source code of almost

all viruses on the web: oddly all the would be hackers seem to

have an aberrant passion for this kind of stuff instead of

studying cracking techniques. But there are millions of lines of

good explained "commercial" assembler code on the net, just fish

it out and study it: the more you know, the better you crack.

I'll restrict myself to some observations, sprinkled throughout

this tutorial. Let's start with some must_know:

------------------------ STRINGS ----------------------------

The string instructions are quite powerful (and play a great role

in password protection scheme). ALL of them have the property


1)   The source of data is described by the combination DS:SI

2)   The destination of data is described by the combination


3)   As part of the operation, the SI and/or DI register(s)

     is(are) incremented or decremented so the operation can be


------------------------- JUMPS -----------------------------

JZ   ero       means what it says

JNZ  ero       means what it says

JG   reater    means "if the SIGNED difference is positive"

JA   bove      means "if the UNSIGNED difference is positive"

JL   ess       means "if the SIGNED difference is negative"

JB   elow      means "if the UNSIGNED difference is negative"

JC   arry      assembles the same as JB, it's a matter of

               aesthetic choice


     Refer to lesson one in order to understand why we are using

games instead of commercial applications as learn material: they

offer the same protection used by the more "serious" applications

(or BBS & servers) although inside files that are small enough

to be cracked without loosing too much time.

     A whole series of programs employ copy protection schemes

based upon the possess of the original manual or instructions.

That's obviously not a very big protection -per se- coz everybody

nowadays has access to a photocopier, but it's bothering enough

to motivate our cracks and -besides- you'll find the same schemes

lurking in many other password protected programs.

     Usually, at the beginning of the program, a "nag screen"

requires a word that the user can find somewhere inside the

original manual, something like: "please type in the first word

of line 3 of point 3.3.2". Often, in order to avoid mistakes, the

program indicates the first letter of the password... the user

must therefore only fill the remaining letters.

Some examples, some cracks:


UMS (Universal Military Simulator) version 1

by Dr Ezra SIDRAN

(c) 1987 Intergalactic Development

European Union:     Rainbird Software

United States:      Firebird Software


     This very old EGA program is one of the first I cracked in

my youth, and it's very interesting coz it employs a very basilar

protection scheme (a "PRIMITIVE"! More than 80% of the protection

schemes used to day (January 1996) are directly derived from one

of the 12 primitives.

     The nag screen snaps at the beginning and keeps indefinitely

asking your answer, only the use of CTRL+C will bring you out of

it, back to DOS. That's a clear sign of older protection schemes:

newer schemes let you in for only 3 attempts or even only one,

and pop out to the OS if you fail. In UMS, besides, there is no

"first letter" aid, a later improvement.

     The cracking procedure for password protected programs is,

first of all, to find out where are stored the letters that you

type in. So examine your memory map, find out where the program

dwells in memory, do a snap save of these memory areas and a

series of snap compares as you type your password in.

     Strangely enough, in the case of UMS, as you type your

password there seems to be no difference at all in the memory

locations where this program dwells... yet the data must be

somewhere... Usually such a situation is a clear sign that an

hooked interrupt is used to hide the data.

     Checking the hooked vectors you find out the following:

vecs 00, 02, 22          are hooked where needs be

vecs 34-3D               are hooked at xxxx:0

vec  3E                  is hooked at xxxx:00CA

     Ha! Let's have a closer look at this bizarre 3E hook. Let's

search for some words used in the nag_screen and then let's dump

the area where we find them (in UMS that will be at 3E_hook

address + 7656) and loo! You'll see the content of the nag screen

and, immediately afterwards, ALL the passwords "in extenso", i.e.

not encoded, not scrambled, nothing at all... THERE THEY ARE

(that's a very old protection scheme indeed). You could now, for

instance, easily patch all the different passwords to (for

instance) "PASS", and this would work... it's a very primitive

protection, as we said, nevertheless the use of a hooked vector

as hiding place for the protection code is not yet obsolete...

we'll find it elsewhere, in many "more modern" programs.

     Now let's go deeper and examine the "compare" mechanism, we

want to crack, here, not just to patch.

     Password protected programs (and access protection routines

for server and BBS, for that matter) have quite a lot of weak

points. The most obvious one (you 'll find out the other when

you'll high crack) is that they MUST compare the password of the

user with the original one(s). So you do not need to steal a

password, you just need to "ear" the echo of the original one in

the memory locations used for the compare, or, and that's more

correct, to crack the compare mechanism itself so as to make it

let you in even with a totally false password.

     The compare mechanism of UMS can be found setting a

breakpoint on the memory range that covers the three locations

where the password is stored (and you 'll find these with your

search capabilities and with a pair of snap compares):

ES:0F8E   (here you 'll see a copy of the password that the

          program is asking)

ES:0F5C   (here you 'll see a copy of the password that the user

          types in)

INT_3E hook_address + 7656 (here are all the possible passwords

          in extenso).

Here is how the protection scheme looks out:

MOV       CX,FFFF        Charge MAX in CX

REPNZ     SCASB          Scan ES:DI (the user password)

NOT       CX             Now CX holds the number of the

                         character that the user typed in

MOV       DI,SI          Real password offset to DI

LDS       SI,[BP+0A]     User password offset in SI

REPZ      CMPSB          Compares DS:SI with ES:DI (user

                         password and real password) then snap

                         out at CX=0 or at char_different,

                         whichever comes first.

Nice, we found the compare schema... how do we crack it now?

There are many elegant solutions, but let's remain on a basic

level... you look at the code that follows the CMPSB searching

the "snapping schema"... here it is immediately afterwards

(that's the case in most of the primitives). Remember: we sprung

out of the CMPSB check at the first different char, OR at the end

of the count of the user chars. Here it is what follows:

     MOV  AL,[SI-01]     loads in AL the before_different char

                         of the user password (should be zero)

     SUB  AL,ES:[DI-01]  subs with the before_different char of

                         the real password (should be zero)

     CBW                 zero flag set, "TRUE", if OK_match

Well let's now look for the next JZ near (it's a "74" code)

     CS:IP 740D     JZ  location no_good

Wait, let's continue a little... is there another check (often

you have a double check on DI)... yes there is!

     CS:IP 7590     JNZ location no_good

Cracking such a schema is very easy: you just need to substitute

75 to 74 and 74 to 75: transform your JZ in a JNZ and the JNZ in

a JZ... now you will always pass, no matter what you write,

unless you exactly guess the password!

Now let's quickly crack it:


CRACKING UMS.EXE (by +ORC, January 1996)

ren ums.exe ums.ded

symdeb ums.ded

-    s (cs+0000):0 Lffff 74 0D 1E B8 C2 3F


-    s (cs+1000):0 Lffff 74 0D 1E B8 C2 3F


-    s (cs+2000):0 lffff 74 0D 1E B8 C2 3F

xxxx:yyyy           (this is the answer of the debugger)

-    e xxxx:yyyy    75

-    e xxxx:yyyy+17 74

-    w

-    q

ren ums.ded ums.exe


     In the debug/symdeb crack above we use as search string the

bytes comprising and following immediately the first JZ.

I know, I know... we saw them in [Soft-ice] and we could have

modified them there, but I'm teaching also pupils who may not

have [Soft-ice].

     Note that the program is x431A0 bytes long, and therefore

has a BX=4 sectors adding to the CX=31A0 in the initial

registers... that's the reason I wanted to examine all the

sectors (even if I knew that the snap was in sector (cs+2000):

that's good practice! If you do not find your string in the first

sector you must search for it in the next sectors, till you find

it, coz in many programs there may be MORE THAN ONE repetitions

of the same schema (more about this double check later).

That's it, pupils, that's the way to crack old [UMS.EXE].

Let's go over, now, to more elaborate and more modern password

protection schemes.


LIGHTSPEED, from Microprose (we crack here version 461.01)


     This program, released in 1990, operates a more "modern"

variation of the previous scheme. You 'll find this variation in

many access routines of remote servers (and this makes it very

interesting indeed).

     Let's begin as usual, with our hooked vectors examination

and our snap compares.

Hooked vectors: 00, 08, 1B, 22, 23: nothing particular.

The snap_comparisons of the main memory area -as you type the

password in- gives more than six pages of changing locations...

that's clearly much too much to examine.

What now?

     Sit down, have a Martini Wodka (I'm afraid that only

Moskovskaja 'll do) and meditate. Get the memory map of the

program's layout. Start anew: snap_save (before typing anything

in). Type as password "ABCDE". Get the print of the snap

compares. Sit down, sip Martini Wodka, relax. You know that the

code for A is x41, for B x42, for C x43 and so on... and in the

snap_compares, that you made between letters, you 'll have only

some locations with these values changing. Focus on these.

     You 'll soon enough find out that for LIGHTSPEED absolute

location (in my computer) 404307, i.e.: relative locations (in

my computer) 30BE:F857 or 4043:0007 evoke the characters you

type, i.e. something like


F855 F856 F857                F858                F859...

41   3E   first_ready_letter  your_1st_letter     your_2nd_one...


Inspecting the same prints, you 'll find out that absolute

location 30C64 (imc) or relative location 30BE:F83E evokes the

LAST character you typed in. The relative code line is:

     CS:0097   MOV  AX,[BP-08] where SS:F83E = 00+letter_code

     Now breakpoint at these locations and investigate what's

going on (for instance, the instruction that follows is

     CS:009A   MOV [BX], AX

and this means that the code of the letter you just typed in will

be now copied in BX=F85A. What else can you do? Time to use a

little intuition: look for an instruction "CMP AX,000D", which

is the typical "IF the user hits ENTER then" instruction, coz

"x1D" its the ENTER keystroke. This must be somewhere around

here. Ha! You 'll soon enough find the line

     CS:0073  3D0D00     CMP AX,000D

And now the way is open to the crack. But YOU DO NOT NEED ALL

THIS! Since the password protection schemes are -as I told you-

all more or less the same, I would suggest that you use first of

all following trick: in the largest part of the program (use

memory map to see where the program dwells) search the "F3A6"

sequence, that's instruction REPZ CMPSB.

     In the case of Lightspd you 'll get as answer FOUR addresses

with this instruction: (pgsg=program main segment)





There you are! Only four... have a short look at each of them:

you 'll see that the second one (pgsg:E5CA) is the "good" one.

The compare mechanism in this program of 1990 it's more or less

the same as in 1987'UMS (and do believe me: the same mechanism

is still in use to day (1996)!

B9FFFF    MOV       CX,FFFF   charge Max in CX

F2AE      REPNZ     SCASB     this scans ES:DI (the original


F7D1      NOT       CX        so many chars in the original pw

2BF9      SUB       DI,CX     change DI for compare

F3A6      REPZ      CMPSB     compares DS:SI with ES:DI (real

                              pw with user pw) then snaps out

                              at CX=0 or at char_differs

     See how easy? They all use the same old tricks the lazy

bastards! Here the section is preceded by a small routine to

lowercase the user password, coz the original muster is always


     Now you would like, may be, to breakpoint at one of these

locations, in order to stop the program "in the snap area" and

inspect the snap mechanism... that WILL NOT DO with a "fixed"

breakpoint, coz these locations are called by the snap with a

different segment:offset numeration as the one you found (that's

old dos magic). So you MUST first set a memory_read/write

breakpoint on these locations, and then get at them at the snap.

Now you can find out the segment:offset used by the snap and only

now you'll be able to set a fixed breakpoint (for instance on the

NOT CX instruction).

     Now run the program and breakpoint in: have a dump of the

ES:DI and see the original password. How nice! We have now the

original password in extenso in our memory dump window. That's

the "echo". By the way, there is a whole school of cracking

devoted to find and use these echoes... we work on different

paths, nevertheless password fishing can be interesting: where

are the password stored? From which locations do they come from?

A common practice of the protectionists is to hide them in

different files, far away, or in hooked vectors, or in SMC parts.

This is a program of 1990, that differs in respect to UMS: the

passwords are not "hidden" inside a hooked vector, coz that's a

pretty stupid protection: any hexdump utility would still permit

you to see them. Here the passwords are encoded (albeit in a very

primitive manner): looking for them (with memory range

breakpoints) you'll quickly find a section of the program code

that looks like this:

sg:0118   8C 91 9D 95 9B 8D 00 B8 EC 94 9B 8D 8F 8B 9B

sg:0128   94 9B 8D 00 AE EC 9C 9B 8A 9B 86 00 A9 EC 91

This is a typical encoded matrix, with clear 00 fences between

the encoded passwords.

Ha! If all codes where so easy to crack! This is no better than

children's crypt! It's a NEG matrix! And there is direct

correspondence: 91=6F="o"; 92=6E="n"; 93=6D="m" and so on... Ha!

     Let's now leave the "hidden" passwords and proceed with our

cracking... let's follow the snap procedure after the REPZ CMPSB

instruction looking for the "jump to OK" instruction...

F3A6      REPZ      CMPSB          ; compares DS:SI with ES:DI

7405      JZ   preserved_AX=0000   <--- Here the first JZ

1BC0      SBB  AX,AX



8BF3      MOV  SI,BX

8BFA      MOV  DI,DX

5D        POP  BP

CB        RETF


83C404    ADD  SP,+04

0BC0      OR   AX,AX

7509      JNZ  0276                <------ And here it is!

     Now, remembering the UMS crack, you would probably want to

change the JZ instruction in a JNZ instruction (you tried it on

the fly INSIDE  [Soft-Ice] and it did work!), the "74" with a

"75" also. And then you would like to change the JNZ instruction

in a JZ instruction... Please feel free to try it... it will NOT

work! (You will not even find the second JNZ in the program

code). You should always be aware of the SMC (self modifying

code) protections: parts of the code my be decrypted "on the

fly", as needs arise, by the program. The code you modify while

the program is running may be different from the code of the

"dead" program.

     Here we have a small "improvement" of the primitive: the

same instruction is used as "muster" for manipulation of other

parts of the program... if you do change it in a JNZ you get an

overlay message and the program pops out with instability! You

cannot easily modify the JNZ instruction either, coz the part

after the RETF will be compiled "on the fly" by lightspeed, and

you would therefore have to search the decryption mechanism and

modify the original encrypted byte somewhere... and may be they

do encrypt it twice... and then you must hack all night long...

very annoying.

     So do the following: back to the snap, a sip of martini-

Wodka and meditate: loo! The only thing that happens after the

JZ, is the setting of the AX register to flag *FALSE* (AX=1...

that's what the two SBB instructions do) if the snap went out

with a non-zero flag... i.e. if you did not know the password.

So let's nop the 5 bytes of the two SBB instructions, or, more

elegantly, let's have a INC AX, DEC AX, NOP, INC AX, DEC AX

sequence instead of the two SBB! There is a good reason to use

a sequence of working instructions instead of a series of NOPs:

recent protection schemes "smell" patched nops inside the program

and trash everything if they find more than -say- three

consecutive NOPs! You should always try to choose THE LESS

INTRUSIVE and MORE "CAMOUFLAGED" solution when you crack!

     Eliminating the two SBBs we get our crack! No need to bother

with the second JNZ either... the program will work as if you got

the password if you have it AND if you do not (that's better as

the previous type of crack -seen for UMS- when you crack computer

accesses: hereby the legitimate user will not have any suspects

'coz the system will not shut him out... everybody will access:

the good guys and the bad ones... that's nice isn't it?).

     Now let's quickly crack LIGHTSPD:



ren lightspd.exe lightspd.ded

symdeb lightspd.ded

-    s (cs+0000):0 Lffff 2B F9 F3 A6 74

xxxx:yyyy           (this is the answer of the debugger)

-    s (cs+1000):0 Lffff 2B F9 F3 A6 74

(nothing, but do it nonetheless, just to be sure)

-    s (cs+2000):0 lffff 2B F9 F3 A6 74

(nothing, just to be sure, now it's enough)

-    e xxxx:yyyy+6  40 [SPACE] 48 [SP] 90 [SP] 40 [SP] 48

-    w

-    q

ren lightspd.ded lightspd.exe


All this CMPSB is very common. Some programs, nevertheless,

utilize a password protection scheme that is slightly different,

and does not rely on a F3A6 REPZ CMPSB instruction. Let's

analyze, for instance, the protection scheme used in the first

version of Perfect general I from QQP-White wolf, July 1992.

When you break in, at the nag screen, you are in the middle of

the BIOS procedures, coz the program expects your input (your

password, that's is). You 'll quickly find out (MAP MEMORY

USAGE!) that [General.exe] dwells in two main areas; Setting

breakpoints on memory write you 'll find out that the memory area

"queried" by the protection mechanism is

     xxxx:1180 to xxxx:11C0

where xxxx represents the second of the memory segments where the

program dwells. Now do the following (a very common cracking


*    Breakpoint on memory range WRITE for the small memory area

     touched by the program in querying you for the password.

*    Breakpoint TRACE on the whole memory range of the MAIN


*    Run anew everything

It's already done! Now it's your intuition that should work a

little: Here the last 9 traces (traces [!], not instructions

following on a line) before the calling of the procedure sniffing

your memory area:

-9   xxxx:0185 7425           JZ   somewhere, not taken

-8   xxxx:0187 2D1103         SUB  AX,0311

-7   xxxx:018A 7430           JZ   somewhere, not taken

-6   xxxx:018C 2DFD04         SUB  AX,04FD

-5   xxxx:018F 7443           JZ   next_trace, taken

-4   xxxx:01D4 E85500         CALL funny_procedure

-3   xxxx:022C 803E8F8C11     CMP  BYTE PTR[8C8F],11

-2   xxxx:0231 750E           JNZ  somewhere, not taken

-1   xxxx:0233 9A0A0AC33E     CALL procedure_that_sniffs


Well, the call to funny_procedure followed by a byte compare

"feels" fishy from very far away, so let's immediately look at

this part of the code of [General.exe]


     803E8F8C11     CMP  BYTE PTR[8C8F],11

     750E           JNZ  compare_byte

     9A0A0AC333     CALL procedure_that_sniffs

     0AC0           OR   AL,AL

     7405           J2   compare_byte

     C6068F8C2A     MOV  BYTE PTR [8C8F],2A


     803E8F8C2A     CMP  BYTE PTR [8C8F],2A

     7504           JNZ  after_ret

     B001           MOV  AL,01

     C3             RET

You should be enough crack-able ;=), by this lesson, to notice

immediately the inconsistency of the two successive instructions

MOV 2A and CMP 2A, coz there would be no sense in comparing the

"2A" in order to JNZ to after_ret if you just had the 2A set with

the precedent MOV instruction... but the first JNZ jumps to the

compare WITHOUT putting the "2A" inside. And "2A" is nothing else

as the "*" symbol, commonly used by programmer as "OK"! This

protection works in the following way (this is the above code


-    compare holy_location with 11

-    jump non zero to compare holy_loc with "*"

-    else call sniffing protection part

-    or al,al (al must be zero, else)

-    jump zero to compare holy_loc with "*"

-    if al was zero mov "*" inside holy_loc

-    compare holy_loc with "*"

-    if there is a difference then JNZ beggar_off_ugly_copier

-    else ret_ahead_nice_buyer

Now let's quickly crack it:


CRACKING GENERAL.EXE (by +ORC, January 1996)

ren general.exe general.ded

symdeb general.ded

-    s (cs+0000):0 Lffff 8C 11 75 0E

xxxx:yyyy           (this is the answer of the debugger)

-    e xxxx:yyyy+2  EB [SPACE] 09

-    w

-    q

ren general.ded general.exe


And in this way you changed the JNZ to the cmp "*" instruction

in a JMP to the mov "*" instruction. So no more nag screens, no

more protections... serene, placid, untroubled [general.exe].

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


                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


                Lesson 3.2: hands on, paper protections (2)


                [TOP.EXE] [F19.EXE] [POPULOUS.EXE] [MAP.EXE]


You have seen in the previous lesson that the use of a password

protection, independently of the coding and hiding methods used

to store them in memory, implies the use of a comparing procedure

with the password that the user types in. You therefore have many

options to begin your cracking work:

-    find the location of the user password

-    find the "echo" in memory of the real password

-    find the routine that compares both

-    find the passwords hideout and encryption type

-    find the go_ahead_nice_buyer exit or jump

-    find the beggar_off_ugly_copier exit or jump

just to name the more obvious ones. In order to make things more

difficult for us crackers, the protectionists have devised many

counter-strategies, the more obvious ones being:

-    keeping the various part of the store/compare/hide routines

well apart in code (no match for zen-cracking);

-    filling these routines with "bogus" compares, bogus jumps

and bogus variables, in order to make things more difficult for

the crack (no match for decent crackers);

-    disseminating the code with anti-debugger tricks, like INT_3

instructions or jumps in and out protected mode (no match for our

beloved [Soft-Ice]);

-    trying to eliminate the need for passwords altogether

letting the user input "one letter" or "one number" or "one

image" as answer to some variable question. In this lesson I'll

teach you how to crack these "passletters" protection techniques.

Let's first resume the "uses" of a password protection:


These passwords serve to acknowledge that a legitimate user is

using the program. This is the type of password that you'll find,

for example, protecting your user account on Compuserve, on

Networks or even in ATM machines used by banks or corporations.

These require a little hardwiring to crack: ATM passnumber

protection schemes rely on an answer from the central computer

(they do NOT verify only the three magnetic areas in the magnetic

strip on the card). The lines between ATM's & their hosts are

usually 'weak' in the sense that the information transmitted on

them is generally not encrypted in any way. (Some banks use

encrypted information, but this is fairly easy to crack too).

So for ATMs you should do the following 1) cross over the

dedicated line between the ATM and the host; 2) insert your

computer between the ATM and the host; 3) Listen to the "normal"

messages and DO NOT INTERFERE YET; 4) Try out some operations

with a legal card, make some mistakes, take note of the various

codes; 5) When you are ready insert a fraudulent card into the

ATM. Now the following happens:

-    the ATM sends a signal to the host, saying "Hey! Can I give

this guy money, or is he broke, or is this funny card invalid?";

-    the microcomputer intercepts the signal from the host,

discards it, sends on the "there's no one using the ATM" signal;

-    the host gets the "no one using" signal and sends back its

"good, keep watching out if somebody comes by, and for God's sake

don't spit out any money on the street!" signal to the ATM;

-    the microcomputer intercepts this signal (again), throws it

away (again), and sends the "Wow! That guy is like TOO rich! Give

him as much money as he wants. In fact, he's so loaded, give him

ALL the cash we have!  He is a really valued customer." signal.

-    the ATM obediently dispenses cash till the cows come home.

     All this should be possible, but as a matter of fact it has

not much to do with cracking, unless there is a special software

protection on the line... so if you want to work on ATMs contact

our fellow phreakers/hackers and learn their trade... and

please remember to hack only cash dispenser that DO NOT HAVE a

control camera :=)


This type of password is often used in shareware programs. When

you register the shareware program, you are sent a password that

you use to upgrade your shareware program to a complete and more

powerful version. This method, used frequently for commercial

applications, has recently been used quite a lot by many windows

applications that come "crippled" on the magazines cover CD-roms,

requiring you to telephone a hot line (and paying) in order to

get the "unique key" to unlock the "special protection". It's all

bullshit: we'll learn in the "how to crack windows" lessons how

easy it is to disable the various routines that verify your



This type of password is often used for games and entertainment

software. The password query does not usually appear any more at

the start of the program, or as the program is loading. Instead,

the password query appears after one or more levels are completed

(this innovation was pioneered by "EOB I" and the "Ultima"

series) or when the user reloads a saved game or session.


     A few extremely expensive programs use a dongle (also called

an hardware key). A dongle is a small hardware device containing

a password or checksum which plugs into either a parallel or a

serial port. Some specially designed dongles even include

complete program routines. Dongles can be cracked, but the amount

of work involved is considerable and the trial and error

procedure currently used to crack them via software is extremely

tedious. It took me more than a week to crack MULTITERM,

Luxembourger dongle protected program. The quickest method to

crack dongle protected programs, involves the use of pretty

complicated hardware devices that cannot be dealt with here. I

myself have only seldom seen them, and do not like at all to

crack dongles via software, coz it requires a huge amount of zen

thinking and of luck and of time. If you want more information

on the hardware way to crack dongles, try to contact the older

ones on the appropriate web sites, they may even answer you if

you are nice, humble and really technically interested.

     The obvious principle, that applies to the software password

types mentioned above is the following: The better the password

is hidden, and the better it is encrypted, the more secure the

program will be. The password may be

-    encrypted and/or

-    in a hooked vector and/or

-    in an external file and/or

-    in a SMC (Self modifying code) part

     Let's finally inspect the common "ready_made" protection

schemes (used by many programmers that do not program


*    password read in

*    letters added to a key to be entered

*    complement of the letters formed xoring with 255

*    saved key (1 char)

*    saved password (256 chars)

*    saved checksum (1 char), as protection, against simple


*    generating file PASSWORD.DAT with password, to be inserted

     inside a different file than the one containing the calling


Now the lazy programmer that wants to "protect" his program

searches first the file where the password is stored, then loads

the key, the password and the checksum. He uses a decrypt

procedure to decrypt the password and a check_checksum procedure

to check whether the password was modified. All this is obviously

crackabe in few seconds.


     Some computers have a password protected access INSIDE the

Setup (at the beginning), the protection scheme does not allow

a boot with a floppy and does not allow a setup modify. In these

cases the only possible crack is an old hack method:

*    open the PC

*    find on the motherboard a small jumper (bridge) with the

     words "Pw"

*    take it away

*    PC on

*    run the setup with F1 or Del (depending from the BIOS) (the

     protection will not work any more)

*    deactivate inside the setup the option password

*    PC off

*    put the small jumper (bridge) back again

*    close the PC

*    PC on, cracked (if you want to be nasty you could now use

     the setup to set YOUR password)

     If you want to know more about access refuse and access

denying, encryption and locking of the FAT tables, get from the

web, and study, the (very well written) code of a virus called

"Monkey", that does exactly this kind of devastation. Virus

studying is, in general, very useful for cracking purposes, coz

the virus'code is at times

-    very well written (pure, tight assembly)

-    using concealing techniques not much different from the

     protection schemes (often far superior)

-    using the most recent and best SMC (self modifying code)


     But, and this is very important, do not believe that the

protection schemes are very complicated! Most of the time the

protection used are incredibly ordinary: as a final example of

our paper protection schemes, let's take a program released not

long ago (1994), but with a ridiculous protection scheme: TOP

(Tiger on the prowl) a simulation from HPS.

Here the cracking is straightforward:

-    MAP(memory_usage) and find main_sector

-    type "AAAA" as password

-    (s)earch main_sector:0 lffff "AAAA"

-    dump L80 "AAAA" location -40 (gives you a "wide" dump),

     this gives you already the "echo" of the correct password

-    breakpoint on memory read & write to "AAAA" location and

     backtrace the complete main_sector

it's done! Here the code_lines that do protect TOP:

     8A841C12  MOV  AL,[SI+121C]   move in AL first user letter

     3A840812  CMP  AL,[SI+1208]   compare with echo

     7402      JZ   go_ahead_nice_buyer

     EB13      JMP  beggar_off_ugly_cracker

Now let's quickly crack it:


CRACKING TOP.EXE (by +ORC, January 1996)

ren top.exe top.ded

symdeb top.ded

-    s (cs+0000):0 Lffff 8A 84 1C 12 3A 84

xxxx:yyyy           (this is the answer of the debugger)

-    e xxxx:yyyy+2  08 (instead of 1C)

-    w

-    q

ren top.ded top.exe


And you changed the MOV  AL, [SI+121C] instruction in a MOV AL,

[SI+1208] instruction... it is now reading the ECHO instead of

the characters you typed in... no wonder that the ECHO does

compare exactly with itself... and you pass!


Back to the "Passletter" type of password protected programs.

Let's take as an example the protection used in a game of 1990:

"F19", where the protection scheme asks you to identify a

particular plane's silhouette. This kind of protection is used

in order to avoid the use of memory locations where the passwords

are stored: we saw in the first part of our "passwords hands on"

how easy it is to crack those schemes.

To crack this kind of protection, you could try a technique know

as "memory snuffing". The protected program, START.EXE, install

itself first at location xxxx:0000 with a length of 6C62 bytes,

but proceeds to a relocation of its modules (with some SMC, self

modifying code parts) in different locations. What does all this

mean? Well, this could mean quite many things... the most

important one for crackers is that the protection code will

probably snap way ahead of the actual user input phase.

Now you 'll quickly find out that the routine determining

(randomly) which plane is being chosen, leaves the progressive

number of this plane in one memory location: (imc) 43CD:DADA.

This brings us to the random triggering mechanism:

E87FAF    CALL random_seed

83C402    ADD  SP,02

8946E8    MOV  [BP-18],AX     and ds:(BP-18) is the location

                              you are looking for

Now, every time this random triggers, you get a different number

(00-x14) in this location, corresponding to the different plane

the user should choose.

The random seed routine, evidently, comes back with the random

seed in AX... what we now need is to zero it: the user will

always have to choose the same plane: "plane 0", and he will have

given the correct answer. Note how elegant all this is: we do not

need to interfere with the whole mouse pointing routines, nor

with the actual choosing of the planes... the random seed may

choose whatever plane it wishes... the memory location for this

choice will always report the (legitimate) choice of zero.

So, let's quickly crack this program:


CRACKING "F19" [START.EXE] (by +ORC, January 1996)

ren start.exe start.ded       <- let's have a dead file

symdeb start.ded              <- let's debug it

- s cs:O lffff 83 C4 02 89 46 E8 <- search ADD SP,02

xxxx:yyyy                     <- debugger's answer

- e xxxx:yyyy 58 [SPACE] 31 [SPACE] C0 [SPACE]

- w                           <- write the crack

- q                           <- back to the OS

ren start.ded start.exe       <- re-write the exe


You just transformed the instruction you searched for

     83C402    ADD  SP,+02

in the following sequence:

     58        POP  AX        <- respecting ADD SP,+02

     31C0      XOR  AX,AX     <- xoring to zero

(the POP AX instruction increments the stack pointer by 2, in

order to respect the previous ADD SP,+02).

Well, nice. It's getting easier, isnt'it? Now let's take as

example a protection that has no "echo" in memory. (At the

beginning this was a smart idea: "the cracker won't find the

correct password, 'coz it's not there, ah!". We'll now therefore

crack one of the first programs that used this scheme:

[Populous.exe], from Bullfrog.


     A old example of the protection scheme "password that is not

a password" can be found in [Populous.exe], from Bullfrog. It's

a very widespread program, and you'll surely be able to find a

copy of it in order to follow this lesson. The program asks for

the identification of a particular "shield", a combination of

letters of various length: the memory location were the user

password is stored is easily found, but there is (apparently) no

"echo" of the correct password. You should be able, by now, to

find by yourself the memory location were the user password is

stored. Set a breakpoint memory read & write on this area, and

you 'll soon come to the following section of code:

F7AE4EFF  IMUL WORD PTR [BP+FF4E]       <- IMUL with magic_N░

40        INC  AX

3B460C    CMP  AX, [BP+0C]

7509      JNZ  beggar_off_ugly_copier

8B460C    MOV  AX, [BP+0C]

A3822A    MOV  [2A82], AX

E930FE    JMP  nice_buyer

817E0C7017CMP  WORD PTR[BP+0C],1770     <- beggar_off

I don't think that you need much more now... how do you prefer

to crack this protection scheme? Would you choose to insert a MOV

[BP+0C], AX and three NOPS (=6 bytes) after the IMUL instruction?

Wouldn't you rather prefer the more elegant JMP to nice_buyer

instruction at the place of the JNZ beggar_off? This solution has

less nops: remember that newer protection schemes smell

NOPs_patches!). Yeah, let's do it this way:


CRACKING [Populous.exe] (by +ORC, January 1996)

ren populous.exe populous.ded      <- let's have a dead file

symdeb populous.ded                <- let's debug it

-    s cs:O lffff F7 AE 4E FF      <- the imul magic_N░

xxxx:yyyy                          <- debugger's answer

-    e xxxx:yyyy+4  EB [SPACE] 03  <- JMP anyway

-    w                             <- modify ded

-    q                             <- back to the OS

ren populous.ded populous.exe      <- let's re-have the exe


This time was easy, wasnt'it?

     Now you are almost ready with this course... let's crack a

last application, a memory utility that is very widespread, very

good (the programmers at Clockwork software are Codemasters),

very useful for our purposes (you'll use it later to crack a lot

of TSR) and, unfortunately for Clockworkers, very easy to crack

at the level you are now.

But, Hey! Do not forget that you would have never done it without

this tutorial, so do the following: look toward east from your

window, sip a Martini-Wodka (Two blocks of ice first, 1/3 dry

Martini from Martini & Rossi, 1/3 Moskovskaia Wodka, 1/3

Schweppes indian tonic) and say three times: Thank-you +ORC!.


     Let's now go over to one of the best TOOLS for mapping your

memory usage that exist: MAP.EXE (version 2) from the masters at

Clockwork software. The usage of this tool has been recommended

in Lesson 2, and you should learn how to crack it, coz it comes

with an annoying nag-screen ("Nigel" screen). In [Map.exe] this

ubiquitous "Nigel" screen appears at random waiting for a random

amount of time before asking the user to press a key which varies

every time and is also selected at random.

     The use of a single letter -mostly encrypted with some XOR

or SHR- as "password" makes the individuation of the relevant

locations using "snap compares" of memory much more difficult.

But the crack technique is here pretty straightforward: just

break in and have a good look around you.

     The INT_16 routine for keyboard reading is called just after

the loading of the nag screen. You 'll quickly find the relative

LODSB routine inside a routine that paints on screen the word

"Press" and a box-edge after a given time delay:

     B95000         MOV  CX,0050

     2EFF366601     PUSH CS:[0166]

     07             POP  ES

     AC             LODSB


You could already eliminate the delay and you could already force

always the same passletter, in order to temperate the effects of

the protection... but we crack deep!: let's do the job and track

back the caller! The previous routine is called from the

following section of the code:

     91             XCHG AX,CX

     6792           XCHG AX,DX

     28939193       SUB  [BP+DI+9391],DL

     2394AA94       AND  DX,[SI+94AA]

     2EC7064B880100 MOV  WORD PTR CS:[884B],0001

     2E803E5C0106   CMP  BYTE PTR CS:[015C],06

     7416           JZ   ret       <- Ha! jumping PUSHa & POPa!

     505351525756   PUSH the lot

     E882F3         CALL 8870

     2E3B064B88     CMP  AX,CS:[884B]

     7307           JAE  after RET <- Ha! Not taking the RET!

     5E5F5A595B58   POP  the lot

     C3             RET

     ...                                <- some more instructions

     E86700         CALL delay_user

     BE9195         MOV  SI,9591

     2E8B3E255C     MOV  DI,CS:[5C25]

     83EF16         SUB  DI,+16

     2E8A263D01     MOV  AH,CS:[013D]

     50             PUSH AH

     E892C7         CALL routine_LODSB  <-- HERE!

     B42C           MOV  AH,2C

     CD21           INT  21             <- get seconds in DH

     80E60F         AND  DH,0F

     80C641         ADD  DH,41

     58             POP  AX

     8AC6           MOV  AL,DH

     83EF04         SUB  DI,+4

     AB             STOSW

     E85A00         CALL INT_16_AH=01

     B400           MOV  AH,00

     CD16           INT  16

     24DF           AND  AL,DF     <- code user's letter_answer

     3AC6           CMP  AL,DH     <- pass_compare

     75F3           JNZ  CALL INT_16_AH=01

     E807F3         go_ahead

     You just need to look at these instructions to feel it: I

think that unnecessary code segments (in this case protections)

are somehow like little snakes moving under a cover: you cannot

easily say what's exactly going on yet, but you could bet that

there is something fishy going on. Look at the code preceding

your LODSB routine call: you find two JUMPS there: a JZ ret, that

leaves a lot of pusha and popa aside, and a JAE after RET, that

does not take the previous ret. If you did smell something here

you are thoroughly right: The first JZ triggers the NIGEL screen

protection, and the second JAE does THE SAME THING (as usual,

there are always redundances, exactly as there are a lot of

possibilities to disable a single protection). Now you know...

you can disable this protection at different points: the two

easiest blueprints being

1)   to change 7416 (JZ ret) in a EB16 (JMP ret anyway)

2)   to change 7307 (JAE after ret) in a 7306 (JAE ret).

     We have not terminated yet: if you try locating this part

of the code in order to change it, you won't have any luck: it's

a SMC (Self modifying code) part: it is loaded -partly- from

other sections of the code (here without any encryption). You

must therefore first of all set a breakpoint on memory range;

find out the LODSW routine; find out the real area; dump that

memory region; find out a search sequence for the "dead" code...

and finally modify the "dead" program.

Now let's quickly crack it:


CRACKING MEM.EXE (version 2) (by +ORC, January 1996)

ren map.exe map.ded

symdeb map.ded

-    s (cs+0000):0 Lffff 74 16 50 53 51 52 57

xxxx:yyyy           <- this is the debugger's answer

-    e xxxx:yyyy    EB

-    w

-    q

ren map.ded map.exe


Now you have done it, NIGEL has been cracked!

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


                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


                 Lesson 5.1: Disk & CD-Rom access (basics)


              [MARIO ANDRETTI] [REACH FOR THE SKY] [FS v.2.12]


LESSON 5 (1) - HOW TO CRACK, HANDS ON - Disk/CDROM access (plus

bypasses "on the fly")

Somewhere I have to put the bypasses (loader programs) in this

tutorial, allow me to put them here:

Preparing a loader to bypass a protection [MARIO ANDRETTI]

     At time the protectionists hook vectors in order to impose

a particular protection. In this (and similar) cases a good

crack-way is to prepare a "loader" program, that "de-hooks" the

vector used for the protection. This kind of crack can be used

also for internet cracking (on some firewall configurations, see

lesson A.2).

     As example let's take "Mario andretti racing challenge", a

stupid game that uses the SAME (!) protection scheme you'll still

find to day on some access routines of military servers around

the witlessly called "free" world.

In order to crack this cram you would prepare a loader on the

following lines:

loc   code           instruction        what's going on


:0100 EB44           JMP 0146


:0142 0000           <- storing for offset of INT_21

:0144 5887           <- storing for segment of INT_21

:0146 FA             CLI

:0147 0E             PUSH CS

:0148 1F             POP DS

:0149 BCB403         MOV SP,03B4

:014C FB             STI

:014D 8C1EA901       MOV [01A9],DS      <- save DS

:0151 8C1EAD01       MOV [01AD],DS         three

:0155 8C1EB101       MOV [01B1],DS         times

:0159 B82135         MOV AX,3521        <- get INT_21

:015C CD21           INT 21                in ES:BX

:015E 891E4201       MOV [0142],BX      <- store offset

:0162 8C064401       MOV [0144],ES      <- store segment

:0166 BA0201         MOV DX,0102

:0169 B82125         MOV AX,2521        <- set INT_21 to

:016C CD21           INT 21                DS:0102

:016E 0E             PUSH CS

:016F 07             POP ES             <- ES= current CS

:0170 BBB403         MOV BX,03B4

:0173 83C30F         ADD BX,+0F

:0176 B104           MOV CL,04

:0178 D3EB           SHR BX,CL          <- BX= 3C

:017A B8004A         MOV AX,4A00        <- Modify memory block

:017D CD21           INT 21                to 3C paragraphs

:017F BA9E01         MOV DX,019E        <- ds:dx=program name

:0182 BBA501         MOV BX,01A5        <- es:bx = param. block

:0185 B8004B         MOV AX,4B00        <- load ma.com

:0188 CD21           INT 21

:018A 2E8B164201     MOV DX,CS:[0142]   <- reset old int_21

:018F 2E8E1E4401     MOV DS,CS:[0144]

:0194 B82125         MOV AX,2521

:0197 CD21           INT 21

:0199 B8004C         MOV AX,4C00        <- terminate with return

:019C CD21           INT 21                code

:019E 6D612E636F6D00 "ma.com"

      0000           fence

:01A7 B2015887

:01AB B2015887

:O1AF B2015887

      0000           fence

let's now prepare a routine that hooks INT_21:

push all

CMP AX,2500    <- go on if INT_21 service 25

JNZ ret

CMP Word Ptr [0065], C00B <- go on if location 65 = C00B

JNZ ret

MOV  Byte Ptr [0060], EB  <- crack instructions

MOV  Byte Ptr [0061], 3C

MOV  Byte Ptr [0062], 40  <- INC AX

MOV  Byte Ptr [0063], 90  <- NOP

MOV  Byte Ptr [0064], 48  <- DEC AX

pop all

JMP  FAR CS:[0142]  <- JMP previous INT_21

     From now on this loader will work every time that a program

with location [0065] containing an 0R AX,AX instruction (0BC0:

it's the case of ma.com) calls INT_21 service 25 (hook a vector),

the target program will be modified on the fly and will get, at

location [0060], the instruction JMP 3C locations ahead, despite

the fact that it has routines capable of self checking in order

to make sure it has not been modified.

     The most important thing is the routine that YOU write that

will precede the call to INT_21 (or any other INT) service 25 (or

any other service) in order to crack on the fly the offending

program. I'll show you another one, this one for [Reach for the

skies] (reach.com):

push all

CMP  AH,3D      <- is it service 3D? (open file)

JNZ  ret        <- no, so ret

CMP  DX,13CE    <- you wanna open file at 13CE?

JNZ  ret        <- no, so ret

MOV  AX,[BP+04] <- in this case


CMP  Byte Ptr [B6DA],74 <- old instructions

JNZ  015B

CMP  Byte Ptr [B6DB],0F <- ditto

JNZ  015B

CMP  Byte Ptr [B6DC],80 <- ditto, now we now where we are

JNZ  015B

MOV  Byte Ptr [B6DA],EB <- crack

MOV  Byte Ptr [B697],40 <- camouflaged  no-opping

MOV  Byte Ptr [B698],48 <- cam          nop

MOV  Byte Ptr [B699],90 <- cam          nop

MOV  Byte Ptr [B69A],40 <- cam          nop

MOV  Byte Ptr [B69B],48 <- cam          nop

MOV  DX,CS:[0165]

MOV  DS,CS:[0167]

MOV  AX,2521  <- set hook

INT  21

POP  all

JMP  FAR CS:[0165]

Here you did change the instruction 740F in the instruction EB0F,

and you did "noop" the instructions at B697-B69B. (Well, more

elegantly than "noop" them with "90" bytes, you choose a INC AX,

DEC AX, NOP, INC AX, DEC AX sequence instead! There are sound

reasons to use a sequence of "working" instructions instead of

NOPs: recent protection schemes "smell" patched nops inside the

program and trash everything if they find more than -say- three

consecutive NOPs! You should always try to choose THE LESS

INTRUSIVE and MORE "CAMOUFLAGED" solution when you crack!)

     You can apply this kind of crack, on the same lines, to many

programs that perform self checking of the code and hook the



     Now we may come to the subject of this lesson:

     As usual, let's begin from the beginning: history is always

the key that allows an understanding of present and future, in

cracking matters too. As the older 5 1/4 inch big black floppy

disks were still used (the 320K/8 tracks or 360K/9 tracks ones,

that were really "floppy" and have nowadays almost disappeared)

one of the more common methods to protect a program, was to

format the "master" (key) disk in a weird way. Old floppy disk

for the PC did usually store 360K at 9 sectors per track.

     Some basics for those of you that do not know anything: in

order to defeat this kind of cracks you need to know two things:

the floppy disk parameter block (FDPB) and the interrupt routines

dealing with format/read disk (basically INT_13).

     Most often, the protection scheme is to either format one

or more sectors or tracks with sector sizes other than the

standard 512 bytes, or to either give one of the sectors a wild

sector number like 211 or just not format a whole track of

eight/nine/15 sectors. If you, for instance, have got the same

(very old) copy of VisiCalc master I do, you'll find that sector

8 on track 39 is missing entirely. The interrogation with

assembly or with an "ad hoc" utility (I use the tools I wrote

myself, but you 'll be able to find many such utilities in public

domain, the oldest one, from 1984 (!) being the seasoned [U-ZAP]

an "Ultra utility" from the "Freesoft company") will tell you

which sector numbers were altered, their size in bytes, and if

they were formatted with a CRC error (another not so fancy


     The floppy disk parameters are stored in the BIOS: interrupt

vector 1E contains the address of the floppy disk parameter

block. The FDPB's contents are the following:

Offset    Function                 crackworthy?        Example

0    Step rate & head unload            no                  DF

1    head load time                     no                  02

2    Motor on delay                     no                  25

3    Number of bytes per sector         yes                 02

4    Last sector number                 yes                 12

5    Gap length                         yes                 1B

6    Data track length                  yes                 FF

7    Format gap length                  yes                 54

8    Format byte                        no                  F6

9    Head settle time                   no                  0F

A    Motor start time                   no                  02

0)   Offset #0: the left "nybble" (single digit) of this value

     is the step rate time for the disk drive head. The right

     nybble is the disk head unload time. These values are best

     left alone.

1)   Offset #1: again, don't fool around with these values. The

     left nybble is the disk head load time, and the right

     nybble is the direct memory access mode select.

2)   Wait time until motor is turned off. Not normally of use.

3)   Bytes-per-sector value: AH-HAH! If you place a "0" in this

     value, the PC expects all sectors to be 128 bytes long. A

     "1" means a  sector size of 256 bytes, a "2" means 512

     bytes (this is the standard DOS value), and a "3" means

     1024 bytes per sector.

4)   Highest sector number on a track: this is used for

     formatting and tells DOS how many sectors there are on each


5)   Gap length for diskette reads: this is what you fool around

     with if you keep getting CRC errors when you try to read a

     non-standard size sector. Normally, you can just leave this

     alone except when formatting with a U-Format tool.

6)   Data length: This contains the number of bytes in a sector

     when the value in table byte #4 doesn't contain a 0, 1, 2,

     or 3.

7)   Number of bytes in the gap between sectors: this is also

     only used when formatting special tracks.

8)   Format fill byte: When formatting, this is the

     initialization byte that will be placed in all new sectors.

9)   Head settle time: leave this alone.

A)   Motor start time: don't fool with this either.

In order to modify globally the number of tracks on a given disk

and the number of sectors per track you can always format with

the DOS command switches "/t:" and "/n:"

                  FORMAT /t:tracks /n:sectors

     If you want to find out what the existing parameters are,

run [Debug.exe] or [Symdeb.exe] and enter the following commands:

-    d 0:78    l 4                 <- get FDPB address

 0000:0070     22 05 00       <- debugger's likely response

-    d 0:522   l a                 <- get 10 FDPB values

 0000:520 DF 02 25 02 12 1B FF...  <- see preceding table

     Remember that all standard disk formats under DOS support

a sector size of 512 bytes, therefore, for one-sided 5.25 inch


               40t*8s*512b=163.840 bytes (160Kb)

               40t*9s*512b=184.320 bytes (180Kb)

and for two-sided 5.25 inch floppies:

           40t*8s*512b*2sides=327.680 bytes (320Kb)

           40t*9s*512b*2sides=368.640 bytes (360Kb)

     Beginning with DOS version 3.0 (Yeah, more and more

history!) a new floppy disk format has been supported: The IBM

AT (80286 CPU) introduced the so called "high capacity" 5.25 u-

inch floppy, capable of storing 1.2M at 15 sectors per track:

          80t*15s*512b*2sides=1.228.800 bytes (1.2Mb)

     Later on were introduced the to-day universally used 3.5

inch floppies, the ones inside a rigid small plastic cartridge,

and we have, similarly:

             3.5-inch double sided/double density      720K

            3.5-inch double sided/quad density (HD)    1440K

              3.5-inch double sided/high density       2880K

[INT_13, AH=18, Set media type for format]

     In order to create weird layouts, the protectionists use

interrupt 13h, service 18h, that specifies to the formatting

routines the number of tracks and sectors per track to be placed

on the media:

*    Registers on entry: AH=18h; CH=N░ of tracks; CL= Sectors

     per track; DL= Drive number (A=0; B=1;C=2... bit 7 is set

     if the drive is an hard disk)

*    Registers on Return: DI: Offset address of 11-byte

     parameter table; ES: Segment address of 11-byte parameter


[INT_13, AH=2, Read disk sectors]

In order to read them, they have to use INT_13, service 2, read

disk sectors, with following layout:

*    Registers on entry: AH=2h; AL= N░ of sectors; BX= Offset

     address of data buffer; CH=track; CL= Sector; DH= Head

     (side) number; DL= Drive number; ES: Segment address of

     data buffer.

*    Registers on Return: AH= return code. If the carry flag is

     not set, AH=0, therefore the weird sector has been read, if

     on the contrary the carry flag is set, AH reports the

     status byte as follows:

76543210  HEX  DEC       Meaning

1         80h  128       Time out - drive crazy

 1        40h  064       Seek failure, could not move to track

  1       20h  032       Controller kaputt

   1      10h  016       Bad CRC on disk read

    1     09h  009       DMA error - 64K boundary crossed

    1     08h  008       DMA overrun

     1    04h  004       Bad sector - sector not found

      11  03h  003       Write protect!

      1   02h  002       Bad sector ID (address mark

       1  01h  001       Bad command

[Return code AH=9: DMA boundary error]

     One of the possible errors should be explained, coz it is

used in some protection schemes: AH=9 DMA boundary error, means

that an illegal boundary was crossed when the in formation was

placed into RAM. DMA (Direct memory access) is used by the disk

service routines to place information into RAM. If a memory

offset address ending in three zeros (ES:1000, ES: 2000...) falls

in the middle of the area being overlaid by a sector, this error

will occur.

[INT_13, AH=4 Verify disk sectors]

     Another possible protection interrupt is interrupt 13H,

service 4, Verify disk sectors. Disk verification takes place on

the disk and DOES NOT involve verification of the data on the

disk against data in memory! This function has no buffer

specification, does not read or write a disk: it causes the

system to read the data in the designated sector or sectors and

to check its computed cyclic redundancy check (CRC) against data

stored on the disk. See INT_13, AH=2 registers and error report.


     The CRC is a checksum, that detects general errors. When a

sector is written to disk, an original CRC is calculated AND

WRITTEN ALONG with the sector data. The verification service

reads the sector, recalculates the CRC, and compares the

recalculated CRC with the original CRC.

     We saw that some protection schemes attempt to disguise

interrupt calls. This is particularly frequent in the disk access

protection schemes that utilize INT_13 (the "disk" interrupt).

     If you are attempting to crack such programs, the usual

course of action is to search for occurrences of "CD13", which

is machine language for interrupt 13. One way or another, the

protection scheme has to use this interrupt to check for the

special sectors of the disk. If you examine a cross section of

the program, however, you'll find programs which do not have

"CD13" in their machine code, but which clearly are checking the

key disk for weird sectors. How comez?

     There are several techniques which can be used to camouflage

the protection scheme from our nice prying eyes. I'll describe

here the three such techniques that are more frequent:

1)   The following section of code is equivalent to issuing an

INT 13 command to read one sector from drive A, side 0, track

29h, sector ffh, and then checking for a status code of 10h:

     cs:1000   MOV  AH,02     ;read operation

     cs:1002   MOV  AL,01     ;1 sector to read

     cs:1004   MOV  CH,29     ;track 29h

     cs:1006   MOV  CL,FF     ;sector ffh

     cs:1008   MOV  DX,0000   ;side 0, drive A

     cs:100B   XOR  BX,BX     ;move 0...

     cs:100D   MOV  DS,BX     ;...to DS register

     cs:100F   PUSHF          ;pusha flags

     cs:1010   PUSH CS        ;pusha CX

     cs:1011   CALL 1100      ;push address for next

                              instruction onto stack and branch

     cs:1014   COMP AH,10     ;check CRC error

     cs:1017   ... rest of verification code



     cs:1100   PUSHF          ;pusha flags

     cs:1101   MOV  BX,004C   ;address of INT_13 vector

     cs:1104   PUSH [BX+02]   ;push CS of INT_13 routine

     cs:1107   PUSH [BX]      ;push IP of INT_13 routine

     cs:1109   IRET           ;pop IP,CS and flags

Notice that there is no INT 13 command in the source code, so if

you had simply used a debugger to search for "CD13" in the

machine code, you would never have found the protection routine.

2)   Another technique is to put in a substitute interrupt

instruction, such as INT 10, which looks harmless enough, and

have the program change the "10" to "13 (and then back to "10")

on the fly. A search for "CD13" would turn up nothing.

3)   The best camouflage method for interrupts I have ever

cracked (albeit not on a INT 13) was a jump to a section of the

PROGRAM code that reproduces in extenso the interrupt code. This

elegant (if a little overbloated) disguise mocks every call to

the replicated interrupt.


Old good [debug.com] has been called the "swiss army knife" of

the cracker. It allows a lot of nice things, inter alia the

loading, reading, modifying and writing of absolute sectors of

the disks. The sector count starts with the first sector of track

0, next sector is track 0, second side (if double sided), then,

back to the first side, track 1, and so on, until the end of the

disk. Up to 80h (128) sectors can be loaded at one time. To use

you must specify starting address, drive (0=A, 1=B, etc...),

starting sector and number of sectors to load.

                               -   l 100 0 10 20

This instruction tells DEBUG to load, starting at DS:0100, from

drive A, sector 10h for 20h sectors. This allows at times the

retrieval of hidden and/or weird formatted data. If you get an

error, check the memory location for that data. Often times, part

of the data has been transferred before the error occurs, and the

remainder can be manually entered or gathered through repetitive


Bear all this in mind learning the following cracks.

Let's now crack an "oldie" primitive:

MS Flight simulator (old version 2.12, from 1985!)

This old program used -in 1985!- following beautiful protection

scheme: on the disk you had only a "stub", called FS.COM with few

bytes, which had following instructions:

loc   code           instruction        what's going on


:0100 FA             CLI                ;why not?

:0101 33C0           XOR AX,AX          ;ax=0

:0103 8ED0           MOV SS,AX          ;ss=0

:0105 BCB0C0         MOV SP,C0B0        ;SP=C0B0

:0108 8EC0           MOV ES,AX          ;ES=0

:010A 26C70678003001 MOV Wptr ES:[0078],0130 ;Wp 0:78=130

:0111 268C0E7A00     MOV ES:[007A],CS   ;0:7A=Segment

:0116 BB0010         MOV BX,1000        ;BX=1000

:0119 8EC3           MOV ES,BX          ;ES=1000

:011B 33DB           XOR BX,BX          ;BX=0

:011D B80102         MOV AX,0201        ;AH=2 AL=1 sector

:0120 BA0000         MOV DX,0000        ;head=0 drive=0

:0123 B96501         MOV CX,0165        ;track=1 sector=65 (!)

:0126 CD13           INT 13             ;INT 13/AH=2

:0128 B83412         MOV AX,1234        ;AX=1234

:012B EA00000010     JMP 1000:0000      ;JMP to data we just read

:0130 CF             IRET               ;Pavlovian, useless ret

     You see what's happening in this old protection scheme,

don't you? Herein you can watch the same snap that happens in

more recent (much more recent) protection schemes (as you'll see

in the next lesson): the protection searches for a weird

formatted sector and/or for particular data.

     That should be no problem for you any more: you should just

reverse engineer everything (and that goes on pretty quickly:

just watch and break on the INT_13 calls), fetch the "weird"

data, tamper the whole crap and have your soup as you like it.

     One more word about "old" protection schemes. Be careful not

to spurn them! Some of them are

     -- CLEVER

     -- STILL USED

     -- DIFFICULT TO CRACK... I mean, this older DOS programs had

nice protections... it's pretty annoying to crack windows

programs that require a registration number: as you saw in Lesson

3, you just type your name and a serial number of your choice in,

say "666666666", break into the program with WINICE, search the

"666666666" and search too, for good measure, your own name, set

a memory read breakpoint where the number dwells and look at the

code that manipulates your input. As [Chris] rightly pointed out,

you can even rip the code straight out of the program and create

a key generator which will produce a valid code. This code will

work for any name you typed in only in the "pure maths

manipulation" protection schemes, and will on the contrary be

specific, following the name you typed in, the "alpha-maths

manipulation" protection schemes (like MOD4WIN, see the Windows

lessons), watch in this case the "pseudo-random xoring" of the

letters that compose your name.

     -- STUNNING, coz new ideas have always been infrequent, and

they are getting more and more rare in this objectionable world

of lazy, incapable programmers patronizing us with ill-cooked

outrages like Windows'95... yeah, as usual there is no

"development" at all, quite the contrary, I would say. Take a

step backward, sip a good Martini-Wodka (please remember that

only Ice cubes, Dry Martini, Wodka Moskovskaja, Schweppes'

"Indian tonic" a green olive from Tuskany and a maltese lemon

zest will really be perfect) and watch from your balcony, with

unsullied eyes, your town and the people around you: slaves

everywhere, leaving home at 7.30 in the morning, stinking in a

progression of identical cars, forced to interminably watch

advertisement panels and endlessly listen to boorish publicity,

happy to go to work (if they happen to have the "luck" to work,

in this inequitable society) the whole day long in order to

produce other cars in order to buy, one day, a new car with a

different colour...

     Why people don't look at the stars, love each other, feel

the winds, ban the stinking cars from the places where they live

and eat, study colours... name yourself a not-consumistic

activity? Why don't they read any poems any more? No poetry any

more, in the grey society of the publicity-spots slaves...poetry

will soon be forbidden, coz you cannot CONSUME as you read poems,

and in this farce of a society you are BOUND to consume, that's

the only thing they want you to do... you are CULTIVATED to

consume... no books worth to read any more... stupid american

conventional cram everywhere... boy, at times I'm missing some

well placed neutron bombs, the ones that would kill all these

useless zombies and leave noble books and good Wodka untouched.

It's difficult to believe in democracy any more... if I ever

did... all the useless zombie do -unfortunately- vote, and they

do vote for "smiling semblances", for "conventionally minded

idiots" that so act as if they would "really" be like what they

"look" like and could not care less about anything else than

making bucks and defend intolerant and petty patterns. The slaves

choose the people they have "seen" on TV... as if the egyptians

would VOTE for their pharaohs, exhilarated under the whips of

publicity... sorry, at times I forget that you are here for the

cracks, and could not care less about what I think...

     You 'll obtain the OTHER 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


                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


                        Lesson 6.1: Funny tricks (1)


LESSON 6 (1) - Funny tricks.  Xoring, Junking, Sliding

EXERCISE 01: [LARRY in search of the King]

     Before the next step let's resume what you have learned in

the lessons 3-5, beginning with a very simple crack exercise

(again, we'll use the protection scheme of a game, for the

reasons explained in lesson 1): SEARCH FOR THE KING (Version

1.1.). This old "Larry" protection sequence, is a "paper

protection" primitive. It's a very widespread (and therefore easy

to find) program, and one of the first programs that instead of

asking meaningful passwords (which offer us the possibility to

immediately track them down in memory) asked for a random number

that the good buyer could find on the manual, whereby the bad

cracker could not. (Here you choose -with the mouse- one number

out of 5 possible for a "gadget" choosen at random). I don't need

any more to teach you how to find the relevant section of code

(-> see lesson 3). Once you find the protection, this is what you



 :C922 8E0614A3       MOV     ES,[A314]


 :C952 50 0E          PUSH    AX & CS

 :C954 E81BFF         CALL    C872      <- call protection scheme

 :C957 5B             POP     BX twice

 :C959 8B76FA         MOV     SI,[BP-06] <- prepare store_room

 :C95C D1E6           SHL     SI,1       <- final prepare

 :C95E 8942FC         MOV     [BP+SI-04],AX  <- store AX

 :C961 837EFA00       CMP     Word Ptr [BP-06],+00  <- good_guy?

 :C965 75BB           JNZ     C922           <- loop, bad guy

 :C967 8E0614A3       MOV     ES,[A314]

 :C96B 26F606BE3501   TEST    Byte Ptr ES:[35BE],01  <- bad_guy?

 :C971 74AF           JZ C922                <- loop, bad guy

 :C973 8B46FC         MOV     AX,[BP-04]...  <- go on good guy

Let's see now the protection scheme called from :C954

 :C872 55             PUSH    BP


 :C8F7 90             NOP

 :C8F8 0E             PUSH    CS

 :C8F9 E87234         CALL    FD6E <- call user input

 :C8FC 5B             POP     BX

 :C8FD 5B             POP     BX

 :C8FE 8B5E06         MOV     BX,[BP+06]

 :C901 D1E3           SHL     BX,1

 :C903 39872266       CMP     [BX+6622],AX  <- right answer?

 :C907 7505           JNZ     C90E      <- no, beggar_off

 :C909 B80100         MOV     AX,0001   <- yes, AX=1

 :C90C EB02           JMP     C910

 :C90E 2BC0           SUB     AX,AX     <- beggar_off with AX=0

 :C910 8BE5           MOV     SP,BP

 :C912 5D             POP     BP

 :C913 CB             RETF              <- back to main

Here follow 5 questions, please answer all of them:

1)   Where in memory (in which locations) are stored the "right"

     passnumbers? Where in memory is the SEGMENT of this

     locations stored? How does the scheme get the OFFSET?

2)   Would setting NOPs instructions at :C965 and :C971 crack?

     Would it be a good idea?

3)   Would changing :C907 to JZ crack? Would it be a good idea?

4)   Would changing :C907 to JNZ C909 crack? Would it be a good


5)   Write down (and try) at least 7 OTHER different patches to

     crack this scheme in spades (without using any NOP!).

Uff! By now you should be able to do the above 5 exercises in

less than 15 minutes WITHOUT USING THE DEBUGGER! Just look at the

data above and find the right answers feeling them... (you 'll

now which one are the right one checking with your debugger...

score as many points as you like for each correct answer and sip

a good Martini-Wodka... do you know that the sequence should

ALWAYS be 1) Ice cubes 2) Martini Dry 3) Wodka Moskovskaja 4)

olive 5) lemon 6) Schweppes Indian tonic?

Let's now come to the subject of this lesson:

-----> [Xoring] (Simple encryption methods)

     One easy way to encrypt data is the XOR method. XOR is a bit

manipulation instruction that can be used in order to cipher and

decipher data with the same key:

 Byte to encrypt                   key            result

     FF                  XOR       A1               5E

     5E                  XOR       A1               FF

As you can see XOR offers a very easy way to encrypt or to

decrypt data, for instance using the following routine:


     mov  bx, offset_where_encryption/decryption_starts


     mov  ah, [bx]            <-   get current byte

     xor  ah, encrypt_value   <-   engage/disengage xor

     mov [bx], ah             <-   back where you got it

     inc  bx                  <-   ahead one byte

     cmp  bx, offset_start_+_size  <- are we done?

     jle  xor_loop            <-   no, then next cycle

     ret                      <-   back where we came from

The encrypt_value can be always the same (fixed) or chosen at

random, for instance using INT_21, service 2Ch (get current time)

and choosing as encrypt_value the value reported in DL (but

remembering to discard the eventual value 0, coz otherwise it

would not xor anything at all!)


     mov  ah,2Ch

     int  21h

     cmp  dl,0

     je   random_value

     mov  encrypt_value,dl

     The problem with XORing (and with many other encryption

methods), is that the part of the code that calls the encryption

routine cannot be itself encrypted. You'll somewhere have, "in

clear" the encryption key.

     The protectionist do at times their best to hide the

decrypting routine, here are some common methods:


  These are the more common protection method for the small

decryption part of the program code. This methods, originally

devised to fool signature virus scanners, have been pinched from

the polymorphic virus engines of our fellows viriwriters, and are

still in use for many simple decryption protection schemes. For

parts of the following many thanks go to the [Black Baron], it's

a real pity that so many potential good crackers dedicate so much

time to useless (and pretty repetitive) virus writing instead of

helping in our work. This said, virus studying is VERY important

for crackers coz the code of the viri is




Let's show as example of the abovementioned protection tactics

the following ultra-simple decryptor:

          MOV      SI,jumbled_data     ;Point to the jumbled data

          MOV      CX,10               ;Ten bytes to decrypt

mn_loop:  XOR      BYTE PTR [SI],44    ;XOR (un_scramble!) a byte

          INC      SI                  ;Next byte

          LOOP     mn_loop             ;Loop the 9 other bytes

This small program will XOR the ten bytes at the location pointed

to by SI with the value 44.  Providing the ten bytes were XORed

with 44 prior to running this decryptor the ten bytes will be

restored to their original state.

In this very simple case the "key" is the value 44. But there are

several tricks involving keys, the simplest one being the use of

a "sliding" key: a key that will be increased, or decreased, or

multiplied, or bit-shifted, or whatever, at every pass of the


A possible protection can also create a true "Polymorph"

decryptor, a whole decryptor ROUTINE that looks completely

different on each generation. The trick is to pepper totally

random amounts of totally random instructions, including JUMPS

and CALLS, that DO NOT AFFECT the registers that are used for the

decryption. Also this kind of protection oft uses a different

main decryptor (possibly from a selection of pre-coded ones) and

oft alters on each generation also all the registers that the

decryptor uses, invariably making sure that the JUNK code that

it generates doesn't destroy any of the registers used by the

real decryptor!  So, with these rules in mind, here is our simple

decryptor again:

         MOV      DX,10              ;Real part of the decryptor!

         MOV      SI,1234            ;junk

         AND      AX,[SI+1234]       ;junk

         CLD                         ;junk

         MOV      DI,jumbled_data    ;Real part of the decryptor!

         TEST     [SI+1234],BL       ;junk

         OR       AL,CL              ;junk

mn_loop: ADD      SI,SI              ;junk instr, but real loop!

         XOR      AX,1234            ;junk

         XOR      BYTE PTR [DI],44   ;Real part of the decryptor!

         SUB      SI,123             ;junk

         INC      DI                 ;Real part of the decryptor!

         TEST     DX,1234            ;junk

         AND      AL,[BP+1234]       ;junk

         DEC      DX                 ;Real part of the decryptor!

         NOP                         ;junk

         XOR      AX,DX              ;junk

         SBB      AX,[SI+1234]       ;junk

         AND      DX,DX              ;Real part of the decryptor!

         JNZ      mn_loop            ;Real part of the decryptor!

As you should be able to see, quite a mess! But still executable

code. It is essential that any junk code generated by the

Polymorph protection is executable, as it is going to be peppered

throughout the decryptor. Note, in this example, that some of the

junk instructions use registers that are actually used in the

decryptor! This is fine, providing the values in these

registers aren't destroyed. Also note, that now we have random

registers and random instructions on each generation. So, a

Polymorph protection Engine can be summed up into three major


  1 .. The random number generator.

  2 .. The junk code generator.

  3 .. The decryptor generator.

There are other discrete parts but these three are the ones where

most of the work goes on!

How does it all work?  Well a good protection would

*    choose a random selection of registers to use for the

decryptor and leave the remaining registers as "junk" registers

for the junk code generator.

*    choose one of the compressed pre-coded decryptors.

*    go into a loop generating the real decryptor, peppered with

junk code.

From the protectionist's point of view, the advantages of this

kind of method are mainly:

*    the casual cracker will have to sweat to find the decryptor.

*    the casual cracker will not be able to prepare a "patch" for

the lamers, unless he locates and patches the generators, (that

may be compressed) coz otherwise the decryptor will vary every


To defeat this kind of protection you need a little "zen" feeling

and a moderate knowledge of assembler language... some of the

junk instructions "feel" quite singular when you look at them

(->see lesson B). Besides, you (now) know what may be going on

and memory breakpoints will immediately trigger on decryption...

the road is open and the rest is easy (->see lessons 3-5).

-----> Starting point number magic

For example, say the encrypted code started at address 10h, the

following could be used to index this address:

 MOV   SI,10h         ;Start address

 MOV   AL,[SI]        ;Index from initial address

But sometimes you'll instead find something like the following,

again based on the encrypted code starting at address 10h:

 MOV   DI,0BFAAh      ;Indirect start address

 MOV   AL,[DI+4066h)  ;4066h + 0BFAAh = 10010h (and FFFF = 10h)!!

The possible combinations are obviously infinite.

[BIG KEYS] (Complicated encryption methods)

     Prime number factoring is the encryption used to protect

sensible data and very expensive applications. Obviously for few

digit keys the decoding is much easier than for, say, 129 or 250

digit keys. Nevertheless you can crack those huge encryption too,

using distributed processing of quadratic sieve equations (which

is far superior for cracking purpose to the sequential processing

methods) in order to break the key into prime numbers. To teach

you how to do this sort of "high" cracking is a little outside

the scope of my tutorial: you'll have to write a specific short

dedicated program, linking together more or less half a thousand

PC for a couple of hours, for a 250 bit key, this kind of things

have been done quite often on Internet, were you can also find

many sites that do untangle the mysteries (and vagaries) of such


  As References I would advocate the works of Lai Xueejia, those

swiss guys can crack *everything*. Begin with the following:

Xuejia Lai, James Massey, Sean Murphy, "Markov Ciphers and

     Differential Cryptanalysis", Advances in Cryptology,

     Eurocrypt 1991.

Xuejia Lai, "On the Design and Security of Block Ciphers",

     Institute for Signal and Information Processing,

     ETH-Zentrum, Zurich, Switzerland, 1992

Factoring and primality testing is obviously very important for

this kind of crack. The most comprehensive work I know of is:

(300 pages with lengthy bibliography!)

    W. Bosma & M. van der Hulst

    Primality Testing with Cyclotomy

    Thesis, University of Amsterdam Press.

A very good old book you can incorporate in your probes to build

very effective crack programs (not only for BBS accesses :=) is

*the* "pomerance" catalog:

Pomerance, Selfridge, & Wagstaff Jr.

    The pseudoprimes to 25*10^9

    Math. Comp. Vol 35 1980 pp. 1003-1026

Anyway... make a good search with Lykos, and visit the relevant

sites... if encryption really interests you, you'll be back in

two or three (or thirty) years and you'll resume cracking with

deeper erudite knowledge.


  The study of the patented enciphering methods is also *quite*

interesting for our aims :=) Here are some interesting patents,

if you want to walk these paths get the complete texts:

     [BEST]    USPat 4168396 to Best discloses a microprocessor

for executing enciphered programs. Computer programs which have

been enciphered during manufacture to deter the execution of the

programs in unauthorized computers, must be decrypted before

execution. The disclosed microprocessor deciphers and executes

an enciphered program one instruction at a time, instead of on

a continuous basis, through a combination of substitutions,

transpositions, and exclusive OR additions, in which the address

of each instruction is combined with the instruction. Each unit

may use a unique set of substitutions so that a program which can

be executed on one microprocessor cannot be run on any other

microprocessor. Further, Best cannot accommodate a mixture of

encrypted and plain text programs.

     [JOHNSTONE]    USPat 4120030 to Johnstone describes a

computer in which the data portion of instructions are scrambled

and in which the data is of necessity stored in a separate

memory. There is no disclosure of operating with instructions

which are completely encrypted with both the operation code and

the data address portion being unreadable without a corresponding

key kernel.

     [TWINPROGS]    USPat 4183085 describes a technique for

protecting software by providing two separate program storages.

The first program storage is a secure storage and the second

program storage is a free storage. Security logic is provided to

check whether an output instruction has originated in the secure

store and to prevent operation of an output unit which receives

output instructions from the free storage. This makes it

difficult to produce information by loading a program into free


     [AUTHENTICATOR]     USPat 3996449 entitled "Operating System

Authenticator," discloses a technique for authenticating the

validity of a plain text program read into a computer, by

exclusive OR'ing the plain text of the program with a key to

generate a code word which must be a standard recognizable code

word which is successfully compared with a standard corresponding

code word stored in the computer. If there is a successful

compare, then the plain text program is considered to be

authenticated and is allowed to run, otherwise the program

is not allowed to run.


In order to try to crack PGP, you need to understand how these

public/private keys systems work. Cracking PGP seems extremely

difficult, though... I have a special dedicated "attack" computer

that runs 24 hours on 24 only to this aim and yet have only begun

to see the light at the famous other end of the tunnel. It's

hard, but good crackers never resign! We'll see... I publish here

the following only in the hope that somebody else will one day

be able to help...

In the public key cryptosystems, like PGP, each user has an

associated encryption key E=(e,n) and decryption key D=(d,n),

wherein the encryption keys for all users are available in a

public file, while the decryption keys for the users are only

known to the respective users. In order to maintain a high level

of security a user's decoding key is not determinable in a

practical manner from that user's encoding (public) key. Normally

in such systems, since

     e.multidot.d.ident.1 (mod(1 cm((p-1),(q-1)))),

(where "1 cm((p-1),(q-1))" is the least common multiple of the

numbers p-1 and q-1)

d can be determined from e provided p and q are also known.

Accordingly, the security of the system is dependent upon the

ability to determine p and q which are the prime factors of n.

By selecting p and q to be large primes, the resultant composite

number n is also large, and correspondingly difficult to factor.

For example, using known computer-implemented factorization

methods, on the order of 10.sup.9 years is required to factor a

200 digit long number. Thus, as a practical matter, although a

user's encryption key E=(e,n) is public, the prime factors p and

q of n are effectively hidden from anyone due to the enormous

difficulty in factoring n. These aspects are described more fully

in the abundant publications on digital signatures and Public-Key

Cryptosystems. Most public/private systems relies on a message-

digest algorithm.

  A message-digest algorithm maps a message of arbitrary length

to a "digest" of fixed length, and has three properties:

Computing the digest is easy, finding a message with a given

digest "inversion" is hard, and finding two messages with the

same digest "collision" is also hard. Message-digest algorithms

have many applications, not only digital signatures and message

authentication. RSA Data Security's MD5 message-digest algorithm,

developed by Ron Rivest, maps a message to a 128-bit message

digest. Computing the digest of a one-megabyte message takes as

little as a second.  While no message-digest algorithm can yet

be secure, MD5 is believed to be at least as good as any other

that maps to a 128-bit digest.

  As a final gift, I'll tell you that PGP relies on MD5 for a

secure one-way hash function. For PGP this is troublesome, to say

the least, coz an approximate relation exists between any four

consecutive additive constants. This means that one of the design

principles behind MD4 (and MD5), namely to design a collision

resistant function, is not satisfied. You can construct two

chaining variables (that only differ in the most significant bit

of every word) and a single message block that yield the same

hashcode. The attack takes a few minutes on a PC. From here you

should start, as I did.

[DOS 4GW] cracking - This is only a very provisory part of this

tutorial. DOS 4GW cracking will be much better described as soon

as [Lost soul] sends his stuff, if he ever does. For (parts of)

the following I thank [The Interrupt].

     Most applications of every OS, and also of DOS 4GW, are

written in C language, coz as you'll have already learned or,

either, you'll learn, only C allows you to get the "guts" of a

program, almost approaching the effectiveness of assembler


     C is therefore the LANGUAGE OF CHOICE for crackers, when you

prepare your tools and do not directly use assembler routines.

Besides... you'll be able to find VERY GOOD books about C for

next to nothing in the second hand bookshops. All the lusers are

throwing money away in spades buying huge, coloured and

absolutely useless books on unproductive "bloated" languages like

Visual basic, C++ and Delphy. Good C new books are now rare

(books on assembler language have always been) and can be found

almost exclusively on the second hand market. Find them, buy

them, read them, use them for your/our aims. You can find a lot

of C tutorials and of C material on the Web, by all means DO IT!

Be a conscientious cracker... learn C! It's cheap, lean, mean and

very productive (and creative) :=)

     Back to the point: most stuff is written in C and therefore

you need to find the "main" sub-routine inside the asm. With

DOS/4GW programs, search the exe file for "90 90 90 90", almost

always it'll be at the start of the compiled code. Now search for

an INT_21 executed with 4C in AH, the exec to dos code (if you

cannot "BPINT 21 AH=4C" with your tool, then search for the

sequence "b4 4c cd 21". This is the equivalent to [mov AH,4C &

int 21]: it's the most direct call, but as you'll have already

learned, there are half a dozen ways to put 4C in AX, try them

all in the order of their frequency).

     A few bytes above the INT_21 service 4C, you'll find the

call to the "main" subroutine: "E8 xx xx". Now place a "CC" byte

a few bytes above the call in the exe and run the exe under a

debugger. When the computer tries to execute the instruction

you'll be throw back in the debugger coz the "CC" byte acts as

INT_01 instruction. Then proceed as usual.


  A last, very nice trick should be explained to every wannabe

cracker, coz it would be embarrassing to search for passwords or

protection routines that (apparently) are not there. They may be

hidden INSIDE a picture (or a *.waw file for that matter). This

is steganography, a method of disguising messages within other


  Depending on how many shades of grey or hues of colour you want

to have, a pixel can be expressed using 8. 16, 32 or even more

bits. If the least significant bit is changed. the shade of the

pixel is altered only one-256th, one-65,OOOth or even less. No

human eye could tell the difference.

  What the protectionist does, is hijack the least significant

bit in each pixel of a picture. It uses that bit to store one bit

of a protection, or of a password (or of a file, or of a secret

message). Because digitized pictures have lots of pixels, it's

possible to store lots of data in a single picture. A simple

algorithm will transfer them to the relevant parts of the program

when it needs be, and there we'll intercept them. You'll need to

learn very well the zen-cracking techniques to smell this kind

of stuff though (-> see lesson B).

Well, that's it for this lesson, reader. Not all lessons of my

tutorial are on the Web.

     You 'll obtain the OTHER 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


                                E-mail +ORC

                       an526164@anon.penet.fi (+ORC)
                     HOW TO CRACK, by +ORC, A TUTORIAL


               Lesson 8.1: How to crack Windows, an approach





     SPECIAL NOTE: Please excuse the somehow "unshaven"

     character of the windows lessons... I'm cracking the

     newest Windows '95 applications right now, therefore

     at times I had to add "on the fly" some corrections to

     the older Windows 3.1 and Windows NT findings.

                "homines, dum docent, discunt".



The NE format does give every windows executable the equivalent

of a debug symbol table: A CRACKER BLISS!


One of the many feature of Windows based on undocumented

foundations is the "ability to debug".

A word about undocumented functions in the MS-Operating Systems:

Microsoft manipulates its rule and domination of the operating

systems in use to day (MS-DOS, Windows, Windows '95) with two

main wicked aims:

1)   getting the concurrence completely bankrupt (that's the

     scope of all the using of undocumented functions and

     CHANGING them as soon as the concurrence uses them). The

     battle against Borland was fought in this way.

2)   getting all future "programmers" to use windows as a "black

     box" that only Microsoft engineers (if ever) can master, so

     that everybody will have to sip the ill-cooked abominations

     from Microsoft without ever having a chance to alter or

     ameliorate them.

Strange as it may seem, only the sublime cracker community fights

against these intolerable plans. All stupid governments and

lobbies -on the contrary- hide behind the fig-leaf of the

"market" "freedom" in order to ALLOW such heinous developments

(I'm speaking as if they were capable to opposing them even if

they wanted, which they do not. Be assured, they couldn't anyway,

"Governments" are deliberately MADE to serve Gates and all the

remaining suckers, and lobbies are the shield of feudalism. You

can forget "democracy", the only rule existing is a malevolent

oligarchy based on money, personal connections, defect of

culture, lack of knowledge and dictatorship of bad taste through

television in order to keep the slaves tamed... enough now...)

The windows situation is particularly reminiscent of the older

situation in DOS, where for years the key "load but don't

execute" function, used by debuggers, such as [DEBUG], [SYMDEB]

and [CODEVIEW], was "reserved" by Microsoft.

     The windows debugging library, WINDEBUG.DLL, a number of

undocumented functions and even the interface it provides are

undocumented! The WinDebug() function is used by all available

windows debuggers, including [CVW] (CodeView for Windows), [TDW]

(TurboDebugger for Windows), [Multiscope] and [Quick C for

Windows] (the last two are GUI, not text debuggers. The use of

WinDebug() doesn't show up in MAPWIN output 'coz debuggers link

to it at run-time via the amazing GetProcAddress() function.

     WinDebug() is a hacked 32-bit version, for the old Windows

3.0, of the poorly documented DOSPTrace() function from OS/2 1.x

(study these older Operating Systems! Studying the past you'll

understand EVERYTHING! Sometime I think that the only way to hack

and crack correctly is to be more a software historian than a

programmer... fac sapias et liber eris!). DOSPTrace is, in turn,

based on the ptrace() function in Unix.

     Like DosPTrace(), WinDebug() takes commands such as Go,

Single-Step, Write&Read Registers, Write&Read Memory. It returns

to its caller either when the command completes or when a

breakpoint occurs (or a DLL load). These commands and

notifications appear in a large structure whose address is passed

in WinDebug().

     WinDebug() was renamed CVWIN.DLL (and TDWIN.DLL) for Windows

3.1., all crackers should study it and get the maximum possible

documentation about it. As you will see in the following, it is

worth to study also TOOLHELP.DLL (what Microsoft would like you

to fiddle with) and INT_41h (the real debugging interface).

Interrupt handling under Windows

     Interrupt handling under Windows can be tricky: you need to

use Toolhelp (a rather scaring lobotomy for your programs) or to

have special code for Standard vs. Enhanced modes, because the

information on the stack of an interrupt or exception handler

differs between the two windows modes. In addition, some handlers

would be installed using INT_21h, while others are set up using

DPMI services. Toolhelp has quite a bit of internal code that

"cooks" the interrupts and sends them to you in an easily

digestible form.

     Remember that Windows uses GP faults as a "hacker" method

of doing ring transitions that are not allowed with legal 80x86

instructions: the virtual memory system of Enhanced mode is

implemented via the page fault.

Some tools for cracking windows (-> see lesson 9)

-----------------          DEBUGGERS

CVW and TDW         (you have to know the function's

                    segment:offset address beforehand in order

                    to crack a function)

WCB                 [Windows Codeback] by Leslie Pusztai (it's

                    a really cool tool!)

WDEB386             Microsoft's WDEB386 (clumsy, and requires a

                    second monitor)

Soft-Ice/Windows    best (BY FAR!) windows debugger! NuMega is

                    so good I am at times really sorry to crack

                    their products! [WINICE] is the single,

                    absolutely essential debugger and snooping

                    utility for windows crackers. Get it!

-----------------   POST MORTEM INSPECTORS

CORONER, etc.            (a lot of shareware)

MS-DrWatson              Old and clumsy

Borland's Winspector     THE BEST! It has the BUILDSYM utility

                         that allows the creation of a debug

                         .SYM file from an .EXE without debug


-----------------         INSPECTORS

MS-Spy                   Old

Borland's WinSight       (Best one, select "Other")

MicroQuill's Windows DeMystifiers (from Jeff Richter):

     VOYEUR (hold SHIFT picking Message Selection), COLONEL,


-----------------          SNOOPERS

[INFSPY.EXE], 231.424 bytes, version 2.05 28/8/1994 by Dean

Software Design, may be the more complete one.

[SUPERSPY.EXE], 24.576 bytes, 10,6,1994, quite handy for quick


[WINVIEW.EXE], 30.832 bytes, Version 3.00 by Scott McCraw, MS(c)

1990-1992, this is the old MS-Spy, distributed by MS

[TPWSPY.EXE], 9.472 bytes, quite primitive, but you get the

pascal source code with it.


     You can debug a program at the assembly-language level

without any debugging information. The DOS [DEBUG] program does

that, allowing breakpoints and single-stepping, all of which

implies that the hardware must be cooperating. Back in the time

of the 4-MHz Z-80s, you used a debugger that plugged interrupt

op codes into the instruction stream to generate breakpoints.

     Nothing has changed. That's how you debug a program on a

80586 (=Pentium). The x86 architecture includes software

interrupts. The 1-byte op code xCC is the INT_03 instruction,

reserved for debuggers. You can put the INT_03 op code in place

of the program instruction op code where the break is to occur

and replace the original op code at the time of the interrupt.

In the 80386 and later, you can set a register flag that tells

the processor to generate a not-intrusive INT_01 instruction for

every machine instruction executed. That device supports single


     The Win32SDK (Windows '95 software developer's kit) includes

functions that allow one program to launch another program and

debug it. The SDK's debug API takes care of how the interrupts

and interrupt vectors get managed. The logical consequence of

such an approach is that fewer and fewer people will be able to

know what's going on inside an application. The bulk of the

programmers -in few years time- will not be able any more to

reverse engineer an application, unless the few that will still

understand assembler-language do offer them the tools to do it.

Microsoft -it is evident- would like the programmers to use a

"black box" approach to programming, writing nice little "hallo

world" application and leaving to the engineers in Microsoft

alone the capacity to push forward (and sell) real programs that

are not toy application.

     The Win32 documentation seems vast, almost luxurious, until

you begin serious work and you discover its shortcomings, like

the fact that extended error codes are not documented, and

numerous APIs are documented either incorrectly or so poorly that

you must burn precious time testing them. What we definitely need

is to find some secret fellows inside Microsoft (like good old

Prometeus) that smuggles to the outside the real documentation

that the Microsoft engineers have reserved for themselves. If you

are reading this and do work for Microsoft, consider the

possibility of double-crossing your masters for the sake of

humanity and smuggle us the secret information.

     In windows '95 a debugger program launches a program to be

debugged by calling the _CreateProcess function, specifying in

an argument that the program is to be debugged. Then the debugger

program enters a loop to run the program. At the top of the loop

the debugger calls _WaitForDebugEvent.

     Each time _WaitForDebugEvent returns it sets indicators that

tell about the vent that suspended the program being debugged.

This is where the debugger traps breakpoints and single-step

exceptions. _WaitForDebugEvent fills in an event structure that

contains among other things the address that was interrupted end

the event that caused the interrupt.

     The debugger calls _GetThreadContext to get the running

context of the debugged program, including the contents of the

registers. The debugger can, as the result of cracker

interaction, modify these values and the contents of the debugged

program's memory.

     The debugger sets breakpoints by saving the op code at the

instruction to be intercepted and putting the INT_03 op code at

its place, it's always the same old marmalade. When the

breakpoint occurs, the debugger replaces the original op code in

the program's instruction memory, and decrements the interrupted

program counter in the saved context so that execution resumes

at the instruction that was broken.

     To single-step a program, the debugger sets a bit in the

context's flags register that tells the processor to generate an

INT_01 for every instruction cycle. When that interrupt occurs,

the debugger checks to see if the interrupted address is at a new

source-code line number. If not, the debugger continues

execution. Otherwise, the debugger displays the new line in the

IDE and waits for the cracker to take an action that resumes the


     While the debugged program is suspended, the debugger

interacts with the cracker and provides full access to the

debugged program's context and memory. This access permits the

cracker to examine and modify part of the code.

     To resume the debugged program, the debugger resets the

program's context by calling _SetThreadContext and calls

_ContinueDebugEvent. Then, the debugger returns to the top of the

loop to call _WaitForDebugEvent again.

     To extract debug information from a Win32 executable file,

you must understand the format of that file (best thing to do,

to practice yourself, would be to reverse engineer small

programs). The executable file has two sections not found in

other executable files: ".stab" and ".stabstr". How nice that

they used names that suggest their purpose (nomen est omen).

You'll find them inside a table of fixed-length entries that

include entries for .text, .bss, .data and .idata. Inside these

sections the compilers put different parts of a program.

     There are several different formats for encoding debug

information in an executable file. Borland's Turbo Debugger  one

format. Microsoft's CodeView  another. The gnu-win32 port from

Cygnus the stab format, an acronym meaning "symbol table",

although the table contains much more than just symbol


     The .stab section in a portable executable file is a table

of fixed-length entries that represent debugging information in

the stab format. The .stabstr section contains variable-length,

null terminated strings into which the .stab table entries point.

     The documentation for the stab format is available in text

format on the Cygnus ftp site (ftp.cygnus.com//pub/gnu-win32).

     Stabs contain, in a most cryptic format, the names and

characteristics of all intrinsic and user-defined types, the

memory address of every symbol in external memory and on the

stack, the program counter address of every function, the program

counter address where every brace-surrounded statement block

starts and ends, the memory address of line numbers within

source-code files, and anything else that a debugger needs. The

format is complex and cryptic because it is intended to support

any source-code language. It is the responsibility of a debugger

program to translate the stab entries into something meaningful

to the debugger in the language being debugged.

     Windows '95 invokes dozens of INT_21 services from 32-bit

code, including KERNEL32.DLL and possess Krn32Mutex, which

apparently controls access to certain parts of the kernel. Some

of the functions in KERNEL32 can be blocked by the Win16Mutex,

even though Microsoft says this isn't the case.


     I'll show you a simple windows crack, so easy it can be done

without WINICE: let's take [WINPGP4.1.] (front-end for PGPing in

windows, by Geib - I must thank "Q" for the idea to work on this


     Using WCB you'll find out quickly that the "CONGRATULATIONS

your registration number is OK" and the "SORRY, your registration

number is not correct" data blocks are at the block starting at

36.38B8 (respectively at 36.38D5 and 36.3937), that relocs to


     Looking at 13.0000 and following code, you'll find a push

38D5 (68D538) and a push 3937 (683739) at 13.064D and 13.06AE.

     The road to the crack is now open, you just need to find and

"fool" the calling routines. You'll learn the exact procedures

for this kind of WINcracks in part 2 and 3 of -> Lesson 8. Let's

now have a look at the protection scheme (disassembly from WCB):


13.0E88   660FBF46F8     movsx     eax, word ptr [bp-08]

13.0E8D   668946F4       mov       [bp-0C], eax

13.0E91   668B46F4       mov       eax, [bp-0C]

13.0E95   6669C00A000300 imul      eax, 0003000A

13.0E9C   668946F0       mov       [bp-10], eax

13.0EA0   668B4606       mov       eax, [bp+06]

13.0EA4   663B46F0       cmp       eax, [bp-10]

13.0EA8   7505           jne       0EAF      <- beggar_off

13.0EAA   B80100         mov       ax, 0001  <- flag 1 = "Right!"

13.0EAD   EB04           jmp       0EB3      <- and go on


13.0EAF   33C0           xor       ax,ax     <- flag 0 = "Nope!"

13.0EB1   EB00           jmp       0EB3      <- and go on

     I want you to have a good look at this protection scheme.

IT'S THE SAME OLD SOUP! You do remember lesson 3 and the

protection schemes of the old DOS stupid games of the '80s, don't

you? IT'S THE SAME OLD SOUP! In this "up-to-date" "new" windows

application, in WINPGP version 4.1 of 1995/1996, exactly the same

kind of protection is used to "conceal" the password!

A)   compare user input with memory echo

B)   beggar off if not equal with AX=0

C)   go on if equal with AX=1... how boring!

     Besides, look at all the mov eax, and  eax, moves preceding

the compare! That's a typical pattern for these "number_password"

protections! I wrote (years ago) a little crack utility that

searches for code blocks with a "66" as first instruction_byte

repeating in four or more consecutive instructions and it still

allows me to crack more than half of these windows password smuts

in less than three seconds flat. The IMUL instruction creates the

"magic" number, and if you give a closer look at the mathematical

part of the "conceal" routine, it could help you to crack

analogous schemes used in order to protect the "Instant access"

(c) & (tm) time_crippled software :=)

     Now you could crack the above code in 101 different ways,

the most elegant one would probably substitute je 0EAF (or jZ

0EAF, that's the same) to the jne 0EAF at 13.0EA8. You just write

a 74 at the place of the 75, like you did for the cracks in

1978... how boring: it's really the same old soup! (But you'll

see some new tricks in the next lessons).

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


                                E-mail +ORC

                         +ORC 526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


             Lesson 8.2: How to crack Windows, a deepr approach


                         [SNAP95] [WINZIP] [WINCAT]


     SPECIAL NOTE: Please excuse the somehow "unshaven"

     character of the windows lessons... I'm cracking the

     newest Windows '95 applications right now, therefore

     at times I had to add "on the fly" some corrections to

     the older Windows 3.1 and Windows NT findings.

                "homines, dum docent, discunt".



If you thought that DOS was a mess, please notice that windows

3.1 is a ghastly chaos, and windows 95 a gruesome nightmare of

ill-cooked spaghetti code. Old Basic "GOTO" abominations were

quite elegant in comparison with this concoction... One thing is

sure: This OS will not last... it's way too messy organised,

impossible to consolidate, slow and neurotic (but I must warn

you... I thought exactly the same things about DOS in 1981).

  The most striking thing about windows 95 is that it is neither

meat not fish: neither 16 nor 32... you could call it a "24 bit"

operating system.

  We'll never damage Microsoft interests enough to compensate for

this moronic situation... where you have to wait three minutes

to get on screen a wordprocessor that older OS (and even old DOS)

kick up in 5 seconds. I decide therefore, hic et nunc, to add an

ADDENDUM to this tutorial: Addendum 1 will be dedicated to teach

everybody how to crack ALL Microsoft programs that do exist on

this planet. I'll write it this sommer and give it away between

the "allowed" lessons.

  Anyway you can rely on good WINICE to crack everything, you'll

find it on the web for free, I use version 1.95, cracked by [The

Lexicon] (do not bother me for Warez, learn how to use the search

engines on the web and fish them out yourself). Learn how to use

this tool... read the whole manual! Resist the temptation to

crack immediatly everything in sight... you 'll regret pretty

soon that you did not wanted to learn how to use it properly.

A little tip: as Winice is intended more for software developers

than for crackers, we have to adapt it a little to our purposes,

in order to make it even more effective: a good idea is to have

in the *.DAT initialization file following lines:

     INIT = "CODE ON; watchd es:di; watchd ds:si;"

     TRA = 92

This way you'll always have the hexadecimal notation on, two very

useful watch windows for passwords deprotection and enough buffer

for your traces.


     The most used windows protections are "registration codes",

these must follow a special pattern: have a "-" or a "+" in a

predetermined position, have a particular number in particular

position... and so on.

For the program [SHEZ], for instance, the pattern is to have a

14 bytes long alphanumeric sequence containing CDCE1357 in the

first 8 bytes.

     The second level of protection is to "connect" such a

pattern to the alphanumeric contents of the NAME of the user...

every user name will give a different "access key". This is the

most commonly used system.

     As most of these protections have a "-" inside the answering

code, you do not need to go through the normal cracking procedure

(described in the next lesson):

*    load WINICE

*    hwnd [name_of_the_crackanda_module]

*    choose the window Handle of the snap, i.e, the exact

     "FIELD" where the code number input arrives... say 091C(2)


*    Run anew

*    Look at the memory location(s)

*    Do the same for the "Username" input FIELD. (Sometimes

     linked, sometimes not, does not change much, though)

*    BPR (eventually with TRACE) on the memory locations (these

     will be most of the time FOUR: two NUMBERCODES and two

     USERNAMES). The two "mirrored" ones are the most important

     for your crack. At times there will be a "5th" location,

     where the algebraic play will go on...

*    Look at the code that performs algebraic manipulations on

     these locations and understand what it does...

*    Disable the routine or jump over it, or reverse it, or

     defeat it with your own code... there are thousand


*    Reassemble everything.

Uff... quite a long cracking work just to crack some miserable

program... isn'there a quicker way? OF COURSE THERE IS! Actually

there are quite a lot of them (see also the crack of Wincat Pro

below): Look at the following code (taken from SNAP32, a screen

capture utility for Windows 95, that uses a pretty recent

protection scheme):

     XOR  EBX,EBX   ; make sure EBX is zeroed

     MOV  BL, [ESI] ; load input char in BL

     INC  ESI       ; point at the next character

     MOV  EDI,EBX   ; save the input character in EDI

     CMP  EBX,+2D   ; input char is a "-" ?

     JZ   ok_it's_a_+_or_a_-

     CMP  EBX,+2B   ; input char is a "+" ?

     JNZ  Jesus_it's_neither_a_minus_nor_a_plus_let's_check_it


     XOR  EBX,EBX   ; EBX is zeroed

     MOV  BL,[ESI]  ; recharge BL

     INC  ESI       ; point to next char (do not check - or +)


     XOR  EBP,EBP   ; zero EBP

     CMP  DWORD PTR [boguschecker], +01


even if you did not read all my precedent lessons, you do not

need much more explications... this is a part of the algebraic

check_procedure inside the SNAP32 module...  you could also get

here through the usual




Windows wretched and detestable APIs used for copy protections,

as usual with WINICE cracking, and as described elsewhere in my


  The above code is the part of the routine that checks for the

presence of a "+" or a "-" inside the registration number (many

protections scheme requires them at a given position, other need

to jump over them).

  Now sit down, make yourself comfortable and sip a good Martini-

Wodka (invariably very useful in order to crack... but be aware

that only Moskowskaia russian Wodka and a correct "Tumball" glass

will do, do not forget the lemon)... what does this "-" stuff

mean for us little crackers?

  It means that we can search directly for the CMP EBX,+2B

sequence inside any file protected with these schemes... and

we'll land smack in the middle of the protection scheme! That's

amazing... but you will never underrate enough the commercial

programmers... the only really amazing thing is how simpleton the

protectionists are! You don't believe me? Try it... you 'll get

your crack at least 4 out of 5 times.

  Yes I know, to find this code is not yet to crack it... but for

this kind of copy protection (that's the reason it is so

widespread) there is no single solution... each makes a slightly

different algebraic manipulation of the alphanumeric and of the

numeric data. It's up to you to crack the various schemes... here

you can only learn how to find them and circumvene them. I'll not

give you therefore a "debug" crack solution. You'll find it

yourself using my indications (see the crack of the Wincat Pro

program below).



Most of the time the protection schemes use their own *.ini files

in the c:\WINDOWS directory for registration purposes... at time

they even use the "garbage sammler" win.ini file. Let's take as

example WINZIP (versions 5 and 5.5), a very widespread program,

you'll surely have one shareware copy of it somewhere between

your files.

  In theory, winzip should be registered per post, in order to

get a "NEW" copy of it, a "registered" copy.

  This scares most newby crackers, since if the copy you have

it's not full, there is no way to crack it and make it work,

unless you get the REAL stuff. The youngest among us do not

realize that the production of a real "downsized" demo copy is

a very expensive nightmare for the money-infatuated commercial

programmers, and that therefore almost nobody does it really...

nearly all "demos" and "trywares" are therefore CRIPPLED COMPLETE

PROGRAMS, and not "downsized" demos, independently of what the

programmers and the protectionists have written inside them.

  Back to Winzip... all you need, to crack winzip, is to add a

few lines inside the win.ini file, under the heading [WinZip],

that has already been created with the demo version, before the

line with "version=5.0".

 I will not help you any further with this... I'll leave it to

you to experiment with the correct sequences... inside win.ini

you must have following sequence (these are only template to

substitute for your tries inside WINICE... you'll get it, believe



   name=Azert Qwerty



  The *important* thing is that this means that you DO NOT NEED

to have a "new registered version" shipped to you in order to

make it work, as the protectionist sellers would like you to

believe. The same applies most of the time... never believe what

you read in the read.me or in the registration files...

  This brings me to a broader question: NEVER believe the

information they give you... never believe what television and/or

newspapers tell you... you can be sure that the only reason they

are notifying you something is to hinder you to read or

understand something else... this stupid_slaves_society can only

subsist if nobody thinks... if you are really interested in what

is going on, real information can be gathered, but surely not

through the "conventional" newspapers and/or news_agencies (and

definitely NEVER through television, that's really only for the

stupid slaves)... yes, some bit of information can be

(laboriously) gathered... it's a cracking work, though.



  In the middle of the hugest junk collection of the planet, some

real information can be laboriously gathered if you do learn how

to use well the search engines (or if you do build your ones...

my spiders are doing most of the work for me... get your robots

templates from "Harvest" or "Verify" and start your "spider

building" activity beginning from Martijn Koster's page). As

usual in our society, in the Internet the real point is exactly

the same point you'll have to confront all your life long: HOW



difficult art to learn per se. Internet offers some information,

though, mainly BECAUSE it's (still) unregulated. You want a

proof? You are reading it.


  The newspaper of the real enemies, the economic powers that

rule this slaves world, are paradoxically most of the time the

only ones worth studying... somewhere even the real rulers have

to pass each other some bits of real information. The "Neue

Zuercher Zeitung", a newspaper of the Swiss industrials from

Zuerich, is possibly the best "not_conformist trend analyzer"

around that you can easily find (even on the web). These

swissuckers do not give a shit for ideology, nor preconcerted

petty ideas, the only thing they really want is to sell

everywhere their ubiquitous watches and their chocolates... in

order to do it, a land like Switzerland, with very high salaries

and a good (and expensive) social system, must use something

brilliant... they found it: a clear vision of the world... as a

consequence this newspaper is very often "against" the trend of

all the other medias in the world, the ones that are used only

in order to tame the slaves... If the only language you know is

english (poor guy) you could try your luck with the weekly

"Economist"... you'll have to work a lot with it, coz it has been

tailored for the "new riches" of the Tatcher disaster, but you

can (at times) fish something out of it... they do a lot of

idiotic propaganda, but are nevertheless compelled to write some

truth. American newspapers (at least the ones you can get here

in Europe) are absolute shit... one wonders where the hell do the

americans hyde the real information.

  On the "non-capitalistic" side of information there is a

spanish newspaper "El Pais" that seems to know about what's going

on in South America, but it's so full of useless propaganda about

irrelevant Spanish politics that it's not really worth reading.

The monthly "Le Monde diplomatique" offers something too... this

one exaggerates a little on the pauperistic "third world" side,

but has a lot of useful information. See what you can do with all

this information (or disinformation?)


     Another good rule of thumb in choosing your medias is the

following... if all medias around you assure, for instance, that

"the Serbians are evil"... the only logical consequence is that

the Serbians are not so evil at all and that "the Croats" or some

other Yugoslavian shits are the real culprits. This does not mean

at all that the Serbians are good, I warn you, it means only what

I say: something is surely hidden behind the concerted propaganda

you hear, the best reaction is to exaggerate in the other

direction and believe the few bit of information that do say the

countrary of the trend. This rule of thumb may be puerile, but

it works somehow most of the time... if somewhere everybody

writes that the commies are bad then THERE the commies must not

be so bad at all and, conversely, if everybody in another place

writes that the commies are all good and nice and perfect (like

the Soviet propaganda did) then THERE the commies are surely not

so good... it's a matter of perspective, much depends on where

you are, i.e. whose interests are really at stake. There is NEVER

real information in this society, only propaganda... if you still

do not believe me do yourself a little experiment... just read

the media description of a past event (say the Vietnam war) as

written AT THE MOMENT of the event and (say) as described 10

years later. You'll quickly realize how untrustworthy all

newspapers and medias are.

*    SEMIOTICS You'll have to study it (as soon as you can) to

interpret what they let you believe, in order to get your

bearings. A passing knowledge of ancient RHETORIC can help quite

a lot. Rhetoric is the "Softice" debugger you need to read

through the propaganda medias: concentrate on Periphrasis,

Synecdoche, Antonomasia, Emphasis, Litotes and Hyperbole at the

beginning... you'll later crack higher with Annominatio,

Polyptoton, Isocolon and all the other lovely "figurae


Enough, back to software cracking.


     Let's take as an example for the next crack, a Username-

algebraic registration code, WINCAT Pro, version 3.4., a 1994

shareware program by Mart Heubel. It's a good program, pretty

useful to catalogue the millions of files that you have on all

your cd-roms (and to find them when you need them).

The kind of protection Wincat Pro uses is the most utilized

around: the username string is manipulated with particular

algorithms, and the registration key will be made "ad hoc" and

depends on the name_string. It's a protection incredibly easy to

crack when you learn how the relevant procedures work.

     [WINCAT Pro] is a good choice for cracking studies, coz you

can register "over your registration" one thousand times, and you

can herefore try for this crack different user_names to see all

the algebrical correspondences you may need to understand the

protection code.

     In this program, when you select the option "register", you

get a window where you can input your name and your registration

number (that's what you would get, emailed, after registering

your copy). If you load winice and do your routinely hwnd to

individuate the nag window, and then breakpoint on the

appropriate memory ranges you'll peep in the working of the whole

bazaar (this is completely useless in order to crack these

schemes, but it'll teach you a lot for higher cracking, so you

better do it also with two or three other programs, even if it

is a little boring): a series of routines act on the input (the

name) of the user: the User_name_string (usn). First of all the

usn_length will be calculated (with a REPNZ SCASB and a following

STOSB). Then various routines store and move in memory the usn

and the registration_number (rn) and their relative lengths. In

order to compare their lengths and to check the correct

alphanumeric correspondence between usn and rn, the program first

uppercases the usn and strips all eventual spaces away.

     Here the relevant code (when you see an instruction like

SUB  AL,20 you should immediately realize that you are in a

uppercasing routine, which is important for us, since these are

mostly used for password comparisons)... here the relevant Winice

unassemble and my comments:

253F:00000260  AC        LODSB          <- get the usn chars

253F:00000261  08C0      OR   AL,AL     <- check if zero

253F:00000263  740F      JZ   0274      <- 0: so usn finished

253F:00000265  3C61      CMP  AL,61     <- x61 is "a", man

253F:00000267  72F7      JB   0260      <- not a lower, so loop

253F:00000269  3C7A      CMP  AL,7A     <- x7A is "z", what else?

253F:0000026B  77F3      JA   0260      <- not a lower, so loop

253F:0000026D  2C20      SUB  AL,20     <- upper it if it's lower

253F:0000026F  8844FF    MOV  [SI-01],AL<- and hyde it away

253F:00000272  EBEC      JMP  0260      <- loop to next char

253F:00000274  93        XCHG AX,BX


The instruction  MOV [SI-01],AL that you see here is important

at times, coz it points to the location of the "pre-digested"

usn, i.e. the usn formatted as it should be for the number

comparison that will happen later. In some more complicated

protection schemes the reasoning behind this formatting is the

following: "Stupid cracker will never get the relation algorhitm

usn <-> rn, coz he does not know that usn AND rn are slightly

changed before comparing, ah ah... no direct guessing is

possible". Here is only "polishing": you have to "polish" a

string before comparing it in order to concede some mistakes to

the legitimate user (too many spaces in the name, upper-lower

case mismatch, foreign accents in the name etc.) You just need

to know, for now, that this checking is usually still 5 or 6

calls ahead of the real checking (it's what we call a "green


     You should in general realize that the real checking of the

algebrical correspondence follows after a whole series of memory

operations, i.e.: cancelling (and erasing) the previous (if ever)

attempts; reduplicating the usn and the rn somewhere else in

memory; double checking the string lengths (and saving all these

values somewhere... be particularly attentive when you meet stack

pointers (for instance [BP+05]): most of the programs you'll find

have been written in C (what else?). C uses the stack (SS:SP) to

pass parameters or to create local variables for his procedures.

The passwords, in particular, are most of the time compared to

data contained within the stack. If inside a protection a BP

register points to the stack you have most of the time fished

something... remember it pupils: it will spare you hours of

useless cracking inside irrelevant routines. Back to our CATWIN:

another little check is about the "minimal" length allowed for

a user name, in our babe, for instance, the usn must have at

least 6 chars:

     230F:00003483  3D0600    CMP  AX,0006

     230F:00003486  730F      JAE  3497      <- go to nice_name


     230F:00003488  BF9245    MOV  DI,4592   <- no good: short

  After a lot of other winicing you'll finally come across

following section of the code:

2467:00000CA3  B90100    MOV  CX,0001

2467:00000CA6  03F1      ADD  SI,CX

2467:00000CA8  2BC1      SUB  AX,CX

2467:00000CAA  7213      JB   0CBF

2467:00000CAC  40        INC  AX

2467:00000CAD  368B4F04  MOV  CX,SS:[BX+04]  <- here

2467:00000CB1  0BC9      0R   CX,CX

2467:00000CB3  7D02      JGE  0CB7

2467:00000CB5  33C9      XOR  CX,CX

2467:00000CB7  3BC1      CMP  AX,CX

2467:00000CB9  7606      JBE  0CC1

2467:00000CBB  8BC1      MOV  AX,CX

2467:00000CBD  EB02      JMP  0CC1

2467:00000CBF  33C0      XOR  AX,AX

2467:00000CC1  AA        STOSB               <- and here

2467:00000CC2  8BC8      MOV  CX,AX

2467:00000CC4  F3A4      REPZ MOVSB          <- and here!

2467:00000CC6  8EDA      MOV  DS,DX

2467:00000CC8  FC        RETF 0008

     This is obviously the last part of the checking routine

(I'll not delve here with the mathematical tampering of it, if

you want to check its workings, by all means, go ahead, it's

quite interesting, albeit such study is NOT necessary to crack

these schemes). The important lines are obviously the MOV

CX,SS:[BX+04], the STOSB and the REPZ MOVSB (as usual in password

protection schemes, you do remember lesson 3, don't you?).

     You should be enough crack-able :=) by now (if you have read

all the precedent lessons of my tutorial), to find out easily,

with these hints, how the working of the protection goes and

where dwells in memory the ECHO of the correct rn (passkey) that

matches the name you typed in. Remember that in these kind of

cracks the ECHO is present somewhere (90% of the cases). There

are obviously one thousand way to find such ECHOs directly,

without going through the verificayions routines... for instance

you could also find them with a couple of well placed

snap_compares, it's a "5 minutes" cracking, once you get the

working of it. I leave you to find, as interesting exercise, the

routine that checks for a "-" inside the rn, a very common

protection element.

  In order to help you understand the working of the protection

code in [Wincat Pro] I'll give you another hint, though: if you

type "+ORC+ORC+ORC" as usn, you'll have to type 38108-37864 as

rn, if you usn as usn "+ORC+ORC" then the relative rn will be

14055-87593. But these are my personal cracks... I have offered

this information only to let you better explore the mathematical

tampering of this specific program... you'll better see the

snapping mechanism trying them out (going through the routines

inside Winice) alternatively with a correct and with a false

password. Do not crack Wincat with my combination! If you use a

different usn than your own name to crack a program you only show

that you are a miserable lamer... no better than the lamers that

believe to "crack" software using huge lists of serial numbers...

that is really software that they have stolen (Yeah: stolen, not

cracked). You should crack your programs, not steal them...

"Warez_kids" and "serial#_aficionados" are only useless zombies.

I bomb them as soon as I spot them. YOU ARE (gonna be) A CRACKER!

It makes a lot of a difference, believe me.

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


     "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"

                                E-mail +ORC

                     HOW TO CRACK, by +ORC, A TUTORIAL


                Lesson 9 (1): How to crack Windows, Hands on




     I have chosen an older windows application for Win 3.1.
(WIN4MANT.EXE, 562271 bytes, Version 1.10, by Joseph B. Albanese;
you'll find it searching the web with the usual tools, see how
to do it at the end of this lesson), in order to show you how to
use a nice little trick, at times really useful in cracking
password protected programs: [data_constraint]. Inside almost all
protection routines, as you have already learned, there is a
moment when on the stack the ECHO of the real, "correct"
passnumber or password appears. The location of this ECHO varies,
but most of the time it'll be in a range of +- 0x90 bytes from
one of the locations where the user input dwells. This is due to
datadump windows constraints inside the tools used by the
protectionists... but this use is bound to diminish... especially
after this lesson :=)

 This application is -per se- crappy, I doubt you'll ever use
it... but its curious (and pretty rare) "deactivate" mode is
nevertheless very interesting for us: you can "unregister"
Winformant on the fly if you feel the need to.
 This feature is pretty useful for scholars that like to
investigate password algorithms with valid and invalid codes
without having to reinstall every time to delete a valid code.
For your cracking exercises choose programs that have
"REVERSIBLE" protections (rare) or that can be re-registered a
billion times (more frequent). Programs that keep the valid
registration on *.ini or special files will also do the job: you
just change a couple of lines to "unregister" them.
 The trick of this lesson: [data_constraint], or "password
proximity", bases on the protectionist's need to keep an eye on
the protection "working" when he assembles it. He must "see" the
and the CORRECT NUMBER ANSWER (in our jargon: the "Bingo"). These
relationships must be constantly checked In order to debug the
protection code. Mostly they will dwell TOGETHER inside a small
stack area, allowing them to be "seen" in the SAME watchwindow.
Most of the time, therefore, the "ECHO" will "materialize"
shortly not very far away from one of the locations of the USER
INPUT. Let's crack:

* Fire Winice and then Winformant
* Choose HELP and then choose REGISTRATION
* Fill the registration fields with "+ORC+ORC" as "Registrant"
and "12121212" as "Activation" code (use whatever you fancy).
CTRL+D              ;switch to Winice
:task               ;let's see what's the name of this crap
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?
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
... and many more irrelevant windows.

Let's pinpoint the code, here the relevant window is the first
"Edit" one, for obvious reasons (more on this later).
:bmsg 3710 wm_gettext           ;set breakpoint
CTRL+D                          ;run the babe until you get:
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 we have "pinpointed" the babe (more on "pinpointing"
later). Let's snoop around a little: look at the stack to fetch
your babe's last call (if it does not show immediately, just keep
pinpointing, for instance on GetWindowText() or do a BPRW
diskomat (very useful), and then try and retry the stack...
should this too fail to work, 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... until you get
the "real" list of calls coming from your babe's protection.
:stack              ; let's see
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 fishing! Do immediately a BPX on babe:EA20.
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; get strlen "ORC+ORC"
2C7F:EA44 83C404       ADD    SP,+04
2C7F:EA47 3D2800       CMP    AX,0028
2C7F:EA4A 762C         JBE    EA78
2C7F:EA97 8D46AE       LEA    AX,[BP-52]     ;load ptr "+ORC+ORC"
2C7F:EA9A 16           PUSH   SS     ;various algors on input
2C7F:EA9B 50           PUSH   AX     ;follow here, we do not
...                                  ;need to care
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 ;get strlen "12121212"
2C7F:EAC1 83C404       ADD    SP,+04
2C7F:EAC4 50           PUSH   AX
2C7F:EAC5 8D865CFF     LEA    AX,[BP+FF5C] ;ptr "12121212" HERE!
2C7F:EAC9 16           PUSH   SS
2C7F:EACA 50           PUSH   AX
...etc, various algors on input follow here

  OK, it's enough: now obviously follows the code that
"algorithmize" the number string, and then, somewhere, you'll
have the hideous compare that divides good guys and bad crackers.
You could examine, and crack, and search...
it: The echo must be somewhere... how do we find it? Searching
"12121212" in memory fishes at least 10 different locations...
:s 30:0 lffffffff '12121212'
Pattern Found at 0030:0005AD6A
.... (7 more)
Pattern Found at 0030:80509D6A
Pattern Found at 0030:8145AD6A
 Should we look for all occurrences of string '12121212',
starting with the two at 80000000, dumping +-0x90 around it...
until we find the echo? We could, and it would work, but that's
not zen... that's boring! In other protections these locations
could proliferate on purpose, to deter the casual cracker. There
must be some other way... And lo and behold! YES! There is a
quicker way... THE LAST loading of the numeric input string in
the code (the one after the strlen count) is the "right" one for
our cracking purposes, coz protections follow (mostly) this
pattern (remember: we are inside a "stack-heavy" section of the
code... if you want to crack higher I suggest you read some good
literature about stack working, stack tricks and stack magics
with the Intel processors):
     LOAD NAMEString - COUNT NAMEStringLen
     LOAD CODEString - COUNT CODEStringLen
     LOAD CODEString
               *ECHO must be here*
               *ECHO must be here*

  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   ;these numbers will differ in your computer
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 01 00-04 2C 2F 06 AE 24 36 62 00 00  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 0C 00 BC 02 00 00 00  12121212........
00 49 00 BA 0F-AE 24 F2 24 2F 06 00 00 00 00 00  ....I....$.$/...
AF 17 00 E2 5F-7A 62 FE FF 79 1B BA 0F 00 00 00  ......._zb..y...
96 0B 01 00 02 4E 00-37 01 8A 62 D2 0F 8F 17 00  .....N..7..b....
2F 06 00 37 01-98 62 20 10 16 03 2F 06 00 00 00  /.....7..b .../.
C2 62 2B 4F 52 43 2B 4F-52 43 00 0D AE 24 2F 06  .b+ORC+ORC......

 Look at this dump: everybody is there! The stack pointers points
in the middle, at string "12121212". 0x50 bytes before it you'll
find our good old ECHO (i.e. the CORRECT passnumber) and 0x50
bytes afterwards you'll see your handle: here "+ORC+ORC".
     It's cracked! The code for my "+ORC+ORC" is 8037-646-3836...
Now begin your assignments: if you rally want to learn cracking:
-    "Unregister" and find anew your own code for your own
     handle. *DO NOT* use serial numbers with any other name
     that your own handle, that's miserable stealing, not
     cracking. I'll begin to punish the serial#_aficionados on
     the Web, coz I like real outlaws, but I detest stupid
-    Study the two coding algorithms, the one for the input name
     and the one for the input number, this will be very useful
     for your future cracking sessions.
-    Find the "Compare", i.e. the code that sets the two usual
     flags "good guy, you may move on" and "bad cracker, beggar
     off", and
-    Create a "real" crack for this protection, that will allow
     anybody you think deserves it, with any name and any
     password number, to get through.

     Snap 32  (SNAP32.EXE 356.352 bytes, 24/11/95,  Version 2.54,
by Greg Kochaniak) is a "snapshot" shareware program for Windows
95, that allows users to save the screen, parts of it, or a
single window. It's a very common 'try before you buy' program,
limited to 30 days use. You'll find it everywhere on the Web. If
you do not know how to search the Web (poor guy!), learn at the
end of this lesson the correct procedure to find all the files
you need on the Net and get them automatically emailed to you
(that's something you should learn: SEARCHING! It's even more
important than cracking!).
     Snap32 is not very interesting (I don't think I used it more
than a couple of times), but its protection is: in order to (try
to) deter casual crackers it does not compare strings, it
compares a "magic" sum (from Namestring) with another magic sum
(from Numberstring). And:
*    SUMS magics inside the GDI, not inside its own code;
*    USES a look_up table for input validation instead of
     "plain" code;
*    COMPARES the "magic" manipulation from input NUMBER with
     the "magic" manipulation from input NAME.

  The cracking procedure for most of these windows programs is
pretty simple and relatively straightforward:

:task     ;This is the Winice95 command you type after firing
snap32 and getting at the "Enter License" nag window:

TaskName SS:SP     StckTp   StckBt  StckLw TaskDB  Hqueue  Events
Snap32   0000:0000 006 AC000 006B0000       270E    D27    0000

OK, the babe is Snap32,it's HQUEUE is 0xD27, it's TaskDB is
0x27OE, orright.

:map32 snap32       ;Your command
Owner     Obj Name  Obj#  Address        Size      Type
SNAP32    .text     0001  0137:00401000  00043000  CODE  RO
SNAP32    .rdata    0002  013F:00444000  00002E00  IDATA RO
SNAP32    .data     0003  013F:00447000  00009000  IDATA RW
SNAP32    .idata    0004  013F:00471000  00001C00  IDATA RW
SNAP32    .rsrc     0005  013F:00473000  00001600  IDATA RO
SNAP32    .reloc    0006  013F:00475000  00004C00  IDATA RO

OK, so the code is in selector 137:(as usual), and you have there
43000 bytes of code from 401000 to 401000+43000; the DATA,
ReadWrite and ReadOnly, are in selector 13F: (as usual).

:hwnd snap32             ;Your command
Window Handle  Hqueue  SZ  Qowner   Class Name Window Procedure
 0350(1)       0D27    32  SNAP32   #02071     144F:0560
  0354(2)      0D27    32  SNAP32   #02071     17CF:102E
  ... and many more windows that we do not care of.

  OK, so, for our cracking purposes, it's Handle 0x350. Most of
the times the "nag" window you want to crack will be the first
one in the hwnd listing (coz it was the last one to appear).
Watch the number in parentheses that follows the Whandle: (1) is
a mother, (2) are "children" windows. At times you'll find under
"Class Name" something like "Edit" (see before the Winformant
cracking)... SNIFF THERE! At times the "Window Procedure" code
location in a list of more than twenty, will be slightly
different for one or two windows... SNIFF THERE!

4) BREAKPOINT MESSAGE WM_GETTEXT (or any other WM_ that you can
think of in order to "pinpoint" the code of our babe).
"Pinpointing" the code is extremely important in windows
cracking... this idiotic OS moves code, data and stack out and
inside the pages all the time... so you'll keep getting on
"INVALID" sections without a correct pinpointing. Good
Pinpointing points are in general:
  BMSG xxxx WM_GETTEXT   (good for passwords)
  BMSG xxxx WM_COMMAND   (good fro OK buttons)
  BPRW *your babe* TW    (good for tracking)
  u USER!GETWINDOWTEXT   (u and then BPX inside the code)
  u GETDLGITEM           (for the Hwnd of an Item inside a
                         Dialog Box)
  CSIP NOT GDI           (if you have too many interferences)
  u USER!SHOWWINDOW      (bpx with counter occurrence to get to
                         the "right" window)
  u GETSYSTEMTIME        (for "time-crippled" software)
and many others pinpointing points you'll learn. If you are
really desperate for pinpointing, just do a BMSG xxxx WM_MOVE and
then move the nag window, this will always work. Let's go on:

:bmsg 350 wm_gettext     ;Your command
OK, so the code is ready to be pinpointed.

CTRL+D                   ;Your command to exit Winice and run
                         until it pops out at breakpoint
OK, now you pop out inside Winice somewhere... (look at the stack
to know where) so the code has been pinpointed.

6) SEARCH THE DATA AREA for your input string (4 Gigabytes from
30:0... remember that DATA are *always* in 30:0 to 30:FFFFFFFF
and CODE is *always* in 28:0 to 28:FFFFFFFF). In most protection
the "registration_number" string must match the "username"
string, which cannot be constrained, in order to allow users to
choose whatever stupid name they fancy. Some protections requires
fixed symbols inside the "username" string, though... in these
rare eventualities, just apply to the "username" string what
we'll do here with the "registration_number" string. The point
to remember is: begin always with the protection fumbling your
number, crack only if necessary the protection that fumbles your
name. Let's search now.

:s 30:0 lffffffff '12121212'  ;Your command
     Pattern Found at 0030:80308612

80000000 is good. Lower era videos, mirrors and BIOS, higher
(around C0000000) you have the OS dustbins... the point to
remember is: investigate always FIRST the 80000000 locations.

By the way: prepare a watch window  dex 3 es:di, you'll soon see
how useful such an automated watchwindow is in password cracking.

:bpr 30:80308612 30:80308612+8 RW  ;Your command

OK Now we'll begin to dig out the relevant parts of the code.
Remember that you must breakpoint *every* copy of the string that
protection generates. A typical copy routine, very frequently
used in windows copy protection schemes, dwells inside

0117:9E8E 66C1E902      SHR     ECX,02
0117:9E92 F36766A5      REPZ MOVSD      ;makes a copy in es:di
0117:9E96 6659          POP     ECX
0117:9E98 6683E103      AND     ECX,+03
0117:9E9C F367A4        REPZ MOVSB
0117:9E9F 33D2          XOR     DX,DX

In fact, this piece of copying code is so often used for password
verifications that sometimes you just need to bpx on 0117:9E92
to get the correct stack sequence... but let's, for now, continue
without such little tricks: just keep on BPRring (Breakpoint on
memory range) all copies that protection makes.

8) LET THE BABE RUN, it will breakpoint on all manipulations of
your input string. One of them will lead to the magic.
8.1.)     VALIDATION phase
There are many routines that check and "validate" your inputs.
The most common ones check that your numbers ARE really numbers,
i.e. in the range 0x30-0x39. Usually this is done with:
          CMP  EAX,+30
          JB   no_number
          CMP  EAX,+39
          JA   no_number
At times the protectionists use TABLES instead... The number
itself is used as a pointer to a "ready made" table where the
relevant magic can be used as a protection. Imagine that a number
4  in your input points to a code section that throws you
immediately outside the validation routine... or imagine that a
number 7, if found in your input, fetches a magic code that
removes the whole program from your harddisk (or worse): "Ah, ah!
Stupid cracker will never know that he should not have used
number 4... and definitely not number 7! Next time he'll
learn..." Yes, tables have been used for such nasty tricks.
Here the relevant code for the "validation" part of our
protection (still checking my favourite input string '12121212'):
0137:4364AE 8A16       MOV     DL,[ESI] ;load license number
0137:4364B0 33C0       XOR     EAX,EAX  ;zero AX
0137:4364B2 668B0451   MOV     AX,[ECX+2*EDX] ;look table for 84
0137:4364B6 83E008     AND     EAX,+08  ;OK if AND'S TO zero
0137:4364B9 85C0       TEST    EAX,EAX  ;and therefore
0137:4364BB 7403       JZ      004364C0 ;go on
0137:4364BD 46         INC     ESI      ; ready for next number
0137:4364BE EBCD       JMP     0043648D
0137:4364C0 33DB       XOR     EBX,EBX  ;clean BX
0137:4364C2 8A1E       MOV     BL,[ESI] ;load license number
0137:4364C4 46         INC     ESI      ;ready for next
0137:4364C5 8BFB       MOV     EDI,EBX  ;save copy
0137:4364C7 83FB2D     CMP     EBX,+2D  ;is it a "-"?
0137:4364CA 7405       JZ      004364D1
0137:4364CC 83FB2B     CMP     EBX,+2B  ;is it a "+"?

8.2.)     MANIPULATION (summing magic numbers)
Your wisely set breakpoints on memory range for the occurrence
of the string "12121212" will pop you out, inter alia, inside
following piece of code (note how this part of protection dwells
inside GDI, and  NOT inside the code selector of snap32):
0557:11BD 33C0         XOR  EAX,EAX        ;zero AX
0557:11BF 66648B06     MOV  AX,FS:[ESI]    ;load number
0557:11C3 83C602       ADD  ESI,+02        ;point to next
0557:11C6 66833C4700   CMP  WORD PTR [EDI+2*EAX],+00
0557:11CB 0F8424010000 JE   000012F5
0557:11D1 668B0442     MOV  AX,[EDX+2*EAX] ;load from magic table
0557:11D5 03D8         ADD  EBX,EAX        ;save sum in EBX
0557:11D7 49           DEC  ECX            ;till we are done
0557:11D8 75E5         JNZ  000011BF       ;loop along

Interesting, isn't it? Protection is using this GDI routine to
create a SUM (through pointers to another table) that depends on
your very input numbers. We are now very near to the crack... can
you *feel* it? If not, prepare yourself a good Martini Vodka!
This is the correct way to do it:
 * Get a "highball" glass;
 * Put some ice cubes inside it (2 or 3);
 * Add Martini Dry (From Martini & Rossi). Fill to 1/3;
 * Add Moskowskaja Wodka (the only real Vodka). Fill to 2/3;
 * Add a zest of lemon (From Malta or Southern France);
 * Add a green "sound" olive (from Italy or Israel);
 * Add Schweppes Indian Tonic. Fill to the brim.
Sit deeper and relax, sip slowly and *feel* where the code of the
protection scheme you are cracking "moves"... It's like a
current... a slow tide. If you still do not believe me, just try

We'll now find out where protection stores the "magic" sum (and
now you'll pop out inside the very own snap32 code, this is the
"real" protection part):

8.3.)     The ludicrous "HIDING" of the magic sum
0137:40437E 83C404       ADD     ESP,+04
0137:404381 8B4DE8       MOV     ECX,[EBP-18]
0137:404384 8945F0       MOV     [EBP-10],EAX  ;***HERE!***
0137:404387 68FF000000   PUSH    000000FF
0137:40438C 8D8574FBFFFF LEA     EAX,[EBP+FFFFFB74] ;load string
0137:404392 50    PUSH   EAX                      ;push it
0137:404393 E886410100   CALL    0041851E         ;manipulate
0137:404398 8D8574FBFFFF LEA     EAX,[EBP+FFFFFB74] ;load string
0137:40439E 50    PUSH   EAX                      ;push it
0137:40439F E88C210300   CALL    00436530         ;manipulate

As you can see, the protection is very simple: The "magic" sum
is hidden only two lines before the further manipulations of the
input string. We have found location 137:404384, here, in the
CORRECT way, through bprring of the string that has been
manipulated in the GDI, but actually, we could have found it
quickly just checking superficially what's happening "around" all
manipulations of the input string. Do we really need to follow
all manipulations of our registration_number and eventually also
all manipulation of our username? NO, not at all: we just set a
BPR on the stack location where protection hides the sum [EBP-10]
and we'll see what happens: 90% of these protections just create
two sums, a sum from your username and a sum from your
registration_number... somewhere there will be a compare that
must use this location (or a copy of it... we'll see).

Breakpoint on memory range on the sum location [EBP-10] that you
saw in the previous code and you'll land at this piece of code:
0137:404412 E82F050000   CALL 00404946
0137:404417 83C40C       ADD  ESP,+0C
0137:40441A 3B45F0       CMP  EAX,[EBP-10] ;comp AX & magicsum
0137:40441D 740F         JZ   0040442E
0137:40441F 68C0874400   PUSH 004487C0
0137:404424 E8149E0000   CALL 0040E23D
0137:404429 83C404       ADD  ESP,+04
0137:40442C EB5B         JMP  00404489
0137:40442E 893DA0714400 MOV  [004471A0],EDI
0137:404434 85FF         TEST EDI,EDI

That's it, you have made it! We found the compare between the
"username" magic number (for my "+ORC+ORC" string that's here
0x7C25621B) in AX (we do not need to know how this landed
there... it's irrelevant!) and the "license_number" '12121212'
(whose magic is here 0x00B8F47C) stored in [pointer-10.] How do
we find now the correct INPUT number for +ORC+ORC? Well, it's
easy...  the "magic number" must be the same... therefore:


     That was it. Old Snap32 has been cracked. You could now
prepare a crack in order to distribute this program around
without its simple protection. Good cracked applications should
be given free (i.e. cracked) to all the people that NEED them and
do not have the money to buy them. Don't forget that in this
intolerable society the 0,5% of the citizens own the 56% of the
industrial capital and the 63% of the propaganda machines (data
from US researchers... therefore suspect... the real situation
is probably even worser) effectively conditioning the destiny of
millions of slaves, moronized by television watching. So crack
the applications and give them to the people you care and the
peolple that need them, but for the others... just EXPLAIN
everybody how you did it... this is real help: giving knowledge,
not wares. DO NOT use my handle and my codes to crack this
program, get yours, I gave you mine only as an help for this
cracking lesson. I have showed you the way enough... THIEFS, not
crackers, use the codes that others have found. You are (gonna
be) CRACKERS! Remember it, look straight ahead, crack accurately
and keep your tommy in.

  It's amazing: most of the people roaming around inside Internet
DO NOT know how to use effectively the web. I'll be very
altruistic and explain how to fetch the very example of Snap32,
the babe we cracked in this lesson.

1) Choose an archie from this list (I will not explain you what
an archie is, you should know it... if you do not, be ashamed):
     archie.univie.ac.at        Austria
     archie.belnet.be      Belgium
     archie.funet.fi       Finland
     archie.univ-rennes1.fr        France
     archie.th-darmstadt.de         Germany
     archie.ac.il            Israel
     archie.unipi.it       Italy
     archie.uninett.no         Norway

2) Email a message to your archie:
     To:       archie.univie.ac.at (for instance)
     Subject:                      (nothing on this field)
     Body:     set search sub      (substrings too)
               set maxhits 140     (max 140 hits)
               set maxhitspm 9     (not the same file all over)
               find snap32         (we want this)

3) After a while you'll get (per email) your answer: Here the
answer from the Austrian archie

Host ftp.wu-wien.ac.at    (
 Last updated 17:48  9 Aug 1995
 Location: /pub/systems/windows.32/misc
  FILE    -rw-r-----  128957 bytes  15:59 16 Jun 1995  snap32.zip
Host space.mit.edu    (
 Last updated 00:45  4 Mar 1996
 Location: /pub/mydir
  FILE    -rw-r--r--  407040 bytes  11:55 28 Nov 1995  snap32.exe

4) ftpmail your file (Browsing is no good: too busy and lame).
Again, I will not explain you what an FTPMAIL server is: learn
it by yourself... choose a good one from this list (there are
many more... you'll learn):
   bitftp@vm.gmd.de                           (Germany)
   ftpmail@ieunet.ie                          (Ireland)
   bitftp@plearn.edu.pl                       (Poland)
   ftpmail@ftp.sun.ac.za                      (South Africa)
   ftpmail@ftp.sunet.se                       (Sweden)
   ftpmail@ftp.luth.se                        (Sweden)
   ftpmail@src.doc.ic.ac.uk                   (United Kingdom)

To:       ftpmail@ftp.sun.ac.za.   (for instance)
Subject:                           (leave blank)
Body:     open space.mit.edu       (the last occurrence that
                                   the archie sent)
          cd/pub/mydir             (get the correct subdir)
          bin                      (prepare for BINARY)
          get snap32.exe           (I want this)
          quit                     (bye)

5) Your FTPMAIL server will first notice you a receipt:

FTP EMAIL response...
ftpmail has received the following job from you:
      reply-to +ORC
      open space.mit.edu +ORC@now.here
      get snap32.exe
ftpmail has queued your job as: 1834131821.5514
Your priority is 1 (0 = highest, 9 = lowest)
Requests to sunsite.doc.ic.ac.uk will be done before other jobs.
There are 14 jobs ahead of this one in the queue.
4 ftpmail handlers available.
To remove send a message to ftpmail containing just:
delete 1834131821.5514

After a while you'll get a second message, with your file
uuencoded inside... everything has been done.
YESSIR! there is absolutely no need to loose time on the WWW,
"surfing" idiotically from a junk site to the next or waiting
hours to download some slow file from an instable server! Wasting
time of your own LIFE, that you could use to read poetry, to make
love, to look at the stars, to sail slowly between the Aegean
islands or to start a nice cracking session. What's the point of
wasting your time when machines can perform all the searches you
need better, more productively and faster than you ever could...
YESSIR! You can get *everything* on the Web, and without paying
your Internet provider more than a couple of dimes... Nice, isn't

By now, if you have followed all my lessons, you should be able
to crack relatively quickly "normal" applications. There are some
new projects for 1997: a cracking "university", that will allow
us to prepare for the divine war against Microsoft repulsive
dominion. If you do not have already chosen your handle (your
"cracker" name, that's it), you may consider choosing an handle
with a "+" somewhere inside it or, eventually, add a "+" to your
handle. This sign is used by me and by friends that have studied
and/or contributed. But a "+" in your handle ("official +ORC
cracker") will mean even more:
1)   allows support from me personally (on a "do ut des" basis)
2)   allows pupils to identify each other (good for joining
3)   will open you (eventually) the doors to the "higher"
     cracking university I'll set up on the Web in 1997.
(I'm not getting megalomaniac... In reality I only need a "quick"
method to know on which (anonymous) people I can count on for the
next phase).

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

                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


          Lesson A.1: Advanced Cracking: Internet Cracking (Unix)



     With each new company that connects to the "Information

Superhighway" new frontiers are created for crackers to explore.

Site administrators (Siteads) have implemented various security

measures to protect their internal networks. One of these is

xinetd, covered later. A more general solution is to construct

a guarded gateway, called a [Firewall], that sits between a

site's internal network and the wild and woolly Internet where

we roam. In fact only one third of all Internet connected

machines are already behind firewalls. Most information services

have to deal with the same problem we have: getting OUT through

a local firewall or GETTING INTO a service through their

Firewall. There lays also the crack_solution.

------------>         What is a Firewall?

     The main purpose of a Firewall is to prevent unauthorized

access between networks. Generally this means protecting a site's

inner network from the Internet. If a site has a firewall,

decisions have been made as to what is allowed and disallowed

across the firewall. These decisions are always different and

always incomplete, given the multiplicity of Internet, there are

always loopholes where a cracker can capitalize on.

     A firewall basically works by examining the IP packets that

travel between the server and the client. This provides a way to

control the information flow for each service by IP address, by

port and in each direction.

     A firewall embodies a "stance". The stance of a firewall

describes the trade-off between security and ease-of-use. A

stance of the form "that which is not expressly permitted is

prohibited" requires that each new service be enabled

individually and is seldom used, coz very slow and annoying.

Conversely, the stance "that which is not expressly prohibited

is permitted" has traded a level of security for convenience. It

will be useful to guess the stance of the firewall you are

cracking when making probe decisions.

     A firewall has some general responsibilities:

*    First and foremost if a particular action is not allowed by

the policy of the site, the firewall must make sure that all

attempts to perform the action will fail.

*    The firewall should log suspicious events

*    The firewall should alert internal administration of all

cracking attempts

*    Some firewall provide usage statistics as well.

------------>          Types of Firewall

     In order to avoid head-scratching, it's a good idea to know

the TOPOLOGY of "your" firewall -and its limitations- before

attempting to get through it. Discussed below are two popular

firewall topologies. Although other types exist, the two below

represent the basic forms; most other firewalls employ the same

concepts and thus have -luckily- the same limitations.

                   1) THE DUAL-HOMED GATEWAY

     A dual-homed Gateway is a firewall composed of a single

system with at least two network interfaces. This system is

normally configured such that packets are not directly routed

from one network (the Internet) to the other (the internal net

you want to crack). Machines on the Internet can talk to the

gateway, as can machines on the internal network, but direct

traffic between nets is blocked.

     In discussing firewalls, it's generally accepted that you

should think of the inner network as a medieval castle. The

"bastions" of a castle are the critical points where defence is

concentrated. In a dual-homed gateway topology, the dual-homed

host itself is called the [BASTION HOST].

     The main disadvantage of a dual-homed gateway, from the

viewpoints of the users of the network and us crackers alike, is

the fact that it blocks direct IP traffic in both directions. Any

programs running on the inner network that require a routed path

to external machines will not function in this environment. The

services on the internal network don't have a routed path to the

clients outside. To resolve these difficulties, dual-homed

gateways run programs called [PROXIES] to forward application

packets between nets. A proxy controls the conversation between

client and server processes in a firewalled environment. Rather

than communicating directly, the client and the server both talk

to the proxy, which is usually running on the bastion host

itself. Normally the proxy is transparent to the users.

     A proxy on the bastion host does not just allow free rein

for certain services. Most proxy software can be configured to

allow or deny forwarding based on source or destination addresses

or ports. Proxies may also require authentication of the

requester using encryption- or password-based systems.

     The use of proxy software on the bastion host means that the

firewall administrator has to provide replacements for the

standard networking clients, a nightmare in heterogeneous

environments (sites with many different operating systems

platforms, PC, Sun, IBM, DEC, HP...) and a great burden for

administrator and users alike.

                 2) THE SCREENED HOST GATEWAY

     A screened host gateway is a firewall consisting of at least

one router and a bastion host with a single network interface.

The router is typically configured to block (screen) all traffic

to the internal net such that the bastion host is the only

machine that can be reached from the outside. Unlike the dual-

homed gateway, a screened host gateway does not necessarily force

all traffic through the bastion host; through configuration of

the screening router, it's possible to open "holes" in the

firewall to the other machines on the internal net you want to

get into.

     The bastion host in a screened host firewall is protected

from the outside net by the screening router. The router is

generally configured to only allow traffic FROM SPECIFIC PORTS

on the bastion host. Further, it may allow that traffic only FROM

SPECIFIC EXTERNAL HOSTS. For example the router may allow Usenet

news traffic to reach the bastion host ONLY if the traffic

originated from the site's news provider. This filtering can be

easily cracked: it is relying on the IP address of a remote

machine, which can be forged.

     Most sites configure their router such that any connection

(or a set of allowed connections) initiated from the inside net

is allowed to pass. This is done by examining the SYN and ACK

bits of TCP packets. The "start of connection" packet will have

both bits set. If this packets source address is internal... or

seems to be internal :=) the packet is allowed to pass. This

allows users on the internal net to communicate with the internet

without a proxy service.

     As mentioned, this design also allows "holes" to be opened

in the firewall for machines on the internal net. In this case

you can crack not only the bastion host, but also the inner

machine offering the service. Mostly this or these machine/s will

be far less secure than the bastion host.

     New services, for instance recent WEB services, contain a

lot of back doors and bugs, that you'll find in the appropriate

usenet discussion groups, and that you could use at freedom to

crack inner machines with firewall holes. Sendmail is a good

example of how you could crack in this way, read the whole

related history... very instructive. The rule of thumb is "big

is good": the bigger the software package, the more chance that

we can find some security related bugs... and all packages are

huge nowadays, 'coz the lazy bunch of programmers uses

overbloated, buggy and fatty languages like Visual Basic or


Finally, remember that the logs are 'mostly) not on the bastion

host! Most administrators collect them on an internal machine not

accessible from the Internet. An automated process scan the logs

regularly and reports suspicious information.


The dual-homed gateway and the screened host are probably the

most popular, but by no mean the only firewall topologies. Other

configurations include the simple screening router (no bastion

host), the screened subnet (two screening routers and a bastion

host) as well as many commercial vendor solutions.

------------>   Which software should we study?

Three popular unix software solutions allow clients inside a

firewall to communicate with server outside: CERN Web server in

proxy mode, SOCKS and the TIS Firewall toolkit.

1)   The CERN Web server handles not only HTTP but also the other

protocols that Web clients use and makes the remote connections,

passing the information back to the client transparently. X-based

Mosaic can be configured for proxy mode simply by setting a few

environment variables.

2)   The SOCKS package (available free for anonymous ftp from

ftp.nec.com in the file


includes a proxy server that runs on the bastion host of a

firewall. The package includes replacements for standard IP

socket calls such as connect(), getsockname(), bind(), accept(),

listen() and select(). In the package there is a library which

can be used to SOCKSify your crack probes.

3)   The Firewall Toolkit

The toolkit contains many useful tools for cracking firewall and

proxy server. netacl can be used in inetd.conf to conceal

incoming requests against an access table before spawning ftpd,

httpd or other inetd-capable daemons. Mail will be stored in a

chroot()ed area of the bastion for processing (mostly by


The Firewall toolkit is available for free, in anonymous ftp from

ftp.tis.com in the file


The popular PC firewall solution is the "PC Socks Pack", for MS-

Windows, available from ftp.nec.com It includes a winsock.dll


     The cracking attempts should concentrate on ftpd, normally

located on the bastion host. It's a huge application, necessary

to allow anonymous ftp on and from the inner net, and full of

bugs and back doors. Normally, on the bastion host, ftpd is

located in a chroot()ed area and runs as nonprivileged user. If

the protection is run from an internal machine (as opposing the

bastion host), you could take advantage of the special inner-net

privileges in hostp.equiv or .rhosts. If the internal machine

"trusts" the server machine, you'll be in pretty easily.

     Another good method, that really works, is to locate your

PC physically somewhere along the route between network and

archie server and "spoof" the firewall into believing that you

are the archie server. You'll need the help of a fellow hacker

for this, though.

     Remember that if you gain supervisor privileges on a machine

you can send packets from port 20, and that in a screened host

environment, unless FTP is being used in proxy mode, the access

filters allow often connections from any external host if the

source port is 20 and the destination port is greater than 1023!

     remember that NCSA Mosaic uses several protocols, each on

a different port, and that -if on the firewall no proxy Web

server is operating- each protocol must be dealt with

individually, what lazy administrators seldom do.

     Be careful for TRAPS: networking clients like telnet and ftp

are often viciously replaced with programs that APPEAR to execute

like their namesake, but actually email an administrator. A

fellow cracker was almost intercepted, once, by a command that

simulated network delays and spat out random error messages in

order to keep me interested long enough to catch me. Read the

(fictions) horror story from Bill Cheswick: "An evening with

Berferd in which a cracked is lured, endured and studied",

available from ftp.research.att.com in


As usual, all kind of traps can be located and uncovered by

correct zen-cracking: you must *FEEL* that some code (or that

some software behaviour) is not "genuine". Hope you believe me

and learn it before attempting this kind of cracks.

------------>      How do I crack Firewalls?

     Some suggestions have been given above, but teaching you how

to crack firewalls would take at least six complete tutorial

lessons for a relatively unimportant cracking sector, and you

would almost surely get snatched immediately, 'coz you would

believe you can crack it without knowing nothing at all. So, for

your sake, I'll teach you HOW TO LEARN IT, not HOW TO DO IT

(quite a fascinating difference): First Text, then the software

above. For text, start with Marcus Ranum's paper "Thinking about

Firewalls", available from ftp.tis.com in the file/pub/firewalls/firewalls.ps.Z

and do an archie search for newer literature.

Join the firewall discussion list sending a message to

majordomo@greatcircle.com, you'll get a message with

instructions, as usual, lurk only... never show yourself to the


     You can find for free on the web quite a lot of early

versions of proxy software. Study it, study it and then study it

again. The cracking efforts on your copies, and your machines,

before attempting anything serious, are MANDATORY if you do not

want to be immediately busted on the Internet. When you feel

ready to try serious cracking, you must OBLIGATORY start with a

small BBS which uses a firewall version you already studied very

well (sysops are not firewall administrators, and many of them

do not know nothing about the software they use). As soon as you

gain access to the bastion host, remember to subvert entirely the

firewall itself before entering the inner net.

If you feel ready and everything went well so far, if your zen-

cracking abilities are working well... then take a moment for

yourself... prepare yourself a good Martini-Wodka (you should

only use Moskovskaia), take a deep breath and by all means go

ahead! You will then be able to try your luck on the Cyberspace

and get quickly busted (if you did not follow my admonitions and

if you cannot zen-crack) or, may be, fish quite a lot of

jewels... :=)

------------->     INTERNET CRACKING: XINETD

     [Xinetd] a freely available enhanced replacement for the

internet service daemon inetd, allows just those particular users

to have FTP or Telnet access, without opening up access to the

world. Xinetd can only protect the system from intrusion by

controlling INITIAL access to most system services and by logging

activities so that you can detect break-in attempts. However,

once a connection has been allowed to a service, xinetd is out

of the picture. It cannot protect against a server program that

has security problems internally. For example, the finger server

had a bug several years ago that allowed a particularly clever

person to overwrite part of its memory. This was used to gain

access to many systems. Even placing finger under the control of

xinetd wouldn't have helped.

     Think of the secured firewall system as a fortress wall:

each service that is enabled for incoming connections can be

viewed as a door or window in the walls. Not all these doors have

secure and reliable locks. The more openings are available, the

more opportunities are open for us.

------------->         What xinetd does

Xinetd listens to all enabled service ports and permits only

those incoming connection request that meet authorization


-    Accept connections from only certain IP addresses

-    Accept connections only from authorized users

-    Reject connections outside of aithorized hours

-    Log selected service when connections are accepted or

     rejected, capturing following informations:

     * Remote Host Address

     * User ID of remote user (in some cases)

     * Entry and Exit time

     * Terminal type

     Support login, shell, exec and finger

------------->        SERVICES TO CRACK &


In this order the easy services:

     FTP  TELNET    LOGIN (rlogin) SHELL (rcmd)   EXEC

In this order the more difficult ones:

     MOUNT     TFT  FINGER    NFS(Network File System)

     DNS(Domain Name Service)

Remember that sendmail (SMTP), by default, accepts a message from

any incoming connection. The "sender" of such a message can

appear to have originated anywhere, therefore your claim of

identity will be accepted! Thus you can forge a message's

originator. Most of the recipients inside the protected

(firewalled) net will take your claim at face value and send you

(to the "return address" you provide) all the sensitive

information you need to crack the system. Finding unwitting

inside complices is most of the time pretty easy.

     By far the best method, for entering xinetd, is to get the

real version from panos@cs.colorado.edu, modify the system files

in order to have some backdoors, and then distribute them to the

mirror servers on the WEB. Each time a new administrator will

download "your" version of xinetd, you'll have an easy access to

the "protected" system.

     On the Nets, it's important to conceal your identity (they

will find you out pretty quickly if you do not). The best method

is to obtain the IP address of a legitimate workstation during

normal hours. Then, late at night, when the workstation is known

to be powered-off or disconnected from a dialup PPP link, a

different node on the network can be configured to use the

counterfeit IP address. To everyone on the network, it will

appear that the "legitimate" user is active. If you follow this

strategy, you may want to crack somehow more negligently... the

search for the cracker will go on -later- in the false confidence

that a sloppy novice (the legitimate user) is at work, this will

muddle the waters a little more.

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


                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


              LESSON C (1) - How to crack, Cracking as an art


                        [BARCODES] [INSTANT ACCESS]


     First of all, let me stress the importance of cracking in
our everyday life. Cracking it's not just about software, it's
about information, about all patterns of life. To crack is to
refuse to be controlled and used by others, to crack is to be
free. But you must also be yourself free from petty conventions
in order to crack properly.
     You must learn to discerne cracking possibilities all around
yourself, and believe me, the development of this ghastly society
brings every day new codes, protections and concealing
     All around us grows a world of codes and secret and not so
secret patterns. Codes that are at times so familiar and common
that we do not even notice them any more... and yet they are
there to fool us, and yet they offer marvellous cracking
     Let's take as an striking example BARCODES... those little
lines that you see on any book you buy, on any bottle you get,
on any item around you... do you know how they work? If you do
not you may be excused, but you cannot be excused if you never
had the impulse to understand them... crackers are curious by
nature... heirs of an almost extinct race of researchers that has
nothing in common with the television slaves and the publicity
and trend zombies around us. Cracker should always be capable of
going beyond the obvious, seek knowledge where others do not see
and do not venture.

     Let's begin with a little history. Universal Product Code
(UPC) was adopted for commercial use by the grocery industry in
the USA. Among the advantages were a rapid, accurate and reliable
way of entering stock information into a computer and the
possibility to sack a lot of workers and to do more profit. The
early success led to the development of the European Article
Numbering System (EAN), a symbology similar to UPC, that is
widely used in Europe and in the rest of the World. I'll teach
you to crack this one, since I do not -fortunately- live in the
States. Keep in mind, anyway, that there are different barcode
symbologies, each with its own particular pattern of bars. The
UPC/EAN code used on retail products is an all-numeric code; so
is the Interleaved 2 of 5 Code. Code 39 includes upper case
letters, digits, and a few symbols. Code 128 includes every
printable and unprintable ASCII character code. The most new one
is a 2-D code. These are special rectangular codes, called
stacked barcodes or matrix codes. They can store considerably
more information than a standard barcode. They require special
readers which cost more than a standard scanner. The practical
limit for a standard barcode depends on a number of factors, but
20 to 25 characters is an approximate maximum. For applications
that need more data, matrix codes are used. For example, the next
time you receive a package from United Parcel Service look for
a small square label with a pattern of dots and a small bullseye
in the centre. This is a MaxiCode label, and it is used by UPS
for automatic destination sortition.
     The manufacturer's ID number on the barcode uniquely
identifies products. These numbers are managed by the Uniform
Code Council in Dayton, Ohio for the States and Canada and by the
EAN authority (Internationale Article Numbering Association) in
Bruxelles, for Europe and the rest of the World. The
manufacturer's ID number accounts for some digits of the code,
which leaves other digits to be assigned in any way the producer
wants. He provides retail outlets with a list of his products and
their assigned codes so that they can be entered in the cash
register system. Many codes are NOT on the products and are added
by the supermarkets on the fly, using an internal code schema
that may be non standard. Now it's enough... let's crack.
     BARCODES are the only thing an automated casher needs to see
on a product to calculate its price and automatically catalogate
the sold merchandise... imagine (just imagine it :=) coz it would
be extremely illegal to act in this way) somebody would fasten
an adhesive home-made codebar label direct on the top of the
supermarket/mall/retail store label, say on a bottle of Pomerol
(that's a very good but unfortunately very expensive french
     The new label would mean for the casher something like
"cheap wine from Bordeaux, France, cost so and so, everything
it's OK, do not worry"... do you think that anybody would come
to the idea that there is something wrong with the label, with
the bottle or with you? I have been codebaring for years and had
only once a problem, coz my printer was running out of ink and
the scanner in the supermarket could not read it... so what? Act
uninterested, always wear jackets of the utmost quality, shetland
pullovers and beautiful expensive shoes... (all articles that you
may codebar too, by the way), in this society appearance and look
count much more than substance and knowledge... LET'S USE THIS
TO OUR ADVANTAGE! Nobody will ever come to the idea that you may
actually really know the working of the scheme... coz codebar is
pretty complicated and not exactly exceptionally public. On the
Web there are a lot information about it, but most of them are
useless, unless you know how to search most of the time you'll
find only sentences like this one:
          "The calculated check digit is the twelfth and final
          digit in the U.P.C.code. It is calculated based on a
          specific algorithm, and is necessary to ensure that
          the number is read or key-entered correctly."

But good +ORC will now explain you everything you need to crack:

Each barcode label has 13 values, from #0 to #12 (that's the EAN
code, the UPC american one has only 12, from #0 to #11).
     #0 and #1 indicate the origin of the product.
     #2 to #11 give the article code
     #12 (the last and 13th one) is a checksum value, that
     verifies the validity of all the other numbers.
How is it calculated? #12 is calculated in 4 steps
     VALUE A:  You sum odd position numbers (#0+#2+#4+#6+#8+#10)
     VALUE B:  You sum even position numbers and multiply by 3
     VALUE C:  You sum value A and value B
     VALUE D:  You mod value C (you divide by 10 and only keep
     the remaining units, a very widespread checking scheme as
     you'll see in the software part of this lesson)
     If the result is not zero, you subtract it from 10.
Now look at a barcode label, get some books or other barcoded
items and *watch* it...
Bar codes are supposed to have "quiet zones" on either side of
the symbol. Quiet zones are blank areas, free of any printing or
marks,typically 10 times the width of the narrowest bar or space
in the bar code. Failure to allow adequate space on either side
of the symbol for quiet zones can make it impossible to read the
bar code.
On the barcode there are two "borders", left and right, and a
"middle" longer line. These three lines are longer than the
others and are used to "regulate" the scanner to whatever
dimension has been used for the barcode.
#0 dwells left of the first (left) border and has a special
meaning, the other 12 numbers are written "inside" the code and
are divided in two "groups" by the middle bar.
Each value is coded through SEVEN bars: black=1 and White=0.
These form two couples of "optic" bars of different widths.
We come now to the "magic" part: In order to bluff the
simpletons, barcode uses three different SETS of characters to
represent the values 0-9. This should make it impossible for you
to understand what's going on, as usual, in this society, slaves
should not need to worry with the real functioning of things.
   Here are the graphic codes of the three graphic sets:

     CODE A            CODE B (XOR C)    CODE C (NOT A)
0:  0001101   (13)     0100111   (39)    1110010   (114)
1:  0011001   (25)     0110011   (51)    1100110   (102)
2:  0010011   (19)     0011011   (27)    1101100   (108)
3:  0111101   (61)     0100001   (33)    1000010   (066)
4:  0100011   (35)     0011101   (29)    1011100   (092)
5:  0110001   (49)     0111001   (57)    1001110   (078)
6:  0101111   (47)     0000101   (05)    1010000   (080)
7:  0111011   (59)     0010001   (17)    1000100   (068)
8:  0110111   (55)     0001001   (09)    1001000   (072)
9:  0001011   (11)     0010111   (23)    1110100   (116)

Borders:       101
Centre:        01010

- The C graphic set is a "NOT A" graphic set.
- The B graphic set is a "XOR C" graphic set.
- each value has two couples of bars with different widths

 Now watch some labels yourself... see the difference between the
numbers left and the numbers right? The first "half" of the
barcode is coded using sets A and B, the second "half" using set
C. As if that were not enough, A and B are used inside the first
"half" in a combination that varies and depends from value #0,
following 10 different patterns:
              #1   #2   #3   #4   #5  #6
   0          A    A    A    A    A    A
   1          A    A    B    A    B    B
   2          A    A    B    B    A    B
   3          A    A    B    B    B    A
   4          A    B    A    A    B    B
   5          A    B    B    A    A    B
   6          A    B    B    B    A    A
   7          A    B    A    B    A    B
   8          A    B    A    B    B    A
   9          A    B    B    A    B    A

"Ah! Stupid buyer will never understand why the same values gives
different bars! Nothing is as reliable as barcodes!" :=)

Let's take as example the codebar for Martini Dry:
BARCODE:    8 0 00570 00425 7
Let's see: we have a 8 0 0 = booze
Then a 000570 as ABABBA and a 004257 as C
"Even" sum: 8+0+5+0+0+2 = 15 (even sum)
Then a 0+0+7+0+4+5= 16 and 16 *3 = 48 (odd sum)
Then a 15+48=63
63 === 3
10 - 3 = 7 = checksum
Pattern = 8 = ABABBA CCCCCC

OK, one more example: Osborne Windows programming series Volume
2 General purpose API functions (always here on my table)...
BARCODE: 9 7 80078 81991 9
Let's see: we have a 9 7 8 = book
Then a 780078 as ABBABA and a 819919 as C
"Even" sum: 9+8+5+8+8+4 = 42 (even sum)
Then a 7+1+5+2+4+4= 23 and 23 * 3 = 69 (odd sum)
Then a 42+69=111
111 === 1
10 - 1 = 9 = checksum
Pattern = 9 = ABBABA

Well... what's the point of all this?
The point, my pupils, is that who DOES NOT KNOW is taken along
on a boat ride, who KNOWS and LEARNS can use his knowledge in
order to try to beat blue and black the loathsome consumistic
oligarchy where we are compelled to live. Try it out for
yourself... if you crack correctly and wisely your supermarket,
mall and library bills will be cut to almost zero.
     Write a small program to print whichever codebar you fancy
(or whichever your mall uses) in whichever size on whichever sort
of label you (or better your targets) fancy... it's quickly done
with Visualbasic or Delphy... but you'll not find much on the Web
Alternatively you could also write, as I did long ago, a short
c program in dos, using a modified upper char set... and there
you are, have labels... see the world.
     A small word of caution... crack only ONE item at time and
try it out first with the SAME label for the same product... i.e.
the correct code for that item, but on your own label. If it goes
through your program works good, if not, nobody will ever be able
to harm you. Anyway it never happens anything, never: the bar
code reading equipments have great tolerance, coz the scanners
must be able to recognize barcodes that have been printed on many
different medias. You should choose labels similar to the ones
effectively used only in order not to arise human suspects, coz
for all the scanner itself cares, your label could be pink with
green stripes and with orange hand-written, numbers. Mind you,
we are still just academically imagining hypothetical situations,
coz it would be extremely illegal to act in such an inconsiderate
     CRACKING POWER! It's true for barcodes, for Telecom bills,
for Compuserve accounts, for Amexco cards, for banking cheques
(do you know what MICR is? Magnetic Ink Character Recognition...
the stylized little printing on the lower left of new cheques...
there is a whole cracking school working on it), for registration
numbers... you name it, they develope it, we crack it...
     Begin with barcodes: it's easy, nice and pretty useful! Live
in opulence, with the dignity and affluence that should always
distinguish real crackers. Besides... you should see the
assortment of 'Pomerols' in my "Cave-a-vin" :=)

     The (c) Instant access routines are a commercial protection
scheme used to "unlock" complete commercial applications that
have been encrypted on CD-
ROMs which are distributed (mostly) through reviews.
     This is an ideal cracking target: it's commercial software,
complete, uncrippled and of (relatively) prominent quality, that
you can get in tons for the price of a coke. Obviously this kind
of protection represents an ideal subject for our lessons. This
fairly intricate protection scheme has not yet been cracked by
anybody that I am aware of, anyway not publicly, therefore it's
an ideal candidate for a "strainer" to my university. I'll teach
you here how to crack it in three lessons, C.1, C.2 and C.3. I warn
you... it's a difficult cracking session, and this protection
represents quite an intellectual challenge. But if you are
seriously interested in our trade you will enjoy these lessons
more than anything else.
     This cracking is intended as an "assignment" for my +HCU
"cracking university": you'll find inside lessons C.1 and C.2 a
relatively deep "introduction" to Instant access cracking. This
will teach you a lot anyway, and spare you hours of useless
roaming around, bringing you straight to the cracking point. But
I'll release the third part of this session, with the complete
solution (lesson C.3) on the Web only in october 1996, not a day
before. All the students that would like to apply to the Higher
Cracking University, opening on the web 01/01/1997, should work
in July, August and September (three months is more than enough
time) on this assignment. They should crack completely the
instant access scheme and send me their solutions, with a good
documentation of their cracking sessions, before 30/09/1996
(WATCH IT! You can crack this scheme in -at least- three
different paths, be careful and choose the *best* one. WATCH IT!
Some of the informations) in lesson C.1 and C.2 are slightly incorrect:
check it!).
There are four possibilities:
1)   The candidate has not found the crack or his solution is
     not enough documented or not enough viable... the candidate
     is therefore not (yet) crack-able, he will not be admitted
     to the +HCU 1997 curses, better luck in 1998;
2)   The cracking solution proposed by the candidate is not as
     good as mine (you'll judge for yourself in october) but it
     works nevertheless... he'll be admitted at the 1997
3)   The cracking solution of the candidate is more or less
     equal to mine, he'll be admitted, personally monitored, and
     he'll get all the material he needs to crack on higher
4)   The cracking solution of the candidate is better than mine,
     he'll be admitted, get all the material he wishes and asked
     to teach us as well as study with us: "homines, dum docent,

[Cracking Instant access]
     The user that wants to "unlock" a software application
protected with (c) Instant Access must enter first of all a
REGISTRATION number string, which through a series of
mathematical manipulations gives birth to a special "product"
code. On the basis of this "product code" the user is asked to
phone the commercial protectors (and pay) in order to get a
special "unlock code" that will allow him to decrypt the relevant
     This kind of "passnumber" protection routines are widely
used for software unlocking, BBS access, server access, backdoor
opening and many other protection schemes. We have already seen
password cracks in different lessons of this tutorial (in
particular Lessons 3.1 and 3.2 for DOS and Lessons 8.1, 8.2 and
9.1 for WIN) albeit on a more simplistic scale: there it did
mostly not matter very much *HOW* you passed the protection: once
passed, you could have access to the application. This is not the
case with (c) Instant Access. Face it: it's a little boring, but
important that you learn how to defeat intricate protection
routines (you'll meet them often in the next years) and I believe
that the following example will give you a "feeling" for the
right cracking approach.
     In this case we must not only "crack" this protection scheme
but also study it thoroughly in order to achieve our blessed
aims. This is a very good exercise: reverse disassembling will
teach you a lot of little tricks that you'll be able to use in
your other future cracking sessions.
     Instant access (c) is a exceptionally widespread protection
scheme, and it should be relatively easy for you to gather some
encrypted software that has been protected with this method...
*DO IT QUICKLY!!* After the Web publishing of this lessons (I am
sending C.1 to 8 pages and 4 usenet groups on 25/06/1996) this
protection is obviously as dead as a Dodo. The "Accessors" guys
will have to conceive something smarter if they want to keep
selling "protections" to the lamer producers of "big" software.
     BTW, if you are reading this and are working for some
commercial "protection" company, consider the possibility to
double cross your masters! Deliver me anonymously all the future
projects you are working on! That will amuse me, speed up the
advent of a true altruistic society and earn you the respect of
the better part of humanity.
     As I said, many "huge" application are still protected with
this "Instant access" system. I have personally bought at least
7 or 8 "second hand" CD-ROMs packed full with Microsoft, Lotus,
Norton, Symantec, you name it, applications all "protected"
through this crap. The cost of this bunch of CD-ROMs was the
equivalent of a bottle of Dry Martini, maybe less. The same
software is sold, unlocked, to zombies and lusers for ludicrous
amounts of money.
     Never buy CD-ROMs magazines when they appear! Be cool! Buy
them two or three months after the publishing date! Buy
"remainders" or "second hand" CD-ROM magazines "at kilo price"...
Come to think of it, never buy *anything* when it appears or when
some (paid) advertiser tells you to... remember that "trends",
"vogues", "fashions" and "modes" are only different names for the
whips that drill and chain the dull-witted slaves of this
loathsome society: "clever crackers consider cool, crack cheap,
cheat customary culture" (a rhetorical figure: an "Alliteration".
To defend yourself learn rhetoric... it's a more powerful and
more useful weapon than Kung-fu).
     The "triple" password protection routine in (c) Instant
Access is very interesting from a cracker point of view. It's a
relatively complex scheme: I'll teach you to crack it in two
phases: First of all you must find the "allowed" registration
code, the one that "ignites" the "product code". We must crack
and understand this re_code first if we want to crack the rest.
     Just for the records, I am cracking here (c) Action Instant
access version 1.0 (CD-ROM found on a old copy of "Personal
Computer World" of August 1994, packed full with encrypted Lotus,
Symantec, Claris and Wordperfect applications. Just to be sure
I crosschecked my results with another CD-ROM which also has
applications protected with (c) Instant Access: Paragon
Publishing's PC OFFICE: the protection scheme remains the same).
I am focusing for this lesson on the cracking of the specific
protection for the encrypted Symantec's Norton Utilities v.8.0.
     Please refer to the previous lessons for the basic
techniques used in order to find the protection routine inside
our babe... for "low" cracking purposes you -basically- type a
number (in this case, where the input gets 10 numbers, we'll use
"1212-1212-12"), do your search inside the memory (s 30:0
lffffffff "your_string") and then set memory breakpoints on all
the relevant memory locations till winice pops (I know, I know,
buddies... there are more effective ways... but hold your mouth:
for now we'll keep them among us: let's make things a little
harder for the protectionists who read this... Besides: the old
approach works here flawlessly). After getting the Registration
window on screen the Winice standard procedure is:
 :task                        ; how
 :heap IABROWSE               ; where & what
 :hwnd IABROWSE               ; get the Winhandle
 :bpx [winhandle] WM_GETTEXT  ; pinpoint code
 :bpx GetProcAddress          ; in case of funny routines
 :dex 0 ds:dx                 ;          let's see their name
 :gdt                         ; sniff the selectors
 :s 30:0 lffffffff "Your_input_string" ; search in 4 giga data
 :bpr [all memory ranges for your string that are above 80000000]
and so on.  (continued in lesson C.2)

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

                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
                     HOW TO CRACK, by +ORC, A TUTORIAL


              LESSON C (2) - How to crack, Cracking as an art


                              [INSTANT ACCESS]


      cracking Instant Access (2) - strainer for the +HCU

[SEE LESSON C.1 for the first part of this cracking session]
     Here follow the relevant protection routines for the first
(The "Registration") number_code of Instant Access, with my
comments: you have to investigate a little the following code.
     Later, when you'll crack on your own, try to recognize the
many routines that fiddle with input BEFORE the relevant (real
protection) one. In this case, for instance, a routine checks the
correctness of the numbers of your input:

1B0F:2B00 C45E06    LES    BX,[BP+06]  ; set/reset pointer
1B0F:2B03 03DF      ADD    BX,DI
1B0F:2B05 268A07    MOV    AL,ES:[BX]  ; get number
1B0F:2B08 8846FD    MOV    [BP-03],AL  ; store
1B0F:2B0B 807EFD30  CMP    BYTE PTR [BP-03],30
1B0F:2B0F 7C06      JL     2B17        ; less than zero?
1B0F:2B11 807EFD39  CMP    BYTE PTR [BP-03],39
1B0F:2B15 7E05      JLE    2B1C        ; between 0 & 9?
1B0F:2B17 B80100    MOV    AX,0001     ; no, set flag=1
1B0F:2B1A EB02      JMP    2B1E        ; keep flag
1B0F:2B1C 33C0      XOR    AX,AX       ; flag=0
1B0F:2B1E 0BC0      OR     AX,AX       ; is it zero?
1B0F:2B20 7507      JNZ    2B29        ; flag NO jumps away
1B0F:2B22 8A46FD    MOV    AL,[BP-03]  ; Ok, get number
1B0F:2B25 8842CC    MOV    [BP+SI-34],AL ; Ok, store number
1B0F:2B28 46        INC    SI          ; inc storespace
1B0F:2B29 47        INC    DI          ; inc counter
1B0F:2B2A C45E06    LES    BX,[BP+06]  ; reset pointer
1B0F:2B2D 03DF      ADD    BX,DI       ; point next number
1B0F:2B2F 26803F00  CMP    BYTE PTR ES:[BX],00 ; input end?
1B0F:2B33 75CB      JNZ    2B00        ; no:loop next num

     You now obviously understand that the "real" string is
stored inside memory location [BP+SI-34]... set a memory
breakpoint on this area to get the next block of code that
fiddles with the transformed input. Notice how this routine
"normalizes" the input, strips the "-" off and puts the 10
numbers together:
user input:  1  2  1  2  1  2  1  2  1  2 End
  1E7F:92E2 31 32 31 32 31 32 31 32 31 32 00 45 AF 1F 70 9B
 Stack ptr:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
     Let's now look at the "real" protection routine: the one
that checks these numbers and throw you out if they are not
"sound". Please pay attention to the following block of code:

:4B79 8CD0       MOV    AX,SS ; we'll work inside the stack...
:4B7B 90         NOP
:4B7C 45         INC    BP
:4B7D 55         PUSH   BP    ; save real BP
:4B7E 8BEC       MOV    BP,SP ; BP = stackpointer
:4B80 1E         PUSH   DS    ; save real Datasegment
:4B81 8ED8       MOV    DS,AX ; Datasegment = stacksegment
:4B83 83EC04     SUB    SP,+04
:4B86 C45E06     LES    BX,[BP+06] ; BX points input_start
:4B89 268A07     MOV    AL,ES:[BX] ; load first number
:4B8C 98         CBW               ; care only for low
:4B8D C45E06     LES    BX,[BP+06] ; reset pointer
:4B90 50         PUSH   AX         ; save 1st number
:4B91 268A4701   MOV    AL,ES:[BX+01] ; load 2nd number
:4B95 98         CBW               ; only low
:4B96 8BD0       MOV    DX,AX      ; 2nd number in DX
:4B98 58         POP    AX         ; get 1st number
:4B99 03C2       ADD    AX,DX      ; sum with second
:4B9B C45E06     LES    BX,[BP+06] ; reset pointer
:4B9E 50         PUSH   AX         ; save sum
:4B9F 268A4707   MOV    AL,ES:[BX+07] ; load 8th number
:4BA3 98         CBW               ; only low
:4BA4 8BD0       MOV    DX,AX      ; 8th number in DX
:4BA6 58         POP    AX         ; old sum is back
:4BA7 03C2       ADD    AX,DX      ; sum 1+2+8
:4BA9 C45E06     LES    BX,[BP+06] ; reset pointer
:4BAC 50         PUSH   AX         ; save sum
:4BAD 268A4703   MOV    AL,ES:[BX+03] ; load 4rd number
:4BB1 98         CBW               ; only low
:4BB2 8BD0       MOV    DX,AX      ; #4 in DX
:4BB4 58         POP    AX         ; sum is back
:4BB5 03C2       ADD    AX,DX      ; sum 1+2+8+4
:4BB7 C45E06     LES    BX,[BP+06] ; reset pointer
:4BBA 50         PUSH   AX         ; save sum
:4BBB 268A4704   MOV    AL,ES:[BX+04] ; load 5th number
:4BBF 98         CBW               ; only low
:4BC0 8BD0       MOV    DX,AX      ; #5 in DX
:4BC2 58         POP    AX         ; sum is back
:4BC3 03C2       ADD    AX,DX      ; 1+2+8+4+5
:4BC5 C45E06     LES    BX,[BP+06] ; reset pointer
:4BC8 50         PUSH   AX         ; save sum
:4BC9 268A4705   MOV    AL,ES:[BX+05] ; load 6th number
:4BCD 98         CBW               ; only low
:4BCE 8BD0       MOV    DX,AX      ; #6 in DX
:4BD0 58         POP    AX         ; sum is back
:4BD1 03C2       ADD    AX,DX      ; 1+2+8+4+5+6
:4BD3 C45E06     LES    BX,[BP+06] ; reset pointer
:4BD6 50         PUSH   AX         ; save sum
:4BD7 268A4706   MOV    AL,ES:[BX+06] ; load 7th number
:4BDB 98         CBW               ; only low
:4BDC 8BD0       MOV    DX,AX      ; #7 in DX
:4BDE 58         POP    AX         ; sum is back
:4BDF 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7
:4BE1 C45E06     LES    BX,[BP+06] ; reset pointer
:4BE4 50         PUSH   AX         ; save sum
:4BE5 268A4708   MOV    AL,ES:[BX+08] ; load 9th number
:4BE9 98         CBW               ; only low
:4BEA 8BD0       MOV    DX,AX      ; #9 in DX
:4BEC 58         POP    AX         ; sum is back
:4BED 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7+9
:4BEF C45E06     LES    BX,[BP+06] ; reset pointer
:4BF2 50         PUSH   AX         ; save sum
:4BF3 268A4709   MOV    AL,ES:[BX+09] ; load 10th #
:4BF7 98         CBW               ; only low
:4BF8 8BD0       MOV    DX,AX      ; #10 in DX
:4BFA 58         POP    AX         ; sum is back
:4BFB 03C2       ADD    AX,DX      ; 1+2+8+4+5+6+7+9+10
:4BFD 0550FE     ADD    AX,FE50    ; clean sum to 0-51
:4C00 BB0A00     MOV    BX,000A    ; BX holds 10
:4C03 99         CWD               ; only AL
:4C04 F7FB       IDIV   BX         ; remainder in DX
:4C06 C45E06     LES    BX,[BP+06] ; reset pointer
:4C09 268A4702   MOV    AL,ES:[BX+02] ; load now # 3
:4C0D 98         CBW               ; only low
:4C0E 05D0FF     ADD    AX,FFD0    ; clean # 3 to 0-9
:4C11 3BD0       CMP    DX,AX  ; remainder = pampered #3?
:4C13 7407       JZ     4C1C       ; yes, go on good guy
:4C15 33D2       XOR    DX,DX  ; no! beggar off! Zero DX
:4C17 33C0       XOR    AX,AX  ;     and FLAG_AX = FALSE
:4C19 E91701     JMP    4D33       ; go to EXIT
:4C1C C45E06     LES    BX,[BP+06] ; reset pointer
:4C1F 268A4701   MOV    AL,ES:[BX+01] ; now load #2 anew
:4C23 98         CBW               ; only low
:4C24 05D7FF     ADD    AX,FFD7    ; pamper adding +3
:4C27 A38D5E     MOV    [5E8D],AX  ; save SEC_+3
:4C2A 3D0900     CMP    AX,0009    ; was it < 9? (no A-F)
:4C2D 7E05       JLE    4C34       ; ok, no 0xletter
:4C2F 832E8D5E0A SUB    WORD PTR [5E8D],+0A ; 0-5 if A-F
:4C34 C45E06     LES    BX,[BP+06] ; reset pointer
:4C37 268A07     MOV    AL,ES:[BX] ; load 1st input number
:4C3A 98         CBW               ; only low
:4C3B 05C9FF     ADD    AX,FFC9    ; pamper adding +7
:4C3E A38F5E     MOV    [5E8F],AX  ; save it in FIR_+7
:4C41 0BC0       OR     AX,AX      ; if #1 > 7
:4C43 7D05       JGE    4C4A       ; no need to add 0xA
:4C45 83068F5E0A ADD    WORD PTR [5E8F],+0A ; FIR_+7 + 0xA
:4C4A C45E0E     LES    BX,[BP+0E] ; Set pointer to E
:4C4D 26C747020000 MOV  WORD PTR ES:[BX+02],0000 ; 0 flag
:4C53 26C7070000   MOV  WORD PTR ES:[BX],0000    ; 0 flag
:4C58 C706975E0900 MOV  WORD PTR [5E97],0009     ; counter=9
:4C5E E99500     JMP    4CF6       ; Jmp check_counter
:4C61 C45E06     LES    BX,[BP+06] ; reset pointer
:4C64 031E975E   ADD    BX,[5E97]  ; add running counter
:4C68 268A07     MOV    AL,ES:[BX] ; load # counter+1
:4C6B 98         CBW               ; only low
:4C6C 50         PUSH   AX         ; save 10th number
:4C6D A18D5E     MOV    AX,[5E8D]  ; ld SEC_+3 down_slider
:4C70 BA0A00     MOV    DX,000A    ; BX holds 0xA
:4C73 F7EA       IMUL   DX         ; SEC_+3 * 0xA
:4C75 03068F5E   ADD    AX,[5E8F]  ; plus FIR_+7 up_slider
:4C79 BAA71E     MOV    DX,1EA7    ; fixed segment
:4C7C 8BD8       MOV    BX,AX ; BX = Lkup_val=(SEC_+3*10+FIR_+7)
:4C7E 8EC2       MOV    ES,DX      ; ES = 1EA7
:4C80 268A870000 MOV    AL,ES:[BX+0000] ; ld 1EA7:[Lkup_val]
:4C85 98         CBW               ; only low: KEY_PAR
:4C86 8BD0       MOV    DX,AX      ; save KEY_PAR in DX
:4C88 58         POP    AX         ; repops 10th number
:4C89 03C2       ADD    AX,DX      ; RE_SULT=KEY_PAR+#10
:4C8B 05D0FF     ADD    AX,FFD0    ; polish RE_SULT
:4C8E 99         CWD               ; only low: RE_SULT
:4C8F 8956FC     MOV    [BP-04],DX ; save here KEY_PAR [9548]
:4C92 8946FA     MOV    [BP-06],AX ; save here RE_SULT [9546]
:4C95 0BD2       OR     DX,DX      ; KEY_PAR < 0?
:4C97 7C0F       JL     4CA8       ; yes: KEY_PAR < 0
:4C99 7F05       JG     4CA0       ; no: KEY_PAR > 0
:4C9B 3D0900     CMP    AX,0009    ; KEY_PAR = 0
:4C9E 7608       JBE    4CA8 ; no pampering if RE_SULT < 9
:4CA0 836EFA0A   SUB    WORD PTR [BP-06],+0A ; else pamper
:4CA4 835EFC00   SBB    WORD PTR [BP-04],+00 ; and SBB [9548]
:4CA8 C45E0E     LES    BX,[BP+0E] ; reset pointer to E
:4CAB 268B4F02   MOV    CX,ES:[BX+02] ; charge CX [958C]
:4CAF 268B1F     MOV    BX,ES:[BX] ; charge BX slider [958A]
:4CB2 33D2       XOR    DX,DX      ; clear DX to zero
:4CB4 B80A00     MOV    AX,000A    ; 10 in AX
:4CB7 9A930D2720 CALL   2027:0D93  ; call following RO_routine

  This is the only routine called from our protection, inside the
loop (therefore 8 times), disassembly from WCB. Examining this
code please remember that we entered here with following
configuration: DX=0, AX=0xA, CX=[958C] and BX=[958A]...
 1.0D93  56      push   si     ; save si
 1.0D94  96      xchg   ax, si ; ax=si, si=0xA
 1.0D95  92      xchg   ax, dx ; dx=0xA ax=dx
 1.0D96  85C0    test   ax, ax ; TEST this zero
 1.0D98  7402    je     0D9C   ; zero only 1st time
 1.0D9A  F7E3    mul    bx     ; BX slider! 0/9/5E/3B2...
 1.0D9C >E305    jcxz   0DA3   ; cx=0? don't multiply!
 1.0D9E  91      xchg   ax, cx ; cx !=0? cx = ax & ax = cx
 1.0D9F  F7E6    mul    si     ;     ax*0xA in ax
 1.0DA1  03C1    add    ax, cx ; ax=  ax*0xA+cx = M_ULT
 1.0DA3 >96      xchg   ax, si ; ax=0xA; si evtl. holds M_ULT
 1.0DA4  F7E3    mul    bx     ; ax= bx*0xA
 1.0DA6  03D6    add    dx, si ; dx= dx_add
 1.0DA8  5E      pop    si     ; restore si
 1.0DA9  CB      retf          ; back to caller with two
                                        parameters: DX and AX
:4CBC C45E0E     LES    BX,[BP+0E] ; reset pointer
:4CBF 26895702   MOV    ES:[BX+02],DX ; save R_DX par  [958C]
:4CC3 268907     MOV    ES:[BX],AX ; save R_AX par     [958A]
:4CC6 0346FA     ADD    AX,[BP-06] ; add to AX RE_SULT [9546]
:4CC9 1356FC     ADC    DX,[BP-04] ; add to DX KEY_PAR [9548]
:4CCC C45E0E     LES    BX,[BP+0E] ; reset pointer
:4CCF 26895702   MOV    ES:[BX+02],DX ; save R_DX+KEY_PAR [958C]
:4CD3 268907     MOV    ES:[BX],AX ; save R_AX+RE_SULT    [958A]
:4CD6 FF0E8D5E   DEC    WORD PTR [5E8D] ; down_slide SEC_+3
:4CDA 7D05       JGE    4CE1       ; no need to add
:4CDC 83068D5E0A ADD    WORD PTR [5E8D],+0A  ; pamper adding 10
:4CE1 FF068F5E   INC    WORD PTR [5E8F] ; up_slide FIR_+7
:4CE5 A18F5E     MOV    AX,[5E8F]  ; save upslided FIR_+7 in AX
:4CE8 3D0900     CMP    AX,0009    ; is it over 9?
:4CEB 7E05       JLE    4CF2       ; no, go on
:4CED 832E8F5E0A SUB    WORD PTR [5E8F],+0A ; yes, pamper -10
:4CF2 FF0E975E   DEC    WORD PTR [5E97]  ; decrease loop counter
:4CF6 833E975E03 CMP    WORD PTR [5E97],+03  ; counter = 3?
:4CFB 7C03       JL     4D00       ; finish if counter under 3
:4CFD E961FF     JMP    4C61       ; not yet, loop_next_count
:4D00 C45E06     LES    BX,[BP+06] ; reset pointer to input
:4D03 268A4701   MOV    AL,ES:[BX+01] ; load 2nd number (2)
:4D07 98         CBW               ; only low
:4D08 05D0FF     ADD    AX,FFD0    ; clean it
:4D0B BA0A00     MOV    DX,000A    ; DX = 10
:4D0E F7EA       IMUL   DX         ; AX = SEC_*10 = 14
:4D10 C45E06     LES    BX,[BP+06] ; reset pointer
:4D13 50         PUSH   AX         ; save SEC_*10
:4D14 268A07     MOV    AL,ES:[BX] ; load 1st number (1)
:4D17 98         CBW               ; only low
:4D18 8BD0       MOV    DX,AX      ; save in DX
:4D1A 58         POP    AX         ; get SEC_*10
:4D1B 03C2       ADD    AX,DX      ; sum SEC_*10+1st number
:4D1D 05D0FF     ADD    AX,FFD0    ; clean it
:4D20 99         CWD               ; only low
:4D21 C45E0A     LES    BX,[BP+0A] ; get pointer    to   [9582]
:4D24 26895702   MOV    ES:[BX+02],DX ; save 1st (1) in  [9584]
:4D28 268907     MOV    ES:[BX],AX ; save FINAL_SUM (15) [9582]
:4D2B 33D2       XOR    DX,DX      ; DX = 0
:4D2D B80100     MOV    AX,0001    ; FLAG TRUE !
:4D30 E9E6FE     JMP    4C19       ; OK, you_are_a_nice_guy
:4D33 59         POP    CX         ; pop everything and
:4D34 59         POP    CX         ;  return with flag
:4D35 1F         POP    DS         ;  AX=TRUE if RegNum OK
:4D36 5D         POP    BP         ;  with 1st # in     [9584]
:4D37 4D         DEC    BP         ;  with FINAL_SUM in [9582]
:4D38 CB         RETF

  Let's translate the preceding code: first of all the pointers:
At line :4B86 we have the first of a long list of stack ptrs:
                        LES BX,[BP+06]
 This stack pointer points to the beginning of the input string,
which, once polished from the "-", has now a length of 10 bytes,
concluded by a 00 fence. At the beginning, before the main loop,
9 out of our 10 numbers are added, all but the third one.
  Notice that protection has jumped # 3 (and added # 8 out of the
line). The rest is straightforward. Now, at line :4BFD we have
our first "cleaning" instruction. You see: the numbers are
hexadecimal represented by the codes 0x30 to 0x39. If you add
FE50 to the minimum sum you can get adding 9 numbers (0x30*9 =
0x160) You get 0. The maximum you could have adding 9 numbers,
on the contrary is (0x39*9=0x201), which, added to FE50 gives
0x51. So we'll have a "magic" number between 0x0 and 0x51 instead
of a number between 0x160 and 0x201. Protection pampers this
result, and retains only the last ciffer: 0-9.  Then protection
divides this number through 0xA, and what happens? DX get's the
  If we sum the hexcodes of our (1212-1212-12) we get 0x1BE (we
sum only 9 out of then numbers: the third "1" -i.e. "31"- does
not comes into our count); 0x1BE, cleaned and pampered gives E.
Therefore (0xE/0xA = 1) We get 1 with a remainder of 4.
  You may observe that of all possible answers, only sums
finishing with A, B, C, D, E or F give 1 (and rem=0,1,2,3,4 or
5). Sums finishing 0 1 2 3 4 5 6 7 8 or 9 give 0 as result and
themselves as reminder. The chance of getting a 0,1,2,3 or 4 are
therefore bigger as the chance of getting a 5, 6, 7, 8 or 9. We
are just observing... we do not know yet if this should play a
role or not.
  Now this remainder is compared at :4C11 with the third number
polished from 0x30-0x39 to 0-9. This is the only protection check
for the registration number input: If your third number does not
match with the remainder of the sum of all the 9 others numbers
of your input you are immediately thrown out with FLAG AX=FALSE
(i.e. zero).
 To crack the protection you now have to MODIFY your input string
accordingly. Our new input string will from now on be "1242-1212-
12": we have changed our third number (originally a "2") to a "4"
to get through this first strainer in the correct way. Only now
protection starts its mathematical part (We do not know yet why
it does it... in order to seed the random product number? To
provide a check for the registration number you'll input at the
end? We'll see).
-    Protection saves the second number of your input (cleaned
     with FFD7) in SEC_+3 [5E8D], pampering it if it is bigger
     than 9 (i.e. if it is 0xA-0xF). Here you'll have therefore
     following correspondence: 0=7 1=8 2=9 3=0 4=1 5=2 6=3 7=4
     8=5 9=6. The second number of your input has got added +3.
     This is value SEC_+3. In (lengthy) C it would look like
       If (RegString(2)is lower than  7) RegString(2) = RegString(2)+3
       Else Regstring(2) = ((RegString(2)-10)+3)
-    Protection saves your first number in FIR_+7 [5E8F] with a
     different cleaning parameter (FFC9). The next pampering
     adds 0xA if it was not 7/8/9 therefore you have here
     following correspondence 7=0 8=1 9=2 0=3 1=4 2=5 3=6 4=7
     5=8 6=9). This is value FIR_+7. In (lengthy) C it would
     look like this:
       If (RegString(1) is lower than 3) RegString(1) = RegString(1)+7
       Else Regstring(1) = ((RegString(1)-10)+7)
  So protection has "transformed" and stored in [5E8D] and [5E8F]
the two numbers 1 and 2. In our RegString: 1242-1212-12 the first
two numbers "12" are now stored as "94". These will be used as
"slider" parameters inside the main loop, as you will see.
 Only now does protection begin its main loop, starting from the
LAST number, because the counter has been set to 9 (i.e. the
tenth number of RegString). The loop, as you'll see, handles only
the numbers from 10 to 3: it's an 8-times loop that ends without
handling the first and second number. What happens in this
loop?... Well, quite a lot: Protection begins the loop loading
the number (counter+1) from the RegString. Protection then loads
the SEC_+3 down_slider parameter (which began its life as second
number "transformed"), multiplies it with 0xA and then adds the
up_slider parameter FIR_+7 (at the beginning it was the first
number transformed).
     This sum is used as "lookup pointer" to find a parameter
inside a table of parameters in memory, which are all numbers
between 0 and 9. Let's call this value Lkup_val.
Protection looks for data in 1EA7:[Lkup_val]. In our case (we
entered 1242-1212-12, therefore the first SEC_+3 value is 9 and
the first FIR_+7 value is 4): [Lkup_val] = 9*0xA+4; 0x5A+4 =
0x5E. At line :4C80 therefore AL would load the byte at 1EA7:005E
(let's call it KEY_PAR), which now would be ADDED to the #
counter+1 of this loop. In our case KEY_PAR at 1EA7:005E it's a
"7" and is added to the pampered 0x32=2, giving 9.
     Let's establish first of all which KEY_PAR can possibly get
fetched: the maximum is 0x63 and the minimum is 0x0. The possible
KEY_PARs do therefore dwell in memory between 1EA7: and
1EA7:0063. Let's have a look at the relative table in memory,
where these KEY_PARs are stored ("our" first 0x5Eth byte is
1EA7:0000 01 03 03 01 09 02 03 00-09 00 04 03 08 07 04 04
1EA7:0010 05 02 09 00 02 04 01 05-06 06 03 02 00 08 05 06
1EA7:0020 08 09 05 00 04 06 07 07-02 00 08 00 06 02 04 07
1EA7:0030 04 04 09 05 09 06 00 06-08 07 00 03 05 09 00 08
1EA7:0040 03 07 07 06 08 09 01 05-07 04 06 01 04 02 07 01
1EA7:0050 03 01 08 01 05 03 03 01-02 08 02 01 06 05 07 02
1EA7:0060 05 09 09 08 02 09 03 00-00 04 05 01 01 03 08 06
1EA7:0070 01 01 09 00 02 05 05 05-01 07 01 05 08 07 01 09
1EA7:0080 08 07 07 04 04 08 03 00-06 01 09 08 08 04 09 09
1EA7:0090 00 07 05 02 03 01 03 08-06 05 07 06 03 07 06 07
1EA7:00A0 04 02 02 05 02 04 06 02-06 09 09 01 05 02 03 04
1EA7:00B0 04 00 03 05 00 03 08 07-06 04 08 08 02 00 03 06
1EA7:00C0 09 00 00 06 09 04 07 02-00 01 01 01 01 00 01 FF
1EA7:00D0 00 FF FF FF FF 00 FF 01-00 00 00 00 00 00 00 00

     An interesting table, where all the correspondences are
between 0 and 9... are we getting some "secret" number here? But,
hey, look there... funny, isn't it? Instead of only 0-0x63 bytes
we have roughly the DOUBLE here: 0-0xC8 bytes (the 01 sequence
starting at CA "feels" like a fence). We'll see later how
important this is. At the moment you should only "perceive" that
something must be going on with a table that's two time what she
should be.
     As I said the result of KEY_PAR + input number is polished
(with a FFDO) and pampered (subtracting, if necessary, 0xA).
Therefore the result will be the (counter+1) input number +
KEY_PAR (let's call it RE_SULT], in our case, (at the beginning
of the loop) a 9. Now (DX=0 because of the CWD instruction) DX
will be saved in [9548] and RE_SULT in [9546].
 Now Protection prepares for the RO_routine: resets its pointer
and charges CX and BX from [958C] and from [958A] respectively,
charges AX with 0xA and sets DX to zero.
 The routine performs various operations on AX and DX and saves
the results in the above mentioned locations [958A] and [958C].
 Now KEY_PAR and RE_SULT are added respectively to the DX and AX
value we got back from the RO_routine call, and saved once more
in the last two locations: AX+RE_SULT in [958A] and DX+KEY_PAR
in [958C]
 Now the value in SEC_+3 is diminished by 1 (if it was 9 it's now
8, if it was zero it will be pampered to 9). It's a "slider"
parameter (in this case a down_slider), typically used in
relatively complicated protections to give a "random" impression
to the casual observer. The value in FIR_+7, on the contrary, is
augmented by one, from 4 to 5... up_sliding also.
     Protection now handles the next number of your input for the
loop. In our case this loop uses following protection
configuration with our "sliding" parameters:
 Input #  pamp_2nd   pamp_1st   Lookup value  KEY_PAR  # RE_SULT
# 10 = 2, SEC_+3= 9, FIR_+7= 4, Lkup_val = 0x5E, KEY=7 +2 = 9
# 9  = 1, SEC_+3= 8, FIR_+7= 5, Lkup_val = 0x55, KEY=3 +1 = 4
# 8  = 2, SEC_+3= 7, FIR_+7= 6, Lkup_val = 0x4C, KEY=4 +2 = 6
# 7  = 1, SEC_+3= 6, FIR_+7= 7, Lkup_val = 0x43, KEY=7 +1 = 7
# 6  = 2, SEC_+3= 5, FIR_+7= 8, Lkup_val = 0x3A, KEY=0 +2 = 2
# 5  = 1, SEC_+3= 4, FIR_+7= 9, Lkup_val = 0x31, KEY=4 +1 = 5
# 4  = 2, SEC_+3= 3, FIR_+7= 0, Lkup_val = 0x1E, KEY=5 +2 = 7
# 3  = 4, SEC_+3= 2, FIR_+7= 1, Lkup_val = 0x15, KEY=2 +4 = 5
Notice how our "regular" input 21212124 has given an "irregular"
     You may legitimately ask yourself what should all this mean:
what are these RE_SULTs used for? Well they are used to slide
another parameter: this one inside the called routine... this is
what happens to AX and DX inside the routine, and the lines after
the called routine:
:4CBF 26895702   MOV    ES:[BX+02],DX ; save R_DX par  [958C]
:4CC3 268907     MOV    ES:[BX],AX ; save R_AX par     [958A]
:4CC6 0346FA     ADD    AX,[BP-06] ; add to AX RE_SULT [9546]
:4CC9 1356FC     ADC    DX,[BP-04] ; add to DX KEY_PAR [9548]
:4CCC C45E0E     LES    BX,[BP+0E] ; reset pointer to E
:4CCF 26895702   MOV    ES:[BX+02],DX ; save R_DX+KEY_PAR [958C]
:4CD3 268907     MOV    ES:[BX],AX ; save R_AX+RE_SULT    [958A]

            :4CC6     :4CC9  :4CCF Odd_DX  :4CD3 slider_sum
  RE_SULT   [958A]    [958C]   [958C]        [958A]
     0         0        0        0            0
     9         5A       0        0            9
     4         3AC      0        0            5E
     6         24F4     0        0            3B2
     7         71CE     1        1            24FB
     2         7220     4        E            71D0
     5         7572     4        90           7225

Now the loops ends, having handled the input numbers from tenth
to third. Protection loads the second number and multiplies it
by 10 (let's call this result SEC_*10), in our case 2*0xA=14.
Protection loads the first number and adds it to the
multiplication, in our case 1+0x14=0x15 (FINAL_SUM].
Now everything will be added to FFDO to "clean" it.
Pointer will now be set to the end of the input number.
DX, zeroed by CDW, will be saved as parameter in [9584] and the
cleaned and pampered sum will be saved in [9582].
FLAG is set to true and this routine is finished! No parameter
are passed and the only interesting thing is what actually
happens in the locations [9582], [9584], [958A] and [958C], i.e.:
FINAL_SUM, 0, slider_sum, odd_dx.
     In the next lesson we'll crack everything, but I'll give you
already some hints here, in case you would like to go ahead on
your own: we'll see how the scheme used for the third (the
registration) number show analogies and differences with the
scheme we have studied (and cracked) here for the first number.
Our 3434-3434-3434-3434-34 input string for the registration
number will be transformed in the magic string
141593384841547431, but this will not work because the "magic"
12th number: "1" will not correspond to the remainder calculated
inside this check through the previous locations of the other
     Here the things are more complicated because every little
change in your input string transforms COMPLETELY the "magic"
string... therefore in order to pass the strainer you'll have to
change 3434-3434-3434-3434-34 in (for instance) 7434-3434-3434-
3434-96. The "magic" string 219702960974498056 that this
registration input gives will go through the protection strainer.
Only then we'll be able to step over and finally crack the whole
protection... it's a pretty complicated one as I said. Now crack
it pupils... you have three months time. From this crack depends
your admission to the Uni, there will be no other admission text
till summer 1997 (it's a hell of work to prepare this crap)...
work well.

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) some tricks of the trade I may not
know but YOU've discovered. I'll probably know most of 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

                                E-mail +ORC

                        +ORC an526164@anon.penet.fi
howtocrk.txt 113x9216 Font