How2crk Fontsize5 #1

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 66

HOW TO CRACK, A TUTORIAL - LESSON 1

by +ORC (the old red cracker)

-> How to crack, an approach LESSON 1


How to crack, tools and tricks of the trade LESSON 2
How to crack, hands on, paper protections LESSON 3 (1-2)
How to crack, hands on, time limits LESSON 4
How to crack, hands on, disk-CDrom access LESSON 5
How to crack, funny tricks LESSON 6 (1-2)
How to crack, intuition and luck LESSON 7
How to crack windows, an approach LESSON 8
How to crack windows, tools of the trade LESSON 9
How to crack, advanced cracking LESSON A (1-2)
How to crack, zen-cracking LESSON B
How to crack, cracking as an art LESSON C
How to crack INDEX

LESSON 1 - HOW TO CRACK, 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
stay).

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)or peppered with "junk" instructions (fairly easy
to crack)
7. None of the above (sometimes difficult to crack)

WHERE TO GET THE STUFF


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, Delphi or Visual C++. (Don't
worry... I'll nevertheless teach you how to crack -and quickly- those huge applications too).

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 IT AND DISABLE IT!
2. They may fetch the time_clock interrupts in your machine: INTERCEPT THEM YOURSELF!
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 vectors)
- 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)

1
- 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, i.e.:
ren POOLDEMO.EXE POOLDEMO.DED
symdeb POOLDEMO.DED
-s (cs+0000):0 Lffff C7 06 F1 01 3C <- this string corresponds to the refill line).
cs:3E85 <- symdeb gives you two locations as answer
cs:3EEA
-e cs:3E85+4 EE <- refill changed from 3C to EE
-w
ren POOLDEMO.DED POOLDEMO.EXE

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 timer_clicker!

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 now?

A rather drastic measure would be, in such circumstances, To 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
ret
RETURN
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 register.

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
ret
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!

2
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

BINGO!: FOUND!

Now let's quickly crack it:


------------------------------------------------
CRACKING POOLDEMO.EXE (by +ORC, January 1996)

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 welcomed.

+ORC an526164@anon.penet.fi

LESSON 2- How to crack, tools and tricks of the trade

LOST IN THE DARK CODEWOODS


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 important.

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.

YOUR DEBUGGER: YOUR FAVOURITE TOOL


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 possibility.

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.

3
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 time.

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 luck.

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).

ALL SYSTEM CALLS IN ONE LOCATION


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 case.

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.

ASCIIZ IN CODE
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 simplified.

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 console.

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.

CODE AND DATA


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.

HOOKED VECTORS
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" utility.

APPLYING A MEMORY WRITE BREAKPOINT TO A SPECIFIC VECTOR OR 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.

LITTLE TRICKS OF THE TRADE:


* 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

4
19AC3-16CC0 = 2E03 (offset)
address for 19AC3 in segment 16CC = 16CC:2E03

TOOLS OF THE TRADE


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.

[MEMSCAN.EXE]
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.

[TRACKMEM.COM]
A very good tool by James W.Birdsall, tracks memory usage of programs (EMS, XMS, conventional).

[SCANCODE.COM]
"THE" scancode lister, by the code_masters from clockwork software. The must utility for crackers that do not learn all scancodes by heart.

[MAP.EXE]
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).

[FILEDUMP.COM] [HEXDUMP.COM] [TDUMP.EXE] [DUMP.EXE]


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.

[SPRAY.COM]
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 ">").

[VEXE.EXE]
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 useful.

[SNOOP UTILITIES --> KGB.EXE INTMON.EXE INTRSPY.EXE etc...]


[TRACE UTILITIES --> TRACE.EXE STEPDOS.EXE etc...]
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 :=)

[SOURCERING UTILITIES]
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).

[HEXEDITORS]
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.

[DEBUGGER]
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 :=)

HOW TO CRACK, ZEN-CRACKING


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


:compare_loop
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.


------------------------------------------------

5
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?

WHY WE CRACK
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 welcomed.

+ORC an526164@anon.penet.fi

LESSON 3 (1)
HOW TO CRACK, HANDS ON - Password protected programs

SOME PROBLEMS WITH INTEL's INT

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.

A LITTLE BASIC ASSEMBLER

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 that:

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


2) The destination of data is described by the combination ES:DI
3) As part of the operation, the SI and/or DI register(s) is(are) incremented or decremented so the operation can be repeated.

------------------------- 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

CRACKING PASSWORD PROTECTED PROGRAMS

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.

6
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
(nothing)
- s (cs+1000):0 Lffff 74 0D 1E B8 C2 3F
(nothing)
- 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

-----------------------------------------------------

7
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)

pgsg:C6F9
pgsg:E5CA
pgsg:E63E
pgsg:EAB0

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
password)
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 lowercased.

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
ADFFFF SBB AX,FFFF
:preserved_AX=0000
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:

------------------------------------------------
CRACKING LIGHTSPEED.EXE (by +ORC, January 1996)

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

8
Where xxxx represents the second of the memory segments where the program dwells. Now do the following (a very common cracking procedure):

* 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 CODE.
* 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
our_memory_area

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]

:funny_procedure
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
:compare_byte
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 explained):

- 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 welcomed.

+ORC an526164@anon.penet.fi

LESSON 3 (2) - HOW TO CRACK, HANDS ON (3.2) Passwords, second


part, and something about passletters

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:

PASSWORDS AS PERMISSION TO ACCESS

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.

9
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 :=)

PASSWORDS AS REGISTRATION
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 entry.

PASSWORDS AS COPY PROTECTIONS


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.

DONGLE PASSWORDS
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 themselves):

* 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 manipulations
* generating file PASSWORD.DAT with password, to be inserted inside a different file than the one containing the calling routine

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.

[PASSWORD ACCESS INSIDE THE SETUP]


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)
tricks

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!

"SOMETHING FISHY UNDER COVERS"


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:

10
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.

[POPULOUS.EXE]
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!.

[MAP.EXE]
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]

11
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 welcomed.

+ORC an526164@anon.penet.fi

LESSON 4 - HOW TO CRACK, HANDS ON, Time Limits

For 'time protections' we intend a serie of protection schemes which are aimed to restrict the use of an application

ONE
- to a predetermined amount of days, say 30 days, starting with the first day of installation... 'CINDERELLA' TIME PROTECTIONS

TWO
- to a predetermined period of time (ending at a specific fixed date) independently from the start date... 'BEST_BEFORE' TIME PROTECTIONS

THREE
- to a predetermined amount of minutes and/or seconds each time you fire them... 'COUNTDOWN' TIME PROTECTIONS

FOUR
- to a predetermined amount of 'times' you use them, say 30 times. Strictly speaking these protections are not 'time' dependent, but since their schemas are more or less on the same lines as in the
cases ONE, TWO and THREE, we will examine them inside this part of my tutorial. Let's call them 'QUIVER' protections since, as with a quiver, you only have a predetermined amount of 'arrows' to shoot (and if
you never went fishing with bow and arrows, on a mountain river, you do not know what's real zen... the fish springs out suddendly, but you 'knew' it, and your fingers had already reacted... a lot of broken arrows
on the rocks, though :=)

As first example I have chosen a double protected application: it has a time protection (of the 'Cinderella' type, limited to 90 days) as well as a 'quiver' protection scheme, which is the other -not time
bounded- current variante of the shareware protections... i.e. you should use this program only 25 times before a protection lock.

It's a relatively 'old' windows protection (april 1995). I found the program on a cheap cd-rom, which I bought (in a bunch with 9 others) a month ago: 6000 megabytes of bad protected software for the price
of a good glass of wine! PCPLUS SUPER CD nø13, originally edited in July 1995. I believe it should be pretty easy to find it or to find this program on the Web if you do not already have it inside your collection of
cheap CD-ROM. Another advantage of this program, from our perspective, is that the whole PCFILE.EXE represents de facto the protection scheme itself... not excessively overbloated: only 8912 bytes, when the
'real' application works inside the (huge and overbloated) pcf.dll, which will be called only if the user passes the protection. You can easily print the WHOLE disassembled listing of PCFILE.EXE (46 Wordperfect
pages), that you'll quickly get through wcb (for instance). For once you'll have a COMPLETE and COMPLICATED protection scheme under your eyes.

Basically we'll study here the 'beginning' of more complex time protection schemes, the ones we'll crack with our later lessons. Some protection elements are here still 'na‹v', but the protectionists have -at
least- worked a little against easy cracks... which makes this protection even more interesting for us :=)

This program shows even a 'nasty' behaviour: should you use it after the locking snapped, it will obliterate the whole (main) pcf.dll from your harddisk, without any warning. This obviously does not mean
anything at all here, but it's the secret to more advanced (and nastier) protection schemes, so you better have a look at it too. Nice, enough let's start now.

[PCFILE] (aka the 'dll counter' method)


PCFILE, version 8, (PCFILE.EXE, 8912 bytes, 17 apr 1995, Atlantic Coast software) is a database program which will be disabled after having 90 days from its first use or after having used it 25 times,
whichever comes first.

We'll begin as usual: just use your wordprocessor search capacities to search inside the whole directory (and subdirectories) of PCFILE for words like 'demo' 'order' 'contact' 'expire' 'disabling' 'evaluation'
and so on (alternatively, like I do, you can write your own little C utility to do it even more quickly and automatically on the whole 600 megabytes CD-ROM you have inserted on your drive :=)... You'll see
immediately that only two of the PC-files can interest us: PCFILE.EXE and PCFRES.DLL. A quick 'turbodumping' of PCFILE.EXE itself will fetch all filenames and nagstrings we need to be happy from the end of
the file... here they are:

A) 010C PCF.DAT
B) 0114 PCF.DLL
1) 2.011C PC-FIle demo has been disabled...
2) 2.01A2 The PC-File demo program has reached the maximum allowable 25 sessions...
3) 2.0298 This demo version of PC-File 8 is designed...
4) 2.035A The PC-File demo program has reached... 90 days
5) 2.0474 This is the last demo session...

When I see something like this I know that the crack is already made... it's so easy I can't understand why they don't just give their software away for free... money I suppose, people seem to be obsessed
with this prepuberal problem... how stupid, besides: neminem pecunia divitem fecit.

Beside, snooping inside files can be graet fun! At times you find some 'real' info inside them... Have a look at lotus Wordpro, for instance, you'll read something like: 'You idiot! Can't flow a partial
paragraph!'; 'Yow! Need to SetFoundry() on this object!'; 'Dude! I couldn't find myself!'; 'Ain't nothing to pop!' and many other amenities which throw a crude light on the life (and possible blunders) of commercial
programmers and on the well know fact that most application are throw out FULL of bugs just in order to make money ('bugs for bucks').

OK, back to our cracking: let's just search for the above NUMBERS inside the code of PCFILE:

12
1) PC-File has been disabled: 011C

1.1100 >C8040100 enter 0104, 00


1.1104 56 push si
1.1105 C70632060000 mov word ptr [0632], 0000
1.110B 6A00 push 0000
1.110D B81401 mov ax, 0114; THIS is PCF.DLL
1.1110 8946FE mov [bp-02], ax
1.1113 50 push ax
1.1114 9A2E0D0212 call 1:0D2E ;what happens here?
1.1119 83C404 add sp, 0004
1.111C 40 inc ax
1.111D 7532 jne 1151
1.111F 1E push ds
1.1120 681C01 push 011C ;HERE****
1.1123 8D86FCFE lea ax, [bp-0104]
1.1127 16 push ss
1.1128 50 push ax
1.1129 9A6E110000 call USER._WSPRINTF

Therefore this target will be disabled after a check at the beginning of WinMain (1.1100) if ax, after having been incremented is non zero. We should have a look at the routine at 1:0D2E to see what
happens... but let's first check the other nagstrings... no point in delving immediatly inside routines.

2) The PC-File demo has reached the maximum allowable 25 sessions... 01A2

1.11C9 >807EFC66 cmp byte ptr [bp-04], 66


1.11CD 7C0F jl 11DE
1.11CF 6AFF push FFFF
1.11D1 9A36120000 call USER.MESSAGEBEEP
1.11D6 6A00 push 0000
1.11D8 1E push ds
1.11D9 68A201 push 01A2 ; HERE ****
1.11DC EB62 jmp 1240

Therefore 25 sessions if byte ptr [bp-04] >= 66 (as you can see, the protectionists did not use anything vaguely similar to 25dec, which is 19hex).

3) This demo version of PC-File 8 is designed... : 0298

1.11DE >807EFC4D cmp byte ptr [bp-04], 4D


1.11E2 7518 jne 11FC
1.11E4 6A00 push 0000
1.11E6 1E push ds
1.11E7 689802 push 0298 ;HERE ****
1.11EA 1E push ds
1.11EB FF361000 push word ptr [0010]
1.11EF 6A00 push 0000
1.11F1 9A48120000 call USER.MESSAGEBOX
1.11F6 C70632060100 mov word ptr [0632], 1 ;Flag 632!

This 'Welcome nagged user' message appears therefore only THE FIRST time you run, when our byte ptr [bp-04] has been set to 4D. That figures: 66h - 4Dh = 19h, which are the 25 times allowed... the
programmers from Atlantic Coast must have thought something like 'Stupid crackers will not fetch our nice clever protection: he'll be searching for byte 19h! Ah!' Note the flag set in location [632] if it's the first run
:=)

4) The PC-File demo program has reached... 90 days : 035A

1.1211 833E320600 cmp word ptr [0632], 0000


1.1216 7565 jne 127D
1.1218 A13406 mov ax, [0634]
1.121B 8B163606 mov dx, [0636]
1.121F 2B062C06 sub ax, [062C]
1.1223 1B162E06 sbb dx, [062E]
1.1227 83FA76 cmp dx, 0076
1.122A 7251 jb 127D
1.122C 7705 ja 1233
1.122E 3D00A7 cmp ax, A700
1.1231 764A jbe 127D

1.1233 >6AFF push FFFF


1.1235 9A3C130000 call USER.MESSAGEBEEP
1.123A 6A00 push 0000
1.123C 1E push ds
1.123D 685A03 push 035A ; HERE!

There, location [634] in ax and location [636] in dx. ax subtracts location [62C] and dx subtracts with carry location [62E]. Is it more than 76h? (Which is 118 dec), Tell user he has reached 90 days. Is it
exactly 76h? Then have a look at ax, if it is more than A700 then tell user the same.

5) This is the last demo session... : 0474

1.132D >56 push si


1.132E 9AFFFF0000 call KERNEL._LCLOSE
1.1333 807EFC66 cmp byte ptr [bp-04], 66
1.1337 7C19 jl 1352
1.1339 6AFF push FFFF
1.133B 9AFFFF0000 call USER.MESSAGEBEEP
1.1340 6A00 push 0000
1.1342 1E push ds
1.1343 687404 push 0474 ;HERE****
1.1346 1E push ds
1.1347 FF361000 push word ptr [0010]
1.134B 6A10 push 0010
1.134D 9AFFFF0000 call USER.MESSAGEBOX

1.1352 >1E push ds


1.1353 681401 push 0114 ;this is PCF.DLL
1.1356 6A01 push 0001
1.1358 9AFFFF0000 call KERNEL.WINEXEC ;exec PCF.DLL

And here, finally we have our good old [bp-04] -once more- compared to 66h. Notice that there is no Jumpequal nor jumpgreater check. This means that the program ALREADY KNOWS that the user has
reached here for the first time the fatidic 66. This means (of course) that this code will be examined AFTER having incremented the counter of the protection, which must therefore happen somewhere between
1.123D and 1.132D (the end of routine 4 and the beginning of routine 5). If you have printed the whole disassembled listing of PCFILE.EXE and if you have read my other lessons about dead listing (-> 9.3 and 9.4)
you do not need any more to read the following part of this lesson. Choose your armchair and sit there with a pen, your listing and a good cocktail (may I suggest a good Martini-Wodka? Don't use anything else but
Moskowskaja). The moment to start 'feeling' the code has come! You can do everything alone. Write colored arrows on your listing! The first (or the fourth) simphony of Mahler on your CD! Everything will appear!

Indeed, if you prefer to follow here, behold: at 1.12B2 we have a call KERNEL._LOPEN wich opens the file PCF.DLL (0114):

1.12AD 681401 push 0114 ;want pcf.dll


1.12B0 6A01 push 0001
1.12B2 9AFFFF0000 call KERNEL._LOPEN ;open it

and at 1.12CD we have the exact point where, inside pcf.dll, a byte will be modified (at 10AF8):

1.12C6 6A01 push 0001


1.12C8 68F80A push 0AF8
1.12CB 6A00 push 0000
1.12CD 9AFFFF0000 call KERNEL._LLSEEK

13
The only modification takes place therefore inside PCF.DLL, a monstruosity of 1088832 bytes, where location 10af8 grows WITHOUT any change in the date of the dll. You can easily check this:

* copy pcf.dll pcf.ded


* (run pcfile a couple of time)
* fc /b pcf.dll pcf.ded
fc /b is file compare /binary, good old (and quick) dos, duh?
And this is what you get...

Comparing files PCF.DLL and PCF.DED


00010AF8: 55 50

Et voila mesdames et messieurs, found the other way round, please note that this more 'practical' method can also be used *before* beginning the dead listing examination of the file (and would have given
you the '0AF8' string to search for).

Well, what did we learn? A lot: an hidden counter grows in another file without leaving many traces. The 'quiver' protection snaps after growing more than 66h, having started at 4Dh. The flag for first time
user is inside [0632]. [0634] and [0636] are used for the current date, [062C] and [062E] are the original date against which they are checked in a funny way.

There are two different protections, therefore we'll need two different cracks to deprotect this cram. Let's begin with the easiest one.

Our FIRST crack, must destroy the counter that increases inside pcf.dll (the '25' session allowance). This will be made cracking following instruction:

1.12F3 FE46FC inc byte ptr [bp-04]

which is obviously the increasing instruction we are searching for (BECAUSE it's the only 'inc byte ptr' in the whole stupid program, AND because it is located short after the _LLSEEK, AND because it's
incrementing nobody else than our good old [bp- 04]... what do you want more, a neon green flashing arrow light on the top of it?)

We'll very simply "noop" this instruction, transforming it, for instance, in 40 90 48 (inc ax, nop, dec ax = do nothing). Well, yes, that was it for the '25 sessions' lock protection, thankyou, you may use the
program a zillion times now. What now? Ah, yes, the DATE lock, let's have a look once more at it:

1.1218 A13406 mov ax, [0634]


1.121B 8B163606 mov dx, [0636]
1.121F 2B062C06 sub ax, [062C]
1.1223 1B162E06 sbb dx, [062E]
1.1227 83FA76 cmp dx, 0076 ;118 (-90=1c)
1.122A 7251 jb 127D
1.122C 7705 ja 1233
1.122E 3D00A7 cmp ax, A700 ;(42572)
1.1231 764A jbe 127D

1.1233 >6AFF push FFFF


1.1235 9A3C130000 call USER.MESSAGEBEEP
1.123A 6A00 push 0000
1.123C 1E push ds
1.123D 685A03 push 035A ;HERE! 90 days!

Therefore, if location [636] is > than 76, the nag snaps. This 76 is calculated through what SEEMS a simple comparison between the actual date and the installation date.

1.1218 A13406 mov ax, [0634] ;load date ax


1.121B 8B163606 mov dx, [0636] ;load date dx
1.121F 2B062C06 sub ax, [062C] ;subtract first date
1.1223 1B162E06 sbb dx, [062E] ;subtract first date
1.1227 83FA76 cmp dx, 0076 ;allowed limit (?)
1.122A 7251 jb 127D ;ok: you may
1.122C 7705 ja 1233 ;beggar off
1.122E 3D00A7 cmp ax, A700 ;well, what's this
1.1231 764A jbe 127D ;then?

In the reality there are various mathematical checkings going on here, as the second check on ax = A700 shows. This DOES NOT need to concern us much (we'll crack this code, later, changing the 'first
time user' flag), but it's useful you have a rough understanding of what goes on inside these schemes, therefore let's delve a little inside it.

Basically, the good old dos function GetSystemDate (21/2A) works like this:

On entry: ah = 2a
On return:
al = day of the week (0 = Sunday, 1 = Monday...)
cx = year
dh = month
dl = day

Short before the 90 days check, the protection calls two routines:

1:09B4 (GetSystemDate) and 1:0D64 (FetchInstallationCode)

The first one fetches the date (1.9D3-1.9D7) and the Time (21/2C, at 1.9E2), get's ONCE MORE the system date (1.9F7) subtracts the years against 1980 (1.A20: sub cx, 07BC) and then makes quite a lot
of maniuplation of these data (around 1.C7D, where one year LESS than the current year will be stored in [SI+03], in order to calculate the total amount of days). The second one prepares the numbers for the sub
ax and sbb dx of the 90 days check.

As I said all this does not need to concern you much, coz the protectionists have mad a 'protecion blunder': they have made every time snapping depending on a flag, the one in [0632].

What happens is: THE FIRST THING this program makes, smack at the beginning of WinMain, is to set to zero (FALSE) the abovementioned flag:

1.1105 C70632060000 mov word ptr [0632], 0000

Only in case of first time use, this flag will be set to TRUE at

1.11F6 C70632060100 mov word ptr [0632], 0001

knowing that, anyway, as soon as the program runs again this flag will be reset to FALSE by Winmain.

And, as we saw, this flag is checked both for the 90 days snap:

1.1211 833E320600 cmp word ptr [0632], 0000

and for the 'This is your last day Cinderella' Warning:

1.1315 >833E320600 cmp word ptr [0632], 0000

A good fundamental crack will therefore be the 'automatical' setting to TRUE of this flag by our Winmain:

1.1105 C70632060100 mov word ptr [0632], 0001

Everytime the program runs it will believe that's the first time it does it.

I know, theoretically, having nooped the increase inside PCF.DLL, the counter should remain always at 4D, which would set ANEW the flag to true every run... but we do not want the first 'welcome'
nagscreen either, do we? Therefore:

****** Crack for PCFILE version 8, by +ORC, march 1997 ***


psedit pcf.dll
search 4E 49 44 4D (4D only if you did not run it)
modify in 4E 49 44 50 (second time run)
psedit pcfile.exe
search 83 C4 06 FE 46 FC
modify in 83 C4 06 40 90 48 (nooped increase)
search C7 06 32 06 00 00
modify in C7 06 32 06 01 00 (flag always true)

14
*********************************************

As second example I have chosen a fairly interesting 'CINDERELLA' protection scheme of a Window application which can be useful for our purposes: Link Check (Version 5.1), an application written in
august 1996. I'll crack here the Windows 3.1 version, for reasons explained in lesson 9.4, but you'll easily find the Win95 version on the net, whose protection scheme works on the same lines.

Link Check is a suite of three (3) diagnostic programs which allows the user to examine different areas of the system.

1) Link Check (WLCHECK.EXE) enables the user to view the links between an executable file and the modules it requires to run on the system.
2) Memory Check (WMCHECK.EXE) allows the user to view, load and unload modules currently in memory.
3) Function Check (WFCHECK.EXE) allows the user to view actual function calls inside modules.

WLCHECK EXE 40400 24/08/96 5:10


WMCHECK EXE 37104 18/08/96 5:10
WFCHECK EXE 45424 24/08/96 5:10
WLCCOMM DLL 46960 18/08/96 5:10
KSLHOOKS DLL 29568 15/08/96 1:00

The protection scheme inside this program allows a 21 days use of the program, then 'disables' it. Even in the first 21 'allowed' days there are some functions that are disabled, anyway. Another interesting
feature of the protection scheme, is that once you register, an 'electronic key' will be created and sended to you in order to unlock Link Check for the full retail version (which, as usual, means that the shareware
version you are using CAN be unlocked).

Therefore this application:

is TIME-LIMITED
has been CRIPPLED
has some DISABLED functions
can be UNLOCKED.

A wonderful world of cracking possibilities! Let's rub our hands! So much to find! So much to learn! Thanks, Karri Software Ltd! (100422.3521@compuserve.com)

For these protection schemes we must use both the 'Winice' live approach and the 'dead listing' one. (both described elsewhere in my tutorial).

Let's begin at the beginning, i.e. searching for strings inside the WLCHECK.EXE we'll find nothing.

You'll soon realise that the protection scheme hides inside the two *.dll WLCCOMM.DLL & KSLHOOKS.DLL... the real problem, with this kind of protections, is that the 'modalities' to unlock it are not
known, i.e., that you cannot just crack the unlock procedure itself, but you must reverse engineer the program long enough to find the 'switch' that fires your cracked 'unlock' procedure, in order to 'register' this
program and in order to be able to use it ad libitum.

What happens with time protections?

The first problem for the protectionists is the tampering with the system date. Even a stupid user could set the system clock backwards in order to use a program of the CINDERELLA sort. Your target
would be easily fooled by any stupid user if it did just set a variable [START_DATE] and then simply check the system time with something like

if SystemTime > [START_DATE+30] then beggar off


else OK

Therefore (almost) all this program use some sort of 'diode' location. Like diodes, which let current through in only one direction, these locations can only grow... i.e, if you set the system time to 1 January
2000 and then run the program, it will throw you off, as expected, but even when you go back to your current year and date this will be 'remembered'...and the protection will NOT allow you any more to use the
program even should you (theoretically) still have some free 'try me' days... your setting at year 2000 screwed up your license for ever.

if SystemTime > [START_DATE+30] then [MARK_HERE]


else continue
if [MARK_HERE] = true then beggar off
else OK

Let's try altering the system date on our WLCHECK.EXE target...

Woa! As I said... it does not work anymore.

It's fairly easy to get at this part through Winice: Just bpx WritePrivateProfileString (which is a very interesting function indeed) and then have a good look at the pointers: You'll quick find out that
KSLHOOKS (Segment 0B) writes his own xCLSID value inside system.ini. The block of KSLHOOKS.DLL's code responsable for this is the following:

