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

Courtesy of reverser'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


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.


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


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?


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.


MVP Backgammon; Game from MVP Software;
to obtain from www.mvpsoft.com/strategy.htm
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.DIALOGBOX <========================= THIS HERE!

(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.WINEXEC <==============HERE!

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!


MVP Bridge; Game from MVP Software
to obtain from: http://www.mvpsoft.com/cardgame.htm
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.
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. 

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

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


Hedit v2.1.11; Hexeditor from Yuri SoftWare
to obtain from: Everywhere on the Web or direct from http://www.yurisw.com/hedit/
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 Reverser'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:
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       85C0            test eax, eax
:0042741E       752F            jne 0042744F

Now we look for callS followed by compS or testS - like in 00427417, but it's not him this time. We can check any suspective conditional jump by changing to the register window in SoftIce and triggering then the appropriate flag.
I'll spare you the bothersome work. Pressing F12 repeatedly you see that after 5 more F12s the nag window appears, telling you the number you entered is not correct. We'll do the same once more, pressing this time 6 time F12 after the second break due to getwindowtext. Now we are at that code, where the nag is triggered and try to find the reason (call) for that:

:00402200       E8CFCF0100      call 0041F1D4
:00402205       85C0            test eax, eax; <======== WE ARE HERE!
:00402207       743A            je 00402243
:00402209       8B4660          mov eax, dword ptr [esi+60]
:0040220C       8B4E5C          mov ecx, dword ptr [esi+5C]
:0040220F       50              push eax
:00402210       51              push ecx
:00402211       8BCF            mov ecx, edi
:00402213       E878170000      call 00403990; <======== THIS ONE...?
:00402218       85C0            test eax, eax
:0040221A       7419            je 00402235
:0040221C       8B5660          mov edx, dword ptr [esi+60]
:0040221F       8B465C          mov eax, dword ptr [esi+5C]
:00402222       52              push edx
:00402223       50              push eax
:00402224       8BCF            mov ecx, edi
:00402226       E815170000      call 00403940
:0040222B       8BCE            mov ecx, esi
:0040222D       E837A50100      call 0041C769
:00402232       5F              pop edi
:00402233       5E              pop esi
:00402234       C3              ret

:00402235       6AFF            push FFFFFFFF
:00402237       6A00            push 00000000 |
:00402239       6888000000      push 00000088
:0040223E       E8ED560200      call 00427930; <========= DISPLAYS the NAG

:00402243       5F              pop edi
:00402244       5E              pop esi
:00402245       C3              ret

There are here only two calls with consecutive test and conditional jump after that. The first is where we came from and it jumps directly to the exit of our function. When you now trace this snippet with F10, you'll see that the call at 0040223E causes the nag to display. So we have to concentrate our efforts on the second of the suspective calls at 00402213, since it jumps around the nag and looks more likely to hide the encoding scheme.
We now set a breakpoint at its address and run once more the registration procedure. When SoftIce stops at 00402213 we press F8 and trace into it. And Bingo! We are in the middle of something that looks very like a encoding routine:


:004039C0       8BC1            mov eax, ecx; <============<
:004039C2       99              cdq
:004039C3       33C2            xor eax, edx
:004039C5       2BC2            sub eax, edx
:004039C7       83E003          and eax, 00000003
:004039CA       33C2            xor eax, edx
:004039CC       2BC2            sub eax, edx
:004039CE       8A540C04        mov dl, byte ptr [esp+ecx+04]
:004039D2       8A5C0404        mov bl, byte ptr [esp+eax+04]
:004039D6       8D440404        lea eax, dword ptr [esp+eax+04]
:004039DA       32DA            xor bl, dl
:004039DC       41              inc ecx
:004039DD       81F900010000    cmp ecx, 00000100 ; <<<<<<<< !
:004039E3       8818            mov byte ptr [eax], bl
:004039E5       7CD9            jl 004039C0; >================>
:004039E7       8B442404        mov eax, dword ptr [esp+04]
:004039EB       85C0 test       eax, eax; <===== BREAKPOINT HERE!

We see here the "heart" of the scheme. The code between my comments is executed 100h(!) times (256 dec), calculating in this stupid manner your "magic" number. We can set a breakpoint on 004039EB, thus let the processor do this job. Since right after the encoding something is placed in EAX, we "ask" SoftIce:
? eax
and SoftIce responds with:
02021810 33691664 " "
The first is the hex value in eax, and can you guess what the second is? Yes, this is our User Number as decimal! It wasn't heavy, don't you mean?


IconEdit Pro, v4.01 from Hagen Wieshofer
To obtain from: everywhere on the Web
This is a Visual Basic target. I never use VB programs but since I've read various essays about this I decided to proof whether the common approach with SoftIce and/or W32dasm is applicable on such targets too and I was pretty suprised. I think, that we don't need very special tools or methods to crack the visual tools; a good, solid basic cracking experience should be enough.
My assumption was, that unlike comon tasks - like registering windows, reading user input etcetera - a protection can NOT delegate its basic deal - the decision right number/bad number - to the OS or some run time DLL; it must make this decision inside its OWN code, and perform the necessary "preparations" for displaying nags or so inside its OWN body too.
But lets look at these problems one after another.
This icon editor is shareware and has a nag screen with countdown - before starting and quitting... you must wait at least 10 sec. as if it was not enough for waiting till this monster loads in memory. The author provides an online registration option too, which we are now gonna crack.
I first disassembled the exe, but the listing looks very disappointing, unless you feel convinient with something like this:

:00489C3E       8D4DDC  lea ecx, dword ptr [ebp-24]

* Reference To: MSVBVM50.__vbaFreeObj, Ord:0000h
:00489C41       FF15D0744E00    Call dword ptr [004E74D0]
:00489C47       8B4D14          mov ecx, dword ptr [ebp+14]
:00489C4A       D901            fld dword ptr [ecx]
:00489C4C       D8357C114000    fdiv dword ptr [0040117C]

* Reference To: MSVBVM50.__vbaFPInt, Ord:0000h
:00489C52       FF15C4744E00    Call dword ptr [004E74C4]
:00489C58       D80D7C114000    fmul dword ptr [0040117C]

* Reference To: MSVBVM50.__vbaFpI2, Ord:0000h
:00489C5E       FF1580744E00    Call dword ptr [004E7480]
:00489C64       8B5518          mov edx, dword ptr [ebp+18]
:00489C67       66A392B04D00    mov word ptr [004DB092], ax
:00489C6D       D902            fld dword ptr [edx]

* Reference To: MSVBVM50.__vbaR8IntI2, Ord:0000h
:00489C6F       FF1594744E00    Call dword ptr [004E7494]
:00489C75       668B0D92B04D00  mov cx, word ptr [004DB092]

Really ugly, if you'r not a VB-buff eh? And micro$oft propagates this as up-to-date programming environment! Poor people those who believe it! Now we'll see how easy it is to crack all this... like it weren't protected at all.
In this case we have to export the M$VBVM50.DLL to SoftIce, else we can never land in the body of our target; the registration form is implemented as a thread - a very clever boy, that Hagen Wieshofer, but he has no chance with his VBv5!
We add the DLL to the exported symbols in the Symbol Loader, then - the same procedure as last time - Load SoftIce, launch the target, select Help-Enter-Registration and type as User Name whatever you want and as Registration Number 1234567890 again. For me the name was UncleVan.
Man, it's a hell of varios functions! Some have pretty easy names, other are totaly cryptic:

+++++++++++++++++++ IMPORT MODULE DETAILS +++++++++++++++

 Import Module 001: MSVBVM50.DLL

 Addr:0F0F92B5 hint(0000) Name: __vbaVarSub
 Addr:0F0FE1BC hint(0000) Name: __vbaVarTstGt
 Addr:0F0452A5 hint(0000) Name: __vbaStrI2
 Addr:0F023E4A hint(0000) Name: _CIcos
 Addr:0F0E395F hint(0000) Name: _adj_fptan
 Addr:0F0FEC72 hint(0000) Name: __vbaVarMove
 Addr:0F0245F0 hint(0000) Name: __vbaStrI4

Where should we begin?
Well, even without any VisualBasic experience I "feel" the MSVBVM50.rtcMsgBox as the most meaningful among them. Since a message--box complains to us that the code was wrong, we bpx it:

:addr iconedit
:bpx rtcmsgbox

Now Ctrl-D again and back in the Icon Editor we press OK in the registration form as usual. SoftIce pops up at the beginning of the rtcMsgBox:
By pressing F11 we see th emessage-box itself and clicking on OK we land directly into the body of iconedit, right after the call was issued:
As we are interested in how the program came there we scroll up and look observing at the code above. The only jump OVER the message box procedure is at:

0137:00495A27   E9FE000000      JMP 00495B2A ; <== Jumps OVER the message box
0137:00495A2C   A1C4BF4D00      MOV EAX,[004DBFC4]; <= How it gets there?

and it is on unconditional jump; that means for the instruction at 00495A2C to recieve control MUST be referenced from somewhere else.
Let search for a jump to it. There is indeed only one, quite above this code and right after a suspective construction with the following "strange" statements:

0137:004956B1   FF15D4744E00    CALL  [MSVBVM50!__vbaFreeStr]
0137:004956B7   8D4DB8          LEA ECX,[EBP-48]
0137:004956BA   FF15D0744E00    CALL  [MSVBVM50!__vbaFreeObj]
0137:004956C0   DD45D8          FLD REAL8 PTR [EBP-28] ;<==== OUR NUMBER!
0137:004956C3   EB06            JMP 004956CB
0137:004956C5   DD05B8254000    FLD REAL8 PTR [004025B8]
0137:004956CB   DD45E0          FLD REAL8 PTR [EBP-20] ; <==== THE GOOD NUMBER
0137:004956CE   DC1DB8254000    FCOMP REAL8 PTR [004025B8]
0137:004956D4   DFE0            FSTSW AX
0137:004956D6   F6C440          TEST  AH,40
0137:004956D9   7408            JZ  004956E3
0137:004956DB   DDD8            FSTP  ST(0)
0137:004956DD   DD05C0254000    FLD REAL8 PTR [004025C0]
0137:004956E3   DC5DE0          FCOMP REAL8 PTR [EBP-20]; <==== THE COMPARE
0137:004956E6   DFE0            FSTSW AX
0137:004956E8   F6C440          TEST  AH,40; <=== BAD OR GOOD?
0137:004956EB   0F843B030000    JZ  00495A2C; <=== THIS ONE JUMPS TO BAD BOX!
0137:004956F1   56              PUSH  ESI
0137:004956F2   FF9524FFFFFF    CALL  [EBP-00DC]
0137:004956F8   50              PUSH  EAX
0137:004956F9   8D45B8          LEA EAX,[EBP-48]
0137:004956FC   50              PUSH  EAX
0137:004956FD   FFD3            CALL  EBX
0137:004956FF   8B08            MOV ECX,[EAX]

Interesting, isn't it? Now it is important to know, that all Fxxx instructions deal with the FPU, the arithmetic coprocesor. At this point you must turn on the FPU window in SoftIce, if you have never done that before, learn it now: It's a pretty useful cracking feature!
The command for this is WF.
Once you have done it, you will see something like this the following below the register window:

ST0     empty           ST4     empty
ST1     empty           ST5     empty
ST3     empty           ST7     empty

These are the eight FPU registers. You can also change the format of the numbers shown (read in the manuals - good old SoftIce has everything!) but now this is not necessary. We bpx on the first FLD instruction and do once more the whole registration procedure. On the FLD we press F10 to step trough the program. This right loads the ST0 register with our number:

ST0     1234567890.

The next FLD shifts our number in ST1 and (stack-alike) loads another number in ST0:

ST0     127323. 
ST1     1234567890.

Beautefull, isn't it? Then a FCOMP and the decision is made.... And we can see the right number, no need to calculate it or so. Poor VB people! This guy tried to conceal its secrets (consciously or not) as float reals, but Visual Basic lets him fall down... He deserved his sad fate!
Needles to say, the registration information is stored in a file named ieui.dat (!) in the system directory.


Hex Workshop v2.54; BreakPoint Software
to obtain from: www.bpsoft.com and everywhere on the Web
A weak protection is even worse then no protection at all!
Yes, I've read Reverser's "Most stupid protection award" and Hex Workshop is already mentioned there. I'll qoute here Aesculapius from his essay:

         ; Lady's and gentleman we're inside the
         ; protection scheme itself... and we
         ; found TWO calls... that means that
         ; the valid serial is calculated two
         ; times, how touching, probably, the
         ; first one when application starts
         ; and the other when the user tries
         ; to register it. 

Aesculapius was (for once) wrong. The validation of the serial is made ONLY ONCE, when you enter it, this gives us the possibility to register it with ANY number you like, and this without any need for cracking or patching it, only with our beloved SoftIce!
Lets start from the beginning.
As we already know, this target needs a "valid" serial number in order to let one type in his name and organisation (!). Then it generates a .reg file, where:
-serial number
-user name..
-..and eventualy organisation
are placed, but "embeded" in a very special way and encoded with the additional data there. On start it checks out the .reg file, but due to the nature of this protection it proofs only the consistence of the data there (whether the file is properly encoded or not), and not the serial itself.
Probably BPSoft lets this way a open door for future serial's changes, dividing therefore the protection in two independent parts - one for the serial, and another for the encoding, which works separately from the first part.
You understand now the approach: If we would be able to fool the algorithm making it think that the RIGHT serial was entered, it then would generate the RIGHT .reg file for us, even with a wrong number!
And there is really a way to do this!
Now start as usual: Choose help-about-register, type 1234567890 or whatever combination you want to have as serial, Ctrl-D, bpx GETWINDOWTEXT(), Ctrl-D again and then OK in the form. Now F12 until you see the message box with the nag - that means 6 times. This code is VERY similar to the one of Hedit, I'm wondering if both are derivates from a common source, and which one it could be... "software collation, may be we should learn these techniques ;-)
Now repeat the whole once more and this time press F12 only FIVE times, lets look now closer. I have made it for you this time:

0137:0042625B   E8CC4E0200      CALL  0044B12C
0137:00426260   8B8DFCFEFFFF    MOV ECX,[EBP-0104] ;<=== WE POP UP HERE
0137:00426266   83C164          ADD ECX,64
0137:00426269   E812BAFDFF      CALL  00401C80
0137:0042626E   50              PUSH  EAX
0137:0042626F   8D45DC          LEA EAX,[EBP-24]
0137:00426272   50              PUSH  EAX
0137:00426273   E8C82D0100      CALL  00439040
0137:00426278   83C408          ADD ESP,08
0137:0042627B   68E8F74700      PUSH  0047F7E8
0137:00426280   8D45DC          LEA EAX,[EBP-24]
0137:00426283   50              PUSH  EAX
0137:00426284   E867450100      CALL  0043A7F0
0137:00426289   83C408          ADD ESP,08
0137:0042628C   85C0            TEST  EAX,EAX ;<==== it's NOT this...
0137:0042628E   0F8414000000    JZ  004262A8 
0137:00426294   8D45DC          LEA EAX,[EBP-24]
0137:00426297   50              PUSH  EAX
0137:00426298   E823110100      CALL  004373C0
0137:0042629D   83C404          ADD ESP,04
0137:004262A0   8945EC          MOV [EBP-14],EAX
0137:004262A3   E907000000      JMP 004262AF
0137:004262A8   C745EC00000000  MOV DWORD PTR [EBP-14],00000000
0137:004262AF   837DEC00  CMP   DWORD PTR [EBP-14],00;<===== THIS IS THE ONE!
0137:004262B3   0F8479000000    JZ 00426332 
0137:004262B9   8B8DFCFEFFFF    MOV ECX,[EBP-0104] ; <=== WE NEED TO GO HERE!
0137:004262BF   83C164          ADD ECX,64
0137:004262C2   E8B9B9FDFF      CALL  00401C80

The one at 0137:004262AF triggers the "bad" jump.
Now we proceed so: We step with F10 until we reach

0137:004262B3  0F8479000000     JZ  00426332

The idea is to re-jump it, in order to make the algorithm to "believe" that we have entered the right serial.
We switch for this to the register window - with the mouse, or if you don't have a Pentium processor press Alt-R. Now we place the caret over the Z flag - since it causes the jump - and switch it to z with the Insert key, thus forcing the program to "not jump". When we change back to the command window (WC) the text on the current instruction changes to "no jump". Now GO - and a second form appears inviting us to enter User Name and Organization.
There is no return at this point for the poor stupid protection scheme, it accepts everything and after we are ready, we become registered users with a properly encoded (with the fake serial) .REG file in Hex Workshop's directory.
Isn't cracking great? Even better than playing bridge or chess!
I have made it months ago on the 2.52 version and in the latest 2.54 version it still works. I hope the next few versions will NOT have this same stupid protection... I'm getting bored...
But if you now think that this is a unique case of stupidity you should see the protection of Win-eXpose I/O for Win95 - a very usefull tool BTW; you should try it - it has exactly the same scheme! Just BPX on 00461D9, after you filled out the registration form with your data and any serial:

:004061D7 85C0                    test eax, eax
:004061D9 0F84CF000000            je 004062AE; <======= HERE!

change then the Zero flag in the registers window and GO. The program generates the right key for you and writes it down (with the other data) in its .ini file. BTW, you can find the right password for your fake serial when you BPX on 004061B2 and issue:

d eax

You should see then in the data window the correct password for the serial you entered terminated with a zero byte; ignore case.
On both programs you don't need to patch anything!
The competition on Reverser's Most Stupid Protection Award becomes harder and harder ;-)

And now to the serios stuff.


Gif Construction Set 32, 1.0Q ; Alchemy Mindworks
To obtain from: www.mindworkshop.com/alchemy/alchemy.html (and from everywhere else on the Web)
Well, a pretty easy scheme, it is really a ten minute crack, but the encoding algorithm is great. There is no way to see or even guess the right keyword at all. If there were an award for encoding passwords GifCon would be a major pretender.
We do it as usual: From the main window select SETUP, put your User Name there (must be at least 6 characters long!) then press the ACCEPT button. In the second dialog window enter some "key word", for now it is not relevant which exactly. It is the moment for entering SoftIce and setting a breakpoint at GETWINDOWTEXT(). Then press OK in the dialog and after two F12's SoftIce pops you here:

0137:00409723   50              PUSH  EAX
0137:00409724   E8F60F0500      CALL  USER32!GetWindowTextA
0137:00409729   682EB84500      PUSH  0045B82E ; <==== WE ARE HERE!
0137:0040972E   6828B74500      PUSH  0045B728
0137:00409733   E858000000      CALL  00409790 ; <==== TO MAIN ENCODING
0137:00409738   83C408          ADD ESP,08
0137:0040973B   85C0            TEST  EAX,EAX ; <===== NAG HIM OR NOT?
0137:0040973D   740A            JZ  00409749 ; <==== DO IT!
0137:0040973F   6A01            PUSH  01
0137:00409741   53              PUSH  EBX
0137:00409742   E8E0100500      CALL  USER32!EndDialog

There is nothing unusual. When we ask SoftIce:

:? @0045B82E
70616261  1885430369  "Our Keyword here"
:? @0045B728
20494246  0541672006  "Our User Name here" (both in reverse order!)

we see that the first call is "ours". We go with F8 into it and see the holy encoding routine:

0137:00409790   55    PUSH  EBP
0137:00409791   8BEC  MOV EBP,ESP
0137:004097F0   0FB7C8          MOVZX ECX,AX
0137:004097F3   C1E304          SHL EBX,04
0137:004097F6   3B8B5CC34500    CMP ECX,[EBX+0045C35C]
0137:004097FC   7507            JNZ 00409805 ; <===== CHANGE THIS!
0137:004097FE   B801000000      MOV EAX,00000001
0137:00409803   EB02            JMP 00409807
0137:00409805   33C0            XOR EAX,EAX
0137:00409807   5B              POP EBX
0137:00409808   8BE5            MOV ESP,EBP
0137:0040980A   5D              POP EBP
0137:0040980B   C3              RET

When we look closer we soon see the simple crack we need, if we want to register the program with any name and any keyword we fancy:

change  0137:004097FC  75 07  JNZ 00409805
to      0137:004097FC  EB 00  JMP 004097FE

And the crack is commited!
But we want more. We want to register with the right keyword that corresponds to our user name. Since it is really a very complex algorithm, I've commented it for you and explain briefly the main idea.
GifCon manipulates first the user name. It uses four different algorithmes for each character in a four-char-cycle. The result is accumulated in ESI. After each char has been proceeded the final score is divided by 1Ch (28 dec). The remainder from this division is then multiplied by 16 (SHL 04) and this is what I called our "Magic Offset". With this offset the program then addresses a doubleword inside a table in its own data area (in the exe!). The value of this doubleword -at least- is our real Magic Number.
And now comes the tricky part.
The keyword we entered is encoded with the same algorithm, just without the division and multiplication at the end. The final value from the encoded keyword must then match the Magic Number from the table in the exe.
So we never have the chance to see the right keyword, the comparision allways operates with the encoded strings! For me, it is much like p.e. UNIX stores logins and passwords, therefore I speak for password- instead of key-generator. The program uses further another table (hardcoded in its exe too) in order to "filter" the input; so you can p.e. mix your (right) keyword with as many digits or country specific characters as you like - they are ignored by the encoder; upper case is converted to lower in the User Name etc. The advantage of such approach is, that even peoples with the same name may have different keywords.
Because of the complexity of all this I have included the full commented disassebmly among all other things in a extra file which you can download separately - uvcrack.zip. You can find there the password generator with source code, and both tables from the body of the Gifcon32.exe as well.
My first idea was simply to copy the encoding routine in my cracker.exe, a kind of "with his stowns over his own head" - maybe someone help me to find the right idiom ;-), and it was such a hell of a job, that once I've adjusted everything I never came back again to improve it, so please bear with me!
It implements a simle word generator which just generates all possibly words, beginning with "aaaa" (but you can change the initials); for each of them it then calculates the Magic Number and compares it with the one that came out from the table when encoding your User Name. And so on until they match.
It works reliably -though terribly slow- but this is because it tries every possible word. Since every char has its own "weight", depending on its ordinal number in the string, with an algorithm that accepts a criteria too - such as General Backtracing - one could achieve better run times.
You can try to reverse the encoding algorithm itself too, thus obtaining the password right from the magic number, if possible at all. Feel free to change everything you like, don't forget to paste both tables after each compilation at the appropriate locations (look for the initial strings).
Of course, you have to adjust the Makefile too.
I just wanted to show that such idiotic approach can work. I had no problems with the latest version of Gifcon 32 bit. When you experience any problems let me know, this will be the sign that the algorithm (or one of its parameters) has changed. But the fate even of the most stupid protection is to remain the same, or the shareware can't be accepted by the customer anymore!

That was all for now folks. Hope you enjoied this.

Here is a "quick reference" for the above targets:

HexWorkshop BPX 004262AF
Hedit BPX 004039E7
Iconedit BPX 004956C0
Win-eXpose I/O BPX 004061D9
Gif Construction Set BPX 00409733

Thanks to +ORC for the wonderfull tutorials, who opened this incredible world of possibilities to me, and of course to Reverser+ for maintaining one of the most useful sites on the Web; and a great thank to all other +HCUkers too!. Man, you learn, I learn, you teach, I teach!


Coming soon: Dongle protections - Taylor for Windows (a very expensive simulator; already cracked!), Autocad 14 and many others!

Please send your questions/comments/offences/crack requests to me!

(c) UncleVan, 1997. All rights reserved.