UncleVan's "live approach" techniques (for beginners and semy-advanced)
(simple nag-screen (-dialogs) removing, limit-protection cracking, fishing serialz, and some key- generator programming)

(29 November 1997, slightly edited by fravia+)


Courtesy of fravia's page of reverse engineering
Well, UncleVan writes: "Since +He went over to his dead listing approach it seemed that the community begun to underestimate the live-one with our beloved SoftIce. I'll show you the dangers... since many incredible features are tainted when you dead list, like the one in HexWorkshop that I show below". He's in part right, of course: the live approach is UNESTIMABLE (especially for beginners and other non-zen creatures :-) and you better head that what UncleVan explains in here... Besides his style is quite humorous, and the choice of a whole SERIES of targets is very interesting, for beginners and intermediates (semi-advanced) as well... Enjoy!


UncleVan's "live approach" techniques (for beginners and semy-advanced)

simple nag-screen (-dialogs) removing, limit-protection cracking, fishing serialz, and some key- generator programming


AUDITORIUM:

In this essay I'll try to cover the most specific problems that a NEWBEE till SEMY-ADVANCED cracker will encounter at the beginning of his career. My text includes simple nag-screen (-dialogs) removing, limit-protection cracking, fishing serialz, and some elements of key- generator programming.
I'll try to submit you my opinion about what "really" cracking should be. I think, since limit protections of any kind should be defended in any way you fancy, cracking a online-registration target should always include at least one "true" Serial Number matching your key. Most of the cracks roaming the Web are just quick-and-dirty rejump-ed schemes... and you can never be sure of their efficiency as the targets are actually NOT registered at all! You can avoid some ugly surprise later only if you see your target answering with the message:

Thank You for ...(...that you gave me your money!)

after the registering prompt AND your own User Name (handle) inside the Help-About dialog... "as it should be".
Furthermore, to reverse the algorithm itself is one of the higher arts of our trade, and it is a useful exercise indeed.
The reader is supposed to be familiar with our main tools - SoftIce and W32Dasm - at some beginners level too, I'll not teach you here how to load exports or how to set breakpoints: there are many other good essays covering these themes.
I have collected some targets that I have cracked sincelast August. I hope I established some graduation too, so you'll be prepared for the more difficult jobs at the end.
And... excuse my horrible english too...
And now lets start, putting our targets one after another.

THEMES:

MVP Backgammon, game - nag screen, annoying Editor start
MVP Bridge, game - same as above + "triple" limit protection
Hedit, very fast HexEditor - fishing serial number
Hex Workshop + Win-eXpose I/O - THE most stupid protections - new feature not published yet!
IconEdit Pro (;-) - a Visual Basic 5 approach
Gif Construction Set - and we make a password-generator!

Quick reference

TOOLS:

SoftIce for W95 from NuMega - THE debugger
W32dasm v89 - try to fetch it, it is just around your nose! - disassembler
A good Win32 reference tool, may I suggest the Borlands C++v5 help files?

GENERAL APPROACH:

Since +He went over to his dead listing approach it seemed that the community begun to underestimate the live-one with our beloved SoftIce. I'll show you the dangers such aproach still hides, since many incredible features are tainted by the dead listing, like the one in HexWorkshop that comes below. I wish to say here, that the live approach is at least so important as the dead one, and that you should always check your targets using both approaches. Sometimes this will spare you a lot of work.

NOTE: for both MVP Backgammon and Bridge we could also "apply" the Borland Resource Workshop approach successfully, but if you want to see how these targets maintain nags, I suggest you to follow me, it will not be so boring and you'll learn something new.

Theme:

MVP Backgammon; Game from MVP Software;
to obtain from www.mvpsoft.com/strategy.htm
<<BACK
This is a very pretty game, although quite simple, and as the name suggest it is a implementation of this antique amusement. The program is shareware, not protected at all, yet with some annoying features that focus our attention:
When you start the game, right after the (fully warrantable) MVP-logo, a dialog pops up with two elements - a edit field with a quite long text inside, disabusing us about what we should do as next, if we - undoubtfully - like this exclusive product (we have to run immediately to the store/bank), and a button - OK - , that we press after we've thoroughly read the explanations above - and only now the game starts. The whole thing appears again when you want to stop enjoying it, you must then press OK again to scratch the backgammon from your desktop. But that is not all!
After finishing the game, like a dead spirit greeting you from the other side, your very own editor launches and presents to you a stupid Order Form, by which you could buy this bothersome game for, believe it or not, just 40 bucks
Jolly guys, this MVP Soft programmers!
Since we don't like when OTHERS waste OUR resources for such a crap (and anyway just and solely for learning purposes) we gonna change all this. This time the dead approach will be enough, but when you wish to test against side-effects, you must use SoftIce.

Now you disassembled the target and we are going together to crack it. In this example we will try to bypass the annoying pieces of code, thus jumping over the relevant calls to this dialog and over the place where our Editor is launched.
Where should we begin?
The Nag Screen is a Dialog with the title "Registering MVP Backgammon". Since dialogs are mainly created via DIALOGBOX() and CREATEDIALOG() windo$e functions, it is a good idea to look at the imported functions of our program to check for the above two. This is done in Wdasm when you select Imports from the Functions menu, or simply press the ImpFn button, duh
Scrolling down we see:

..........................
USER.CREATEWINDOW
USER.DEFWINDOWPROC
USER.DESTROYCURSOR
USER.DESTROYWINDOW
USER.DIALOGBOX <========================= THIS HERE!
USER.DISPATCHMESSAGE
..........................

(there will be many more functions).
When we doubleclick the DIALOGBOX item, Wdasm locates the first reference to this function in the listing. To see the other references we just keep doubleclicking the item.
There are lots of DIALOGBOX references in the listing, it's almost impossible to trace them all, how can we get "ours"?
Looking at the Dialog Information in the listing (start of the disassembly) we can see:

+++++++++++++++++ DIALOG INFORMATION ++++++++++++++++++