11.0569 9AE4013500 call 7:01E4 ;'Value' and 'SYSTEM.INI'


11.056E 83C408 add sp, 8 ;adjusting stack
11.0571 8D843901 lea ax, [si+0139]
11.0575 57 push di
11.0576 50 push ax ;pushing 'xCLSID'
11.0577 8D46FA lea ax, [bp-06]
11.057A 16 push ss
11.057B 50 push ax ;pushing 'Value'
11.057C 8D468A lea ax, [bp-76]
11.057F 16 push ss
11.0580 50 push ax ;pushing '{6178-0503...}'
11.0581 8D46EE lea ax, [bp-12]
11.0584 16 push ss
11.0585 50 push ax ;pushing 'SYSTEM.INI'
11.0586 9AFFFF0000 call KERNEL.WRITEPRIVATEPROFILESTRING
11.058B 33C0 xor ax, ax
11.058D 5E pop si
11.058E 5F pop di
11.058F C9 leave
11.0590 CB retf

The call to 7.01E4 fetches the strings 'Value' and 'SYSTEM.INI' which are 'hardwired' there byte by byte, for instance, 'INI' is fetched like this:

7.0234 26C6440749 mov byte ptr es:[si+07], 49 ;I


7.0239 26C644084E mov byte ptr es:[si+08], 4E ;N
7.023E 26C6440949 mov byte ptr es:[si+09], 49 ;I

What is really interesting in this part of the protection scheme, is that the function WritePrivateProfileString is one of the MOST COMMON functions used for this kind of protections, being the function
normally used in order to 'keep track' inside an 'INI' file of the particular configuration of an application that the user has chosen... as a matter of fact this program creates an hidden WLCHECK.SWL file inside
c:\windows where it writes its data, it also writes, through the above code,

[xCLSID]
Value={0000006236-0017105173-6326000000}
inside system.ini

and then it writes ANOTHER string inside the reg.dat 'register' of the windows directory. A short digression, about registrations in the reg.dat of the Windows directory. If you never had a look at the reg.dat file (wich
you should not have only firing regedit.exe, but using the switch /v TROUGH THE COMMAND LINE run!) you are in for a big surprise. If you are used to install and de-install programs as much as I do, you'll be
able to see, for instance, real BATTLES between big or widespread software packages (for instance Coreldraw and PaintShopPro) fought there... but you'll also find some cryptic messages like

WB_10=VMWB20
FILTER = 000000000e
OPTION = 0000000005
TAG = 0000001857
KEY = 0000184F
or, even more cryptic:
VxDSettings = {0000006178-0419758349-4326000000}

And this is actually our target, as you can see... the first thing you should know is that some protection schemes hyde the date checking part of their protection inside reg.dat. The above value is the 'ID' of
our target, and the ciffer in the 'middle' varies with the date and with the passing of the time.

As we said, once the protection snaps, there is no 'normal' way to reinstall a working copy of the program, even substituting ALL the files with fresh ones and deleting the 'secret' WLCHECK.SWL will not
help... in order to reinstall this program or to use it for the eternity (in 21 days chunks) you would have to do the following every time the limit snaps:

A) regedit /v

15
delete key VxD

B) edit system.ini
manually delete the block
"[xCLSID]
Value={0000006236-0017105173-6326000000}"

C) attrib c:\windows\wlcheck.swl -r -s -h
del c:\windows\wlcheck.swl

D) reinstall everything anew and run 21 more days... clearly not a satisfactory solution, exspecially given the fact that some routines are disabled... therefore let's delve a little more inside this protection
scheme... we'll find a much neater crack, you'll see... :=)

Since the 'legitimate' user will get 'an electronic key' from the protectionists, there must exist, somewhere, a small menu of the kind 'Enter your electronic key, legitimate sucker'... we could find it searching
with a little imagination (and/or zen) inside our listings, but in these cases, it's much more quicker a small run with WRT (Windows Resource Toolkit) by borland. Since we are already inside KSLHOOKS.DLL, let's
begin with this one.

Wrt loads kslhooks.dll and shows you immediatly that there are only three dialog items, the last one, tagged as 'dialog 503' represents the 'Unlock' little window: ('Please enter your key'), which has two
buttons: OK (1) and Cancel (2). Let's use WRT 'ID_tagging' option: we'll immediatly fetch the ID number of the 'Please enter your key' field: 2035.

2035 dec is 7F3 hex, therefore we now just need to search 07F3 inside our listing... and we land immediatly here:

6.00DE >8B760A mov si, [bp+0A]


6.00E1 FF760E push word ptr [bp+0E]
6.00E4 6A08 push 0008
6.00E6 9AFFFF0000 call USER.GETWINDOWLONG
6.00EB 8946FC mov [bp-04], ax
6.00EE 8956FE mov [bp-02], dx
6.00F1 83FE01 cmp si, 0001
6.00F4 7556 jne 014C
6.00F6 FF760E push word ptr [bp+0E]
6.00F9 68F307 push 07F3 ;HERE! ****
6.00FC 9AFFFF0000 call USER.GETDLGITEM
6.0101 50 push ax
6.0102 8D4698 lea ax, [bp-68]
6.0105 16 push ss
6.0106 50 push ax
6.0107 6A63 push 0063
6.0109 9AFFFF0000 call USER.GETWINDOWTEXT
6.010E 8D4698 lea ax, [bp-68]
6.0111 16 push ss

This block of code is part of an Exported function from kslhooks.dll: KSLHOOKPROC4 - Ord:0006h

Here is the whole sequence:

:CALL_PLEASE_ENTER_ELECTROKEY
6.00DE >8B760A mov si, [bp+0A]
...
6.00F9 68F307 push 07F3 ;HERE ***is called (being at 6.00DE) from
:ENTER 68
6.0082 C8680000 enter 0068, 00
...
6.009B 7441 je 00DE ;HERE ***which (being at 6.00082) is called from
:PUSH_82
6.000F 68FFFF push selector KSLHOOKPROC4
6.0012 688200 push 0082 ;HERE ***
6.0015 FF36200C push word ptr [0C20]
6.0019 9AFFFF0000 call KERNEL.MAKEPROCINSTANCE

Much interesting, but we are not yet there... Let's see if we have other occurrences of our 7F3h instance (which, as we saw through WRT, corresponds to the 'Enter your Key' field of the 'Unlock' window).
Yes, we have one more occurrence (always inside KSLHOOKS.DLL):

4.030A >81FEF307 cmp si, 07F3 ;HERE ***


4.030E 7515 jne 0325 ;don't care if not unlock
4.0310 FF760E push word ptr [bp+0E] ;nID
4.0313 56 push si ;=7F3, =unlock, =hDlg
4.0314 9AFFFF0000 call USER.ISDLGBUTTONCHECKED
4.0319 0BC0 or ax, ax ;mashed button?
4.031B 7408 je 0325 ;Yeah, jump...
4.031D C45EFC les bx, [bp-04]
4.0320 2689B7B104 mov es:[bx+04B1], si
4.0325 >83FE02 cmp si, 0002 ;...here

Now, IsDlgButtonChecked is a 'typical' windows function with following structure:

UINT IsDlgButtonChecked(HWND hFlg, int nID)

where the handle of the dialog box contaning the button control is specified in hDlg. The ID value of the desired button is passed in nID. For two-state buttons this function returns zero if the button is
unchecked and non zero if it is checked, -1 if an error occurs.

What else can we do?

Let's search for the limit (21 days, that corresponds to 15h) inside our code. Well, we'll find two interesting occurrences inside the OTHER dll module: WLCCOMM.DLL:

:OCCURRENCE_1_OF_21_DAYS_LIMIT
1.3E25 >80BEFFFE15 cmp byte ptr [bp-0101], 15 ;here***
1.3E2A 7403 je 3E2F ;Please restart...
1.3E2C E9B900 jmp 3EE8 ;xor ax and retf and now, look what we have
;immediately afterwards...
1.3E2F >FF760E push word ptr [bp+0E]
1.3E32 1E push ds
1.3E33 681306 push 0613 ;Please restart...
1.3E36 1E push ds
1.3E37 68EE05 push 05EE ;Retail version...
1.3E3A 6A40 push 0040
1.3E3C 9A90080000 call USER.MESSAGEBOX
1.3E41 FF760E push word ptr [bp+0E]
1.3E44 6A01 push 0001
1.3E46 9AE03E0000 call USER.ENDDIALOG
1.3E4B E99A00 jmp 3EE8 ;xor ax and retf

Now, string 0613 is

"Please restart the program for the reatil version to take effect"

and string 05EE is

"Retail version successfully unlocked"

...clearly we have found the part of the code where the user gets the appropriate message once he has digited the correct key inside the unlock window in KSLHOOKS.

