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!
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:
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
: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
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 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:
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:
This ensure that you are in the right address space to set the breakpoints. Now type:
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:
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:
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:
The next FLD shifts our number in ST1 and (stack-alike) loads another number in ST0:
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 Fravia’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:
-..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:
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 Fravia’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:
70616261 1885430369 "Our Keyword here"
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.