.......

Name: DialogID_2382, # of Controls=002, Caption:"Registering MVP Backgammon" 
  001 - ControlID:2383, Control Class:"" Control Text:"" 
  002 - ControlID:0001, Control Class:"" Control Text:"&OK" 

...........

So, now look at Dialog Reference (pressing the DLGRef button) and find the one with the DialogID_2382. Doubleclick it for Wdasm to locate it in our Source Code - and we are lucky: only one occurrence!

..................
* Possible Reference to Dialog: DialogID_2382, CONTROL_ID:2383, ""
  |
:0019.0FB7      688323          push 2383
:0019.0FBA      66FF36001E      push word ptr [1E00]
:0019.0FBF      9AFFFF0000      call USER.SETDLGITEMTEXT
...................

Seems to be on the right track... Now look around - above and below - and... just a chunk code before that:

............
Exported fn(): REGDLGPROC(const HWND__*,uint,u,long) - Ord:0017h
:0019.0F90      8CD0    mov ax, ss
:0019.0F92      90      nop <============ ?????? (see below)
:0019.0F93      45      inc bp
:0019.0F94      55      push bp
:0019.0F95      8BEC    mov bp, sp
:0019.0F97      1E      push ds
..............

What the hell does it mean? Why should this function be exported? Is it called from somewhere "outside" our program? Possible from a perfid DLL, hiding a weird protection scheme?
The answer is simple if you are familiar with windo$e programming: We just fetched the DIALOG() procedure for the nag. A dialog procedure under windo$e makes your dialog "go round"; YOU wrote it and it is kind-of-"called back" from windo$e after you created the dialog; but it must not therefore be also exported. Probably it is called from another DLL, it is up to you if you want to proof this.
How does windo$e know about which dialog procedure belongs to a dialog? The programmer tells this. Once you are about to create a dialog you call p.e. the Dialogbox()-windo$e procedure and one of its parameters points to the dialog procedure you intend to use for the specific dialog... Dig it?
Now back to our listing.
As we already know, this is the dialog procedure responsible for the behavior of the nag dialog called "Registering MVP Backgammon" which we are going to "fix". What when we crack immediately this routine, thus gathering from windo$e the ability to create the nag dialog? You see, it wouldn't be a good idea, since this function does only the half of the job on our dialog; and - notice this well! - it outcrops AFTER the dialog has been created, NOT before this! You can try this out as I did, p.e. change :

change  :0019.0F90      8CD0    mov ax, ss
to                      CB      retf (also  retf 000A, if you want)

and look at the mess you created...
So we have to use another approach. I've already mentioned, that this function has to be "reported" to the OS in order to be properly "called back" when it's time for the program to deal with the user's input. When we find the place where this happens, then we'll be closer to the naging mechanism as well.
But how can we do this?
Well, there must be a pointer to this crap somewhere pushed as parameter to the dialogbox(), createdialog() or so (see above!); and since we DO KNOW its address -:0019.0F90 - ...click?...
Now lets search! In W32dasm we simply make a Find Text with 0F90 and the very first hit looks like this:

......................
* Referenced by a  Jump at Address:0019.10F5(U)
|
:0019.112C      68DD11              push SEG ADDR of Segment 0019 <===HALLO,
:0019.112F      68900F              push 0F90 <================ HEEEEREEE!
:0019.1132      FF76F4              push word ptr [bp-0C]
:0019.1135      9AFFFF0000          call KERNEL.MAKEPROCINSTANCE
:0019.113A      8956FC              mov [bp-04], dx
:0019.113D      8946FA              mov [bp-06], ax
:0019.1140      FF76F4              push word ptr [bp-0C]
:0019.1143      666882230000        push 00002382
:0019.1149      FF76F6              push word ptr [bp-0A]
:0019.114C      52                  push dx

:0019.114D      50                  push ax
:0019.114E      9AFFFF0000          call USER.DIALOGBOX
:0019.1153      8946F8              mov [bp-08], ax
:0019.1156      66FF76FA            push word ptr [bp-06]
:0019.115A      9AFFFF0000          call KERNEL.FREEPROCINSTANCE
:0019.115F      66833E001E00        cmp dword ptr [1E00], 00000000
:0019.1165      7419                je 1180
:0019.1167      66C706001E00000000  mov dword ptr [1E00], 00000000
:0019.1170      FF76F0              push word ptr [bp-10]
:0019.1173       9AFFFF0000         call KERNEL.GLOBALUNLOCK
:0019.1178      FF76F0              push word ptr [bp-10]
:0019.117B      9AFFFF0000          call KERNEL.FREERESOURCE
................................

Everyone is here! Good old W32dasm did it this time!
This is almost self explained but here I'll say it again:
MAKEPROCINSTANCE() with the address of our dialog procedure as parameter is needed for system reasons, it returns a handle for the function at 0019.0F90 and this handle is passed then to the DIALOGBOX(), which on turn establishes then the well known nag dialog. After the crime is commited FREEPROCINSTANCE() "unregisters" the dialog procedure since windo$e no more needs it. The last two calls are doing "clean up" jobs.
Congratulations! You just have seen how 16-bit windo$e programs handle our enemys - the nag screen dialogs.
Immediatly after that this finctions rets. We don't need to bother for the function at 0019.0F90, since it is no more relevant to the nag scheme at all. When we crack properly the one that creates the nag, the dialog procedure itself will never come on turn.
Tracing back in the last piece of code we soon notice, that it is entered at:

...........
:0019.1081      8CD0    mov ax, ss
:0019.1083      90      nop <===== ????????
:0019.1084      45      inc bp
:0019.1085      55      push bp
:0019.1086      8BEC    mov bp, sp
:0019.1088      1E      push ds
...........

and after a lot of ressource-relevant calls it comes to the above DIALOGBOX() call. There is also a retf at:

..........
:0019.1128      1F      pop ds
:0019.1129      5D      pop bp
:0019.112A      4D      dec bp
:0019.112B      CB      retf<================ HERE!
.........