But let's use a little more our 'new' WRT approach. Examining the 'dialog' items through WRT, we'll see that inside WLCCOMM.DLL there are 'two' About Link check templates, a 'nice' one (for registered
users) and a 'nag' one (for Cinderella's users).

The nice one is WLCCOMM.DIALOG 130, and its second part reads

16
'This copy of Link check is licensed to'
FIELD 1 = 603 (25bh)
FIELD 2 = 604 (25Ch)

The 'nag' one is WLCCOMM.DIALOG 131 and its second part reads

'UNREGISTERED Shareware notice...' with two buttons:


'How do I register' which is 601 (259h) and
What do I get for it which is 602 (25ah).

Well... let's have a look around our code... and here is (obviously) the relevant part of it inside WLCCOMM.DLL:

1.3C60 >8B760E mov si, [bp+0E]


1.3C63 FF7606 push word ptr [bp+06]
1.3C66 6AF4 push FFF4
1.3C68 9A8A1D0000 call USER.GETWINDOWWORD
1.3C6D 56 push si
1.3C6E 685B02 push 025B ;here***
1.3C71 9A803C0000 call USER.GETDLGITEM
1.3C76 394606 cmp [bp+06], ax
1.3C79 7421 je 3C9C
1.3C7B 56 push si
1.3C7C 685C02 push 025C ;here***
1.3C7F 9ADA3C0000 call USER.GETDLGITEM
1.3C84 394606 cmp [bp+06], ax
1.3C87 7413 je 3C9C
1.3C89 FF760A push word ptr [bp+0A]
1.3C8C FF7608 push word ptr [bp+08]
1.3C8F FF7606 push word ptr [bp+06]
1.3C92 6A01 push 0001
1.3C94 9A08039E3D call KSLCONTROLCOLOR
1.3C99 E94E02 jmp 3EEA

Whereby, here is the part for the shareware user:

1.3EA6 >81FE5902 cmp si, 0259 ;How do I register?


1.3EAA 7513 jne 3EBF
1.3EAC FF760E push word ptr [bp+0E]
1.3EAF 1E push ds
1.3EB0 688B06 push 068B
1.3EB3 6A01 push 0001
1.3EB5 6A00 push 0000
1.3EB7 687217 push 1772
1.3EBA 9AD43E0000 call USER.WINHELP
1.3EBF >81FE5A02 cmp si, 025A ;What do I get for it?
1.3EC3 7523 jne 3EE8
1.3EC5 FF760E push word ptr [bp+0E]
1.3EC8 1E push ds
1.3EC9 689706 push 0697
1.3ECC 6A01 push 0001
1.3ECE 6A00 push 0000
1.3ED0 687117 push 1771
1.3ED3 9AFFFF0000 call USER.WINHELP
1.3ED8 EB0E jmp 3EE8

and as you can easily see, here lays the 'working' for the two mushbuttons of the shareware version. Shareware starts at 1.3EA6 and will be called from here

1.3DB9 >81FE5802 cmp si, 0258


1.3DBD 7403 je 3DC2
1.3DBF E9E400 jmp 3EA6

Unlocked version starts at 1.3C60 and will be called from here:

1.3C3E C8FE0400 enter 04FE, 00


1.3C42 57 push di
1.3C43 56 push si
1.3C44 1E push ds
1.3C45 B87938 mov ax, selector 2:0000
1.3C48 8ED8 mov ds, ax
1.3C4A 8B460C mov ax, [bp+0C]
1.3C4D 2D1900 sub ax, 0019
1.3C50 740E je 3C60 ;***here! UNLOCKED
1.3C52 2DF700 sub ax, 00F7
1.3C55 7465 je 3CBC ;copyright, 1st part
1.3C57 48 dec ax
1.3C58 7503 jne 3C5D ;(jmp 3EE8) out
1.3C5A E94901 jmp 3DA6

Well... if [bp+0C] is 19 (dec25) then we'll jump to our unlocked routine?

********************************************
BELOW IS WORK FROM THE STUDENTS OF THE +HCU
wlcheck for windows 3.1
********************************************

Starting with the nag screen, here is a silly fix for it that works on many programs that use windows resource windows (such as an about box) as the nag screen.

Load up the file with the nagscreen in it (as listed above) with WRT (I am using borland resource workshop - same program, different version) and delete it. I am serious; try it: it works!

save the .DLL and it recompiles the binary without the nagscreen.
(Those borland people scare me sometimes)
---------------------------------------------------------

Back to more serious work...

Since we are learning methods here, this is where I get to go after individual parts of the protection and defeat them. I will work on finding the flag to register the program later, first I want to do a little
digging.

Looking through our dead listing of kslhooks.dll:

Going through our lesson so far, our file included a file reference to SYSTEM.INI by means of a byte-at-a-time string creation rather than a full data statement

(Note: i do this sometimes to make it hard for simpletons to change my name in my programming --- but i at lest jumble the lines around so it isnt so obvious)

I will show you two ways of removing this particular hurdle, here is the first, and most obvious: (THE NULL TERMINATOR)

---------------------------------------------------------
here is the full code from the disassembly:
---------------------------------------------------------
:0007.01E3 90 nop
:0007.01E4 55 push bp
:0007.01E5 8BEC mov bp, sp
:0007.01E7 57 push di
:0007.01E8 56 push si
:0007.01E9 8B7E06 mov di, [bp+06]

17
:0007.01EC 8B760A mov si, [bp+0A]
:0007.01EF 8E4608 mov es, [bp-08]

:0007.01F2 26C60556 mov byte ptr es:[di], 56 ;V


:0007.01F6 26C6450161 mov byte ptr es:[di+01], 61 ;a
:0007.01FB 26C645026C mov byte ptr es:[di+02], 6C ;l
:0007.0200 26C6450375 mov byte ptr es:[di+03], 75 ;u
:0007.0205 26C6450465 mov byte ptr es:[di+04], 65 ;e
:0007.020A 26C6450500 mov byte ptr es:[di+05], 00 ; <00> (end of string)

:0007.020F 8E460C mov es, [bp-0C]

:0007.0212 26C60453 mov byte ptr es:[si], 53 ;S


:0007.0216 26C6440159 mov byte ptr es:[si+01], 59 ;Y
:0007.021B 26C6440253 mov byte ptr es:[si+02], 53 ;S
:0007.0220 26C6440354 mov byte ptr es:[si+03], 54 ;T
:0007.0225 26C6440445 mov byte ptr es:[si+04], 45 ;E
:0007.022A 26C644054D mov byte ptr es:[si+05], 4D ;M
:0007.022F 26C644062E mov byte ptr es:[si+06], 2E ; .
:0007.0234 26C6440749 mov byte ptr es:[si+07], 49 ;I
:0007.0239 26C644084E mov byte ptr es:[si+08], 4E ;N
:0007.023E 26C6440949 mov byte ptr es:[si+09], 49 ;I
:0007.0243 26C6440A00 mov byte ptr es:[si+0A], 00 ;<00> (end of string)

:0007.0248 5E pop si
:0007.0249 5F pop di
:0007.024A C9 leave
:0007.024B CB retf

---------------------------------------------------------------------------

to me this looks like an easy section to defeat - this because the full filename is here, and because it is in a standard string format terminating in hex zero (00) a.k.a.: NULL

as with programs with unencrypted passwords (yes even some programs you may use.. like X-WING have no encryption whatsoever - just try scanning FRONTEND.OVL for DANTOOINE with a hex
editor, and all the passwords are sitting there for you to zero-out)

in other words, why bother disabling the function that calls this data when you can simply change each character in SYSTEM.INI to a hex zero

i did and just as i suspected, out of the three places that are causing us hassles, SYSTEM.INI, WLCHECK.SWL, and the registry (REG.DAT). I no longer have to deal with one of them

just run it, you will see: no more added line in system.ini

NOW FOR THE OTHER WAY:


(This one is more useful for a cracker point of view since good protections tend to be smarter than letting you view filenames like we saw above)

This is where we go back to the WRITEPRIVATEPROFILESTRING function and check it out.

A text search of the dead listing reveals quickly:

:0011.0535 90 nop
:0011.0536 C8760000 enter 0076, 00
:0011.053A 57 push di
:0011.053B 56 push si
:0011.053C 8B7606 mov si, [bp+06]
:0011.053F 33C0 xor ax, ax
:0011.0541 B93200 mov cx, 0032
:0011.0544 8D7E8A lea di, [bp-76]
.
.
.

:0011.0584 16 push ss
:0011.0585 50 push ax
:0011.0586 9AFFFF0000 call KERNEL.WRITEPRIVATEPROFILESTRING
:0011.058B 33C0 xor ax, ax
:0011.058D 5E pop si
:0011.058E 5F pop di
:0011.058F C9 leave
:0011.0590 CB retf

notice the end of the function and how it exits...

5E POP SI
5F POP DI
C9 LEAVE
CB RETF

In order to give the function a little meat to play with but still return early, lets insert this code right at the start of the function, right after push si.

:0011.0536 C8760000 enter 0076, 00


:0011.053A 57 push di
:0011.053B 56 push si
:0011.053C 5E pop si
:0011.053D 5F pop di
:0011.053E C9 leave
:0011.053F CB retf

and it really works out, the function gets called, it starts, quits, and returns... veni, vidi, crakki.

a quick hex edit of the dll to alter this..


searching for a good string to replace, we get 2 occurrances of:

8b760633c0b93200

They are GETPRIVATEPROFILESTRING and WRITEPRIVATEPROFILESTRING respectively. Go ahead and do the same damage that you did above to both of them. You will notice that they are very
similar functions, with exactly the same method of beginning and ending.

so we can change both occurrances toto:

5e5fc9cbc0b93200

NOTE:
This patch takes care of the system.ini change, so no need to do a zero-out of the file. It didnt do any good for the .swl file however, because does some other method of storing it's data.
**********************************************
Here is a little clue in how to find the other filenames that may be hidden in the file.

From the SYSTEM.INI example, which has a period (hex 2E) and a file extension, i knew to look for ", 2E" (COMMA SPACE 2E) in the text editor while reading kslhooks.alf. i decided to give it another
whirl and see if there were any other surprises

Just looking for 2E will work, but you will find many occurrances of it in hex data, so it is best to try to differentiate it as much as possible for sanity reasons.

Apparently it bears fruit...

--------------------------------------------------------------------------
Here is the first block of code i landed in:
--------------------------------------------------------------------------

18
:0003.00B0 F3 repz
:0003.00B1 A5 movsw
:0003.00B2 13C9 adc cx, cx
:0003.00B4 F3 repz
:0003.00B5 A4 movsb
:0003.00B6 1F pop ds
:0003.00B7 39460A cmp [bp+0A], ax COMPARE AND JUMP...
:0003.00BA 7516 jne 00D2

:0003.00BC C646FA2E mov byte ptr [bp-06], 2E ; <----- A .SWL FILENAME


; EXTENSION
:0003.00C0 C646FB53 mov byte ptr [bp-05], 53 ;S
:0003.00C4 C646FC57 mov byte ptr [bp-04], 57 ;W
:0003.00C8 C646FD4C mov byte ptr [bp-03], 4C ;L
:0003.00CC 8846FE mov [bp-02], al
:0003.00CF EB0E jmp 00DF

:0003.00D1 90 nop
:0003.00D2 8D7EFA lea di, [bp-06]

* Possible StringData Ref from Data Seg 013 ->".LIC" <---- A NEW FILENAME EXTENSION ".LIC"
|
:0003.00D5 BE1800 mov si, 0018

--------------------------------------------------------------------------

what it looks like to me is that WHEN registered, the .SWL file extension is replaced by a .LIC file extension though changing the name of the SWL file to LIC does not seem to have any beneficial result at
this time

it may once the other file checks have been disabled regardless, it is apparent that there is a file with a .LIC extension that gets created upon successfully registering this software

--------------------------------------------------------------------------
note that because there appears only once a .SWL reference in the KSLHOOKS.DLL, my guess is that if i hex-zero the .SWL like i did the SYSTEM.INI reference, it would not matter because the file write
command and file read command apparently use the same string for their data. in other words, changing .SWL to anything, the file would just have a different name.

testing this out, i found that i was correct. hexing out .SWL with zeroes resulted in a file in my windows directory called WLCHECK with no extension, rather than .SWL (sometimes it would be nice if my
theories wouldnt be quite so correct)

so we are at least in the ballpark, but no real improvements yet.

It is still going to take more looking to do anything with this yet

----------------------------------------------------------

Now let's try for the registry...


Scan the file for REG, and you will inveitable find quite a few
registry commands. which are registry key edit functions.

:0011.033A C8300100 enter 0130, 00


:0011.033E 57 push di
:0011.033F 56 push si

:0011.0340 8B5E06 mov bx, [bp+06]


:0011.0343 8B4E08 mov cx, [bp+08]
:0011.0346 81C32D01 add bx, 012D
:0011.034A 1E push ds
:0011.034B 8BFB mov di, bx
.
.
:0011.037D 9AFFFF0000 call SHELL.REGCREATEKEY
.
.

and it ends JUST LIKE the previoous functions with a:

5E POP SI
5F POP DI
C9 LEAVE
CB RETF

so we just hexedit the changes...

2 occurrances of:

010057568b5e068b

(regopenkey and regcreatekey respectively - feel free to look for yourself in the dead listing)

it is just fine to change both to:

010057565e5fc9cb

and just like in the case of the writeprivateprofilestring, we have cracked the registry.

NOW -

2 out of 3 of the hoops have been jumped. Now it is time to test the .SWL file and afterwards we will deal with the NAG feature itself.

Here is where i get curious to see the differences in the before and after... i want to see exactly what i have left to conquer, and the resultant file differences in wlcheck.swl BEFORE the 21 day date
expires, and AFTER it expires.

I wrote a program a while back to datecrack stuff like this - but as we already know, this program is a little smarter than the average 'check today's date' type of protection.

The way my program (cdate.exe) works is relatively simple: it alters the system date upon program entry, and changes it back to normal. The interesting thing about this is that it allows future dates to be
set as well as past ones since i didnt care to put a block on WHICH dates could be set with it.

Note that this one works fine past midnight because it has a calendar built in, so if you are to write one yourself remember that when midnight comes and your calendar strangely goes off by a day every
time you pass midnight while using a datecracked program.

CDATE USAGE:
cdate mm dd yyyy

So, since all that is left to crack is the swl file, i can delete it with my handy RM command - which like all of my little unix tools strips all attribs from the file (ignores them really)...

rm c:\windows\wlcheck.swl

...And i can run wlcheck.exe again (this time with false future date)

cdate wlcheck 9 9 1999 (it's now 1997 so this works fine)

note the result: expired program!!!

exit wlcheck and try running it normally (no funky date this time) guess what... STILL expired. that means it records not only date info, but EXPIRED info as well, exactely as +ORC said.

Do the little effect of RM C:\WINDOWS\WLCHECK.SWL again and run wlcheck

19
It isn't expired now

That means that the ONLY recorder for 'expired software' is in that file... doing a little dos file compare between a copy of the swl file before, and after (the BAD one), here are my results again i used
CP.EXE to copy the swl file since it strips attribs and i dont have to worry about them now.

-----------------------------------------------------------
C:\WLCHECK\> FC WLCHECK.SWL WLCHECK.BAD

Comparing files wlcheck.swl and wlcheck.bad shows them to be quite different (you can try this for yourself if you like)
------------------------------------------------------------

There are a few ways we could go about this.

We could either try to make it so the 21 day period cannot expire, or remove the command that records the info to the file. In all honesty, we will probably have to do both in order to deprotect it
completely.
**********************************************************

maybe we should do a little windows directory listing just to see if there are any more surprises

dir /a c:\windows\wlc*

what do we see: wlcheck.ini, wlcheck.ord, and wlcheck.swl

that is all fine, no more surprises yet (if you didnt expect a wlcheck.ini file: WHY NOT?

if you edit wlcheck.ord, it is just your order blank from when you filled out the wlcheck form nothing impressive, but at least it has the product serial number listed at the bottom - sometimes handy
*********************************************************
I cannot seem to find any more windows file commands, so i decided to see if they had included in the dll their own file access commands that means... look for int21

(there are a TON of int21 calls in this program! - and to think that some people think that dos cracking is dead...)

these are the KSL file i/o and system functions, with direct access to hardware through DOS.

upon searching for int21 calls - specifically int21 with ah=2a


b42a (mov ah, 2a) = get system date

I found 3 instances

2 occurrances of:
008C D89045558BEC1E8ED856 B42A

changed to
00CB D89045558BEC1E8ED856 B42A

(CB = retf)

an interesting thing happens, on the first run, it works fine, writes the .swl file, and goes on it's merry way

on any subsequent runs, it says expired that tells me that the changes i made, set the date to a nothing value in the wlcheck.swl file

in easier to understand lingo, i hit the nail on the head. i found the date checker - in old int21 style.

if you wish to play with this more yourself, go ahead. by all means.

i still havent worried with the 3rd date check, which is the hex string:
9045558BEC1E8ED856 B42A

About this time, I begin to think - maybe there is a better way...


(I have gotten a bit tired of playing around, and I want to fully crack it)
----------------------------------------------------------
Now we get down to the nitty gritty.

The above is necessary work.. handy for other protection schemes. It is, however, not incredibly useful here in this one. If you run wlcheck or one of the other executables, you will notice something
frustrating: you cannot print. Only registered users get that option. That means we either have to crack more functions, like above, or just go ahead and register the thing and get it over with.

So we shall.
------------------------------------------------------------
Time to go into the WLCCOMM.DLL...

remember how i said +ORC mentioned 2 occurrances of 15 that were interesting? i search for " 15" (a space in front so it didn't get every 15 in the wsccomm file listing)

i didnt find what i wanted other than the original one, so i looked for 0015 and i found one that looked promising..

:0001.3F5D C786E7FB1500 mov word ptr [bp-0419], 0015


:0001.3F63 B001 mov al, 01
:0001.3F65 8886CEFB mov [bp+FBCE], al
:0001.3F69 8886E9FB mov [bp+FBE9], al
:0001.3F6D 8886EAFB mov [bp+FBEA], al
:0001.3F71 C68648FC15 mov byte ptr [bp-03B8], 15

(I must remember to check for bgoth from now on)

just below all that, i saw something strange... several 'set value to 1' - in other words, it looks like we see a bunch of flags

changing the below statement to 00 returns this error: this is an old version (and quits) - not extremely useful, but a green light shall we say.

:0001.3F63 B001 mov al, 01


:0001.3F65 8886CEFB mov [bp-0432], al
:0001.3F69 8886E9FB mov [bp-0417], al
:0001.3F6D 8886EAFB mov [bp-0416], al

going further down... we have a comparison (in the form of an 'OR')

:0001.3F86 9AFFFF0000 call KSLHOOKS.Ord{0038h}

:0001.3F8B 8BF8 mov di, ax <--- backing up ax

This program apparently wants to save whatever came out of the strange kslhooks call above before making this compare...

:0001.3F8D 0BF8 or di, ax <--- COMPARE BOTH

Note the special nature of this compare.. since both values are the same, it is basically the same as saying if ax is zero, it stays zero, if it is not, it becomes a 1 since the result of any compare is
stored in ax di still has the saved value in it however... for future use by the program as you will see below, it is flag containing error codes

:0001.3F8F 750F jne 3FA0 <--- FIRST JUMP IF NONZERO

This smells to me like a 'beggar off jerk'...


(i already know what i have here, do you?)

:0001.3F91 B80100 mov ax, 0001 <--- SET A FLAG?!?

This just gets better and better, but i still look before i try anything, I don't want to jump the gun and assume anything without proof...

:0001.3F94 C45E06 les bx, [bp+06]

20
:0001.3F97 268987A400 mov es:[bx+00A4], ax

:0001.3F9C E9D600 jmp 4075 <--- 2nd JMP


:0001.3F9F 90 nop

HERE is where jmp 1 takes me...

:0001.3FA0 8B760A mov si, [bp+0A]


:0001.3FA3 83FF0A cmp di, 000A
:0001.3FA6 7510 jne 3FB8
:0001.3FA8 56 push si
:0001.3FA9 1E push ds

* StringData Ref from Data Seg 002 ->"An upgrade is required.


Continuing as shareware only."
|
:0001.3FAA 68CF06 push 06CF

AND WOULD YOU LOOK AT THAT EVIL MESSAGE!


it is very clear that the beggar off guess was correct...

just go down a few lines and you will see ALL SORTS of nasty error messages, including the shareware expiry message we get when we try to run after 21 days (note that it would have been much
easier had we scanned the text for keywords like shareware, reg, exp, or others we could imagine... but that would not work with all programs, and we are here to learn how to crack ALSO protections that do not
do us the favour of carrying their doom inside... therefore the approach above is much more solide :-)

paging down a little we see this at the location JMP 2 sent us at 4075...

:0001.4075 1F pop ds
:0001.4076 5E pop si
:0001.4077 5F pop di
:0001.4078 C9 leave
:0001.4079 CA0600 retf 0006

it just quits... but if you remember up above, it set a flag before it did so!

now how do we get it to ignore those nasty error messages and we ALWAYS jump to 4075 with the flag set?

looking back at our decision code from above:

:0001.3F86 9AFFFF0000 call KSLHOOKS.Ord{0038h}

:0001.3F8B 8BF8 mov di, ax


:0001.3F8D 0BF8 or di, ax
:0001.3F8F 750F jne 3FA0 <---- evil jump

:0001.3F91 B80100 mov ax, 0001


:0001.3F94 C45E06 les bx, [bp+06]
:0001.3F97 268987A400 mov es:[bx+00A4], ax
:0001.3F9C E9D600 jmp 4075 <---- good jump

notice the jne? there are quite a few ways of attacking this, but think about it, there are a few things that must be done.

first, the jne could be changed to a je (or jz) but if we do that, we have to WAIT 21 days to be able to use the program, or screw up the date at install, or something dumb like that (not a good crack)

if AX is set to anything, it is deemed an error by the program and the error code is saved in DI. So we need to make sure ax is zero, and it might be smart to cover our bases and set di to zero as well (you
never know if some value had been sitting in it to be confused as an error for our crazy program wlcheck to find and complain about)

so if we set both to zero, then the jne CANNOT ever jump out and we stay long enough for us to set the AX flag and go along happily.

it just so happens that there is a simple way to set any variable to zero (if you are familiar with assembly, ignore this, i am putting this in here for those who havent become as familiar with it as the rest of
us - this is a tutorial after all isnt it?)

xor ax, ax <--- sets ax to zero


xor di, di <--- sets di to zero

if you are lazy like i am, you can search your dead listing for both (the listing is so large, that you can probably find examples of many byte values that you need)

it turns out that the values are:

33 C0 xor ax, ax
33 FF xor di, di

and here's how our code will look:

:0001.3F86 9AFFFF0000 call KSLHOOKS.Ord{0038h}

:0001.3F8B 33C0 xor ax, ax


:0001.3F8D 33FF xor di, di

:0001.3F8F 750F jne 3FA0

:0001.3F91 B80100 mov ax, 0001


:0001.3F94 C45E06 les bx, [bp+06]
:0001.3F97 268987A400 mov es:[bx+00A4], ax
:0001.3F9C E9D600 jmp 4075

simply enough, now we just need to make the changes in the wlccomm.dll

*****************************************************

Crack for 16-bit wlcheck by +gthorne of the +HCU:

pop into your favorite hex editor and load WLCCOMM.DLL


(File Size: 46,960 bytes)

search for byte pattern:


8BF80BF8750F

replace with:
33C033FF750F

and run it...


it is registered!
----------------------------------------------------------
Note for showoffs:

If you wish it to say that it is registered to you, go to the about box, and run the "registration" part of the program BEFORE you crack it, entering data in the order form as you want it to be registered.

The target stores this info in the windows directory, in the file: WLCHECK.ORD. After cracking, that info is displayed proudly in the about box.
*****************************************************

None of the many changes listed at the beginning of this section are necessary now, not since we have a good, clean crack.

21
Don't disregard the work though, some programs I've seen are defeatable with the kind of work done before the register flag was found.

If this were a program with no flag to register, it would have REQUIRED all that work anyway, and then some.

********************************************
wlcheck for windows 95
********************************************

Ok, building on my fellow +cracker's good work it was pretty easy to defeat the Win'95 protection, which follows the same lines as the 16 bit one above... I lost some time on a stupid beta version of
wlcheck for win 95, that I had inside my collection though... how stupid. This will teach me to ALWAYS work methodically. Therefore:

FIRST OF ALL
perform an archie or ftp search for wlck95, you'll find a whole bunch of servers carrying it, choose a ftp-server near you and get it ftpmailed to you or download it (as you prefer).

You'll soon find all the relevant data:


WLCHK955.ZIP 213.156 bytes

SECOND
You have it, unzip it and examine it:

FILE_ID DIZ 438 23/08/96 5:10 FILE_ID.DIZ


WLCHK95 EXE 70.656 23/08/96 5:10 WLCHK95.EXE
KSLHKS95 DLL 52.224 21/08/96 1:00 KSLHKS95.DLL
WMCHK95 EXE 63.488 23/08/96 5:10 WMCHK95.EXE
WLCHK95 HLP 33.759 23/08/96 5:10 WLCHK95.HLP
WFCHK95 EXE 77.824 23/08/96 5:10 WFCHK95.EXE
WMCHK95 HLP 32.463 23/08/96 5:10 WMCHK95.HLP
WFCHK95 HLP 29.696 23/08/96 5:10 WFCHK95.HLP
README TXT 8.689 23/08/96 5:10 README.TXT
WLCCOM95 DLL 73.216 26/03/97 20:11 WLCCOM95.DLL

(ignore the date of the last dll, that's just because I tampered with it yesterday).

THIRD
Using what we have learned (quite a lot) let's work on wlccom95.dll: here the relevant part of the dead listing:

* Referenced by a Jump at Address:|:1C005B50(C)


|
:1C005B76 C685C3FBFFFF05 mov byte ptr [ebp+FFFFFBC3], 05
:1C005B7D C685C4FBFFFF01 mov byte ptr [ebp+FFFFFBC4], 01
:1C005B84 66C785DDFBFFFF1500 mov word ptr [ebp+FFFFFBDD], 0015
:1C005B8D C685DFFBFFFF01 mov byte ptr [ebp+FFFFFBDF], 01
:1C005B94 C685E0FBFFFF01 mov byte ptr [ebp+FFFFFBE0], 01
:1C005B9B C6853EFCFFFF15 mov byte ptr [ebp+FFFFFC3E], 15
:1C005BA2 8B450C mov eax, [ebp+0C]
:1C005BA5 66C780A80000000000 mov word ptr [ebx+000000A8], 0000
:1C005BAE 8D8598FAFFFF lea eax, [ebp+FFFFFA98]
:1C005BB4 50 push eax

* Reference To: kslhks95._KslHookProc1@4, Ord:0000h


|
:1C005BB5 E872420000 Call 1C009E2C
:1C005BBA 66894598 mov [ebp-68], ax
:1C005BBE 0FBF4598 movsx word ptr eax, [ebp-68]
:1C005BC2 85C0 test eax, eax
:1C005BC4 0F8516000000 jne 1C005BE0
:1C005BCA 8B450C mov eax, [ebp+0C]
:1C005BCD 66C780A80000000100 mov word ptr [ebx+000000A8], 0001
:1C005BD6 B801000000 mov eax, 00000001
:1C005BDB E946010000 jmp 1C005D26

* Referenced by a Jump at Address: |:1C005BC4(C)


|
:1C005BE0 0FBF4598 movsx word ptr eax, [ebp-68]
:1C005BE4 83F80A cmp eax, 0000000A
:1C005BE7 0F8516000000 jne 1C005C03
:1C005BED 6A40 push 00000040

* Possible StringData Ref from Data Obj ->"License Expired"


|
:1C005BEF 6828E8001C push 1C00E828

* Possible StringData Ref from Data Obj ->"An upgrade is required. Continuing "
->"as shareware only."
|
:1C005BF4 6838E8001C push 1C00E838
:1C005BF9 8B4508 mov eax, [ebp+08]
:1C005BFC 50 push eax

* Reference To: USER32.MessageBoxA, Ord:0188h


|
:1C005BFD FF151C04011C Call dword ptr [1C01041C]

* Referenced by a Jump at Address:|:1C005BE7(C)


|
:1C005C03 0FBF4598 movsx word ptr eax, [ebp-68]
:1C005C07 83F807 cmp eax, 00000007
:1C005C0A 0F8516000000 jne 1C005C26
:1C005C10 6A40 push 00000040

* Possible StringData Ref from Data Obj ->"License Violated"


|
:1C005C12 6870E8001C push 1C00E870

* Possible StringData Ref from Data Obj ->"The license file has been changed. "
->"Continuing as shareware only."
|
:1C005C17 6884E8001C push 1C00E884
:1C005C1C 8B4508 mov eax, [ebp+08]
:1C005C1F 50 push eax

* Reference To: USER32.MessageBoxA, Ord:0188h


|
:1C005C20 FF151C04011C Call dword ptr [1C01041C]

* Referenced by a Jump at Address:|:1C005C0A(C)


|
:1C005C26 0FBF4598 movsx word ptr eax, [ebp-68]
:1C005C2A 83F808 cmp eax, 00000008
:1C005C2D 0F8516000000 jne 1C005C49
:1C005C33 6A40 push 00000040

* Possible StringData Ref from Data Obj ->"License Violated"


|
:1C005C35 68C8E8001C push 1C00E8C8

22
* Possible StringData Ref from Data Obj ->"This seems to be an unlicensed "
->"copy. Continuing as shareware "
->"only."
|
:1C005C3A 68DCE8001C push 1C00E8DC
:1C005C3F 8B4508 mov eax, [ebp+08]
:1C005C42 50 push eax

* Reference To: USER32.MessageBoxA, Ord:0188h


|
:1C005C43 FF151C04011C Call dword ptr [1C01041C]

* Referenced by a Jump at Address:|:1C005C2D(C)


|
:1C005C49 8D8598FAFFFF lea eax, [ebp+FFFFFA98]
:1C005C4F 50 push eax

* Reference To: kslhks95._KslHookProc2@4, Ord:0001h


|
:1C005C50 E8D1410000 Call 1C009E26
:1C005C55 66894598 mov [ebp-68], ax
:1C005C59 33C0 xor eax, eax
:1C005C5B 8A853EFCFFFF mov al , [ebp+FFFFFC3E]
:1C005C61 83F80D cmp eax, 0000000D
:1C005C64 0F8536000000 jne 1C005CA0

* Possible StringData Ref from Data Obj ->"Link Check evaluation license "
->"has expired."
|
:1C005C6A 6820E9001C push 1C00E920
:1C005C6F 8D459C lea eax, [ebp-64]
:1C005C72 50 push eax
:1C005C73 E871030000 call 1C005FE9
:1C005C78 83C408 add esp, 00000008
:1C005C7B 6A10 push 00000010

* Possible StringData Ref from Data Obj ->"License Expiry"


|
:1C005C7D 684CE9001C push 1C00E94C
:1C005C82 8D459C lea eax, [ebp-64]
:1C005C85 50 push eax
:1C005C86 8B4508 mov eax, [ebp+08]
:1C005C89 50 push eax

* Reference To: USER32.MessageBoxA, Ord:0188h


|
:1C005C8A FF151C04011C Call dword ptr [1C01041C]
:1C005C90 8B450C mov eax, [ebp+0C]
:1C005C93 50 push eax
:1C005C94 E857E3FFFF call 1C003FF0
:1C005C99 33C0 xor eax, eax
:1C005C9B E986000000 jmp 1C005D26

* Referenced by a Jump at Address:|:1C005C64(C)


|
:1C005CA0 0FBF4598 movsx word ptr eax, [ebp-68]
:1C005CA4 83F804 cmp eax, 00000004
:1C005CA7 0F8536000000 jne 1C005CE3

* Possible StringData Ref from Data Obj ->"This is an old version,"


|
:1C005CAD 685CE9001C push 1C00E95C
:1C005CB2 8D459C lea eax, [ebp-64]
:1C005CB5 50 push eax
:1C005CB6 E82E030000 call 1C005FE9
:1C005CBB 83C408 add esp, 00000008
:1C005CBE 6A10 push 00000010

* Possible StringData Ref from Data Obj ->"License Violation"


|
:1C005CC0 6874E9001C push 1C00E974
:1C005CC5 8D459C lea eax, [ebp-64]
:1C005CC8 50 push eax
:1C005CC9 8B4508 mov eax, [ebp+08]
:1C005CCC 50 push eax

* Reference To: USER32.MessageBoxA, Ord:0188h


|
:1C005CCD FF151C04011C Call dword ptr [1C01041C]
:1C005CD3 8B450C mov eax, [ebp+0C]
:1C005CD6 50 push eax
:1C005CD7 E814E3FFFF call 1C003FF0
:1C005CDC 33C0 xor eax, eax
:1C005CDE E943000000 jmp 1C005D26

* Referenced by a Jump at Address:|:1C005CA7(C)


|
:1C005CE3 0FBF4598 movsx word ptr eax, [ebp-68]
:1C005CE7 85C0 test eax, eax
:1C005CE9 0F8D2D000000 jnl 1C005D1C

* Possible StringData Ref from Data Obj ->"An unexpected error has occurred."
|
:1C005CEF 6888E9001C push 1C00E988
:1C005CF4 8D459C lea eax, [ebp-64]
:1C005CF7 50 push eax
:1C005CF8 E8EC020000 call 1C005FE9
:1C005CFD 83C408 add esp, 00000008
:1C005D00 6A10 push 00000010

* Possible StringData Ref from Data Obj ->"System Error"


|
:1C005D02 68ACE9001C push 1C00E9AC
:1C005D07 8D459C lea eax, [ebp-64]
:1C005D0A 50 push eax
:1C005D0B 8B4508 mov eax, [ebp+08]
:1C005D0E 50 push eax

* Reference To: USER32.MessageBoxA, Ord:0188h


|
:1C005D0F FF151C04011C Call dword ptr [1C01041C]
:1C005D15 33C0 xor eax, eax
:1C005D17 E90A000000 jmp 1C005D26

* Referenced by a Jump at Address:|:1C005CE9(C)


|

23
:1C005D1C B801000000 mov eax, 00000001
:1C005D21 E900000000 jmp 1C005D26

* Referenced by a Jump at Addresses:|:1C005BDB(U),


:1C005C9B(U), :1C005CDE(U), :1C005D17(U), :1C005D21(U)
|
:1C005D26 5F pop edi
:1C005D27 5E pop esi
:1C005D28 5B pop ebx
:1C005D29 C9 leave
:1C005D2A C20800 ret 0008
*******************************************
OK! let's crack...
Well it's all pretty obvious:
After having prepared the call with a lot of parameters

:1C005B76 C685C3FBFFFF05 mov byte ptr [ebp+FFFFFBC3], 05


:1C005B7D C685C4FBFFFF01 mov byte ptr [ebp+FFFFFBC4], 01
:1C005B84 66C785DDFBFFFF1500 mov word ptr [ebp+FFFFFBDD], 0015
:1C005B8D C685DFFBFFFF01 mov byte ptr [ebp+FFFFFBDF], 01
:1C005B94 C685E0FBFFFF01 mov byte ptr [ebp+FFFFFBE0], 01
:1C005B9B C6853EFCFFFF15 mov byte ptr [ebp+FFFFFC3E], 15

note the two x15 parameters... that will of course be the 21 days limit... well, our target calls the kslhks95._KslHookProc1@4 function with all its params and upon return the 32 bit version uses the SAME
protection scheme used in the 16 bit one: it has an "evil" and a "good" jump:

* Reference To: kslhks95._KslHookProc1@4, Ord:0000h


|
:1C005BB5 E872420000 Call 1C009E2C
:1C005BBA 66894598 mov [ebp-68], ax
:1C005BBE 0FBF4598 movsx word ptr eax, [ebp-68]
:1C005BC2 85C0 test eax, eax ;is it zero?
:1C005BC4 0F8516000000 EVIL jne 1C005BE0 ;not 0: bagger off
:1C005BCA 8B450C mov eax, [ebp+0C]
:1C005BCD 66C780A80000000100 mov word ptr [ebx+000000A8], 0001 ;OK, guy
:1C005BD6 B801000000 mov eax, 00000001 ;eat another good flag
:1C005BDB E946010000 HOLY jmp 1C005D26 ;and be happy for ever

if you throw another look at the listing you'll see all the nasty messages following the evil jump

* Referenced by a Jump at Address: |:1C005BC4(C)


|
:1C005BE0 0FBF4598 movsx word ptr eax, [ebp-68]
:1C005BE4 83F80A cmp eax, 0000000A

and the subsequent compare eax ARE intersting, they give you an exact look upon the inner working of our target: here

eax=A means "License expired"


eax=7 means "License violated" (changed)
eax=8 means "License violated" (unlicensed)
eax=4 means "old version" etcetera...

as a matter of fact it may well be that the crack we made goes crazy after 21 days (it won't if you push the date around, we checked) use... in that case it will be only a question of "fine tuning" of this crack,
and you already know where the relevant protection scheme dwells... We do not want to wait 21 days just to be absolutely sure that the crack works perfectly... so it seems, and so it should be... should it have
another check somewhere (that I do not see now), I promise you that you'll find the crack for it in three weeks time, but I'm pretty sure you will not need it :-)

Well, we learned a lot:

Time/Disabling protections may vary a lot, but even in apparently very complicated schemes (like the wlcheck one), wich do tamper with a lot of more or less hidden files, there can be a very simple
"hollow" point, where you can cut mustard with a neat targeted crack... you need to understand and to "feel" a little the program, though, and I'm now beginning to understand what +ORC means with his zen
mystique of "feeling" the code.

So here is the simple crack for wlcheck 32 bits:

search for

:1C005BC2 85C0 test eax, eax


:1C005BC4 0F8516000000 jne 1C005BE0
:1C005BCA 8B450C mov eax, [ebp+0C]
:1C005BCD 66C780A80000000100 mov word ptr [ebx+000000A8], 0001

85C00F8516000000
and at the third occurrence of it (well, if you want -instead of searching the third occurrence of that string- to type a long string... then search directly for the whole set
85C00F85160000008B450C66C780A80000000100) do as you like, as far as you land where you should:

:1C005BC2 85C0 test eax, eax


:1C005BC4 0F8516000000 jne 1C005BE0

it's the time to crack your target! Noop the first 8 bytes out, that is from 85C0 until the three subsequent zeros of instruction :1C005BC2 ... you may even use the nop=90x instruction like the lamers if you
fancy... here there is absolutely no checking-protection that examine eventual patchings... noop as you like.
***************************************
Thinking about it we believe that the aim of this first lesson of the "4" series from +ORC was the following: +he found an apparently overcomplicated protection only to show us that, hidden behind
everything, a single neat crack was needed... as the fellow +cracker of the 16 bit version observed, +he gave us a single (but decisive) hint: he spoke about the second occurrence of the 15x byte, which proved
decisive -as you already did read- in individuating the "hollow" point of our target.

As this lesson 4.1 was intended as second "+HCU" lesson, we believe (and hope) that in finding the neat cracks for the 16 and the 32 bit versions of wlcheck (which is a damn useful program in our trade,
btw) we have accomplished our task.

Now a question arises:

Should really all time protections be variations of this scheme? (we do not know... we are awaiting the next "4" lesson of +ORC like everybody else). In that case there is not a single program (now) able to
elude us :-)

Another system: inside win.ini:


[License]
Installed=854824551
Expires=857416551
LastUsed=854824717
i.e. calculated in seconds,
Where 30 days allowance is 857416551 - 854824551 = 2592000
2592000/30 = 86400 (one day)
86400/24 = 3600 (one hour)
3600/60 = 60 (one minute)

Well, that's it for this lesson, reader. Not all lessons of my tutorial are -or will be- on the Web.

You'll obtain the missing lessons IF AND ONLY IF you mail me back (via anon.penet.fi) with some tricks of the trade I may not know that YOU discovered. Mostly I'll actually know them already, but if they
are really new you'll be given full credit, and even if they are not, should I judge that you "rediscovered" them with your work, or that you actually did good work on them, I'll send you the remaining lessons
nevertheless. Your suggestions and critics on the whole crap I wrote are also welcomed. Do not annoy me with requests for warez, everything is on the Web, learn how to search, for Jimmy Olden sake.

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

+ORC na526164@anon.penet.fi

Lesson 5.1: Disk & CD-Rom access (basics)

24
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
MOV DS,AX
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 vectors.

25
REAL DISK ACCESS STUFF
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 trick).

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 track.
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 floppies:

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&#248; 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 table.

[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&#248; 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.

[CRC]
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).

26
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.

LOADING ABSOLUTE DISK SECTORS


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 retries.

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 welcomed.

+ORC an526164@anon.penet.fi

LESSON 6 (1) - Funny tricks. Xoring, Junking, Sliding

27
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 get:

:protection_loop
: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 idea?
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: encrypt_decrypt:

mov bx, offset_where_encryption/decryption_starts


xor_loop:
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!) random_value:

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:

-----> JUNK FILLING, SLIDING KEYS AND MUTATING DECRYPTORS


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

* ULTRAPROTECTED
* TIGHT AND EFFECTIVE
* CLOAKED AND CONCEALED.

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 loop.

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

28
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 parts:

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 time.

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 techniques.

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.

[PATENTED PROTECTION SYSTEMS]


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 storage.

[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.

ELEMENTS OF [PGP] CRACKING


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

29
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 language.

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.

[THE "STEGONATED" PASSWORD HIDEOUT]


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 media.

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 welcomed.

an526164@anon.penet.fi (+ORC)

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".
---------------------------------------------------------

-> 1st THING TO REMEMBER


The NE format does give every windows executable the equivalent of a debug symbol table: A CRACKER BLISS!

-> UNDOCUMENTED DEBUGGING


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!)

30
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
information.

----------------- 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,
MECHANIC and ECOLOGIST

----------------- 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
informations.
[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.

-> INSIDE A WINDOWS '95 DEBUGGER


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 stepping.

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 program.

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 information.

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.

SO, I WANNA CRACK, WHAT SHOULD I DO?


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 crack).

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 13.081B.

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]

31
13.0EA8 7505 jne 0EAF <- beggar_off
13.0EAA B80100 mov ax, 0001 <- flag 1 = "Right!"
13.0EAD EB04 jmp 0EB3 <- and go on beggar_off:
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 welcomed.

+ORC 526164@anon.penet.fi

Lesson 8.2: How to crack Windows, a deeper 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".
---------------------------------------------------------

-> 1st THING TO REMEMBER


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.

WINDOWS 3.1. basic cracking: [ALGEBRAIC PROTECTIONS]


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)
* BMSG 091C WM_GETTEXT
* 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 possibilities...
* 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
:ok_it's_a_+_or_a_-
XOR EBX,EBX ; EBX is zeroed
MOV BL,[ESI] ; recharge BL
INC ESI ; point to next char (do not check - or +)
:Jesus_it's_neither_a_minus_nor_a_plus_let's_check_it
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

USER!BOZOSLIVEHERE
KERNEL!HMEMCPY
USER!GLOBALGETATOMNAME

Windows wretched and detestable APIs used for copy protections, as usual with WINICE cracking, and as described elsewhere in my tutorial.

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?

32
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).

WHERE ARE THE CODES? WHERE ARE THE MODIFIED FILES? WHERE DO THE PROTECTIONS KEEP COUNT OF THE PASSING DAYS?
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 me):
[WinZip]
name=Azert Qwerty
sn=########
version=5.5

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.

HOW TO CRACK INFORMATION [WHERE WHAT]


* INTERNET
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 TO THROW AWAY TONS OF JUNK, HOW TO SECLUDE MYRIADS OF USELESS INFORMATION and HOW TO FISH RARE
USEFUL INFORMATION, a very 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.

* SOME (RARE) NEWSPAPERS.


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 watch

Lesson 9 (1): How to crack Windows, Hands on


[Winformant][Snap32]

THE [DATA_CONSTRAINT] TRICK - [WINFORMANT 4]


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 :=)

[WINFORMANT CRACKING]
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 relationships
between USER INPUT NUMBER, USER INPUT TRANSFORMED 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

33
== CTL3D(02) at 2C3F:24BE [?] through 04A7:3A3Cæ

Beautiful stack fishing! Do immediately a BPX on babe:EA20.

2C7F:EA35 9A25ABA704 CALL USER!GETWINDOWTEXT


2C7F:EA3A 8D46AE LEA AX,[BP-52] ;load ptr "+ORC+ORC"
2C7F:EA3D 16 PUSH SS ;save pointer segment
2C7F:EA3E 50 PUSH AX ;save pointer offset
2C7F:EA3F 9A768D872C CALL 2C87:8D76; 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...

BUT NOW IT'S THE "MAGIC MOMENT" OF THE ECHO! We know and *feel* 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 NAMEString - TRANSFORM NAMEString


LOAD CODEString - COUNT CODEStringLen
LOAD CODEString
*ECHO must be here*
TRANSFORM CODEString
*ECHO must be here*
COMPARE TRANSFORMED_NAMEString WITH TRANSFORMED_CODEString

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 pickpockets.

- 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.

[CRACKING SNAP 32]


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:

1) SEE THE NAME OF YOUR BABE AND ITS QUEUE SELECTOR


: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.

34
2) SEE THE MODULES OF YOUR BABE:
: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).

3) SEE THE HANDLE OF THE PROTECTION "NAG" WINDOW


: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.

5)RUN THE PROGRAM TO THE BREAKPOINT:


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.

7) BREAKPOINT ON MEMORY RANGE ON THIS STRING.


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 KERNEL!HMEMCPY (+0076):

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'):

:check_if_valid
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
:strip_-_&_+_signs
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

35
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 it.

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).

8.4.) COMPARING THE MAGICS FROM THE TWO INPUT STRING


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:

Cracked=Dec(0x7C25621B)
Cracked=2082824731

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.

HOW TO SEARCH THE INTERNET FOR FILES WITHOUT MOVING A FINGER


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 131.130.1.23 Austria


archie.belnet.be 193.190.248.18 Belgium
archie.funet.fi 128.214.6.102 Finland
archie.univ-rennes1.fr 129.20.254.2 France
archie.th-darmstadt.de 130.83.22.1 Germany
archie.ac.il 132.65.16.8 Israel
archie.unipi.it 131.114.21.10 Italy
archie.uninett.no 128.39.2.20 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 (137.208.8.6)


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 (18.75.0.10)
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)

36
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
it?

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 forces)
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 welcomed.

+ORC an526164@anon.penet.fi

LESSON 9 (2) - How to Wincrack, Hands on


Nagscreens galore: The Paint Shop Pro crack (part A)

Merry Xmas. We'll learn, beginning with this lesson, how to eliminate the "nagscreens", i.e. the protection and or annoying schemes that many commercial and shareware windows programs use in order to
annoy us and push lusers to buy them. In order to understand (simple) nag screen deprotection we'll crack following different approaches Paint Shop Pro, the de facto standard used to day for graphic
manipulation. It's a good choice, I believe, because

- it's a very widespread application:


you'll surely have some copies of it on your CD-ROMs, and you'll find many copies on the Web (albeit not cracked ones until now: the only cracks I am aware of are patches that simulate the
user clicking on the OK button of the nagscreen, thus closing it, but not eliminating it).

- this application has many older versions:


I want to teach you here also a "general" approach strategy that you should often follow when (and if) you'll start higher cracking: the *very* important study of the "embryology" of the software
you want to crack. The long history trail of the "ancient" copies of your target will help you a lot to understand its evolution and the parallel evolution of its protection scheme ("Historia lux veritatis...
magistra vitae", hope you did not forget your Cicero :=)

The case of the nagscreen evolution of PSP is particularly evident:

1) static nagscreen ;1993, Ver. 2.0, PSP.EXE = 525.520 bytes


2) daycount added ;1994, Ver. 3.0, 861.856 bytes
3) delayed OK focus ;1995, Ver. 3.2-32, 1.042.944 bytes
4) ported to Win95 ;1996, Ver. 4.1, 1.151.488 bytes

In the meantime many functions have been added to the program whose size has broken all limits.

Let's begin our crack with the oldest copy of Paint Shop Pro i could find: I want to stress that knowledge of history is very important (there should be a faculty of "software history" in all great universities,
there will be of course one in my +HCU). I'll use the old SHAREWARE version 2.01, whose file PSP.EXE has a length of 525520 bytes and is dated 15 november 1993.

Just to make a comparison, version 3.0 has a PSP.EXE file of 861856 bytes, and is dated 4 march 1995, version 3.12-32 (Win31) has a PSP.EXE length of 1.042.944 bytes, and is dated 27 december
1995 and version 4.1 for windows 95 has a PSP.EXE with much too many bytes which is dated 1 september 1996: a classical example of overbloated programming language involution.

Version after version JASC incorporated added the "counter" that reminds you how many days you have been using this program, telling you to register it after 30 days. This nagscreen is by far and large
not particularly annoying, JASC has been pretty correct (compared with other nagscreens used by less interesting but more preposterous software). Nevertheless we do not like nagscreens all the same, coz we
want to enjoy all programs, commercial or not, without paying any money at all and without silly nagscreens or reminders of any sort (all sort of goods should be free in my opinion, not only software: I think I am a
sort of "aristocratic communist": I believe that private property is a theft -of course- and that everybody should have -at least- a sail Yacht, good books, a lot of caviar and good Wodka-Martinis in crystal glasses
without paying anything at all: all this should be completely free in order to allow each one to concentrate on interesting activities like wind watching, poetry, micro-ethology, study of the colours, cracking, ancient
rhetoric et cetera).

Anyway, in this old PSP, version 2.01, there was in the nagscreen no day counter yet ("you are on day xx of your 30 days..."), a "static" nagscreen, the whole program is still very "basic", nobody would
have said, looking at this midget, that Jasc could have evolved this embryo of a program, in three years, in the de- facto standard graphic manipulation program that we know to day (december 1996).

Let's crack: We fire our Winice (I will not explain any more why you should use Winice: buy (or codebar) a "real" copy of it or else find all three cracked copies, DOS, WIN31 and WIN95, on the Web. Then
learn how to use it well: this tool is the alpha and omega of cracking... I am using for this lesson a Windows 3.1 computer with my Winice for Windows 3.1, version 1.3, cracked by the ubiquitous Marquis de
Soiree).

We begin now, Winice lurks already behind Windows, Microsoft abomination has already been started, a cool breeze blows outside, I fire PSP 2.1.

We'll use in this lesson a couple of different approaches to code pinpointing: you'll remember that we could have done our three steps basic approach, as usual (always working, but at times slower or more
inaccurate than other approaches):

1)task
2)hwnd
3)bmsg relevant_window wm_gettext sequence of commands, as follows

1)
:task
TaskName SS:SP StTop StBot StLow TaskDB hQueue Events
PROGMAN 1727:200A 0936 2070 1426 066F 07F7 0000
PSP * 1D27:D826 9654 D9BE D132 11EF 11D7 0000

37
2)
:hwnd psp
Window Handle hQueue QOwner Class Name Window Procedure
0EB4(0) 11D7 PSP #32769 04A7:9E6B
25B8(1) 11D7 PSP Histogram 1197:07E8
2090(1) 11D7 PSP #32770 1D07:120E
20F0(2) 11D7 PSP Static 1D07:38A6
2138(2) 11D7 PSP Static 1D07:38A6
2180(2) 11D7 PSP Static 1D07:38A6
21D8(2) 11D7 PSP Static 1D07:38A6
2230(2) 11D7 PSP Static 1D07:38A6
2298(2) 11D7 PSP Static 1D07:38A6
22F0(2) 11D7 PSP Button 1D07:2876
2344(2) 11D7 PSP Button 1D07:2876
2398(2) 11D7 PSP Static 1D07:38A6
23F0(2) 11D7 PSP Static 1D07:38A6
2448(2) 11D7 PSP Static 1D07:38A6
24A0(2) 11D7 PSP Static 1D07:38A6
... (and more handles, the segment numbers may obviously differ
from yours)

Since the two "buttons" are the OK and CANCEL buttons inside the
nag screen, we can immediately pinpoint the code with a
3)
:bmsg 22F0 wm_gettext command, which would fire back winice as soon as we click the OK button. You'll please also notice from the hwnd list above that the window #32770 has 6 small "text"
windows inside and two
buttons, that the window procedure for the main nag window is at 1D07:120E, the procedures for text are at 1D07:38A6 and the procedures for the buttons are at 1D07:2876.

We'll come back on this approach later. It's the typical pinpointing used for password protection schemes, as we have seen in the password lessons, but this approach is NOT the best one for nagscreens.

Let's follow now another approach: let's find the nagstrings in the parts of PSP that contains DATA (as opposed to CODE), the :heap command will help us: it's the standard command to understand the
STRUCTURE in memory of your deployed applications, you'll use it a lot for nagscreen cracking and for time limits deprotections.

:heap psp ; we know from :task that the name is "PSP"


Han./Sel Address Length Owner Type Seg/Rsrc
1C37 00027980 00000040 PSP Alloc
0876 000279C0 00000020 PSP Resource IconGrp
1FFE 806EC760 000010A0 PSP Code 03
1BA6 LH 806B2000 0000E9E0 PSP Data 90
2016 807CC340 00003C60 PSP Code 01
200E 80774780 00002940 PSP Code 02
... (many more handles)

As you can see doing your listing, there is only one data block, E9E0 bytes long, at 806B2000. Have a look at the code blocks, though, many of them, as you'll see, have a little "D" after the type CODE, as
you'll use often and often this :heap command to crack protection schemes in the future, you may as well learn right now that these are (most of the time) uninteresting for cracking purposes.

If we now pinpoint this code with a bpr RW on part of the text that the nagscreen displays, we'll land in the middle of the routine that copies this text in various memory locations, each time PSP runs:

:bpr 30:806B2150 30:806B2170 RW

Let's start PSP once more and we'll land here inside winice:
011F:00007A1B D1E9 SHR CX,1
011F:00007A1D F366A5 REPZ MOVSD ;this writes in 806B1250
011F:00007A20 8BC8 MOV CX,AX
011F:00007A22 83E103 AND CX,+03
011F:00007A25 F3A4 REPZ MOVSB

Hope that my readers DO remember that REPZ is repeat string manipulation until cx=0 and that MOVSD moves strings by doublewords, from ds:si to es:di, updating si and di.

We are here in the piece of the main windows KERNEL module, responsible for setting up this part of PSP.

Now things start getting interesting: if you make a search for the string 'freeware' (contained in the nagscreen of PSP) before loading psp you'll get as location only the echoes of your own search string:

:s 30:0 lffffffff 'freeware'


Pattern found at 0030:007DBA58
0030:008E107F
0030:008E1867
0030:008E601A
If you search the same string after the KERNEL's has finished copying around PSP code (as we saw above) you'll fetch quite a lot of locations:

:s 30:0 lffffffff 'freeware'


Pattern found at 0030:0066242D
0030:007DBA58 ;echo
0030:007DBFCA
0030:008E107F ;echo
0030:008E12A8
0030:008E1867 ;echo
0030:008E601A ;echo
0030:009EDF4D
0030:806A4F4D

The last one is the more interesting one, being above 80000000. But, hey, how comes that the 'freeware' text occurrence at 30:806B2170 (the one we breakpointed into) has not been found? It's an
interesting point, and you could now obviously bpr RW all the relevant locations to trace backward to the "culprit" code section of PSP, the one setting up the nagscreen that we want to eliminate.

But we'll now leave even this second approach and follow a third and better one for nagscreen deprotection: the "stack_crack" technique (I want to show you the MANY possibilities that we have for
cracking these programs.

As everybody (should) know, every time a child window (or a pop- up window) is created, the function that must be invoked is HWND CreateWindow, which is called by virtually all windows programs. This
function specifies the window's class, title and style, and may also determine the window's initial screen location and size. This function returns the handle to the newly created window. It's a general purpose API
function with this structure:

HWND CreateWindow(LPCSTR lpszClassName, LPCSTR lpszWindowName,


DWORD dwStyle, int iX, int iY, int iWidth,
int iHeight, HWND hPArent, HMENU hMenu,
HINSTANCE hINst, void FAR *lpvData)

And, for those of you that do not know nothing, lpszClassNAme points to a character string naming the window's class and lpszWindowName points to a character string identifying the window by name,
which is pretty useful for us little crackers... you should study a little this kind of stuff, just to make an example, do you know that EDIT Class control style ES_PASSWORD displays all typed characters as asterisk
symbols? (Whereby setting EM_SETPASSWORDCHAR to zero will print the password echo on the display, but this is stuff for another lesson :=)

Let's work with the breakpoint on the CreateWindow function we have seen above, obviously, now that you know all the parameters, you could as well change the position of the nagscreen (iX, iY, iWidth...)
instead of removing it.

:bpx CreateWindow

And now let's fire PSP, look at the screen! We pop in winice 5 times before the relevant moment (i.e. just before the nagscreen). Therefore we change our breakpoint, setting the occurrence "6" for the
counter:

:bpx USER!CREATEWINDOW C=06

Now we fire PSP once more and this time we look at the stack as soon as we pop inside Winice, because we know that the last CreateWindow has created the nagscreen and we want to know where is
the "culprit" section of PSP code:

:stack
PSP(05) at 1EF7:00AF [?] through 1EF7:00AF

38
PSP(05) at 1EF7:1094 [?] through 1EF7:1076
PSP(01) at 1F3F:0598 [?] through 1F3F:0000
PSP(8A) at 1F0F:0024 [?] through 1F0F:0000
USER(19) at 073F:099B [?] through USER!DIALOGBOX
USER(19) at 073F:0A31 [?] through 073F:09A3
USER(19) at 073F:07FC [?] through 073F:0737
PSP(01) at 1F3F:0BC0 [?] through 1F3F:0BC0
PSP(02) at 1F2F:0DF7 [?] through 1F2F:0000
=> USER!CREATEWINDOW at 06B7:0F1B [?] through 1EBF:0052

That's nice music for us! Let's have a deep look at these pretty data: See! The last CreateWindow occurrence is called by Segment 02 of the PSP code (you remember the :heap PSP command listing, we
made for the first approach, if not do it now: the heap listing will show you the complete structure in memory of your target)...

and yes, let's have a look at segment 2, the locations around


DF7: here the relevant section of code:

1F2F:00000DEB 90 NOP
1F2F:00000DEC 687A70 PUSH 707A
1F2F:00000DEF FF36068F PUSH WORD PTR [8F06]
1F2F:00000DF3 FF36FC70 PUSH WORD PTR [70FC]
1F2F:00000DF7 9A5200BF1E CALL 1EBF:0052 ;call the bazaar

Following this last call, we land in the USER(19) code section of windows USER module, which sets up a child window (in this case the nag screen) and then waits for user's mouse clicks.

073F:0000083E 56 PUSH SI
073F:0000083F 6A01 PUSH 01
073F:00000841 9AF20BE706 CALL 06E7:0BF2 ;makes the nagframe
073F:00000846 56 PUSH SI
073F:00000847 9A0444A704 CALL 04A7:4404 ;writes the nagtext
073F:0000084C 3936E200 CMP [00E2],SI

But USER should obviously not be cracked (well, you could, but not here... see the lesson about windows "guts": KERNEL, USER and GDI and the possibilities you get cracking them directly), but here our
culprit protection scheme must of course dwell inside the PSP code... therefore let's now have another look at the task list we found breakpointing on CreateWindow.

All the three user(19) codes are USER module's routines, let's see... where should we cut mustard with our crack? Obviously BEFORE the call to USER(19), also either in PSP(8A), or in PSP(01) or in
PSP(05).

Three possibilities:

1) Study a disassembled listing.


A nice disassembly listing can be very helpful for our cracks (through good old WCB or through WDASM, cracked copies of all these nice disassemblers are on the Web). Useless an d tedious in this case.

2) Have a direct look.


There are in this case only three sections of code, just have a look at them and find in which one triggers the protection. Useless an d tedious in this case.

3) -Always better- use a little zen.


Relax, sip a Martini-Wodka (be careful: only Moskowskaja will do, do not exceed the correct amount of Schweppes' indian tonic) and look once more at the :heap PSP listing. See? Segment 8A of PSP
code is only A0 bytes long, therefore pretty unlikely to yield a protection scheme.

That leaves segments 05 and 01.


Segment 05 does not have enough "run" to hyde a protection scheme (yes, this is zen): as you can recall from our stack listing, the two occurrence of segment 05 have only a zero run (AF-AF) or a very
short one (76-94).

See? Out of the three sections we started with remains only one: code section 01, which is 3C60 bytes long, has sufficient "run" (0-598) and will therefore -for sure- hide inside the protection scheme. Well,
3C60 bytes is quite a long piece of code to examine (even if we started with more than half a million bytes in the first place)... but we do not need to look much around, the protection will be not far away from our
call (for reasons I'll not delve inside here... remember lesson C3 ?). We'll have a look at fifty bytes, and having to sieve less than 100 bytes do not seem to me to represent an unreasonable amount of work in order
to eliminate a nagscreen, nicht wahr?

Let's have a look at the code in segment 1, examining -say- 50 bytes around the locations at segment PSP(01), all info we found using Winice's :heap command:

...
PSP(01) at 1F3F:0598 [?] through 1F97:0000
...
Here the code -through Winice- with my comments:
1F3F:0000056D 0BC0 OR AX,AX ;conditional
1F3F:0000056F 740D JZ 057E ;jump, if not
1F3F:00000571 9AA802BF10 CALL 10BF:02A8 ;this chooses
1F3F:00000576 50 PUSH AX ;the hWnd which
1F3F:00000577 6A04 PUSH 04 ;04=activates
1F3F:00000579 9A3E10E706 CALL USER!SHOWWINDOW ;herein
1F3F:0000057E A1FC70 MOV AX, [70FC] ;now load AX
1F3F:00000581 A30C6F MOV [6F0C],AX ;save a copy
1F3F:00000584 C706FC700000 MOV WORD PTR [70FC],0000 ;clean
1F3F:0000058A 682711 PUSH 1127 ;and load the other
1F3F:0000058D 686601 PUSH 0166 ;parameters for the
1F3F:00000590 686B0A PUSH 0A6B ;call, which are
1F3F:00000593 FF36068F PUSH WORD PTR [70FC] ;all pushed
1F3F:00000597 50 PUSH AX ;on the stack for
1F3F:00000598 9A00005F11 CALL 115F:0000 ;this final call
1F3F:0000059D 83C40A ADD SP,+0A ;Now it's
1F3F:000005A0 0BC0 OR AX,AX ;finished

Well, what do we have here? We have the whole nagscreen procedure at a glance: The call to USER!SHOWWINDOW is a BOOL ShowWindow (HWND hWnd, int iVisFlag) function, which determines the
specified window's visibility state. hWnd is the handle of the window and iVisFlag determines how the window is shown. This function returns true if the window is already visible, false if the window was hidden.
iVisFlag can be one of the SW_ constants, number 4 is activate and display. The program fetches at the previous call the AX parameter and then calls the routine that prepares the nagscreen.

OK, we found it (was pretty easy, as you saw). Now, how do we crack this? There are one hundred thousand ways (an elegant one would be changing the iVisFlag option).

I would suggest something rock solid: putting a JNZ 059D at line 1F3F:0000056D, replacing the JZ 057E on a "two for two" bytes basis, a clean crack.

And loo! It works flawlessly: we fly over the nagscreen. Here is the crack with good old symdeb... you may use symdeb but you may obviously use more "modern" hexeditors, like PSedit (good old DOS) or
Hexworkshop (bloated Windows), you'll find everything on the Web:

*** cracking PSP 2.1 nagscreen *** by +ORC *** dec 1996 ***
ren psp.exe psp.ded ;need a "dead" copy for old symdeb
symdeb psp.ded ;good old symdeb launched
- s (cs+0000):0 Lffff 0B C0 74 0D 9A ;search 1F3F:0000056D etc
xxxx:yyyy ;result from debug
- e xxxx:yyyy+2 75 ;change JZ in JNZ
- e xxxx:yyyy+3 2C ;jump after final call
-w ;write back our changes
-q ;bye symdeb
ren psp.ded psp.exe ;ok, cracked, restore exe
***** see how easy? ******************************************

But we are not finished yet! Let's now come to the real content of this lesson: how you should apply what you have learned on an OLDER copy of the target software to the newer versions of it. We'll crack
now PSP, version 3.0, where the psp.exe file is 861.856 bytes long, this copy dates 4 march 1995, 2 *YEARS* after the older one, it's a newer and improved program, with a lot of functionality.

Now, you would think that we must start anew, breakpointing with a :bpx CreateWindow C=07 (in this case) command? No. They changed a little the routines (here you would be advised to use a :bpx
ShowWindow breakpoint following the same approach). The new nagscreen has been coupled with a daycounter, that reminds your guilty as the days goes by, but the nagscreen schema has not changed much: it
has been hidden this time in Segment PSP30(07), and you would find it -of course- following the abovementioned approach, but what's the point? there is a much quicker way! I'll never repeat it enough:
PROTECTIONISTS ARE STUPID! As usual with people working for money instead than for pleasure, their capacity is severely limited, one of the ugly consequences of the abominable society we are coerced to
live in. This overvbloated monstrosity, PSP30, is nagscreened with the SAME simple schema used in the older versions, therefore you just search and modify it using the SAME patterns (and in the same way) as
before! We'll use now PSEDIT in order to modify this file, symdeb.com is a good tool, but has memory problems when the programs exceed 600.000 bytes (at the times symdeb was made people knew how to
code in assembler and nobody would have ever thought that you needed so much to perform so little).

39
**** Cracking PSP version 3.0, by +ORC *** December 1996
ren psp.exe psp.ded ;always good, even if psedit does not care
psedit psp.ded ;fire your tool
- use F8 (search) to search for hexstring 0BC0740D9A

You'll find three occurrences of it. Looking at the code you'll


immediately realize that the only good one is the third one. Just
modify the JZ 0D sequence in a JNZ 2D sequence (yes one byte more
than in the previous crack, look at the code) and you'll have
done your crack.

F2 ;quit PSEDIT
ren psp.ded psp.exe ;restore exe
**************** pretty easy, wasn't it? ***********************

A little digression: Why do we search for the hexstring 0BC0740D9A and not for a longer string? You may think that a longer search string would have immediatly given us the correct location, and you may
see no point in using a shorter string, which may obviously give us many more useless hits. You would be dead wrong: one byte more (after 9A) and you would not fetch anything at all!

The problem, for those of you that do not know nothing, is that same hexcodes are RELOCATED each time an EXE program compiles in memory (this was true for DOS, for windows there is a real
relocation galore going on behind the scene, one wonders at times that windows get something accomplished at all, given the huge amount of relocations that this overbloated pseudo-OS pushes around.

Choosing a search hexstring you must always be *very* careful: choose search patterns that DO NOT relocate in memory, like OR AX,AX, JZ fixed length, ADD SP,+0C, JL fixed length and so on. Your
searches for hexstrings that do relocate will not harvest anything at all. Never. HAve a good look at the following code examples, you'll recognize immediately that only the third (and last) occurrence of our search
string is the correct one: it is the only one that shows "later on" shows the correct instruction sequence (the later three moves and five PUSHES we have seen in the listing for PSP 2.1 above).

Let's have a look at the three occurrences of our search string inside PSP30:

Occurrence 1 of search string 0BC0740D9A inside PSP30:


1CEF:0000B8E3 0BC0 OR AX,AX ;checks previous call
1CEF:0000B8E5 740D JZ B8F4 ;it's zero, forget show
1CEF:0000B8E7 9AE413671C CALL 1C67:13E4 ;new call to fetch
1CEF:0000B8EC 50 PUSH AX ;the hWnd for show
1CEF:0000B8ED 6A04 PUSH 04 ;activate
1CEF:0000B8EF 9A3E10E706 CALL USER!SHOWWINDOW ;herein
1CEF:0000B8F4 FF363E46 PUSH WORD PTR [46E3] ;fetch hWnd
1CEF:0000B8F8 9A2D19A704 CALL USER!ISICONIC ;is iconic?
1CEF:0000B8FD 0BC0 OR AX,AX ;check if zero
1CEF:0000B8FF 7537 JNZ B938 ;it's iconic!

Here you see that after our search string "0BC0740D9A" follows a "E4" byte.

The function "IsIconic" has nothing to do with our protection scheme. This function returns non zero if the specified windows (pointer at location 46E3) is displayed in its iconic form, zero if it is not. Well it's
definitely NOT our protection scheme: we should find (at least) three MOV instructions and four PUSHES instructions (see PSP21) after our call to SHOWWINDOW, and our protection scheme has nothing to do
with any call to ISICONIC.

Let's have a look at occurrence 2 of our search string inside the code of our PSP30 target:

Occurrence 2 of search string 0BC0740D9A:


1CEF:0000B927 0BC0 OR AX,AX ;checks previous call
1CEF:0000B929 740D JZ B938 ;it's zero, forget show
1CEF:0000B92B 9A5817A71C CALL 1CA7:1754 ;new call to fetch
1CEF:0000B930 50 PUSH AX ;the hWnd for show
1CEF:0000B931 6A04 PUSH 04 ;activate
1CEF:0000B933 9A3E10E706 CALL USER!SHOWWINDOW ;herein
1CEF:0000B938 FF363E46 PUSH WORD PTR [46E3] ;fetch hWnd
1CEF:0000B93C 9A2D19A704 CALL USER!ISICONIC ;is iconic?
1CEF:0000B941 0BC0 OR AX,AX ;check if zero
1CEF:0000B943 7537 JNZ B97C ;it's iconic!

Well, hey, no, we are not yet there... this is just a "mirror" of the previous occurrence one! That means a complete repetition of the same code of occurrence one... tehrefore the same as above yelds true: it
is not yet our protection scheme. Here you see that after our search string "0BC0740D9A" follows a "58" byte.

Let's see the third (and last) occurrence of our search string:

1CEF:0000B96B 0BC0 OR AX,AX ;checks previous call


1CEF:0000B96D 740D JZ B97C ;it's zero, forget show
1CEF:0000B96F 9A1E958F1C CALL 1C8F:951E ;new call to fetch
1CEF:0000B974 50 PUSH AX ;the hWnd for show
1CEF:0000B975 6A04 PUSH 04 ;activate
1CEF:0000B977 9A3E10E706 CALL USER!SHOWWINDOW ;herein
1CEF:0000B97C A13E46 MOV AX,[463E]
1CEF:0000B97F A33A3C MOV [3C3A],AX
1CEF:0000B982 C7063E460000 MOV WORD PTR [46E3],0000
1CEF:0000B988 68EF1C PUSH 1CEF
1CEF:0000B98B 687C21 PUSH 217C
1CEF:0000B98E 1E PUSH DS
1CEF:0000B98F 680217 PUSH 1702
1CEF:0000B992 FF36105C PUSH WORD PTR [5C10]
1CEF:0000B996 50 PUSH AX
1CEF:0000B997 9AA401271D CALL 1D27:01A4 ;final call
1CEF:0000B99C 83C40C ADD SP, +0C ;resume

Here we are! This is obviously our protection scheme, see the analogies (almost identities) with the older PSP21 nagscreen protection we found and cracked above! In this third occurrence you see that
after our search string "0BC0740D9A" follows a "1E" byte.

To defeat this protection along the same line of our previous PSP21 crack, we could jump -here- to the 1CEF:0000B99C (resume after final call) instruction, modifying the instruction at 1CEF:0000B96D
(740D JZ B97C) -exactly as we did in PSP20- to a nice JNZ B99C 75 2D (that's the distance between the location of this very JNZ instruction and the location where you want to jump, coz b99C-(b96D+2) = 2D.
This crack requires a byte more (2D instead of 2C) than in PSP21 to fly over the nagscreen calls, coz an extra PUSH DS has been added inside this version's nagscreen protection scheme (a reason more to be
careful with "longer" search strings: if you fetch too many occurences with a short search string you just "cross check" the same occurrences with another short search string from a later prortion of the code you
are trying to individuate: write a short program to do it automatically for you: the best cracking tools, remember, are the tools that you write yourself).

A last word, should you be interested in the "final call" of this nagscreen scheme: it's a routine (here inside module PSP30(04) which calls the two functions KERNEL!MAKEPROCINSTANCE (which must
be called for 16 bits Windows in order to effectuate a call to Dialogbox) and USER!DIALOGBOX, which is (de facto) the nagscreen itself.

Now let's go over to the last version of PAint Shop Pro for Windows 3.1 I know of: PSP.EXE version 3.12-32, length: 1.042.944 bytes, 27 december 1995.

Let's bpx on CreateWindow and let's see... We fire PSP and we pop inside Winice at the *only* occurrence of CreateWindow... MMM! Something fishy here? When you proceed as above you get only one
break in Winice on bpx CreateWindow, and no stack at all, just the CreateWindow call! You do not get no heap segments for PSP32 either... how comez?

The fact is, that in order to crack Win32 applications like this one, we must move over to Winice95, coz Winice for Win3.1 has its limits. You'll of course find Winice 95 on the Web, there are always cracked
copies roaming around, the best pages offer some links to them, you should learn HOW TO SEARCH. You'll find everything on the web for free, as a matter of fact. It's amazing HOW MUCH you can get from
internet, and this could make the Web potentially dangerous from a "human-social" point of view... how will we keep social and human contacts if we roam around so much without ever touching each other? A
good idea in order to re-establish somehow our "humanity" "contact" balance is to seek physical contact not only with your loved one (which is always very good) but also with many other human beings: I have for
instance three massage sessions every week with my masseuse, which is half my age but strong enough to cure my rheumatisms... just to make another example, I enjoy very much all restaurants which have the
so called "tables d'hote" i.e. where everybody sits together at a couple of long tables, me, my wife and my kids exchanging views and opinions with other people, people you never saw before and will probably
never see again, drinking excellent wines, instead of sitting grimly on the petty, bourgeois, "4 chairs" little tables for stupid greedy families that abound inside "normal" restaurants... (I'll not ever mention the "fast
food" abominations: I am definitely in favour of "slow food" and believe McDonald should be hanged for what he has done -in the whole world- to 4000 years of gorgeous gastronomical traditions... what's the point
of eating quickly (and badly), unless you are a slave of your time?)... enough: You could crack Win32 applications even using Winice for Windows 3.1 though, albeit slowly... you would have to go through Winice's
VxD command, and need a little zen and a deep understanding of virtual memory management in Windows. Anyway, there is no point in using wrong tools. Should you however try to crack Win32 applications with
Winice 3.1, have a look first of all at the modules inside windows as soon as winice pops up, using Winice's command :mod... there you'll find the

hmod=1C3F W32SCXXXX D:\PSP\PSP.EXE

Now :heap w32sxxxx in order to get the heap segments you need to start your crack with.

40
However, as I said, we better crack applications like this one using Winice for Windows 95 and we'll see together -in the next lesson- that the nagscreen of the 3.12-32 version AND the one in the Windows
95 "4.1" version (the last one I know of) can both be cracked pretty quickly on the same line as the previous ones. We will also see that the nagscreen mechanism -believe it or not- is more or less always the
same. The protectionists added a "delayed" OK button focus and mixed some "alien" (but useful) routines in-between. This said, it's still always the same soup, as usual with nagscreens and mercantile
programmers.

Well, that's it for this lesson, reader. Not all lessons of my tutorial are or will be on the Web.

You 'll obtain the missing lessons IF AND ONLY IF you mail me back (via anon.penet.fi) with some tricks of the trade I may not know that YOU discovered. Mostly I'll actually know them already, but if they
are really new you'll be given full credit, and even if they are not, should I judge that you "rediscovered" them with your work, or that you actually did good work on them, I'll send you the remaining lessons
nevertheless. Your suggestions and critics on the whole crap I wrote are also welcomed. Do not annoy me with requests for warez, everything is on the Web, learn how to search, for goddam sake.

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

+ORC na526164@anon.penet.fi

Lesson 9 (3): How to crack Windows, Hands on


Nagscreens galore (B): The 'Dead listing' approach

In this lesson I'll teach you another cracking technique known as "dead listing" approach, in opposition to the "live" cracking (through Softice/Winice) that we have used (and we'll use) most of the time.