but we don't bother for it, since it is just on "emergency exit" for the program in case it didn't find its resources.
And don't forget what we are about to do! Let's crack!
There is one radical way I know when you want to bypass a routine: Just ret it at the very beginning. You must be sure of course that no other use of this routine is made (but for the nag); and there is a more "subtle" detail: the stack's clean up (after parameters have been passed to it). Thus sometimes you must experiment a little, but in this case we can try it out:

change  :0019.1081      8CD0    mov ax, ss
to      :0019.1081      CBxx    retf (xx means don't care)

You will need for this one of the Hexeditors we'll crack in this essay, be aware, the right offset of the instructions is in the status bar of W32dasm. (Don't forget the backup copy of the target victim!).
So we made it, saved it and know lets see: Launch the Backgammon. Waw! Aren't we wizards?! No more nags at the beginning, no more nags at the end of the game.
We were right.

A little NOP-digression: As you maybe noticed, there are some strange, fully needless nop instructions in the code of some functions, near the entry point. In most cases there are for alignment there, but in some old windo$e versions they are replaced from the OS with other instructions, thus gaining access to the privat data segments of a program. This stupid practice is obsolet in the 32bit world and no more present but you should learn to take hands off from patching NOPs for a very good reason, as +ORC always said: since they could be overwritten in some cases.

Now... the stupid editor remains! We have to fix this too, just for learning purpose of course... this is not the kind of target that you crack because you NEED it, this is the kind of target that you crack and then throw away almost immediately.
There is one quite popular way to start any process from your program - when you call the WINEXEC() function.
To be sure, we take a look at the Imported Functions of our backgammon - press the button "ImpFn" in the toolbar. Then scroll the window untill you reach:

.....................
KERNEL.WAITEVENT
KERNEL.WINEXEC <==============HERE!
KERNEL.WRITEPRIVATEPROFILESTRING
.................

Aha, WINEXEC() is there! Now doubleclick on it, Wdasm locates the reference in its window, doubleclick once more - and we are lucky again, no more occurances.

......................
:0003.1C9B      6A05            push 0005
:0003.1C9D      9AFFFF0000      call KERNEL.WINEXEC ;<=================
:0003.1CA2      5F              pop di
:0003.1CA3      5E              pop si
:0003.1CA4      8D66FE          lea sp, [bp-02]
:0003.1CA7      1F              pop ds
:0003.1CA8      5D              pop bp
:0003.1CA9      4D              dec bp
:0003.1CAA      CB              retf
...................

You guess what comes next? Right! We scroll upside to see where this piece of code is entered, wow, quite a lot of commands!

.................
:0003.1BEA      8CD0    mov ax, ss ; <===== HERE!
:0003.1BEC      90      nop
:0003.1BED      45      inc bp
:0003.1BEE      55      push bp
:0003.1BEF      8BEC    mov bp, sp
..................

Can we do it the same manner as with the dialog? I say yes, since there aren't any relevant system calls before WINEXEC(), the GETMODULEFILENAME serves for ?????????????????. But when we want to be sure, as I already said, we should have to set a breakpoint inside this code perhaps at:

:0003.1BEA 8CD0 mov ax, ss

and then we "walk" trough the game, wating for softice to pop up. If this isn't the case, we can go on and crack:

replace :0003.1BEA      8CD0 mov ax, ss
with    :0003.1BEA      CBxx retf

Now start the program. Quit it. That was all!
<<BACK

Theme:

MVP Bridge; Game from MVP Software
to obtain from: http://www.mvpsoft.com/cardgame.htm
<<BACK
This is another nice product from our friends in MVP, this time a S-class one, if you believe the home-made reclame. In addition to the already known nags (bugs ;-) - dialog before running and quitting, this target starts your own editor as well, whithout asking you, and the game is also limit protected! When you start the game, a nice nag dialog informs you that you have a 30 days trial period or either a 20 times "quiver" for using it, "...whatever comes last." Pretty generous dimensioned from MVP.
I did play this game just a few times and its best feature is the background and "event" music it plays during the rubbers, unfortunately it suffers from some algorithmic weakness (a common MVP feature BTW ;-)
Sometimes I used it when I was general frustrated from life - "This time I'm playing to win...".
I would never have come to the idea to crack this target if not just for learning purposes (you must pay 40 US$ to "gain" this game, a crap that you probably could better program yourself)
I went to work on it. Right after the first attempt it looked somehow fishy to me, like wasting my own resources without permissions... and I in general punish such attempts.
First -of course- I desinstalled (deleted) the game in order to install it once more - no chance. After some I/O trapping I found a file called Clock.tim in the windo$e directory, which is "consulted" by the program everytime it starts. This was already "housebreaking" but after a meaningful text:

  You have exceeded the playing limit!... etcetera

The thought that somebody leaves traces and marks on my own harddisk, without any warning, just to ensure his (fully) hypothetical profit of 40 bucks is for me like a slap on my face. Dear MVP boys -when you will read this- there are perhaps millions of software developers all over the world and I'm testing thousands of different shareware applications every year.
Just imagine the mess, when evryone leaves even a very tiny file inside MY OWN windo$e folder (32KB under Win95 minimum!) or some half-concealed keys in MY OWN registry! Should I buy a new disk just to keep your (futile and pathetical) "secrets" inside the old one? This is only one reason more to crack all your damn protections "black and blue", as the +Masters use to say.
So.
I began working on this when the limit was already over. It is certainly better to start deprotecting when the target still works (a "fresh" target) but in this case is quite interesting to analize its behavior after that, once the target is already stale... and in order to learn something new, we better work this way!
To simulate the situation you could start the game 20 times repeatedly, but since I won't harass you with such trivial tasks here you can find a mvpcount.REG file, reflecting the state of the "hidden" counter after 15 launches, you add it to your registry by simply clicking it twice. Don't forget to delete the CLOCK.TIM in your Window$ directory!
You need also to turn your clock one month forward.
Now you can enjoy the game 5 more times until the protection snaps. When you start the program at this point, you see just a message box as:

 You have exceeded the playing limit. 