Since this approach requires a good Hexeditor and a good disassembler (and a good Wordprocessor), it suits us well to begin the 'hands on' part cracking what we need: a good Hexeditor.

I'll crack here the nagscreens out of Hexworkshop, Version 2.10 (32 bit version). A good and relatively quick (for Windoze's standards) application by Breakpoint software. Many among you will already
have this hexeditor inside their Software collection, if not find it on the Web through an Archie search and download it through ftpmail... searching through the archies will give you something like this:

Host ftp.loria.fr (152.81.10.10)


Last updated 11:25 23 Oct 1996
Location: /pub1/pc/win95/programr
FILE -r--r--r-- 707906 bytes 02:00 13 Aug 1995 hworks32.zip

The exact NAME of this hexediting program is HWORKS32.EXE, it is 524288 bytes LONG, and its DATED 2 February 1996. This program has many little nag annoyances:

- shows a nagscreen reminding you how many days you have used the program;
- keeps a nag_string "unregistered version" on the main screen of the program;
- has, inside help, a "registration serial number form"...

this is the number you could get registering... and should digit inside the HELP/ABOUT HEX WORKSHOP window form.

Elsewhere in this tutorial we have already learned how to defeat this type of protection: through Winice breakpoints. Basically we would type a fake registration number (say '121212121212') and then look
for the occurrences of our string in memory, and then search and investigate the manipulations undertaken by the protection scheme. In this way we would finally be able to crack the nagscreen procedure.

Fine, fine... this would indeed work, but I want to teach you through this lesson ANOTHER, completely different approach to cracking, which is and will be especially useful for 'nagscreen' and 'time-limit'
cracking... i.e. the "dead listing" approach. This approach is a much more "relaxed" sort of crack, which will work flawlessly most of the time.

This approach is particularly easy with Windows programs, since -as I have already told you a hundred times- the modularity of this overbloated atrocity makes it particularly easy for us little crackers to
track back the -mostly primitive- protection methods utilized by the commercial programmers.

I remember older times, when programming was still an art for intelligent (not mercantile) beings, cracking the old (and sometime beautifully crafted) Z-80, CP/M and DOS programs. In those time 'a byte
was a byte'! And good programmers found funny tricks in order to write 'tight' code. We old crackers used the 'dead listing' approach sitting (or snoozing) in pleasant (albeit a little battered) armchairs, inside a huge
university library, drinking very good Martini Wodka (you would be well advised to use only Moskowskaja, coz non Russian Wodkas are repugnant). Four of us at a time, each one just looking at his paper listings.
You cannot imagine how many little (unrelated) tricks we found inside the code cracking in that way! A hacker, a cracker (me), a 'real' programmer and an encryption specialist, all four sitting in the same room,
exchanging pretty clever findings and sipping (much too many) good cocktails... it's long ago, those times (and societies) are gone for ever! Microsoft's abomination has unfortunately created this overbloated world
of huge 'programs' which perform more slowly (and much more awkwardly) what the old programs did quickly and flawlessly.

You don't believe me? Why don't you just install Linux on your harddisk and see for yourself the difference between a good OS and Windoze? Just try it... you'll be amazed and you'll never go back... well,
you'll actually do... only in order to crack the hell out of Windows: We'll never damage enough Microsoft's interests to compensate for this moronic situation: millions of stupid users have to wait hours (and this with
microprocessors that are 1000 times quicker than the old 8086) to perform with MS_Word -slowly- what they could have done immediately with an old copy of Wordperfect for Dos.

Anyway, the huge dimension of all Windows' programs forces us to abandon the printed "dead listing" approach... printing in extenso the listing of a Windows program would consume a couple of ink
cartridges and could easily take ages... therefore we can indeed still crack with the "dead listing" method, and we can indeed still drink our Martinis (and we do, Oh Yessir), but we must keep the overbloated
listings off page, on our PC, printing only the small part of them that are relevant to our crack.

As I said at the beginning, for this art of cracking you'll need basically only two programs (and you will NOT need Softice/Winice).

1) A disassembler like W32DASM (or another good one) in order to find the protection scheme.
You will probably already possess it (else how did you crack until now?)... if not find the last version on the Web -through an Archie search- and download it -through ftpmail-, Searching the archies will give
you something like this:

Host ftp.funet.fi (128.214.248.6)


Last updated 07:57 1 Jan 1997
Location: /pub/mirrors/ftp.cdrom.com/pub/simtelnet/win3/prog
FILE -rwxrwxr-x 650327 bytes 23:25 28 Oct 1996 w32dasm6.zip

2) An hexeditor (Use Hexworkshop version 2.10 itself, since we are already cracking it :=) in order to defeat the protection scheme as soon as you have found it. OK, enough, let's crack.

Here is how the "dead listing" approach works:

1) Run the program you want to crack, in this case Hexworkshop, look at all the nag_strings and write them down (I mean snap them down -automatically- from screen... see elsewhere in my tutorial how
to get and crack snap32);

2) Wdasm the file (that means: 'open' it inside the disassembler in order to get the listing).

3) Transfer the listing to your favorite wordprocessor (we will not need Wdasm any more, bye)

4) Search (Find) inside your wordprocessor the nag_references, say, in our case, the string "unregistered version"

You'll immediately land inside following piece of code:


:MAIN_NAG_ROUTINE
:00415732 CC int 03
:00415733 CC int 03
:00415734 CC int 03
:00415735 CC int 03
:00415736 CC int 03
:00415737 CC int 03
:00415738 CC int 03
:00415739 CC int 03
:0041573A CC int 03
:0041573B CC int 03
:0041573C CC int 03
:0041573D CC int 03
:0041573E CC int 03
:0041573F CC int 03
:00415740 55 push ebp
:00415741 8BEC mov ebp, esp
:00415743 6AFF push FFFFFFFF
:00415745 6873584100 push 00415873
:0041574A 64A100000000 mov eax, fs:[00000000]
:00415750 50 push eax
:00415751 64892500000000 mov fs:[00000000], esp
:00415758 81EC0C020000 sub esp, 0000020C
:0041575E 53 push ebx
:0041575F 56 push esi
:00415760 57 push edi
:00415761 898DE8FDFFFF mov [ebp-00000218], ecx

41
:00415767 8B450C mov eax, [ebp+0C]
:0041576A 50 push eax
:0041576B 6A73 push 00000073
:0041576D 8B8DE8FDFFFF mov ecx, [ebp-00000218]
:00415773 E87EFC0100 call 004353F6
:00415778 C745FC00000000 mov [ebp-04], 00000000
:0041577F 8B8DE8FDFFFF mov ecx, [ebp-00000218]
:00415785 83C144 add ecx, 00000044
:00415788 E84EF40100 call 00434BDB
:0041578D C645FC01 mov [ebp-04], 01
:00415791 8B85E8FDFFFF mov eax, [ebp-00000218]
:00415797 C70028AE4500 mov dword ptr [eax], 0045AE28

*StringData Ref from Data Obj->"An unregistered version of Hex"


->"Workshop has been on"
|
:0041579D 68085B4600 push 00465B08
:004157A2 8D85F4FDFFFF lea eax, [ebp-0000020C]

Good, we immediately see that the above routine starts at instruction

:00415740 55 push ebp

Therefore now we'll search our listing for following string:

call 00415740 (that is: who calls here?).

The reason we must search for the caller is very simple: there is no conditional jump inside the piece of code above... and therefore it'll very unlikely hide a protection and/or a check time or nag routine. If
we do perform our search for the caller we'll immediately land inside following routine:

: CALL_NAG_ROUTINE
:00415DAC 55 push ebp ;pusha lotta values
:00415DAD 8BEC mov ebp, esp
:00415DAF 6AFF push FFFFFFFF
:00415DB1 68045E4100 push 00415E04
:00415DB6 64A100000000 mov eax, fs:[00000000]
:00415DBC 50 push eax
:00415DBD 64892500000000 mov fs:[00000000], esp
:00415DC4 83EC54 sub esp, 00000054
:00415DC7 53 push ebx
:00415DC8 56 push esi
:00415DC9 57 push edi
:00415DCA 894DA0 mov [ebp-60], ecx
:00415DCD 6A00 push 00000000
:00415DCF 8B4508 mov eax, [ebp+08]
:00415DD2 50 push eax
:00415DD3 8D4DA4 lea ecx, [ebp-5C] ;for the call
:00415DD6 E865F9FFFF call 00415740 ;*** HERE !!! ***
:00415DDB C745FC00000000 mov [ebp-04], 00000000
:00415DE2 8D4DA4 lea ecx, [ebp-5C]
:00415DE5 E804F70100 call 004354EE
:00415DEA C745FCFFFFFFFF mov [ebp-04], FFFFFFFF
:00415DF1 E805000000 call 00415DFB
:00415DF6 E913000000 jmp 00415E0E
:00415DFB 8D4DA4 lea ecx, [ebp-5C]
:00415DFE E8FD000000 call 00415F00
:00415E03 C3 ret

Good, OK. Now -once more- who calls this function? As -here too- we don't have any conditional jumps, we are compelled to look further inside the green branches of our code_tree.

Let's go on: searching for


call 00415DAC (the beginning of the above function)
we will land inside following code:

:WILL _I_CALL_THE_CALL_NAG_ROUTINE_?
:0040254C 6808414500 push 00454108
:00402551 8D8568FEFFFF lea eax, [ebp-198]
:00402557 50 push eax
:00402558 E893460200 call 00426BF0
:0040255D 83C408 add esp, 8
:00402560 0FBF0508414500 movsx word ptr eax, [00454108]
:00402567 85C0 test eax, eax
:00402569 0F8586000000 jne 004025F5 ;jump 1 over CALL_NAG
:0040256F 8B8D40FEFFFF mov ecx, [ebp-1C0]
:00402575 E8D3350100 call 00415B4D
:0040257A 85C0 test eax, eax
:0040257C 0F841B000000 je 0040259D
:00402582 8B8D40FEFFFF mov ecx, [ebp-1C0]
:00402588 E866360100 call 00415BF3
:0040258D 8B8D40FEFFFF mov ecx, [ebp-1C0]
:00402593 E8DF360100 call 00415C77
:00402598 E953000000 jmp 004025F0 ;jump 2 over CALL_NAG
:0040259D 8B8D40FEFFFF mov ecx, [ebp-1C0]
:004025A3 E83D370100 call 00415CE5 ;(month year routine)
:004025A8 898570FFFFFF mov [ebp-90], eax
:004025AE 83BD70FFFFFF00 cmp dword ptr [ebp-90], 0
:004025B5 0F8417000000 je 004025D2 ;jump 3 over CALL_NAG
:004025BB 8B8570FFFFFF mov eax, [ebp-90]
:004025C1 50 push eax
:004025C2 8B8D40FEFFFF mov ecx, [ebp-1C0]
:004025C8 E8DF370100 call 00415DAC ;HERE! CALL_NAG! *
:004025CD E91E000000 jmp 004025F0
:004025D2 8D8D7CFFFFFF lea ecx, [ebp-84];jump 3 lands here
:004025D8 E88C420200 call 00426869
:004025DD 85C0 test eax, eax
:004025DF 0F840B000000 je 004025F0
:004025E5 8D8D7CFFFFFF lea ecx, [ebp-84]
:004025EB E8FE2E0300 call 004354EE
:004025F0 E91E000000 jmp 00402613 ;jump 2 lands here
:004025F5 8D8D7CFFFFFF lea ecx, [ebp-84];jump 1 lands here
:004025FB E869420200 call 00426869

Now have a good look at the code above: As you can see there are only three possible jumps which will NOT call the CALL_NAG routine. The one at

:00402598 E953000000 jmp 004025F0 (Jump 2)

is not conditional, and therefore very rarely used for nagscreens protections. Besides, it links to another unconditional jump and it's most probably a "Quick_out" way... let's eliminate it, at least for now.

We remain with only two jumps over the NAG_SCREEN call routine:

00402569 0F8586000000 jne 004025F5 (jump 1)

and

004025B5 0F8417000000 je 004025D2 (jump 3)

42
You may investigate both of them, but, hey, you could eliminate one more jump, again, just using a little Zen code feeling): see how the jump condition for jump_3 is a base pointer value [ebp-90], while the
one for jump_1 is a memory fixed location [00454108]... this sort of condition is usually a green light, for compiler reasons I'll not delve inside here. Therefore let's have a closer look at it and let's forget jump 3, at
least for now.

:JUMP_1_UNDER_THE_LUPE
:0040254C 6808414500 push 00454108 ;values for
:00402551 8D8568FEFFFF lea eax, [ebp-198]
:00402557 50 push eax ;the following
:00402558 E893460200 call 00426BF0 ;call
:0040255D 83C408 add esp, 8 ;modify stack
:00402560 0FBF0508414500 movsx word ptr eax, [00454108] ;HERE
:00402567 85C0 test eax, eax ;conditional test
:00402569 0F8586000000 jne 004025F5 ;jump over CALL_NAG

What will then this mysterious [00454108] location be? Don't you feel it? It's the ACTIVATOR! The location with the flag, which sets the whole nag screen galore for Hexworkshop! Our cracking job is
already finished!

We don't need anything more: we don't need any fiddling with breakpoints, nor to examine hundreds of irrelevant calls... with Windows this kind of "dead listing" cracks works so smooth I could shriek!

But, hey, OK, we will continue our snooping, for the sake of it and just in order to be completely sure... it's not necessary, but let's do it anyway... check a little more around... search, inside your huge listing,
all the other occurrences of the same [00454108] location... you'll get no more than 5 hits. The most striking one from our cracking point of view being the following occurrence:

:00402770 898574FFFFFF mov [ebp-8C], eax ;save old eax


:00402776 0FBF0508414500 movsx word ptr eax, [00454108];FLAG*
:0040277D 85C0 test eax, eax ;flag is zero?
:0040277F 0F8528000000 jne 004027AD ;nope, so we won't
:00402785 8B4DEC mov ecx, [ebp-14]
:00402788 E883280000 call 00405010 ;call this, nor
:0040278D 898574FFFFFF mov [ebp-8C], eax ;write

* Possible StringData Ref from Data Obj ->"Unregistered


Version"
|
:00402793 6854494600 push 00464954 ;on the screen
:00402798 685C800000 push 0000805C ;& we'll jump over
:0040279D 6800400000 push 00004000 ;these pushes
:004027A2 8B8D74FFFFFF mov ecx, [ebp-8C]
:004027A8 E823280000 call 00404FD0 ;and this call

* Possible StringData Ref from Data Obj ->"ControlBars"


|
:004027AD 686C494600 push 0046496C ;directly here

Well, yes, now it's more than enough, thanks... location [00454108] seems indeed to be the flag we are searching. Confirmed. Struck and sunk! Now let's quickly crack Hexworkshop:

*** CRACK FOR HEXWORKSHOP VERSION 2.10 by +ORC (January 1997) **


Use hexworkshop itself (no more debug/symdeb, coz we are working with the overbloated Microsoft monstrosity) and search inside the code of the copy on your harddisk for the hex sequence:

08414500

that's the code for our flag_location, duh?

****(a short digression): BE CAREFUL SEARCHING FOR BYTES *****


Be careful with instructions you try to search for. You should only search for instructions that don't change the bytes they assemble to, depending on their location in memory. For example, searching for the
following instructions presents no problem:

PUSH DX
POP [DI+4]
ADD AX, 100

but searching for the following instructions CAN cause unpredictable results:

JE 123
CALL MYFUNC
LOOP 100
**** (end) ********************************* **** **** ****

Searching for the byte sequence 08 41 45 00 you will obviously find the several occurrences of it we have seen before... you have to modify only one location though, the one followed by the two bytes

0F85... (jne after CALL_NAG)

at the FIFTH (and sixth) position after the search string, because that's the location we are looking for. Once you found it, write over the byte
85
the byte
84
and now you'll have modified the jne in a (je after CALL_NAG).

We'll now jump if equal (as all men should be, by the way)... Look!... no more nagscreens to annoy our proven aesthetic perception, no more silly protections to blemish our suave future hexediting around
:=)

I almost forgot... that's obviously not enough... you must as well modify the location at :0040277F

:0040277F 0F8528000000 jne 004027AD ;jump over 'unregistered'


to
:0040277F 0F8428000000 je 004027AD ;jump equal!

in order to have a well cracked copy of our target.

[PSP 32]
Can we apply this 'dead listing' approach to other programs? Can we use the same strategies for other protection schemes? Sure! Let's remain a little more inside the nagscreens protections.

A logical step, after the invention of the nagscreen itself, has been the "mingling" of the nagscreen calling routine. In this kind of protection the nagscreen routines are 'amalgamated' with other routines,
which cannot be skipped as they are essential for the working of the program. The main disadvantage of this approach, for the mercantile protectionists, is that they have therefore to prepare TWO different
versions of their programs: a 'nagscreened' one and a 'clean' one, since else we would immediately be able to transform the crippled program in a fully functional one using the same approach they would use to
'uncripple' it.

Such mingling is therefore only used by major programs which are well established on the market and can afford the 'doubled' approach. This is the case of the last versions of PaintShopPro (PSP).

Even in this case, though, we can crack nice enough, as I will now demonstrate you with PaintShopPro version 3.2 (a 32 bit program for Windows 95).

You will probably already possess it, if not find the last version on the Web -through an Archie search- and download it -through ftpmail-, Searching the archies will give you something like this:

Host ftp.mds.mdh.se (130.238.252.239)


Last updated 08:10 4 Dec 1996
Location: /pub/windows/win95/graphic_utils/paintshop
FILE -rw-r--r-- 311542 bytes 15:11 27 Jul 1996 psp32bit.zip

We have seen in the preceding lesson (-> lesson 9.2) how to disrupt, through the usual Winice 'live' approach, the PaintShopPro nagscreens for Windows 3.1., cracking the older versions of this program.
Instead we will now try our 'dead listing' approach for PSP 32 and PSP Version 4.1 (both 32 bit programs).