...bla-bla-bla.....

And after pressing OK comes first the nag dialog and then the editor too.
Lets disassemble the thing (Mvpbr.exe). Pressing ImpFn we then look for our DIALOGBOX(). Surprise - we see it along with the similar one DIALOGBOXINDIRECT(), but only at one place in the listing, one after another! This means, that ALL dialogs in this game - and there are many! - come as parameters passed to the function containing both dialogbox() procedures - and the DIALOGBOX() is called at only one place, yet with different parameters for the different dialogs. This a clever approach, since it first:
- spares exports/ load time
and second - and more important for us
- lets us search for our dialogs on a "higher" level and more difficult!
What we should do?
A first approach is to find where in the body of our game the message box with the above text is issued, in the hope that we will land somewhere in the protection scheme as well. In order to do it we can search for the string "exceeded" and for references to it. And here I made a mistake that costs me lot of time and work: I tried the Wdasm Find Text and found nothing, while pretty easy located the word with the Hexeditor in the Mvpbr.exe. Why?
We must never forget what +ORC says:
First analize the target! How is it structured? What kind of windo$e program is it?
In this case it is a 16bit program with 14 different segments, as we can see at the beginning of the disassembly:

............
+++++++++++++++++++ SEGMENT INFO ++++++++++++++++++++++++
Number of Code/Data Segments = 14

  CSEG001  File Offset: 00001000  Size:B7D7  Flags:0x1D50 -> CODE, MOVEABLE
  CSEG002  File Offset: 0000CA00  Size:B68E  Flags:0x1D50 -> CODE, MOVEABLE
  CSEG003  File Offset: 00018200  Size:C4C6  Flags:0x1D50 -> CODE, MOVEABLE
  CSEG004  File Offset: 00024800  Size:E794  Flags:0x1D50 -> CODE, MOVEABLE
  CSEG005  File Offset: 00033200  Size:E4E3  Flags:0x1D50 -> CODE, MOVEABLE
  CSEG006  File Offset: 00041C00  Size:A868  Flags:0x1D50 -> CODE, MOVEABLE
  CSEG007  File Offset: 0004CC00  Size:C33C  Flags:0x1D50 -> CODE, MOVEABLE
  DSEG008  File Offset: 00000000  Size:0000  Flags:0x0C51 -> DATA, MOVEABLE
  DSEG009  File Offset: 00000000  Size:0000  Flags:0x0C51 -> DATA, MOVEABLE
  DSEG010  File Offset: 00000000  Size:0000  Flags:0x0C51 -> DATA, MOVEABLE
  DSEG011  File Offset: 00000000  Size:0000  Flags:0x0C51 -> DATA, MOVEABLE
  DSEG012  File Offset: 00000000  Size:0000  Flags:0x0C51 -> DATA, MOVEABLE
  DSEG013  File Offset: 00000000  Size:0000  Flags:0x0C51 -> DATA, MOVEABLE
  DSEG014  File Offset: 00059400  Size:92D0  Flags:0x0D51 -> DATA, MOVEABLE
.................

Neither Find Text, nor StrRef can help us, we have to look directly in the data segments!
There are 7 of them, but only 1 contains actualy data. We can see this by pressing the HexData button/ menu item.
Browsing trough the segments we soon find in
"Data Segment 14.... Page 1 of 5" following:

:0014.0138 6D 00 59 6F 75 20 68 61  m.You ha <=========== HERE!
:0014.0140 76 65 20 65 78 63 65 65  ve excee
:0014.0148 64 65 64 20 74 68 65 20  ded the 
:0014.0150 70 6C 61 79 69 6E 67 20  playing 
:0014.0158 6C 69 6D 69 74 2E 20 20  limit.
:0014.0160 53 65 65 20 74 68 65 20  See the 
:0014.0168 66 6F 6C 6C 6F 77 69 6E  followin
:0014.0170 67 20 6F 72 64 65 72 20  g order 
:0014.0178 69 6E 66 6F 20 66 6F 72  info for
:0014.0180 20 64 65 74 61 69 6C 73  details
:0014.0188 2E 00 6E 6F 74 65 70 61  ..notepa <=========== AND THIS ONE TOO!
:0014.0190 64 20 6F 72 64 65 72 2E  d order.
:0014.0198 66 72 6D 00 77 62 00 25  frm.wb.%
:0014.01A0 64 00 44 32 00 54 31 00  d.D2.T1.
:0014.01A8 53 79 73 74 65 6D 20 69  System i
:0014.01B0 6E 73 74 61 6C 6C 61 74  nstallat
:0014.01B8 69 6F 6E 20 65 72 72 6F  ion erro

What do you mean? The error message, followed immediately by the command line for launching the editor! Hot!
But how do we proceed further?
Look, to display a message, any windo$e procedure needs a pointer to that string passed as parameter to the procedure. And what looks a pointer like? It is just the offset of the string within some data segment. Since we see above that "our" offset is 013A, we do following search:

Find Text mov ax, 013A (there must be ONE space between the comma and the 013A

Note, that only Find Text 013A would do it too, but there are to much irrelevent occurences of it.
Now Wdasm searches and what? Believe it or not, but there is only one mov ax, 013A in the whole program:

.............
:0001.07C9      3D1E00  cmp ax, 001E
:0001.07CC      7303    jnb 07D1
:0001.07CE      E98800  jmp 0859

:0001.07D1      B83A01  mov ax, 013A <========== HERE!
:0001.07D4      8CDA    mov dx, ds
:0001.07D6      52      push dx
..............

Is that what we need? we can try it! Right above the mov there is a jump-around construction, lets change it:

from  :0001.07CC      7303     jnb 07D1
to    :0001.07CC      7300     jnb 07CE

thus forcing program flow to the mysteriose 0859 location.
Load the mvpbr.exe in the hexeditor, go to location 000017CC (you take it from the status line of the Wdasm!), patch it and save. Now run the game and what? It starts with the nag set to "Time expired" but no more limits there!
Wasn't it easy?
This is not the final crack, as there are many more checks and reefs in our target. At this place I will explain how the protection works to see how many things we still have to do.
The file clock.tim is not so relevant for the protection. You can delete it, but Mvpbr creates it every time anew. It serves only for comparison with the other data.
The main source for the protection is of course the registry. The program creates a new key under HKEY_CLASSES_ROOT named Accessoires. Then it adds to it a subkey Clock, which in turn contains tree subkeys: D1, D2 and T1. These subkeys contain string values, accordingly to the following schema:

D1 represents the date of the last-but-one start of the program;
D2 represents the date of the very last start;
T1 represents the total times you used it.

So even if you "turn back the time", the program recognize it and refuses starting.
And now look: What happens, when you, WITHOUT any intents turn the clock back and try the game (this happens automaticaly when you are playing late night on the day when the or summer-winter time change commits) - you will be never able to start normally this program again, even when in the "allowed" limit!
Is such protection juristic legitim at all?
With this in mind we come back to cracking. Now, where the game works again, we are going to crack first the whole protection, and then we will remove tha nags in order to save our disk space (and for learning purpose, of course!)
We can of course simply delete the Accessoires key in the registry, or, for more fun just copy the value of D2 into D1, but since they are created every time anew and the registry becames more and more a carbage colector we should try these keys to be not created at all.
If you look closer at the HexData dump above, you can see three other messages complaining some "errors":

System error - conflicting dates... at offset 00A9 - this occures when the date in the Clock.tim does not correspond to the one in the Registry;
System date error... at offset 00F9 - when you turn your system time back, and
System installation error... at offset 01A8 - if the registry operation fails

We can easy locate the references to the strings using the same approach as above:
Find Text mov ax, String_Offset
p.e. searching for mov ax, 00A9 will find this:

.......
:0001.0658      8B86C2FC        mov ax, [bp+FCC2]
:0001.065C      8B96C4FC        mov dx, [bp+FCC4]
:0001.0660      3986CEFC        cmp [bp+FCCE], ax
:0001.0664      7403            je 0669
:0001.0666      E93000          jmp 0699

:0001.0669      3996D0FC        cmp [bp+FCD0], dx
:0001.066D      7403            je 0672
:0001.066F      E92700          jmp 0699

:0001.0672      8B869EFC        mov ax, [bp+FC9E]
:0001.0676      8B96A0FC        mov dx, [bp+FCA0]
:0001.067A      3986CAFC        cmp [bp+FCCA], ax
:0001.067E      7403            je 0683
:0001.0680      E91600          jmp 06990001.067E(C)

:0001.0683      3996CCFC        cmp [bp+FCCC], dx
:0001.0687      7403            je 068C
:0001.0689      E90D00          jmp 0699

:0001.068C       8B86B2FD       mov ax, [bp+FDB2]
:0001.0690      3986C0FC        cmp [bp+FCC0], ax
:0001.0694      7503            jne 0699
:0001.0696      E97500          jmp 070E

:0001.0699      B8A900          mov ax, 00A9  <====== HERE!
:0001.069C      8CDA            mov dx, ds
:0001.069E      52              push dx
:0001.069F      50              push ax
................

There is still one occurrence apiece, so you can't do anything wrong. The locations are close to each other and everyone has a short overhead with a jump-around chain, followed by a WINEXEC() call. This means, the program checks everytime for the current condition, and, if "not good" puts the appropriate message, otherwise it jumps to the next check.
Do we need to crack ALL these checks separately in order to become our program run without any nags? You can try it, of course, and it will work (be aware to patch the right jump/conditional jump, it is always the FIRST one of a chain; sometimes you should patch ALL the jumps!) but this will be the hell of a job; furthermore our goal should be to crack it so, that no more registry keys will be added/no files created!
This is done generally by jumping over the culprite code to the location where the "really" game begins. So we need TWO locations: the first where we should jump from, and the second where we're jumping to.
How do we find them?
The latter one is easy. Browsing through the code around the checks we soon find the calls that handles the registry itself:

.....................
:0001.0470      9AFFFF0000      call SHELL.REGQUERYVALUE

.......................

:0001.04AC      9A71040000      call SHELL.REGQUERYVALUE
.......................

etc.
Just after the LAST registry call at:

.................
:0001.0B6F      9A79090000      call SHELL.REGCLOSEKEY

:0001.0B74      B80302          mov ax, 0203  <===< HERE
:0001.0B77      8CDA            mov dx, ds
...................

we may suppose that the deverse checks are finished and is a good place for jumping to. You can call it Zen, if you want, however I have tryed it and it works. Jumping to it from somewhere above the checks puts one through the "back door" directly in the "restricted area"!
Now we have our "entry point". What leaves is the location, where to place the jump itself.
There are lots of registry calls in that code chunk, creating, seting, and reading variose keys. But where exactly are the relevant keys created? The string "Accessiores" doesn't appear in the disassembly or in the HexData, nor can you find it even with a hex-search in the exe or in the DLLs. The same with the "clock.tim".
Mistery?
Look at this beautiful piece of code, just before the first registry-related call:

......................
:0001.03C2      C68618FF41      mov byte ptr [bp-00E8], 41
:0001.03C7      C68619FF63      mov byte ptr [bp-00E7], 63
:0001.03CC      C6861AFF63      mov byte ptr [bp-00E6], 63
:0001.03D1      C6861BFF65      mov byte ptr [bp-00E5], 65
:0001.03D6      C6861CFF73      mov byte ptr [bp-00E4], 73
:0001.03DB      C6861DFF73      mov byte ptr [bp-00E3], 73
:0001.03E0      C6861EFF6F      mov byte ptr [bp-00E2], 6F
:0001.03E5      C6861FFF72      mov byte ptr [bp-00E1], 72
:0001.03EA      C68620FF69      mov byte ptr [bp-00E0], 69
:0001.03EF      C68621FF65      mov byte ptr [bp-00DF], 65
:0001.03F4      C68622FF73      mov byte ptr [bp-00DE], 73
:0001.03F9      C68623FF5C      mov byte ptr [bp-00DD], 5C
:0001.03FE      C68624FF43      mov byte ptr [bp-00DC], 43
:0001.0403      C68625FF6C      mov byte ptr [bp-00DB], 6C
:0001.0408      C68626FF6F      mov byte ptr [bp-00DA], 6F
:0001.040D      C68627FF63      mov byte ptr [bp-00D9], 63
:0001.0412      C68628FF6B      mov byte ptr [bp-00D8], 6B
:0001.0417      C68629FF00      mov byte ptr [bp-00D7], 00
.....................

Don't you see anything? This is the same old trick the protectionists try to foolish us with since the very first days! Now look again, after I've "commented" it for you, together with the other relevant place:

.....................
:0001.03C2      C68618FF41      mov byte ptr [bp-00E8], 41;     A
:0001.03C7      C68619FF63      mov byte ptr [bp-00E7], 63;     c
:0001.03CC      C6861AFF63      mov byte ptr [bp-00E6], 63;     c
:0001.03D1      C6861BFF65      mov byte ptr [bp-00E5], 65;     e
:0001.03D6      C6861CFF73      mov byte ptr [bp-00E4], 73;     s
:0001.03DB      C6861DFF73      mov byte ptr [bp-00E3], 73;     s
:0001.03E0      C6861EFF6F      mov byte ptr [bp-00E2], 6F;     o
:0001.03E5      C6861FFF72      mov byte ptr [bp-00E1], 72;     r
:0001.03EA      C68620FF69      mov byte ptr [bp-00E0], 69;     i
:0001.03EF      C68621FF65      mov byte ptr [bp-00DF], 65;     e
:0001.03F4      C68622FF73      mov byte ptr [bp-00DE], 73;     s
:0001.03F9      C68623FF5C      mov byte ptr [bp-00DD], 5C;     \
:0001.03FE      C68624FF43      mov byte ptr [bp-00DC], 43;     C
:0001.0403      C68625FF6C      mov byte ptr [bp-00DB], 6C;     l
:0001.0408      C68626FF6F      mov byte ptr [bp-00DA], 6F;     o
:0001.040D      C68627FF63      mov byte ptr [bp-00D9], 63;     c
:0001.0412      C68628FF6B      mov byte ptr [bp-00D8], 6B;     k
:0001.0417      C68629FF00      mov byte ptr [bp-00D7], 00; <== terminates it
....................

...and here:

.....................
:0001.00CC      8346E001        add word ptr [bp-20], 0001
:0001.00D0      8D9EEAFC        lea bx, [bp+FCEA]
:0001.00D4      03D8            add bx, ax
:0001.00D6      C6075C          mov byte ptr [bx], 5C;    \ <=====
:0001.00D9      8B46E0          mov ax, [bp-20]
:0001.00DC      8346E001        add word ptr [bp-20], 0001
:0001.00E0      8D9EEAFC  ;      lea bx, [bp+FCEA]
:0001.00E4      03D8            add bx, ax
:0001.00E6      C60743          mov byte ptr [bx], 43;    C <=====
:0001.00E9      8B46E0          mov ax, [bp-20]
:0001.00EC      8346E001        add word ptr [bp-20], 0001
:0001.00F0      8D9EEAFC        lea bx, [bp+FCEA]
:0001.00F4      03D8            add bx, ax
:0001.00F6      C6074C          mov byte ptr [bx], 4C;    L <=====
:0001.00F9      8B46E0         bsp; mov ax, [bp-20]
:0001.00FC      8346E001        add word ptr [bp-20], 0001
:0001.0100      8D9EEAFC        lea bx, [bp+FCEA]
:0001.0104      03D8      p;      add bx, ax
:0001.0106      C6074F          mov byte ptr [bx], 4F;    O <=====
:0001.0109      8B46E0          mov ax, [bp-20]
:0001.010C      8346E001        add word ptr [bp-20], 0001
:0001.0110      8D9EEAFC        lea bx, [bp+FCEA]
:0001.0114      03D8            add bx, ax
:0001.0116      C60743          mov byte ptr [bx], 43;    C <=====
:0001.0119      8B46E0          mov ax, [bp-20]
:0001.011C      8346E001        add word ptr [bp-20], 0001
:0001.0120      8D9EEAFC        lea bx, [bp+FCEA]
:0001.0124      03D8            add bx, ax
:0001.0126      C6074B          mov byte ptr [bx], 4B;    K <=====
:0001.0129      8B46E0          mov ax, [bp-20]
:0001.012C      8346E001        add word ptr [bp-20], 0001
:0001.0130      8D9EEAFC        lea bx, [bp+FCEA]
:0001.0134      03D8            add bx, ax
:0001.0136      C6072E          mov byte ptr [bx], 2E;    . <=====
:0001.0139      8B46E0          mov ax, [bp-20]
:0001.013C      8346E001        add word ptr [bp-20], 0001
:0001.0140      8D9EEAFC        lea bx, [bp+FCEA]
:0001.0144      03D8            add bx, ax
:0001.0146      C60754          mov byte ptr [bx], 54;    T <=====
:0001.0149      8B46E0          mov ax, [bp-20]
:0001.014C      8346E001        add word ptr [bp-20], 0001
:0001.0150      8D9EEAFC        lea bx, [bp+FCEA]
:0001.0154      3D8             add bx, ax
:0001.0156      C60749          mov byte ptr [bx], 49;    I <=====
:0001.0159      8B46E0          mov ax, [bp-20]
:0001.015C      8346E001        add word ptr [bp-20], 0001
:0001.0160      8D9EEAFC        lea bx, [bp+FCEA]
:0001.0164      03D8            add bx, ax
:0001.0166      C6074D          mov byte ptr [bx], 4D;    M <=====
:0001.0169      8B46E0          mov ax, [bp-20];    <====== Here is the index!
:0001.016C      8346E001        add word ptr [bp-20], 0001
:0001.0170      8D9EEAFC        lea bx, [bp+FCEA];  <======Here is the string!
:0001.0174      03D8            add bx, ax;  <====== Calculates the right position...
:0001.0176      C60700          mov byte ptr [bx], 00; <= ...and puts there the current char
...................

Tricky, what?
You should always be aware, when you see such massive byte - constant loads in a target! BTW, since Wdasm still missing a feature as ASCII- dump the constant's manipulation, you can pretty easy "see" such hidden string- buildings with SoftIce - one more advantage of the live approach.
We lhave to:
find a place for our jump before the file is created AND
calculate the offset.
BTW, [bp+FCEA] is indeed [bp-0321] - have you made your homeworks?(;-P) - but it is still not the final address of "CLOCK.TIM". When the file is about to be created it needs three more letters (guess which) for the INT 21 call (yes, this target uses DOS-fashion calls to manipulate this file!), so we have to search for [bp-31F], which looks like [bp+FCDE] in our disassembly.
We find it at :

...................
:0001.03A2      FFB6E0FC        push word ptr [bp+FCE0]
:0001.03A6      FFB6DEFC        push word ptr [bp+FCDE];  <======= HERE!
:0001.03AA      9AD8005403      call 0007.00D8
...................

So our location should be the 0001.03A2.
There is still another problem. The program creates one more file in its directory, called Temp.tst. It is no relevant at all and serves to check whether the game resides on a CD or on the hard disk, but when we place the jump on the above address, this file - automaticaly erased otherwise - remains too.
So we make a final Text Find with:
mov ax, 0026
where 0026 is the offset of the string "\Temp.tst" in the data segment (DataHex!)

..................
:0014.0020 43 3A 00 43 3A 00 5C 54  C:.C:.\T <==== HERE!
:0014.0028 45 4D 50 2E 54 53 54 00  EMP.TST.
:0014.0030 54 45 4D 50 2E 54 53 54  TEMP.TST
..................

What comes at least is what we needed:

............
:0001.02A9      B82600  mov ax, 0026; <==== HERE COMES the JUMP!!!
:0001.02AC      8CDA    mov dx, ds
:0001.02AE      52      push dx
...........

Now the offset.
In the windo$e world most of the jumps are compiled as E9h, what is a relative jump with a 16b offset, which means it needs 3 bytes in the binary. The offset then is calculated as follows:
offset = (jump_destination - jump_address) - 3
In our case:
offset = (0B74 - 02A9) - 3 = 08C8h
but it must be compiled so:
E9 C8 08
due to the weird way the Intel processors store data in memory - the LSB (Low Significant Byte) in the lower addres, the MSB (Most Significant Byte) in the higher.
Now we can crack: Open the Mvpbr.exe in your HexEditor, go to the offset 000012A9h (you've seen it on the task bar of Wdasm!) in Segment 0001 and

change:         B82600  mov ax, 0026
to:             E9C808  jmp 0B74

We did it!
As a nice side effect from this, the "entry" nag screen disapears too! But the final one and the editor with the order form still remains. You have owned already the knowledge nessessary to commit this last crack, but there is still something I want to show you.
We start as usual at the beginning of the W32Dasm listing, looking for the dialog named "Order info" - this is the text presented in the window's caption of the dialog. Here is it:

..................
Name: DialogID_0107, # of Controls=002, Caption:"Order Info"
 001 - ControlID:0001, Control Class:"" Control Text:"OK"
 002 - ControlID:00D9, Control Class:"" Control Text:""
.................

Now press the DlgRef button, find the one with ID 0107 and doubleclick it. Only one reference in our listing:

...................
:0002.5F92      C8020000        enter 0002, 00
:0002.5F96      56              push si
:0002.5F97      57              push di

* Possible Reference to Dialog: DialogID_0107 
  |
:0002.5F98      680701          push 0107; <============ HERE!
:0002.5F9B      6A00            push 0000
:0002.5F9D      6A00            push 0000
:0002.5F9F      FF7608          push word ptr [bp+08]
:0002.5FA2      FF7606          push word ptr [bp+06]
:0002.5FA5      9AD224685F      call 0006.24D2
:0002.5FAA      C45E06          les bx, [bp+06]
:0002.5FAD      26C707889E      mov word ptr es:[bx], 9E88
:0002.5FB2      26C74702865F    mov word ptr es:[bx+02], SEG ADDR of Segment 0007
:0002.5FB8      C45E06          les bx, [bp+06]
:0002.5FBB      8B4610          mov ax, [bp+10]
:0002.5FBE      26894728        mov es:[bx+28], ax
:0002.5FC2      C45E06          les bx, [bp+06]
:0002.5FC5      8B460E          mov ax, [bp+0E]
:0002.5FC8      2689472A        mov es:[bx+2A], ax
:0002.5FCC      8B460A          mov ax, [bp+0A]
:0002.5FCF      8B560C          mov dx, [bp+0C]
:0002.5FD2      C45E06          les bx, [bp+06]
:0002.5FD5      2689472C        mov es:[bx+2C], ax
:0002.5FD9      FF7608          push word ptr [bp+08]
:0002.5FDC      FF7606          push word ptr [bp+06]
:0002.5FDF      9AAA25A85F      call 0006.25AA; <======= WE NEED THIS ONE
:0002.5FE4      8B4606          mov ax, [bp+06]
:0002.5FE7      8B5608          mov dx, [bp+08]
:0002.5FEA      E90000          jmp 5FED
:0002.5FED      5F              pop di
:0002.5FEE      5E              pop si
:0002.5FEF      C9              leave
:0002.5FF0      CA1000          retf 0010
.........................

This target uses enter for the procedure frame, but it doesn't realy matter for us. Note that retf 0010 suggests, that the procedure (in this case) have recieved 10h prameters (inclusive CS:IP!) and at its end it makes clean-up of the stack.
Now we can easy crack it by placing retf 0010 at 0002.5f92 instead of enter. But in this case it won't work!
You see, somwhere in the body of this function they set up a jump-table for later use; when we bypass it, the program crashes when it quits!
An ugly, really ugly trick!
So we must look closer. The second call leads us direct to the dialog routines - you can try it if you will, I don't want to bother you with more code here. Relevant is the fact that we can crack the above:

change  :0002.5FD9      FF7608  push word ptr [bp+08]
to      :0002.5FD9      E90800  jmp 5FE4

Since the editor starts immediately after that it's a good idea to find the place where this function is called from in the hope to eliminate the WINEXEC() too. We do a Text Find (backwards) with call 0002.5F92 as retf tells us that it must be a far call. What You Find is What You Needed:

...............
:0001.30A5      9A908F4730      call 0007.8F90
:0001.30AD      FF7606          push word ptr [bp+06]
:0001.30B0      6A01            push 0001
:0001.30B2      6AFF            push FFFF
:0001.30B4      6AFF            push FFFF|
:0001.30B6      6AFF            push FFFF
:0001.30B8      8D8676FF        lea ax, [bp+FF76]
:0001.30BC      8CD2            mov dx, ss
:0001.30BE      52              push dx
:0001.30BF      50              push ax
:0001.30C0      9A925FBA2B      call 0002.5F92; <==== culprit routine
:0001.30C5      B82008          mov ax, 0820;  <======== FROM HERE...
:0001.30C8      8CDA            mov dx, ds
:0001.30CA      52              push dx
:0001.30CB      50              push ax
:0001.30CC      6A01            push 0001
:0001.30CE      9ACD090000      call KERNEL.WINEXEC; <= !
:0001.30D3      C45E06          les bx, [bp+06]; <======= ...INTO HERE !
...........................

There are many other calls to the same routine, but this is not interesting coze all of them dwells in our bypassed piece of code (from 0b74 to 02a9). We fall back once more on our aproach and patch:

change  :0001.30C5      B82008          mov ax, 0820
to      :0001.30AD      E90B00          jmp 30D3

Now lets try it - and it works fine!
That was all for this target. Pretty much, what? Now sipp your favorite cocktail and prepare yourself for the funny part of this essay - fishing serialz.
<<BACK

Theme:

Hedit v2.1.11; Hexeditor from Yuri SoftWare
to obtain from: Everywhere on the Web or direct from http://www.yurisw.com/hedit/
<<BACK
This is a small and very fast (unlike the monstrose Hex Workshop) HexEditor. Allthough with limited functionality it still offers the most important for us features. If you have only 16MB RAM and have to deal with large files (what I suppose you are doing!) you'll soon learn to appreciate it.
It is time limited and refuses to save changes (during the trial period) to the files too, but is protected with a very banal scheme. I would never bother Fravia's page with such ridiculous thing but since this essay concentrates on the newbee's needs I'll explain this crack here as a foretaste of what comes next.
Little online-registering digression:
In fact there two commonly methods to register a shareware online (I mean: on your computer): Choosing the option "registration" from somwhere in the menus of a target you are prompted to input either a
-serial number (like Hex Workshop) or
-a user name, followed with the apropriate "User Number" - kind of the Login/Password pairs known from Unix and other multiuser OS.
The protection then checks for validity of the users input and acts depending of whether you typed the right values or not. The chek itself uses one of the two approaches:
-It manipulates the UserName item in a more or less "secret" way - this means it ENCODES it. The rezult then represents the Magic Key which the program expects as the second input - the user number (or password, sometimes it is just another string) - to open to you the gates of the unlimited use.
-Sometimes however the user number is encoded too - as by Gif Construnction Set - in order to NOT let us see the right number while debugging the target.
Needless to say, that while the first approach means no protection at all, the second is a really challenge to the cracker genius.
Our Yuri software has implemented the first method ;-)
Let see - load SoftIce and start the target. From the menu item Help in Hedit we select About Hedit and a dialog box pops up with a meaningless text and two buttons. We press the Register one and an other box presents to us the registration form which in this case consists only of two text-edit ields as:
Name:
Registration Number:
I used for this example UncleVan and 123456789, but you can place your name there. Be aware to use longer names, since some schemes require more than few chars for their manipulations.
As number (or password) use always a string with DIFFERENT characters in it, this can be very useful if you are about to trace some longer encoding algorithm.
As you should already know fro +ORCs lessons, they use most of the time the GETWINDOWTEXT() function to get the user input. If you are not sure you can try the GETDIALOGITEMTEXT() too.
At this point you press Ctrl-D. The softice screen should appear. Here you have to bpx the above function. Type first addr to see the name of the target - Hedit in this case. Then change to its addres context with:
addr hedit
This ensure that you are in the right address space to set the breakpoints. Now type:
bpx getwindowtext
Press Ctrl-D again. You return to windo$e. Here you press OK in the registration dialog. SoftIce pops up immediately, but this time we must press G to continue executing Hedit, since this was only the UserName-read. Hedit reads first both fields and then calculates the right number. When SoftIce pops again you are in the very beginning if the GETWINDOWTEXT() procedure, so you have to press F12 twice (or issue twice p ret ) to come back to Hedit, right where the function was called:

.............
:00427406       FF15B80D4500    Call [user!getwindowtext]
:0042740C       8D4518          lea eax, dword ptr [ebp+18]
:0042740F       50              push eax
:00427410       8D45E0          lea eax, dword ptr [ebp-20]
:00427413       FF7510          push [ebp+10]
:00427416       50              push eax
:00427417       E837000000      call 00427453; <==== it's not that!
:0042741C       85C0ets" inside the