Let's fire PSP32 (I am using here the shareware version with a PSP.EXE of 1.042.944 bytes, dated 27 December 1995). Let's have a good look at the nagscreen (snapping it), OK, that's enough.

Now load the target inside Wdasm32 (I am using here version 5 of Wdasm, you'll find cracked versions of it everywhere on the Web).

As soon as you have the complete (huge) listing of PSP.EXE use the option "Save disassembly to text file"... you'll get a huge text file (with 12.590.025 bytes, gosh).

43
Load it inside a (good and quick, i.e. not Microsoft's) Wordprocessor and let's first of all have a look at the code preceding and following our nagscreen (at this point -if you are not completely imbecile- you
should already have grasped the foundation techniques of my "dead listing" cracking approach).

You will see that in the code of PSP we have a lot of USER calls. Therefore we cannot use the same easy 'find the caller' approach used before (more about code mingling later).

Have a look at the following piece of code (the Stringdata for the Shareware notice has landed us there) there is a GetDlgItem(), which is User32.EB and a EnableWindow(), which is User32.AB.

GetDlgItem(), as you should know, returns the handle of the specified ID control (or zero if error). The ID number is the parameter passed, the returned value is the hdlg (handle of the dialog box of ID).

:0041DB69 891D38A04B00 mov [004BA038], ebx ;ebx in here


**
:0041DB6F 6A6C push 6C
:0041DB71 881DF4134C00 mov [004C13F4], bl ;bl in here **
:0041DB77 56 push esi

* Reference To: GetDlgItem, Ord:00EBh in USER32.dll


|
:0041DB78 FF154C5A4C00 call dword ptr [004C5A4C] ;callnag-1
:0041DB7E 50 push eax

* Reference To: EnableWindow, Ord:00ABh in USER32.dll ;callnag-2


|
:0041DB7F FF15DC594C00 call dword ptr [004C59DC]

*StringData Ref from Data Obj->"Paint Shop Pro Shareware Notice"


|
:0041DB85 6820174C00 push 004C1720
:0041DB8A 56 push esi

Now follow me closely:

1) Since the following code pushes two locations (one with bx and the other with bl) just before calling the GetDlgItem and EnableWindow routines for the "PaintShopPro Shareware Notice" Window...

2) ...we just need to search these locations ELSEWHERE, "around" the above section of the code. Let's do it... Searching the STRING "[004BA038]" we'll fetch inside our wordprocessed listing two more
occurrences: Let's look at the first one: this piece of code compares to 1 our location just after enabling a Window:

:REFERENCE_1_OF_OUR_[004BA038]
* Reference To: EnableWindow, Ord:00ABh in USER32.dll
|
:0041DA41 FF15DC594C00 call dword ptr [004C59DC]
:0041DA47 C605F4134C0002 mov byte ptr [004C13F4],2
:0041DA4E 833D38A04B0001 cmp dword ptr [004BA038],1 ;HERE!! **
:0041DA55 7510 jne 0041DA67 ;and the conditional jump!
:0041DA57 6A00 push 00000000 ;If equal (Zero flag),
:0041DA59 6A6C push 0000006C ;push these parameters
:0041DA5B 6811010000 push 00000111 ;for the PostMessage
:0041DA60 56 push esi ;function...

* Reference To: PostMessageA, Ord:01A3h in USER32.dll


|
:0041DA61 FF155C594C00 call dword ptr [004C595C] ;...call)
:0041DA67 B801000000 mov eax, 1 ;our jump here: flag=1
:0041DA6C E9EE030000 jmp 0041DE5F ;end of code snippet, this

jumps to the "popping away" part of the code...


:0041DE5F 5D pop ebp
:0041DE60 5F pop edi
:0041DE61 5E pop esi
:0041DE62 5B pop ebx
:0041DE63 81C434050000 add esp, 00000534
:0041DE69 C21000 ret 0010

AhHa! The value 111! (at :0041DA5B). You know what that means, don't you? For the newbyes among you that don't, learn it here (the others can skip):

************ THE 111 WM_COMMAND RELEVANCE, by +ORC ********

The function PostMessage() has following structure: PostMessage(HWND hWnd, UINT uMsg, WPARAM wMsgParam1, LPARAM lMsgParam2)Where hWnd is the receiving Window, UINT is TRUE or
FALSE WPARAM is a 16 bit value and LPARAM a 32 bit one!

Windows' applications use PostMessage() to deliver WM_Message requests... and parameter 111 is WM_COMMAND! Write it on your cracking notes and underline it! 1 is IDOK, 2 is IDCANCEL and 111 is
WM_COMMAND.

WM_COMMAND is extremely important for understanding the behaviour of the application you want to crack, because the handler for WM_COMMAND is where that application deals with user commands,
such as menu selctions, dialog push button clicks, etcetera. In other words all what makes the 'guts' of an application.

An application can tell wich command a user gives through the wParam parameter to the WM_COMMAND message.

These values are (almost) always part of the application's menu resources, and it is easy to get the menu ID values through any utility for resources dumping.

************ (end) **************

OK, so the above listed piece of code has a jump over the PostMessage routine which (probably) disables the nag screen (6C is the same ID, for both pieces of code we have seen)...let's try a "weak"
crack on it:

***** WEAK CRACK FOR PSP32, by +ORC, January 1997 ********

1) Use Hexworks32
2) Load PSP.EXE
3) Search for the bytes sequences of the instructions
:0041DA4E 833D38A04B0001 cmp dword ptr [004BA038],1
:0041DA55 7510 jne 0041DA67
which are followed by the pushes:
:0041DA57 6A00 push 00000000 ;zero
:0041DA59 6A6C push 0000006C ;ID
:0041DA5B 6811010000 push 00000111 ;WM_COMMAND

And as a quick crack (but there are more elegant ways) we can
4) substitute the byte '75' at :0041DA55 with a 74, transforming the jne in a je, as usual, inverting the jumps. Jump if equal!

Since I have been (blandly) critized by fellow scholars for speaking all the time of more elegant ways and yet presenting only simple ways, here IS a more elegant crack for this code:

4) Substitute with a new ONE the first TWO instructions:

:0041DA4E 66C70538A04B000100 mov word ptr [004BA038],1

and leave all the rest unchanged:

:0041DA57 6A00 push 00000000 ;zero


:0041DA59 6A6C push 0000006C ;ID
:0041DA5B 6811010000 push 00000111 ;WM_COMMAND
*****************************

As you can see, we have just moved the flag '1' inside our location, instead of comparing and jumping away as in the original code and in the quickly cracked one. Estilo muchissimo elegante.

Since this lesson was thought as +HCU material, here is the result of the work on it made by (some of) my students:

44
JANUARY 1997: THIS PART OF LESSON 9.3 HAS BEEN MODIFIED (OR ADDED) BY THE +HCU STUDENTS OF UNIT 4

Let's finish our cracking of the nagscreens of the whole PaintShopPro family with version 4.1, which is the most recentwe know of.

I am using here PSP.EXE 1.151.488 bytes from 1 Sep 1996, fetch it through the archies.

We will crack this shareware program BETTER than the registered version, since we will completely eliminate any nagscreen and we'll not ever have the welcome screen that REMAINS inside the
registered version. We'll do this 'in a hurry', since it is not +ORC speaking, but some of his students... you already know enough about the 'dead listing' method to be able to follow. No Winice in our hands, Ladies
and Gentleman, We never used it on this program. (Well... we actually did, before reading 9.3, but it brought us nowhere, for this crack we (almost) DID NOT, following +his instructions)

1) Get the 'dead listing' of psp.exe (it's huge)


2) Load it inside a fast wordprocessor
3) Find the string 'Purchasing' at :00406710
4) short after 'Purchasing' the only location compared and loaded is location [004BC218]. Let's call it 'BINGO' and let's hope it'll work.
5) this location is handled inside a small part of the code: 00406290 to :004067B5, this reduces the more than one million bytes to 1317 bytes we'll have to examine, not bad.
6) Let's print this nagging part of the code and let's feel it a little
7) Let's see the possible cracks we could think of (we repeat, here is not +ORC's but his students at work, we are not perfect).

You'll see this piece of code


:FIRST_ATTEMPT (NOT SO GOOD)
:004065D0 50 push eax
:004065D1 64892500000000 mov fs:[00000000], esp
:004065D8 81ECB4000000 sub esp, 000000B4
:004065DE 833D18C24B0000 cmp dword ptr [004BC218], 0 ;Is BINGO zero?
:004065E5 56 push esi
:004065E6 57 push edi
:004065E7 0F85A0010000 jne 0040678D ;not really

this is 'pentium optimised' code, with a couple of pushes 'inside' the two logically consecutive instructions following the double 80586 fetching... on a 80486 you would have had: push esi; push edi;
cmp dword ptr [004BC218], 0; jne 0040678D We may just try substituting a 0F84 at :004065E7 (that is a jump equal instead of the jne) and BOUM! We get an 'inamovible' nagscreen, No way to click it
away, it covers the main program PaintShopPro for the eternity. This confirms that we are on the right track (it's a green light). Uncrack the code (or reload the original nagged program). Now look here:

:SECOND_ATTEMPT (NOT SO GOOD)


:00406495 E95AEA0900 jmp 004A4EF4
:0040649A 33F6 xor esi, esi
:0040649C C745FCFFFFFFFF mov [ebp-04], FFFFFFFF
:004064A3 893518C24B00 mov [004BC218], esi ;load esi in BINGO

Since :00406495 jumps away, it would be interesting to know who the cuckoos lands at :0040649A. You'll quickly discover that there are two jumps in this area. One 'xores' the esi before loading it in our
location, the other one does not:

:0040641C 747C je 0040649A ;xores esi


:0040646F EB2B jmp 0040649C ;does not xore esi

So you may be tempted to try '‡a passe ou ‡a casse' following cracks:

:0040641C 747E je 0040649C ;no xoring even if it should


(THIS DOES NOT CHANGE ANYTHING)
:0040646F EB19 jmp 0040649A ; xoring even if it should not
(THIS CRASHES)

Bad score: a frozen nagscreen, a nothing and a crash. Three to zero for our enemies. Let's look a little more around our 1317 bytes listing.

Well, what else?

The following code refers THREE TIMES to our location, that's a lot, let's hope it does not suck:

:THREE_SISTER_BINGOS
:00406547 33C0 xor eax, eax ;xor
:00406549 85C0 test eax, eax ;test ax
:0040654B 7513 jne 00406560 ;don't move in cx
:0040654D 8B0D18C24B00 1! mov ecx, [004BC218] ;move in cx
:00406553 85C9 test ecx, ecx ;test cx
:00406555 7418 je 0040656F ;don't call Updatewin
:00406557 6A01 push 1
:00406559 8B01 mov eax, [ecx] ;move cx in ax
:0040655B FF5004 call [eax+04] ;and call here
:0040655E EB0F jmp 0040656F ;don't call Updatewin
:00406560 A118C24B00 2! mov eax, [004BC218] ;move in ax soon
:00406565 8B4820 mov ecx, [eax+20]
:00406568 51 push ecx
:00406569 FF15C4014C00 call dword ptr [004C01C4] ;call Updatewindow
:0040656F 6A00 push 0
:00406571 A118C24B00 3! mov eax, [004BC218] ;move in ax later

Well, something fishy here, don't you feel it? Who comes in here?

From where? Let's have a GOOD look at the 'preamble', i.e. the part of the code that 'switches' to our THREE_SISTER_BINGOS block above:

:PREAMBLE_TO_THREE_SISTER_BINGOS
:004064DD FF15BCF24B00 call dword ptr [004BF2BC] ;check this loc
:004064E3 85C0 test eax, eax ;test
:004064E5 744E je 00406535 ;zero, go 6535
:004064E7 B896000000 mov eax, 96 ;load par 96
:004064EC 3945E0 cmp [ebp-20], eax ;compare this
:004064EF 7C44 jl 00406535 ;lower, go 6535
:004064F1 3945E4 cmp [ebp-1C], eax ;compare that
:004064F4 7C3F jl 00406535 ;lower, go 6535
:004064F6 8B4508 mov eax, [ebp+08] ;load this
:004064F9 85C0 test eax, eax ;test it
:004064FB 7504 jne 00406501 ;do not xor and...
:004064FD 33C0 xor eax, eax ;xor and
:004064FF EB03 jmp 00406504 ;do not
:00406501 8B4020 mov eax, [eax+20] ;...load this
:00406504 6A00 push 0 ;push
:00406506 8B4DE0 mov ecx, [ebp-20] ;load ecx
:00406509 6A00 push 0 ;push

Let's have a look at the 6535 routine of the switch PREAMBLE:

:00406535 E836560100 call 0041BB70

and

:41BB70 A118C34B00 mov eax, [004BC318]


:41BB75 85C0 test eax, eax
:41BB77 7407 je 0041BB80
:41BB79 50 push eax
:41BB7A FF1530F54B00 call dword ptr [004BF530] ;globalFree
:41BB80 C70518C34B00 mov dword ptr [004BC318], 0
:41BB8A C3 ret

Well, let's try along, what happen if we substitute a ret at

:00406535?
:00406535 C390909090 ret and nops

45
Nothing at all.
And what if we substitute here

:004064F6 8B4508 mov eax, [ebp+08]


:004064F9 85C0 test eax, eax
:004064FB 7504 jne 00406501
:004064FD 33C0 xor eax, eax
:004064FF EB03 jmp 00406504
:00406501 8B4020 mov eax, [eax+20]
:00406504 6A00 push 00000000

... the instruction

:004064FB 7504 jne 00406501

with the instruction 7500 (or 90 90)?

MOST BRILLIANT!
Now we XOR ANYWAY THIS AX without caring for ax+20. The nagscreen is defeated? Not really... the nagscreen has been passed ON THE BACKGROUND, where it still remains when you shut the
'main' window of the program... the nag protection is somewhere there, looking at us square in the faces... but where?

+gthorne here: since i had already seen the production version of paint shop pro, i realized that it also had a nag screen - not per se, but a splash screen (the very same screen without the buttons to push
and the 'number of days elapsed' warning). what this means is that it is very possible that the screen (regardless of what version we are running) could be intermingled with the rest of the code, and not fully
existing within a call. This does not proved it, just allowed the possibility.

Poking around, and being playful, i fired up snap32 and grabbed the nagscreen window and saved it for future reference.

The next thing i did was check into the help screen area of Paint Shop Pro. Often in shareware programs there is a HELP ABOUT, or a HELP REGISTER section. Sometimes those places give away good
info needed (or just plain useful) in the crack routine.

Something that stood out in the help area was the paint shop pro version statement. It seemed to be identical to the printed version as seen on the nag screen. That means one of two things: either the
version number string was just typed in twice, or more likely, just another call to a function: PSP_VERSION() or somesuch.

What that means for the crackist should be pretty clearly a way to locate the protection routine. Since the word SHAREWARE shows up in both version calls, it can be scanned for pretty easily with either
that or the word VERSION itself.

Then, once i felt i had done enough scouting the territory, I ran WDASM and grabbed myself a dead listing. Scanning for SHAREWARE, I found a couple easy references to it... one being a data string that
I promptly blanked out and the other being in the text that comes up on the nagscreen itself. WELL WELL...

This is the nagscreen result here:

* StringData Ref from Data Obj ->"This is a shareware version of "Paint Shop Pro."
|
:00406B64 6810A34B00 push 004BA310
:00406B69 8D4DEC lea ecx, [ebp-14]

Okay, running the program again, and firing softice (old friend) i immediately saw that the version checking routine no longer tacked on
the word SHAREWARE in either the nagscreen or in the help box.. thus proving the version call to be just that.. a call (as suspected).

Immediately, something else came up that I was not expecting, the location of most of the program in memory was exactly the same as seen with softice that it was hardcoded into the disassembly. What i
mean by that is that where softice was reporting 0137:0043FAD1 for a location in memory, identical data was reported at location :0043FAD1 on the disassembly.

Now, talk about convenient!

Simply enough, i breakpointed in softice with a few locations i had located in the disassembly, and voila... landed smack in the middle of the nagscreen data.

It was do-able with soft-ice alone, but tracing into the maze of nested calls in PSP really wasn't worth my time.

Line-by-line'ing it, it was simple to watch the nagscreen build itself call by call, and NOP or alter JZ's & JNZ's to JMP's (74's and 75's become EB's) so that the nagscreen lost more and more functionality.

Then came a little work - not too much, but some things were a little funny. Notice the BITBLT in the nagscreen creation code. I had tried to scan for some of the standard SHOWWINDOW calls with softice
and in the disassembly, but not one was to be found where it needed to be. Apparently PSP was using some other method of showing the screen... and a simple graphics memory copy (known to those who follow
Micro$oft as a BitBlt) was apparently the modus operandi.

Some of the text was already in place before the BitBlt, so here is our reason that some of the nagscreen was not being done as we watched with the debugger... it was being written to a backbuffer before
being copied as a whole window before being blitted to the screen. This, for those of you new to graphics programming, is how people make smooth animation that does not flicker... all of the animating is done in
the background and a whole screen is blitted at one time rather than by bits and pieces (you can tell which programs do not do this very easily since they have images that seem to disappear or flicker wrong in odd
places on the screen)

There were not many calls in that area, and only the ones that referenced string data or the bitblt itself could be effectively nop'ed out.

Here is where i basically stopped the work, since i was having trouble locating what CALLED the nagscreen area.

The reason we are getting the ghost window in the back (notice it's size is EXACTLY the same as the nagscreen, is that windows is being instructed by some window create command to block off the
rectangular space for the screen even though the graphic interior does not get written.

The backgrounding code is invaluable here since the ghost window does not have a way to be removed without paint shop pro closing (which cleans up nicely for itself on exit).

Now we need to locate the call that creates the window in the first place and nop it or whatever... there is probably a nicer way to do all this (if you work at it, you can probably jmp past all the functions i
nop'd - taking care not to leave unmatched pushes or pops which ruin the flow of the program - at some point in the nagscreen area

The funny part of all this is that our cracked version will be better than the registered version since the registered version has a splash screen anyway - and ours does not :)

Using all of this knowledge later can actually benefit us in a different way... we can actually use all of the techniques (since we already know where the nagscreen is) on the executable of the full version as
well.

Since it has no nag functions, it is a smaller executable and cracking it will give is a nagless, splashless (eg. screenless) version of paint shop pro that is smaller (i.e. better and more functional) than by just
cracking the shareware version.

I find that funny somehow :)

So here is all the rest you need:

Let's have a look at the VERSION subroutine that is called both in the nagscreen and the HELP screen:

* StringData Ref from Data Obj ->"4" ;FIRST DIGIT OF VERSION 4.01
|
:004350E4 6874AE4B00 push 004BAE74
:004350E9 8B3D90004C00 mov edi, [004C0090]
:004350EF C645FC07 mov [ebp-04], 07
:004350F3 C706F0A54A00 mov dword ptr [esi], 004AA5F0
:004350F9 FFD7 call edi
:004350FB 83C404 add esp, 00000004
:004350FE 8BD8 mov ebx, eax
:00435100 C1E310 shl ebx, 10

* StringData Ref from Data Obj ->"0" ;SECOND DIGIT OF 4.01


|
:00435103 6860A64B00 push 004BA660
:00435108 FFD7 call edi
:0043510A 83C404 add esp, 00000004
:0043510D 0BD8 or ebx, eax
:0043510F C1E308 shl ebx, 08

46
* StringData Ref from Data Obj ->"1" ;THIRD DIGIT OF 4.01
|
:00435112 685CA64B00 push 004BA65C
:00435117 FFD7 call edi
:00435119 C1E010 shl eax, 10
:0043511C 83C404 add esp, 00000004
:0043511F 0BD8 or ebx, eax

* Possible StringData Ref from Data Obj ->"2"


|
:00435121 68C4A14B00 push 004BA1C4
:00435126 FFD7 call edi
:00435128 83C404 add esp, 00000004
:0043512B 0BD8 or ebx, eax
:0043512D 899ED4000000 mov [esi-000000D4], ebx

* Possible StringData Ref from Data Obj ->"0"


|
:00435133 6860A64B00 push 004BA660
:00435138 FFD7 call edi
:0043513A 83C404 add esp, 00000004
:0043513D 50 push eax

* Possible StringData Ref from Data Obj ->"1"


|
:0043513E 685CA64B00 push 004BA65C
:00435143 FFD7 call edi
:00435145 83C404 add esp, 00000004
:00435148 50 push eax

* Possible StringData Ref from Data Obj ->"4"


|
:00435149 6874AE4B00 push 004BAE74
:0043514E FFD7 call edi
:00435150 83C404 add esp, 00000004
:00435153 50 push eax

* Ref from Data Obj ->"%i.%i%i" ;PRINT 3 INTEGERS: N.NN (4.01)


|
:00435154 686CAE4B00 push 004BAE6C
:00435159 8D86CC000000 lea eax, [esi-000000CC]
:0043515F 50 push eax

* Reference To: n/a, Ord:09A7h in MFC40.DLL


|
:00435160 E815FF0600 call 004A507A
:00435165 83C414 add esp, 00000014
:00435168 8D8ECC000000 lea ecx, [esi-000000CC]

* StringData Ref from Data Obj ->" Shareware" ;PRINT SHAREWARE


|
:0043516E 6860AE4B00 push 004BAE60

The first BitBlt routine of the program puts the screen on!

it is at:

* Reference To: BitBlt, Ord:000Ah in GDI32.dll


|
:00406917 FF15B4F24B00 call dword ptr [004BF2B4]
:0040691D B800000000 mov eax, 00000000
:00406922 85FF test edi, edi
:00406924 7403 je 00406929
:00406926 8B4704 mov eax, [edi+04]
:00406929 50 push eax
:0040692A 8B45B4 mov eax, [ebp-4C]
:0040692D 50 push eax

and here some other annoying pieces of code: The red bar as soon as you use the program more than 30 days...

* Reference To: n/a, Ord:0970h in MFC40.DLL


|
:00406BE3 E836E60900 call 004A521E ;DRAW RED BAR
:00406BE8 6801080000 push 00000801
:00406BED 8D45A0 lea eax, [ebp-60]
:00406BF0 50 push eax
:00406BF1 8B4DEC mov ecx, [ebp-14]
:00406BF4 8B853CFFFFFF mov eax, [ebp-000000C4]
:00406BFA 8B51F8 mov edx, [ecx-08]
:00406BFD 52 push edx
:00406BFE 51 push ecx
:00406BFF 8D8D3CFFFFFF lea ecx, [ebp-000000C4]
:00406C05 FF5070 call [eax+70] ;BOTTOM WINDOW TXT+RED BAR
:00406C08 53 push ebx
:00406C09 8D8D3CFFFFFF lea ecx, [ebp-000000C4]

Once found all the above, the rest is pretty obvious... here all the necessary crackcodes: bytes to find and change. This is a weird, non-elegant crack, but kinda funny, so i had to write it down until i
discover a better one (+gthorne speaking) note: i gave good search strings so lamers don't get confused with similar patterns in the software:

8B450885C07504 to 8B450885C07500 - screen backgrounding


3CFFFFFFFF5070 to 3CFFFFFF750090 - do not draw lower text in box
3CFFFFFFFF5064 to 3CFFFFFFEB0090 - do not report version number
83FF1E7E1E to 83FF1EEB1E - do not draw red bar
000083FFC07403 to 000083FFC0EB03 - turn nagscreen invisible
53686172657761726500 to 20202020202020202000 - disable shareware notice writing phisycally some spaces over it

final note: since psp closes the nagscreen when the program exits, all is now cleaned up.

FF15B4F24B00 to 750090750090 (bitblt) seems to not do anything the above cracks dont do.

Time to explain BitBlt... isn 't it? BitBlt copies a bitmap from the device context sopecified by hdcSource to the device context specified by hdcTarget performing a block copy. On success the function
returns not zero.

It is called with the handle hdcTarget, int nTargetX and nTArgetY (upper left coordinates of the point at which the bitmap will be copied... a 'pixel point' locator may be very useful in our trade) int nWidth and
nHeight of the region, the handle hdcSource and then, finally the upper left coordinates IN the bitmap, the two int nSourceX and nSourcey. Is it all? NO! The final parameter, DWORD dwRaster determines HOW
the bit-by-bit contents of the bitmap will actually be copied (black, inverted, ANDed, ORed, XOred...etc.).

Lotta things to learn if you want to crack a lot...


THE STUDENTS OF UNIT 4 (+HCU, January 1997)
*******************************************

As a matter of fact both cracks here, mine for PSPS32 and my student's VERY smart one for PSP41 are 'weak', though: they will not eliminate the nagscreen (you should search for the remaining
occurrences of our locations and work from them inwards, if you really want to crack completely this scheme, but in this case it would be better to work more with Winice95, in my opinion. But I hope I have made
the point about "dead listing" cracking: It works! Quick and placid! In the PSP32 case the protection will still show you the nagscreen, which will "automatically" disappear, though, leaving you with no annoyance (in
nuce: you cracked the return button), in the other case you have physically eliminated all possible annoyances. The nagscreen is still there, but it does not 'harm' you any more.

47
Anyway I wanted only to show you the POWER and the CHILD'S PLAY working of this "dead listing" approach (that you may combine with some quick winice probes if you really think you need it anytime).

You'll agree with me, though, that this quick "weak" crack, made with the "dead listing" method is far less tiresome than a 'live' crack with our beloved SoftIce/WinIce.

Now, in life, I believe, you should always search to obtain the maximum giving the minimum. There is no point in being altruistic or excessively honest in a society where the tiny minority that profits most
keeps getting richer and richer and the overwhelming majority that lives with meager earnings keeps getting poorer and poorer (and -moronized by TV-watching and other Pavlovian propagandistic sources of
misinformation- keeps voting the same rich bastards that keep it enslaved under the whips of publicity, as if the slaves of ancient Egypt would happily vote for their Pharaohs). I abhor and despise the society I am
compelled to live in... but this does not mean that I renounce to anything. I am (pretty) rich, (yet do not exploit anybody), eat very well, have a big nice house with all the useless objects and cars and garages and
terraces and futile gadgets you are supposed to enjoy in this moronic society (I enjoy foremost my spacious library) and I drink my regular bottle of (Moskowskaja) Wodka every week. My liver (and my nice family)
do not seem to complain :=)

Well, that's it for this lesson, reader. Not all lessons of my tutorial are or will be on the Web.

You'll obtain the missing lessons IF AND ONLY IF you mail me back (via anon.penet.fi) with some tricks of the trade I may not know that YOU discovered. Mostly I'll actually know them already, but if they
are really new you'll be given full credit, and even if they are not, should I judge that you "rediscovered" them with your work, or that you actually did good work on them, I'll send you the remaining lessons
nevertheless. Your suggestions and critics on the whole crap I wrote are also welcomed. Do not annoy me with requests for warez, everything is on the Web, learn how to search, for goddess sake.

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

+ORC na526164@anon.penet.fi

Lesson A.1: Advanced Cracking: Internet Cracking (Unix)

-------------> INTERNET CRACKING: FIREWALLS


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 Delphi!

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.

3) OTHER FIREWALL TOPOLOGIES


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

/pub/security/socks.cstc/socks.cstc.4.2.tar.gz

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 sendmail).

The Firewall toolkit is available for free, in anonymous ftp from ftp.tis.com in the file

/pub/firewalls/toolkit/fwtk.tar.Z

The popular PC firewall solution is the "PC Socks Pack", for MS- Windows, available from ftp.nec.com It includes a winsock.dll file.

48
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

/dist/internet_security/berferd.ps

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 others.

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 criteria.

- 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 &


UNWITTING INSIDE COMPLICES
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 welcomed.

+ORC an526164@anon.penet.fi

LESSON C (1) - How to crack, Cracking as an art


[BARCODES] [INSTANT ACCESS]

[BARCODES]
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 mechanismes.

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 possibilities.

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.

[BARCODE HISTORY]
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

49
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 wine).

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:

[THE 13 BAR "CODES"]


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
((#1+#3+#5+#7+#9+#11)*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

50
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 manner.

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" :=)

[INSTANT ACCESS]
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 courses;
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 paths;
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, discunt".

[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
software.

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 welcomed.

+ORC an526164@anon.penet.fi

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.

51
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:

This_loop_checks_that_numbers_are_numbers:

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:

check_if_sum_other_9_numbers_=_remainder_of_the_third_number:

: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?

52
: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

let's_go_on_if_first_check_passed:

: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

now_we_have_the_sliders_let's_prepare_for_loop:

: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

loop_8_times:

: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

Back_to_main_protection_loop_from_RO_routine:

: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

check_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

loop_is_ended:

53
: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
EXIT:
: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 REMAINDER of it.

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
this:
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 underlined):

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].

54
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" 94672575.

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
7579

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 checks.

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 welcomed.

+ORC an526164@anon.penet.fi

--------------------------------------------------------
LESSON C (3) - How to crack Windows, cracking as anArt:
Web trends, Instant Access (end) and the proximity trick
--------------------------------------------------------

I. [WEB TRENDS]

It's really amazing: I began this tutorial in february 1996... the year is not yet finished but many things have already changed, and how! First of all the Web proves to be even more significant that I would
ever have thought: it's -de facto- an ANTI-ESTABLISHMENT and ANTI-CONSUME "permanent" tool... more than that: it's an EVOLVING and SHARP tool!

I do not know if you will agree with me, but it seems to me that it is now NOT ANY MORE NECESSARY to buy any of the following things (and this is a quite incomplete list:

1) Newspapers Are almost all on the Web for free


2) Magazines Are almost all on the Web for free
3) Software All on the Web for free
4) Books on the Web (even the *images* inside the
books you would have bought are somewhere)
5) Post_stamps e-mail is free and ubiquitous
6) Hard_disks free megabytes everywhere on the Web (for pages and/or software, quite a lot of offering (at the moment, middle november 1996 you can get -for free- about 80 megabytes for each
email address you have). Should you do not deem this space enough, you may multiply them -ad libitum- using one of the many free "alias e-mail addresses" generators or, as a brilliant scholar of mine
(re)discovered, you may easily "caper" (the passwords of) pages established by the lusers.

I assure you that I used to spend quite a lot of money buying all the preceding items. The case of the CD-ROM magazines (and of software in general) seems to me to be the most relevant. In my earlier
lessons I advised you to buy CD-ROM software at "kilo" prices in second hand shops (obviously never when the magazines themselves do appear)... even this trick is now useless: there is NO software that you
cannot find on the Web (I'll bet that the CD-ROM mags are not making any easy money any more now). This truth may be difficult to slurp until you learn HOW to search effectively on the Web, a very difficult art
-per se-, that all real crackers should master. A little tip: if you are in a hurry do your searches using your own search engines instead of using only the ubiquitous AltaVista, FTP and Webcrawler (which you
SHOULD use, of course, but not alone).

And loo! Good old Internet, made by governments and universities with public money and no private partecipation whatsoever reveals itself to be the most striking revolution of the last years in spite of the
continuous blah blah about free markets and private initiative... quite funny, isn't it?

New promising patterns are emerging: it is clear (to me) that the future of cracking lays in JavaScript applets: Netscape has opened quite a Pandora Box... now everybody is scrambling to close it... TOO
LATE! Find the relevant documentation, tutorials, software, tools, examples... even teachers! Everything is there for free on the Web! Study it, and when you are ready study it again... take it easy: we have a long
cracking future before us...

Here is a nice example (by LaDue) of an interesting applet: this one forges an e-mail from the browsers of your page sending it to the address contained in the string "toMe". The browser of your page
initiates the mail by connecting (involuntarily) to port 25 (int mailPort=25).

Now, let's just academically imagine... you would put your own address (faked email address but working depot when you need to fetch the messages, as usual) in the string "toMe"... well, scanning
incoming mail you could get the full e-mail address, including the user name, of many people who have seen your page.

See LaDue example at:


http://www.math.gatech.edu/~mladue/PenPal.java

JavaScript and Java are two completely different things: The coincidence in the name is only a stupid marketing move from Netscape. JavaScript is so easy it's a shame, and this makes it the ideal weapon
for masscracking (Java on the countrary is a "real" programming language). The implications of easy Javascript use, of internet growth and of the "on the fly" JavaScript workings for the drafting of much more
interesting applets are obvious, I'll let them to the intuition (and fantasy) of my cleverest readers.

55
II.[INSTANT ACCESS] End

I'll admit it: I am a little deceived: the +HCU strainer (Instant access protection scheme) has been solved only by very few (pretty competent) crackers. The amount of people that has NOT cracked instant
access (and that as relentlessy asked for more "clues") stood in no sound relation to the very few that solved it. I intended to give my complete solution in this lesson C3 to allow everybody to have (good) software
for free... but too few worked hard on it to let you all lazy ones deserve a "ready- made" solution... I will therefore publish here one of the "incomplete" (albeit very good) solutions.

The solution cracks the scheme but requires a little work of your part to accomplish it... what I mean is this: studying the following you'll be able to crack every Instant access protected code in a couple of
hours, not immediatly... this is good, will make the lazy lurkers work (at least a little :=)

Here it is (C++ code of the solution and admission letter), I only took off the name of the candidate:

Cracking Instant Access_____________


by xxxxxxxx
Application for 1996 Higher Cracking University

This is my solution to the strainer for admittance into your HCU. While I was successful in bypassing the protection (and hence now have a nice collection of software for free) I am the first to admit that my
solution is not the best. However, I am very proud of the work I have done on this project and it is by far the most difficult crack I've ever done. In the past I've traced programs, and when they did something I did
not like, I looked at the jumps immediately before that and reversed them.

Because of idiot programming this worked about 60% of the time, however in many programs I was just stuck. With the hints you provided in your tutors I was able to actually disassemble the program and
understand why it did things. Believe me this is a big jump. Anyway, here is my solution.

I have dozens of handwritten notes and pages of code that I copied out of soft-ice, and any that are important I will type into this report, however most turned out to be unimportant. I have also created a
"Magic" number generator and a reverse generator. I am very proud that I was able to create these, because the "Magic" number seemed so mysterious at first, and now I have complete mastery of it, a great
feeling of power.

I began the project by following the introductory steps in lessons C1 and C2. I got lost somewhere in C2, but I kept going. I got to the end with a vague understanding of what was happening and decided
that I needed to understand this fully before I could do anything useful towards cracking it.

I left my computer alone and read through the code again, making notes and explanations for my own use. About the third time through everything clicked, it was like a light bulb going off in my head. You
mentioned that not everything in Lesson C1 was correct.

Here is a list of what I found to be incorrect.

1. The offsets in the code were not the same. (this is a good idea to keep people from cheating when pinpointing the correct code)

2. The pointers to where things are saved in memory were not the same.

3. You wrote that the 1st digit plus 7 was saved and then you wrote that the 2nd plus 3 was saved. It is the other way around! 1st plus 3 and 2nd plus 7. (just checking if we are paying attention huh?)

I think that's all of the one's I found although there were many specific instances of each one. So here's what I did.

I did a search on the 18 digit code I typed in. I found it at 30:8xxxxx and did a bpr on it. I let it run, and looked each time something accessed that area. Eventually I found code that checked if the digits
were between 30 and 39 and copied them to DS:8CD8. So there lies the code with the "-" 's stripped off of it. I did a bpr on this area. It copied itself to DS:8CB8, and I bpr'ed that as well. I discovered that what
was going on was, it copied itself, then that copy was transformed into the "Magic" number.

So I did a little stack fishing, and found a CALL at offset 5C04 which copies the code from 8CB8 and converts it into the "Magic" number. At this point I traced into the call and got really fucking lost, so I
stepped back had a sip of Vodka and thought. I don't care HOW the "magic" gets there, only that it is there. I figured once I figured out what "magic" I needed I could trace over the call that put it there, and then put
in whatever "magic" I wanted. So I traced on to see what happened to the "magic" number that had been produced. I had a bpr on the "magic" and it stopped on the first line of code below.

The code is copied from my handwritten notes, so not everything is accurate (I only wrote down what I thought was important)

2b67:2598 mov al, es:[bx] ; 12th digit of magic


mov [bp-03], al ; ??????
mov al, [bp-03] ; maybe an inefficient compiler
result
add al, d0 ; clean it
mov [bp-04], al ; save it in [8ca6]
les bx, bp+06
add bx, si ; point to 12th again
mov byte ptr es:bx, 30 ; make it a '0'
push then more crap and then
:253d mov al, es:bx ; 1st digit
mov ah, 00 add ax,ffd0 ; clean it
cwd
add [bp-06], ax ; [8c90] is zero to start
this loop repeats 18 times, summing up the "magic" number, with the 12th set to 0

:256e mov [bp-07], al ; save remainder of sum/a in [8c8f]


cmp [al, bp-05] ; is 12th (in al) save as remainder of sum/a?

Aha!, this is what you were talking about at the end of C2, where the remainder doesn't match the 12th number.

I knew I was on the right track. I could feel it.


I traced down farther after the remainder check (I used 8888-8888-8888-8888-88 as my code from then on because it passed this check and was easy to remember) and I found code which compared the
value at ds:8D00 with the value at ds:8D0C and if it did not match jumped to beggar off.

Then it checks if ds:8D06 is equal to ds:8D0E and if not equal jumps to beggar off. So I knew that 8D00 must equal 8D0C and that 8D06 must equal 8D0E.

All I needed to do was figure out where these came from. I bpr'ed on 8D0C and found code which wrote the number to it.

I did not copy the ASM down, but this is what I wrote:

move 15th of "Magic" into AX fix it to 0-9 by +- A


put it in SI
mov 16th into AX
mul si by A
add ax to si
mov 17th to AX
mul si by A
add ax to it
put 18th in AX
mul si by A
add AX to it ; This is ds:8D0C !!!!
So now I knew where this came from, the last 4 digits of the "magic" I bpr'ed on 8D0E and found out quickly that the first digit of the "magic" was put into ds:8D0E.

Things were looking good. However, I was unable to figure out how ds:8D06 and ds:8D00 were created. I know they are related to the product code because they only change when it does. But they are
put there by a MOVSW command and I cannot figure out how to predict where they are copied from, because it is only done once and it is never from the same place, so all my attempts to bpr on the spot they are
copied from failed because it copies from a new spot each time.

I felt dejected. I could not figure it out, even after days of pointless tracing.

I stepped back and thought, and drank a can of Coke at 2 a.m...

(note from +ORC: Coke is dangerous for your health and your cracking purposes... drink only Martini-Wodka and use by all means only russian Wodka)

...I still had not figured out how the "magic" worked. I decided to do that and come back to the problem of the numbers generated from the Product Code.

I knew the call at cs:5C04 completely generated the "magic" so I started there. I traced through it several times and found that it made a CALL 3517 three times, then looped 6 times. So it called 3517 a
total of 18 times. I also noticed that the CALL changed the number, but nothing else did, it just set up the calls.

So I traced into CALL 3517 and came up with this:

mov ax,ss

56
nop inc bp
push bp
mov bp,sp
push ds
mov ds,ax
xor ax a bunch more unimportant stuff
:356b mov al,es:[bx} ; al = 18th digit
cbw push ax
mov ax, A
sub ax,[5dad] ; subtract 6 from a to get 4
imul [5db1] pop dx ; 18th digit
add dx,ax add dx, -30 ;clean it
mov [5db5], dx ;save it then fix [5db5] to be between 0 and 9
mov al, es:[bx] ; load 18th again
cbw push ax
mov ax,a
sub ax,[5dad]
imul [5db3]
pop dx ; 18th digit
add dx, ax
add dx, -30 ;clean it
:35bb mov [5db7], dx ;save it.
:35d9 mov bx,[5dad]
mov es, bp+1a
add bx,[bp+18]
mov al,es:[bx-1] ; al = 6th digit
mov [5dc3], al ; save it
mov bx,[5dad]
mov es,[bp+1e]
add bx,[bp+1c]
mov al,es:[bx-1] ; 12th digit
mov [5dc4], al ; save it more junk then
3605: mov bx,[5dbf] ; this is the beginning of a loop
mov es,[bp+1a]
add bx,[bp+18]
mov al,es:[bx-1] ; 5th digit
push ax ; save it
mov ax,[5db5] ; [5db5] created above using 18th digit
mov dx,A
imul dx ;[5db] *A
les bx,[bp+0c]
add bx,ax
add bx,[5db7] ; created using 18th
pop ax ;5th digit
sub al,es:[bx};subtract a value from the lookup table
les bx add bx,[5dbf]
mov es:[bx],al ; Put new value in 6th spot fix it so that it's
; between 0 and 9 by +- A
:3656 mov bx,[5dbf]
mov es,[bp+1e]
add bx,[bp+1c]
mov al,es:[bx-1] ; 11th digit
push ax mov ax,[5db5]
mov dx,a
imul dx
les bx
add bx,ax
add bx,[5db7]
pop ax ;11th digit
sub al,es:[bx] ; subtract a value from lookup table
les bx, [bp+1c]
add bx,[5db7]
mov es:[bx],al ;put it in 12th spot fix it to be between 0 and 9.

The loop above repeats doing the same thing, changing 2 numbers, but not always the same two. The next time through it changes 5th and 11th, after that the 4th and 10th, 3rd and 9th then the 2nd and
8th using this same pattern. After the loop it changes the 1st and 7th using the values of the original 6th and 12th which were saved in [5dc3] and [5dc4] using the same pattern. I quickly wrote a program in C
which would produce this number, and it worked fine.

I traced into the second call of 3517 and found that the parameters passed to it changed which values where used to create [5db5] and [5db7], whether they increment or decrement, whether you add 0 or
64 to your index for the lookup and the digits which are changed. All three calls to 3517 have a different arrangement, but the their arrangement is the same each time they are called. For instance, the three calls
are looped over 6 times, on each instance that the 1st call is executed it will change the 6th,12th,5th, 11th, etc. So I modified my C program to mimic the behaviour of each call and looped it six times, expecting
this to be the "magic" number. To my surprise it was not right.

So I followed the code until after the 3 CALL 3517's had been made, this was the number my generator had given me, so it must do something more afterwards.

I found the following code, still within the cs:5c04 call

:44C1 mov al,es:[bx+si-2] ; 17th digit


add al,d0 ;clean it
mov [5dc1], al ;save it
les bx
mov al,es:[bx+si-2] ; 18th digit
add al,d0 ;clean it
mov [5dc2],al ;save it
mov [5dbf],0
jmp 455f :44df
les bx
add bx,[5dbf]
mov al,[5dc1] ;17th cleaned
sub es:[bx],al ;1st digit has 17th cleaned subtracted from it
;fix it between 0 and 9
mov al,[5dc2] ;18th cleaned 4520
sub es:[bx],al ;7th - 18th cleaned is put in 7th spot fix it
; between 0 and 9
:455b inc word ptr [5dbf]
mov ax,[5dbf]
cmp ax,[5dad] ; run six times
jge 456b
jmp 44df 456b: blah blah continue on.

This loop executes six times each time incrementing the digit to be changed by one so that the first change changes the 1st digit, and the next time through the loop the 2nd then the 3rd.....till the sixth. The
second change alters the 7th through the 12th digits. I added code to do this at the end of my Generator, and I now had a "Magic" number generator. However this did not do me much good in itself. The
breakthrough was reversing this program (it wasn't hard, but getting all the bugs out was really tough) so that it takes a "magic" number as input and tells you what registration number will produce it. I have
included the source code for both programs to prove that they are my own work. The coding is not the best, they are my own crude tools, and they do the job I need them for. But now I am home free. Even without
knowing how the product code is manipulated to come up with ds:8D00 and ds:8d06 I can crack it. Here's what I did.

The product code given me was 3850-0118-6260-1057-23 I traced to where ds:8D00 and ds:8D06 are placed they were: ds:8D00 = E03 ds:8D06 = 3 I knew the last 4 digits when added, and multiplied
as explained above must be E03 so this is what I wrote down, using my calculator

DFC + 7 =E03

This is the final answer, but I need to work backwards from here

166 * A = DFC
15E + 8 = 166
23 * A = 15E
1E +5 = 23

57
3 * A = 1E

Just working things backwards from the way the program did it I figured out the last 4 digits of the magic code need to be 3587 in order for it to produce E03 as a result. I also know that the first digit must
be equal to ds:8d06 which is 3 so I now have:

3___-____-____-__35-87

as a "magic" number and I fill it in with 1's

3111-1111-111X-1135-87

I left the 12th number as an X because I remember that the remainder of the sum of all the digits except the 12th must be equal to the 12th.

3+1+1+1+1+1+1+1+1+1+1+1+1+3+5+8+7 = 26 26/A
26 26/A = 3 with a remainder of 8,

so the 12th digit is an 8!

My "magic" number should be 3111-1111-1118-1135-87 So I run my UNINSTAN program, which tells me that in order to get that "magic" I need to enter the following registration code: 4798-8540-6989-
6899-53 I enter this in, the "Retrieve" button is enabled and I install Norton Utilities without a hassle! I used the same method to install Wine Select (I've been interested in wine since reading about your Pomerol),
Labels Unlimited (which I use for what else? Barcodes!), Harvard Graphics, and Lotus Ami Pro, which I'm using to write this report on!

Well, that's it. That is how I cracked Instant Access. As I mentioned above it is not the best way, but I gave everything I had and it's the best I could do.

I have succeeded because I have beaten the protection, and because I taught myself a lot along the way. I'm sure you already have a "magic" number generator of your own, but I included mine so you
could see it. If I just knew how the product code produces those 2 numbers I could create a product code to registration number converter, which I assume is what the operators at Instant Access have when you
call them to buy stuff.

One last note about this assignment. I know that you have realized that Instant Access was hard to find. I want to tell you how I got it, a bit a social engineering in itself. After searching every library and
book/magazine store in the city I got on the Internet and asked. Nobody had it.

So I found the Instant Access homepage. ...

(this will not be published, coz I, +ORC, do not want to expose my crackers, but the way this guy got hold of the protection scheme is in itself worth is access to the +HCU)

...So as you can see, I have gone to great lengths for admittance into your University, and I hope I have earned it. I am proud to wear my +

...address follows
And here are the two C++ programs:

INSTANT.CPP-----------------------------------
// Template for byte patch files
#include
#include
#include
#include
#include

void main()
{
char fix(char x);

char *t; //*stopstring


int save1, save2,fdbf,fdbs, i;
static int table[208] = {1,3,3,1,9,2,3,0, 9,0,4,3,8,7,4,4,
5,2,9,0,2,4,1,5, 6,6,3,2,0,8,5,6,
8,9,5,0,4,6,7,7, 2,0,8,0,6,2,4,7,
4,4,9,5,9,6,0,6, 8,7,0,3,5,9,0,8,
3,7,7,6,8,9,1,5, 7,4,6,1,4,2,7,1,
3,1,8,1,5,3,3,1, 2,8,2,1,6,5,7,2,
5,9,9,8,2,9,3,0, 0,4,5,1,1,3,8,6,
1,1,9,0,2,5,5,5, 1,7,1,5,8,7,1,9,
8,7,7,4,4,8,3,0, 6,1,9,8,8,4,9,9,
0,7,5,2,3,1,3,8, 6,5,7,6,3,7,6,7,
4,2,2,5,2,4,6,2, 6,9,9,1,5,2,3,4,
4,0,3,5,0,3,8,7, 6,4,8,8,2,0,3,6,
9,0,0,6,9,4,7,2, 0,1,1,1,1,0,1} ;

//_clearscreen(_GCLEARSCREEN);
printf("Enter the 18 digit Reg code: ");
gets(t);

for (i=1; i<=6 ; i++)


{
save1 = t[5]; // save the sixth digit
save2 = t[11]; // save the twelfth digit

fdbf = 0xFFC+t[17]-0x1000-0x30 ; // create [5db5]


if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = fdbf; // and [5db7]

t[5] = t[4] - table[fdbf*0xA+fdbs] ; // sixth number


t[5] = fix(t[5]);

t[11] = t[10] - table[fdbf*0xA+fdbs+0x64]; // 12th


number
t[11] = fix(t[11]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[4] = t[3] - table[fdbf*0xA+fdbs] ; // 5th number


t[4] = fix(t[4]);

t[10] = t[9] - table[fdbf*0xA+fdbs+0x64]; // 11th


number
t[10] = fix(t[10]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[3] = t[2] - table[fdbf*0xA+fdbs] ; // 4th number

58
t[3] = fix(t[3]);

t[9] = t[8] - table[fdbf*0xA+fdbs+0x64]; // 10th number


t[9] = fix(t[9]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[2] = t[1] - table[fdbf*0xA+fdbs] ; // 3rd number


t[2] = fix(t[2]);

t[8] = t[7] - table[fdbf*0xA+fdbs+0x64]; // 9th number


t[8] = fix(t[8]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[1] = t[0] - table[fdbf*0xA+fdbs] ; // 2nd number


t[1] = fix(t[1]);

t[7] = t[6] - table[fdbf*0xA+fdbs+0x64]; // 8th number


t[7] = fix(t[7]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[0] = save1 - table[fdbf*0xA+fdbs]; // first digit


t[0] = fix(t[0]);
t[6] = save2 - table[fdbf*0xA+fdbs+0x64]; // 7th digit
t[6] = fix(t[6]);

//puts(t);
// end of first call
////////////////////////////////////////////////

save1 = t[5]; // save the sixth digit


save2 = t[17]; // save the 18th digit

fdbf = t[10]+0x4-0x30 ; // create [5db5]


if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;

fdbs = t[9]+0x4-0x30; // and [5db7]


if (fdbs < 0x0)
fdbs += 0xA; // fix it if necessary
else if (fdbs >= 0xA)
fdbs -= 0xA;

t[5] = t[4] - table[fdbf*0xA+fdbs] ; // sixth number


t[5] = fix(t[5]);

t[17] = t[16] - table[fdbf*0xA+fdbs+0x64]; // 18th


number
t[17] = fix(t[17]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[4] = t[3] - table[fdbf*0xA+fdbs] ; // 5th number


t[4] = fix(t[4]);

t[16] = t[15] - table[fdbf*0xA+fdbs+0x64]; // 17th


number
t[16] = fix(t[16]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[3] = t[2] - table[fdbf*0xA+fdbs] ; // 4th number


t[3] = fix(t[3]);

t[15] = t[14] - table[fdbf*0xA+fdbs+0x64]; // 16th


number
t[15] = fix(t[15]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[2] = t[1] - table[fdbf*0xA+fdbs] ; // 3rd number


t[2] = fix(t[2]);

t[14] = t[13] - table[fdbf*0xA+fdbs+0x64]; // 15th


number
t[14] = fix(t[14]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)

59
fdbs = 0;

t[1] = t[0] - table[fdbf*0xA+fdbs] ; // 2nd number


t[1] = fix(t[1]);

t[13] = t[12] - table[fdbf*0xA+fdbs+0x64]; // 14th


number
t[13] = fix(t[13]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[0] = save1 - table[fdbf*0xA+fdbs]; // first digit


t[0] = fix(t[0]);
t[12] = save2 - table[fdbf*0xA+fdbs+0x64]; // 13th
digit
t[12] = fix(t[12]);

//puts(t);
// end of second call
////////////////////////////////////////////////

save1 = t[11]; // save the 12th digit


save2 = t[17]; // save the 18th digit

fdbf = t[1]+0x4-0x30 ; // create [5db5]


if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;

fdbs = t[2]+0x4-0x30; // and [5db7]


if (fdbs < 0x0)
fdbs += 0xA; // fix it if necessary
else if (fdbs >= 0xA)
fdbs -= 0xA;

t[17] = t[16] - table[fdbf*0xA+fdbs] ; // 18th number


t[17] = fix(t[17]);

t[11] = t[10] - table[fdbf*0xA+fdbs+0x64]; // 12th


number
t[11] = fix(t[11]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[16] = t[15] - table[fdbf*0xA+fdbs] ; // 17th number


t[16] = fix(t[16]);

t[10] = t[9] - table[fdbf*0xA+fdbs+0x64]; // 11th


number
t[10] = fix(t[10]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[15] = t[14] - table[fdbf*0xA+fdbs] ; // 16th number


t[15] = fix(t[15]);

t[9] = t[8] - table[fdbf*0xA+fdbs+0x64]; // 10th number


t[9] = fix(t[9]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[14] = t[13] - table[fdbf*0xA+fdbs] ; // 15th number


t[14] = fix(t[14]);

t[8] = t[7] - table[fdbf*0xA+fdbs+0x64]; // 9th number


t[8] = fix(t[8]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[13] = t[12] - table[fdbf*0xA+fdbs] ; // 14th number


t[13] = fix(t[13]);

t[7] = t[6] - table[fdbf*0xA+fdbs+0x64]; // 8th number


t[7] = fix(t[7]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[12] = save2 - table[fdbf*0xA+fdbs]; // 13th digit


t[12] = fix(t[12]);

t[6] = save1 - table[fdbf*0xA+fdbs+0x64]; // 7th digit


t[6] = fix(t[6]);

60
// end of third call
////////////////////////////////////////////////

} // end of for loop

// Now we finish it up
save1 = t[16] + 0xD0 - 0x100; // [5dc1]
save2 = t[17] + 0xD0 - 0x100; // [5dc2]

for (i=0; i<6; i++)


{
t[i] = t[i] - save1;
t[i] = fix(t[i]);

t[i+6] = t[i+6] - save2;


t[i+6] = fix(t[i+6]);
}

printf("'Magic' code is: ");


for (i=0; i<18 ;i++) // output the string (only first 18)
putc(t[i], stdout);
printf("\n\n Created by xxxxx for +Orc's HCU 1996");

} // end of main()

char fix(char x)
{
if (x < '0')
x = x+0xA;

else if (x > 0x39)


x -= 0xA;

return x;
}

---------------------------------------------------
UNINSTANT.CPP

#include
#include
#include
#include
#include

void main()
{
char fix(char x);

char *t;
int save1, save2,fdbf,fdbs, i,q, fdbssave,fdbfsave;
static int table[208] = {1,3,3,1,9,2,3,0, 9,0,4,3,8,7,4,4,
5,2,9,0,2,4,1,5, 6,6,3,2,0,8,5,6,
8,9,5,0,4,6,7,7, 2,0,8,0,6,2,4,7,
4,4,9,5,9,6,0,6, 8,7,0,3,5,9,0,8,
3,7,7,6,8,9,1,5, 7,4,6,1,4,2,7,1,
3,1,8,1,5,3,3,1, 2,8,2,1,6,5,7,2,
5,9,9,8,2,9,3,0, 0,4,5,1,1,3,8,6,
1,1,9,0,2,5,5,5, 1,7,1,5,8,7,1,9,
8,7,7,4,4,8,3,0, 6,1,9,8,8,4,9,9,
0,7,5,2,3,1,3,8, 6,5,7,6,3,7,6,7,
4,2,2,5,2,4,6,2, 6,9,9,1,5,2,3,4,
4,0,3,5,0,3,8,7, 6,4,8,8,2,0,3,6,
9,0,0,6,9,4,7,2, 0,1,1,1,1,0,1} ;

printf("Enter the 18 digit 'Magic' code: ");


gets(t);

save1 = t[16] + 0xD0 - 0x100; // [5dc1]


save2 = t[17] + 0xD0 - 0x100; // [5dc2]

for (i=5; i>=0 ; i--) // fix it before main loop


{
t[i] = t[i] +save1;
t[i] = fix(t[i]);

t[i+6] = t[i+6] + save2;


t[i+6] = fix(t[i+6]);
}

for (i=1; i<=6 ; i++)


{
// begin third call
fdbf = 0x4+t[1]-0x30 ; // create [5db5]
if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = 0x4+t[2]-0x30 ; // create [5db7]
if (fdbs < 0x0)
fdbs += 0xA; // fix it if necessary
else if (fdbs >= 0xA)
fdbs -= 0xA;

save1 = t[6]; //save 7th


save2 = t[12]; // and 13th

for (q=1; q<=5; q++) // put [ ]'s where they were at end
of loop
{
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
}
fdbssave = fdbs;
fdbfsave = fdbf;

fdbf -= 1; // decrement
if (fdbf == -1)

61
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[6] = t[7] + table[fdbf*0xA+fdbs+0x64]; // 7th digit


t[6] = fix(t[6]);

t[12] = t[13] + table[fdbf*0xA+fdbs]; // 13th digit


t[12] = fix(t[12]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[7] = t[8] + table[fdbf*0xA+fdbs+0x64]; // 8th digit


t[7] = fix(t[7]);

t[13] = t[14] + table[fdbf*0xA+fdbs]; // 14th digit


t[13] = fix(t[13]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[8] = t[9] + table[fdbf*0xA+fdbs+0x64]; // 9th digit


t[8] = fix(t[8]);

t[14] = t[15] + table[fdbf*0xA+fdbs]; // 15th digit


t[14] = fix(t[14]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[9] = t[10] + table[fdbf*0xA+fdbs+0x64]; // 10th digit


t[9] = fix(t[9]);

t[15] = t[16] + table[fdbf*0xA+fdbs]; // 16th digit


t[15] = fix(t[15]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[10] = t[11] + table[fdbf*0xA+fdbs+0x64]; // 11th


digit
t[10] = fix(t[10]);

t[16] = t[17] + table[fdbf*0xA+fdbs]; // 17th digit


t[16] = fix(t[16]);

t[11] = save1 + table[fdbfsave*0xA+fdbssave+0x64]; //


12th digit
t[11] = fix(t[11]);

t[17] = save2 + table[fdbfsave*0xA+fdbssave]; // 18th digit


t[17] = fix(t[17]);

// end of third call

// begin second call


fdbf = 0x4+t[10]-0x30 ; // create [5db5]
if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = 0x4+t[9]-0x30 ; // create [5db7]
if (fdbs < 0x0)
fdbs += 0xA; // fix it if necessary
else if (fdbs >= 0xA)
fdbs -= 0xA;

save1 = t[0]; //save first


save2 = t[12]; // and 13th

for (q=1; q<=5; q++) // put [ ]'s where they were at end
of loop
{
fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;
}
fdbssave = fdbs;
fdbfsave = fdbf;

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[0] = t[1] + table[fdbf*0xA+fdbs]; // 1st digit


t[0] = fix(t[0]);

t[12] = t[13] + table[fdbf*0xA+fdbs+0x64]; // 13th digit


t[12] = fix(t[12]);

62
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[1] = t[2] + table[fdbf*0xA+fdbs]; // 2nd digit


t[1] = fix(t[1]);

t[13] = t[14] + table[fdbf*0xA+fdbs+0x64]; // 14th digit


t[13] = fix(t[13]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[2] = t[3] + table[fdbf*0xA+fdbs]; // 3rd digit


t[2] = fix(t[2]);

t[14] = t[15] + table[fdbf*0xA+fdbs+0x64]; // 15th digit


t[14] = fix(t[14]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[3] = t[4] + table[fdbf*0xA+fdbs]; // 4th digit


t[3] = fix(t[3]);

t[15] = t[16] + table[fdbf*0xA+fdbs+0x64]; // 16th digit


t[15] = fix(t[15]);

fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;

t[4] = t[5] + table[fdbf*0xA+fdbs]; // 5th digit


t[4] = fix(t[4]);

t[16] = t[17] + table[fdbf*0xA+fdbs+0x64]; // 17th digit


t[16] = fix(t[16]);

t[5] = save1 + table[fdbfsave*0xA+fdbssave]; // 6th


digit
t[5] = fix(t[5]);

t[17] = save2 + table[fdbfsave*0xA+fdbssave+0x64]; // 18th


digit
t[17] = fix(t[17]);
// end of second call
// begin first call
fdbf = 0xFFC+t[17]-0x1000-0x30 ; // create [5db5]
if (fdbf < 0x0)
fdbf += 0xA; // fix it if necessary
else if (fdbf >= 0xA)
fdbf -= 0xA;
fdbs = fdbf; // and [5db7]

save1 = t[0]; //save first


save2 = t[6]; // and 7th

for (q=1; q<=5; q++) // put [ ]'s where they were at end
of loop
{
fdbf -= 1; // decrement
if (fdbf == -1)
fdbf = 9;
fdbs -= 1;
if (fdbs == -1)
fdbs = 9;
}
fdbssave = fdbs;
fdbfsave = fdbf;

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[0] = t[1] + table[fdbf*0xA+fdbs]; // 1st digit


t[0] = fix(t[0]);

t[6] = t[7] + table[fdbf*0xA+fdbs+0x64]; // 7th digit


t[6] = fix(t[6]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[1] = t[2] + table[fdbf*0xA+fdbs]; // 2nd digit


t[1] = fix(t[1]);

t[7] = t[8] + table[fdbf*0xA+fdbs+0x64]; // 8th digit


t[7] = fix(t[7]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

63
t[2] = t[3] + table[fdbf*0xA+fdbs]; // 3rd digit
t[2] = fix(t[2]);

t[8] = t[9] + table[fdbf*0xA+fdbs+0x64]; // 9th digit


t[8] = fix(t[8]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[3] = t[4] + table[fdbf*0xA+fdbs]; // 4th digit


t[3] = fix(t[3]);

t[9] = t[10] + table[fdbf*0xA+fdbs+0x64]; // 10th digit


t[9] = fix(t[9]);

fdbf += 1; // increment
if (fdbf == 10)
fdbf = 0;
fdbs += 1;
if (fdbs == 10)
fdbs = 0;

t[4] = t[5] + table[fdbf*0xA+fdbs]; // 5th digit


t[4] = fix(t[4]);

t[10] = t[11] + table[fdbf*0xA+fdbs+0x64]; // 11th digit


t[10] = fix(t[10]);

t[5] = save1 + table[fdbfsave*0xA+fdbssave]; // 6th


digit
t[5] = fix(t[5]);

t[11] = save2 + table[fdbfsave*0xA+fdbssave+0x64]; // 12th


digit
t[11] = fix(t[11]);
// end of first call
} // end for loop

printf("\nTo Get That 'Magic' Use: ");


for (i=0; i<18 ;i++) // output the string (only first 18)
putc(t[i], stdout);
printf("\n\n Created by +xxxxx for +Orc's HCU 1996");

} // end of main()

char fix(char x)
// fixes chars to between 0 and 9
{
if (x < '0')
x = x+0xA;

else if (x > 0x39)


x -= 0xA;

return x;
}

III. THE [DATADUMP_WINDOW] TRICK & HOW TO SEARCH THE WEB.

[WINFORMANT 4 HOW TO FIND IT]


I have chosen (as usual) an older windows application for Win 3.1. (Version 1.10, by Joseph B. Albanese), in order to terminate completely the "password lessons" and at the same time show you a nice
little trick that can be very useful in cracking *ALL* protected programs (password protected or time protected or function disabled): memory windows_dumping. There is in almost all protection routines, as you
have already learned, a moment when on the stack appears the ECHO of the real, "correct" passnumber or password, in order to compare the input of the user with it.

The location of this ECHO varies, but it will be most of the time in a range of +- 0x90 bytes from the user input. This is due to datadump windows restraints inside the tools used by the protectionists I'll not
delve inside here, and this use is bound to diminish (especially after this lesson :=).

You'll find the files that I use in this lesson searching the web with the usual search_tools and search_strategies: These are names, lengths and dates of the relevant files... this will allow you to FTPMAIL
them after having located them through an ARCHIE_search:

CTL3D DLL 20976 17/08/93 4:36


README WRI 2688 08/05/94 1:54
SS3D2 VBX 88096 11/06/92 18:42
STDLL DLL 10880 06/05/94 22:57
THREED VBX 64432 17/07/93 0:00
WIN4MANT EXE 562271 07/06/96 17:51
WIN4MANT HLP 190608 08/05/94 0:36
XLIST VBX 15248 15/02/93 0:00

Please do not underestimate the importance of *EXACT NAMES* on the Web (be it of people, of subjects or of software)... as a matter of fact the Web corroborates (every day more). The old intuition from
Persio: NOMEN ATQUE OMEN: how true! Think a moment about it, the importance of the NAMES on the Web is astonishing (and growing)!

1) It is true for http://... addresses: domains must be unique and registered (and the Web registration burocrats will get from you 100 dollars per year just to keep them registered);

2) It is true for programs (you must know BEFOREHAND the name of a file to find it quickly on the Web); 3) It's even true for your own site denomination (try searching for "Bill's" page instead than for
"WIKKY_WAKKY's" page... that's (reversing this approach) one of the reason I have a "+" inside my handle, this confuses the search engines just enough to give me a little more anonymity (search for me! You'll
get quite a lot of Warcraft stuff :=).

Enough! If you do not know neither why all this happen nor how to search the Web, but are interested in these matters (as you should), study the web search engines themselves and read the relevant help
files (search AltaVista and WebCrawler for "FTPMAIL", "WWW via e-mail", "AGORA", "search strategies" etc).

It's amazing how few crackers (not to mention the lusers) do actually read the help files of the search engines they are using, which should be your bible (or the coran, or some other crap, for all I care
about religions), your alpha and omega! The (growing) amount of junk on the Web makes your ability to search effectively the little grains of interesting truths that are escaping the growing heavy censorship of our
enemies even more important.

Back to our [Winformant] cracking now, and back to our stackdump window trick... here you are:

[WINFORMANT CRACKING]
This application is -per se- absolutely crap, I doubt you'll ever use it: this program is so primitive it must have been one of the first crappy visual basic experiments made by his programmer... but this
[Winformant] program is nevertheless very interesting for us coz it possesses a curious (and pretty rare) "deactivate" mode, i.e. you can "unregister" it on the fly if you feel the need to... it beats me why the
programmer wanted such a feature inside... he was just probably collecting little routines and mixing them without sound reasons.

This feature is as rare as useless, but it is worth for cracking scholars that (should) investigate password algorithms with valid and invalid codes without having to reinstall everything only in order to delete
previous valid codes.

For your cracking exercises you should therefore choose programs that have "REVERSIBLE" protections (like this Winformant... very rare) or that can be re-registered a billion times (that's a more frequent
protection pattern). Programs that keep the valid registration on *.ini or special files can also be useful... you just need to change a couple of lines in these files to restore the "unregistered" mode.

64
The trick we'll use in this lesson: "password proximity", bases on the fact that the protectionists need to keep an eye on their protection when they "build" it and have to *see* closely the relationships
between

1) USER INPUT PASSNUMBER (i.e. the input registration number that the user should have bought, but could be a fake bad guy input)

2) USER INPUT TRANSFORMED (i.e. the result of the working of the protectionist's algorithm on the user input passnumber) and the

3) CORRECT PASSNUMBER ANSWER (The BINGO!) i.e., the Passnumber calculated with some algorithm on the bases of the USER INPUT NAME (the name of the user, eventually transformed in
USER INPUT TRANSFORMED).

In order to clear bugs these relationships must be constantly checked when they prepare the protection... i.e. when they are writing the protection code.

Most of the time all these data will therefore dwell inside a small stack... that means they will be "visible" in the SAME "watchwindow" inside the protectionist's debugger... and they use the same
turbodebugger (or Winice) YOU are using!

This means that most of the time the "ECHO" will swell not very far away from the USER INPUT. Therefore proceed as follows:

Fire Winice
Fire Winformant
Choose HELP
Choose REGISTRATION
Fill the registration fields
this is mine: "+ORC+ORC" as "Registrant"
and "12121212" as "Activation" code
CTRL+D ;switch to Winice
task ;let's see the names

:task
TaskName SS:SP StackTop StackBot StackLow TaskDB hQueue Events
WINWORD 1AD7:85F2 4A52 8670 7532 1247 122F 0000
PROGMAN 1737:200A 0936 2070 1392 066F 07F7 0000
DISKOMAT *2C5F:6634 1D3C 6AC6 5192 2CB7 2C9F 0000

hwnd DISKOMAT ;which window is getting the input?

:hwnd diskomat
WinHandle Hqueue QOwner Class Name Window Procedure
0EB4(0) 2C9F DISKOMAT #32769 04A7:9E6B
0F34(1) 2C9F DISKOMAT #32768 USER!BEAR306
365C(1) 2C9F DISKOMAT #32770 2C3F:0BC6
36BC(2) 2C9F DISKOMAT Button 2C3F:1CEA
3710(2) 2C9F DISKOMAT Edit 2C3F:24BE
3758(2) 2C9F DISKOMAT Edit 2C3F:24BE
37A0(2) 2C9F DISKOMAT Button 2C3F:1CEA
37E4(2) 2C9F DISKOMAT Button 2C3F:1CEA
... and many more irrelevant windows.

bmsg relevant_window wm_gettext ;let's pinpoint the code, here


;the relevant window is the first "edit" one (obviously),
;i.e. wHnd 3710 you could also use GetWindowsText or
;GetDlgItmText to locate the relevant routines

:bmsg 3710 wm_gettext ;set breakpoint


CTRL+D ;run the babe
Break Due to BMSG 3710 WM_GETTEXT C=01
Hwnd=3710 wParam=0050 lParam=2C5F629A msg=000D WM_GETTEXT
2C3F:000024BE B82F2C MOV AX,2C2F

So! Now that we have pinpointed the code... let's snoop around a little: first thing to do is a good stack command which, here, will work OK (in other cracking sessions it may not -magic involved- but do not
worry: if it does not work immediately, just pinpoint a little more... for instance on GetWindowText() (always good) or do a BPRW diskomat (also very useful), and then try and retry the stack... should this too fail to
work, do search for your input in memory (in the 30:0 lffffffff selector, as usual) and breakpoint range on it with ReadWrite, and then stack, stack, stack... till you get the "real" list of calls coming from your babe's
protection (in our example the babe's name is "DISKOMAT").

:stack
USER(19) at 073F:124C [?] through 073F:1239
CTL3D(02) at 2C3F:0D53 [?] through 2C3F:0D53
DISKOMAT(01) at 2C97:20B9 [?] through 2C97:20B9
DISKOMAT(01) at 2C97:3D94 [?] through 2C97:3D94
DISKOMAT(01) at 2C97:49E2 [?] through 2C97:4918
DISKOMAT(04) at 2C7F:EA20 [?] through 2C7F:EA20
USER(01) at 04A7:19BE [?] through USER!GETWINDOWTEXT
=> CTL3D(02) at 2C3F:24BE [?] through 04A7:3A3C‘

Beautiful stack picture! Immediately BPX on 2C7F:EA20 (on your computer the segment will differ, the offset will be the SAME).

2C7F:EA20 9A25ABA704 CALL USER!GETWINDOWTEXT


2C7F:EA25 8E4608 MOV ES,[BP+08]
2C7F:EA28 26FFB42C02 PUSH WORD PTR ES:[SI+022C]
2C7F:EA2D 8D865CFF LEA AX,[BP+FF5C]
2C7F:EA31 16 PUSH SS
2C7F:EA32 50 PUSH AX
2C7F:EA33 6A50 PUSH 50
2C7F:EA35 9A25ABA704 CALL USER!GETWINDOWTEXT
2C7F:EA3A 8D46AE LEA AX,[BP-52] ;load ptr "+ORC+ORC"
2C7F:EA3D 16 PUSH SS ;save pointer segment
2C7F:EA3E 50 PUSH AX ;save pointer offset
2C7F:EA3F 9A768D872C CALL 2C87:8D76 ;strlen "ORC+ORC"
2C7F:EA44 83C404 ADD SP,+04
2C7F:EA47 3D2800 CMP AX,0028
2C7F:EA4A 762C JBE EA78
...
2C7F:EA78 8D442C LEA AX,[SI+2C]
2C7F:EA7B FF7608 PUSH WORD PTR [BP+08]
2C7F:EA7B FF7608 PUSH WORD PTR [BP+08]
2C7F:EA7E 50 PUSH AX
2C7F:EA7F 9AE002772C CALL 2C77:02E0
2C7F:EA84 0BC0 OR AX,AX
2C7F:EA86 740F JZ EA97
2C7F:EA88 687F2C PUSH 2C7F
2C7F:EA8B 68E4ED PUSH EDE4
2C7F:EA8E 6A00 PUSH 00
2C7F:EA90 6A00 PUSH 00
2C7F:EA92 6A00 PUSH 00
2C7F:EA94 E94501 JMP EBDC
2C7F:EA97 8D46AE LEA AX,[BP-52] ;load ptr "+ORC+ORC"
2C7F:EA9A 16 PUSH SS ;various algor on input
2C7F:EA9B 50 PUSH AX ;we do not care
2C7F:EA9C 8D860AFF LEA AX,[BP+FF0A]
2C7F:EAA0 16 PUSH SS
2C7F:EAA1 50 PUSH AX
2C7F:EAA2 6A51 PUSH 51
2C7F:EAA4 8D442C LEA AX,[SI+2C]
2C7F:EAA7 FF7608 PUSH WORD PTR [BP+08]
2C7F:EAAA 50 PUSH AX
2C7F:EAAB 9ABA00772C CALL 2C77:00BA
2C7F:EAB0 0BC0 OR AX,AX
2C7F:EAB2 0F851101 JNE EBC7

65
2C7F:EAB6 8D8E5CFF LEA CX,[BP+FF5C] ;ptr "12121212"
2C7F:EABA 16 PUSH SS
2C7F:EABB 51 PUSH CX
2C7F:EABC 9A768D872C CALL 2C87:8D76 ;strlen "12121212"
2C7F:EAC1 83C404 ADD SP,+04
2C7F:EAC4 50 PUSH AX
2C7F:EAC5 8D865CFF LEA AX,[BP+FF5C] ;ptr "12121212"
2C7F:EAC9 16 PUSH SS
2C7F:EACA 50 PUSH AX
2C7F:EACB 8D860AFF LEA AX,[BP+FF0A] ...etc

OK, it's enough: now what obviously follows is to "algorithmize" this second string, and somewhere, then, you'll have a compare that checks and divides good guys from bad fellows.

BUT NOW IT'S ALSO THE MAGIC MOMENT OF THE ECHO! We know it, we feel it: The echo is somewhere... what can we do to find it? Should we search "12121212" in memory? No, look how many
locations we would find...

:s 30:0 lffffffff '12121212'


Pattern Found at 0030:0005AD6A
Pattern Found at 0030:0048AD6A
Pattern Found at 0030:007DED98
Pattern Found at 0030:007E25F8
Pattern Found at 0030:008E0FE1
Pattern Found at 0030:008E1433
Pattern Found at 0030:008E186F
Pattern Found at 0030:008E1904
Pattern Found at 0030:008E601A
Pattern Found at 0030:80509D6A
Pattern Found at 0030:8145AD6A
Pattern Not Found

And now...should we look for all occurrences of this string and get a memory dump of +- 0x90 around it till we find the echo... that's not zen... that's boring, even if we know that the relevant ones will
ALWAYS be the ones that have MORE than 80000000 in their "offset", i.e., in this case, only two:

Pattern Found at 0030:80509D6A


Pattern Found at 0030:8145AD6A

But this procedure is not always true, and in other protection there will be a proliferation of locations with the aim of deterring casual crackers... clearly the above method is no good... there must be some
other way... YES THERE IS!

THE LAST loading of the numeric input string in the code (the one after the strlen count) is most of the time (exspecially in Visual Basic and Delphy programs) the "right" one for our cracking purposes, coz
the protections follow (most of the time) this pattern (remember that we are here inside a stack "heavy" section of the code... if you want to crack higher I suggest you read some good literature about stack working
and stack magics inside the 80386/80486/80586 processors).

This is the usual sequence:

LOAD NAME
COUNT NAMELENGTH
LOAD NAME_AGAIN
TRANSFORM NAME
LOAD PASSCODE
COUNT PASSCODE_LENGTH
LOAD PASSCODE_AGAIN
<- ECHO CHECK here
TRANSFORM PASSCODE
<- ECHO CHECK here
COMPARE TRANSFORMED_NAME WITH TRANSFORMED_PASSCODE

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

:d 2c5f:61e8

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

and look... everybody is there! The stack pointers points in the middle of this dump, at the string "12121212". 0x50 bytes before is our good old ECHO (i.e. the CORRECT passnumber) and 0x50 bytes
afterwards is my beautiful input name "+ORC+ORC".

Therefore the "right" code for "+ORC+ORC" is 8037-646-3836. It cannot be so easy! You'll protest. It is: this crap protection is already cracked and hunderts of Visual Basic/Delphy schemes are absolutely
identical.

Now begins the hard work: if you really want to learn, accomplish the following tasks:

- First of all "Unregister" and find anew your own code for your own handle. *DO NOT* use serial numbers with any other name that your own handle.
- Study the two coding algorithms, the one for the input name and the one for the input passnumber, this will be useful for ALL your future cracking sessions.
- Find the compare locations, i.e. the code block that sets the two usual flags "good guy, you may move on" and "bad cracker, beggar off", and create a patch crack for this protection, that will allow
anybody, with any name and any password number to get through.

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

Well, that's it for this lesson, reader. Not all lessons of my tutorial are on the Web.

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

"If you give a man a crack he'll be hungry again tomorrow, but if you teach him how to crack, he'll never be hungry again"
+ORC 526164@anon.penet.fi

66

You might also like