End of the dongle old aera ~ Dongles bye bye
(re-uploade version October 1998)
first part ~ second part
"How a single +HCU Fravia can easily blow a whole commercial sector out of history"
That's it, nothing more to add... let's hope we get a new dongle aera to work on.
Awesome essay. Frog's Print's incredible work should be printed (44 pages !) and sipped slowly, it's 'cracking for conoisseurs'... Fravia's vintage 1998 "grand reserve"!
Bye bye to all those that wanted to do some quick bucks selling hardware protections that were NOT protections at all. This is good, nobody will mourn the disappearing of smoke-sellers and bogus protectors. Bye bye to all those that never cared to study assembly. This is good. Bye bye to all the creations of the poor programmers that blindly trusted commercial (and THEREFORE bogus) dongle protections to defend their valuable software instead of writing their own much more solide protections. Tsch Tsch.
You had better read +ORC's students essays first... next time. And learn. And now don't come to the silly idea to blame Frog's Print... blame those dilettantes that have sold you smoke. Blame yourself. A little reality cracking would have done you some good, probably. Well, one never ends learning, does one? I would never have believed myself that (almost) all implementations of the dongle protections scheme were so stupid. Oh my, how low, how deep have the programmers fallen, since Micro$oft introduced its frilly-dizzy rattamazz operating system :-)
Of course anyone of my readers could now just 'go shopping' and download, fetch or get hundred thousand dongle protected software programs, each one of them -incidentally- extremely expensive. DO NOT DO IT. You'll only stuff your already exploding harddisks to death for nothing and bore yourself to death.
See, you don't need to do it: that poor software won't disappear, nor it will go away. It will always be there. It wont be dongle protected any more after this, oh no, no, no :-)
Yet, probably it will be as poorly protected as before by some other charlatans, smoke-selling some other 'infallible' protection scheme... people never learn. Unless they study. That's why you are here, my good reader, to master a difficult but POWERFUL art: reversing.
So don't steal the software that Frog's Print has now stripped naked. Look at those protection schemes, pathetically whining and sobbing under Frog's streng and mighty reversing blick. They wont be ever able to run away, the poor scared things.
Of course -as it happens- this essay could be useful AGAINST THEFT.. for our underfunded public universities for instance, where (as I very well know) hardware dongles are regularly and phisycally stolen from their parallel ports (it's difficult to find a way to fest them there and students don't show any respect for public property any more, having being corrupted by the 'sacrality' of private gains and property)... so this essay may be a good reading, for all colleagues in the public sector, in order to protect against stupid vandalic theft their legally bought software as well :-)
See: +crackers bring solutions for the good ones and ruin for the evil ones :-)
So, Dongles could be a very powerful and strong way to protect a soft...as long as the programmer willing to utilize one knows how to use it. Unfortunately, most of them don't (note that we are not talking about shareware programmers but professional guys! ) and are still using our "beloved" Test eax,eax//jnz Bad_Guy stupid routine, thinking that they don't have to worry about the protection because the dongle will take care of it (same old problem discussed so much often here -: ). Some of them use ridiculous $5 shareware tricks to protect $4.000 professional softs (see Vision XXL) and, worse, others just forgot to read the Dongle documentation manual shipped with their hardware key (see ABBCS31), you'll even find some of the most amazingly stupid protections I can't find any words to describe them (see DigiSHOW). Too bad...specially when those programs are available for free download on the Net.
Sometimes it may be useful to know which dongle is needed for the
program you want to crack (Aladdin's Hasp, Rainbow Technologies' Sentinel,
Dinkey, Everlock...) or, very important if you plan to use SoftICE
and some Breakpoints, the type of dongle (parallel or serial key, internal
or PCMCIA card, Network dongle...), sometimes you won't even have to care
about that. And, finally, in just few cases, you may not be able to crack
a program if you don't have the right dongle (but if you have the dongle
why should you crack it? -: ) or because the program is strongly encrypted
and/or uses too many anti-debugger and anti-w32dasm/IDAPro protections
(usually, those anti-crackers protections are not written by the programer
himself :- ).
For this, never forget to read carefully the program's doc or HLP files, to visit it's company home page (specially the "installation help" or "FAQ" pages) to collect the maximum infos about the dongle needed. You'll find them most of the time, but sometimes you may only find that the program needs a "green" or "red" dongle. So don't forget to monitor the program installation on your Hard Drive : for all the programs of this essay, during their installation I used CleanSweep, WinDelete and TechFacts, all 3 programs running at the same time. Then check for new .Vxd, .Drv, .Sys and .Dll files in you windows(/system) or the programs directories. Do the same the first time you'll run the program because it may use/create and hide a lot of "~x34_m-!.sys" or similar strange named files anywhere on your HD. If you can identify the Dongle manufacturer, then visit its WWW/FTP sites, newsgroups, read newspaper articles about it and visit programmers' tools retailers companies sites like SOSdevelopers (if you can understand French), download their softs/demos (SOSdevelopers download section), get their free catalogue where you'll find all products for programers and the latest protections tools of the market (BTW, SOSdevelopers is probably actually one of the rare place where you can still find SoftICE 3.01 and all others Numega 14 days trial version products available for downloading since Numaga lately removed their Download section from their WWW home site -: ). And finally, if you plan to crack several dongle protected softs, install and monitor the first one, crack it and then delete it before installing the second one, third one... otherwise it'll be to messy and complicated to monitor and crack.
Here is now, for instance, some infos I found at Aladdin
SoftWares (Hasp/NetHasp dongles). They wrote this to help programers
to write a "good" protection for their dongle (blue comments are mine of
The golden rule of HASP-based software protection is that the
protection system is only as secure as the routines that call the key and
decide whether to allow execution of the protected program. In other words,
since the hardware of HASP keys is too complicated to break or duplicate, hackers will usually try to trace the protection code and eliminate the protection routines.
Emulating the Dongle by re-writing its main routine is much funnier than boring tracing and patching (and sometimes a lot easier, specially the Hasp protection routine! )
While we supply you with the best hardware and software protection tools available, and while the HASP Envelope can by itself provide an excellent protection for application programs, if possible, you should enhance your protection system by implementing the Application Programming Interface (API) as well.
If only they knew how to do it...
Please keep in mind that while no single technique can defeat
every hacker, the more traps and safeguards you use, the more difficult
it will be to break your software. In order to achieve maximum protection
with HASP, we suggest you implement at least some of the procedures outlined
Issue as many calls as possible with many different Seed Codes.
The more calls and expected responses you use, the more difficult it will be to trace and remove them.
Boring yes, difficult not really.
Perform logical divisions of the checking procedure. Divide
the checking procedure, and if possible, spread it across your program
at far-away points.
A logical division would be: calling, checking, and reacting routines, each situated in a different section of the program.
Hide parts of the checking code within a regular source code. For example, the calling routine can be hidden within a general initialization routine.
Easy to find with a BPIO 278/378
Use complicated mathematical expressions. In order to
confuse hackers, check for the Return Codes using complicated mathematical
expressions. For example, if you are expecting a Return Code which
equals 26387, incorporate an expression such as the one below to perform
If (ReturnCode1 - 7)/4 = (ExpectedReturnCode1 - 6602)/3 then...
To further enhance your level of security, follow the same procedure throughout your software for any mathematical constants used in implementing your HASP software protection solution.
Yes, and add a beautiful jnz_Bad_Guy at the end...
Use delayed reactions. Do not react immediately to a checking
call. For example,do not test for a certain value and then issue an error
message if you do not like the result. If you do, the hacker will easily
understand what you are doing.
It is better to store the value in a variable A, check A's value a few subroutine calls later, and set a new variable B to say whether or not you like it. Several calls after that, test the value of B, and only then issue the error message.
Force hackers to work backward to figure out how B got a certain value and why the program fails because of that. The relation to the original returned value should no longer be obvious.
Perform check-sums. Perform a check-sum on the program
to find out if it has been
tampered with. The most effective means to do this is with the HASP Pro Kit.
Otherwise, the simplest way to do so is to use the following pattern:
Compare with correct value.
If the two do not match,
issue an error message;
Unfortunately, this technique is vulnerable to several attacks.
After that, there are different ways to crack it:
1/Reverse engineering the dongle protection main routine in order to emulate the dongle (see ABBCS31).
-This is very efficient specially if this routine is called dozens or sometimes hundreds of times throughout the program (otherwise we would have to patch all those cross-references!).
-With this method, you don't need to have the dongle driver loaded (if you have 10 programs using different dongles, you'll need to have 10 different drivers always loaded).
2/Patching some Call, Test or jnz instructions.
Not the most elegant method but useful if:
-you don't know how the dongle protection routine works but you quickly found the right Bad_Guy Flag.
-your program is to slow to start/run . Some overbloated EXE or DLL will check for a dongle, dongle ID and Seed Code and, if they can't find them, will check again and again before telling you that you don't have the requested hardware key. For that reason, those programs may check for the dongle for 15 or sometimes +30 seconds. This even happens sometimes after you "emulated" the Dongle. A real waste of time! (see WellCAD).
3/Brute force approach:
Close to the above solution, this one may be quite useful for program that may react strangely when they are modified. This method just force them to work the way you want (see Ai Damage).
4/You may use your own tips/findings like searching with Hiew the bytes sequence 0xE900000000
jmp Next_Instruction (see OmniMark).
In this essay, we'll just assume that you are familiar with cracking because I won't give a lot of comments about all usual protections routines/tricks... that don't have anything to see with the dongle protection nor will I spend time to explain how to crack it when it will be quite obvious (most of the time).
As said above, all programs cracked in this essay can be found and
download on their companies homepages (see links below).
You'll find plenty of dongle softs to download for free on the Net. Just learn how to search and you'll see what I mean.
OK, now let's have some fun!
W32Dasm v6.x and W32Dasm8.5
+IDA PRO v3.7
A taste of Zen Cracking
1) Micro-Cap V (Spectrum SoftWare) v2.01
2) Vision XL/XXL v2.0 (Impuls) 9.5Mb
3) ABBCS31 v1.02 Klinkmann Automation Softs (DDE Servers) 420Kb
4) WellCAD v2.30 : Full version 10.5Mb or Lite version 2.5Mb (similar but without help files and sample data files)
5) Label Craft v6.01 (Axicon Softs) 1.2Mb
6) Ai Damage v1.4 (Ai Training Services Ltd) 185Kb (requires the DK2 DESkey dongle drivers -dk2wn95.386, dk2win32.dll...- if not installed on your system, you can download them here: Bdk2wn32.exe 720Kb - read the essay for more infos-: )
7) Electro Chemistry 12 Nov.1997 version (Sycopel Scientific Ltd) 531Kb.
8) IPLab v1.7 (Signal Analytics Corp.) 1.5Mb
9) DigiSHOW.vld v1.24 1.59Mb
A) Axon Engineer Pro v2.11e 2.09Mb
B) FTI/DOE v.22.214.171.124 2.78Mb
C) S-Tagger for FrameMaker v2.0 1.32Mb
D) XinTianMa C version 1.04Mb
E) OmniMark V3R1a Win95 1.88Mb
Apparently, Micro-Cap V programmers are the only guys who understood
that the dongle will not do all the job. They tried to add some improvements
to the protection scheme:
-Fake flags (Bad or Good_Guy).
-Several flags hidden at different locations (using different registers).
-Delayed reactions (calling, checking and reacting routines).
-Mathematical expressions for checking the RetCodes (though they could improve this part).
-Several calls with different Seed Codes.
This is the first Hasp dongle of this essay. I hope you read Zafer's essay about the various hasp-dongle services because I will not explain this again. However, I will show you the main Hasp routine from Micro-Cap as it is just a little different from the one describe by Zafer, but it works just the same:
:0054141B 89E5 mov ebp, esp
:0054141D 60 pushad
:0054141E 88C7 mov bh, al ; Service called
:00541420 52 push edx
:00541421 58 pop eax
:00541422 8B5508 mov edx, dword ptr [ebp+08]
:00541425 8B750C mov esi, dword ptr [ebp+0C]
:00541428 8B3E mov edi, dword ptr [esi]
:0054142A 80FF32 cmp bh, 32
:0054142D 7205 jb 00541434
:0054142F 8B7518 mov esi, dword ptr [ebp+18]
:00541432 8B06 mov eax, dword ptr [esi]
:00541434 8B7510 mov esi, dword ptr [ebp+10]
:00541437 8B36 mov esi, dword ptr [esi]
:00541439 55 push ebp
:0054143A E8B1D00000 call 0054E4F0 ; Haspreg
:0054143F 5D pop ebp
:00541440 8B7D0C mov edi, dword ptr [ebp+0C]
:00541443 8907 mov dword ptr [edi], eax ; RetCode1
:00541445 8B7D10 mov edi, dword ptr [ebp+10]
:00541448 891F mov dword ptr [edi], ebx ; RetCode2
:0054144A 8B7D14 mov edi, dword ptr [ebp+14]
:0054144D 890F mov dword ptr [edi], ecx ; RetCode3
:0054144F 8B7D18 mov edi, dword ptr [ebp+18]
:00541452 8917 mov dword ptr [edi], edx ; RetCode3
:00541454 61 popad
:00541455 5D pop ebp
:00541456 C21400 ret 0014
We will rewrite this routine in order to emulate the dongle because there will be too may occurences to patch in this soft.
Running Micro-Cap will display the message box: 'Security Key
missing. Replace the key'.
With SoftICE, Bpx the above routine and run Micro-Cap.
The first break occures here:
:00422C39 B801000000 mov eax, 00000001
:00422C5B E8BAE71100 call 0054141A ; IsHasp
:00422C60 8B45F0 mov eax, dword ptr [ebp-10] ; Store RetCode1 in EAX
:00422C63 89EC mov esp, ebp
:00422C65 5D pop ebp
:00422C66 5A pop edx
:00422C67 59 pop ecx
:00422C68 5B pop ebx
:00422C69 C3 ret
:00422AEC E82F010000 call 00422C20
:00422AF1 85C0 test eax, eax ; Check if OK
:00422AF3 752D jne 00422B22 ; Good_Guy jump
Of course, the RetCode1 should be equal to 1.
The second break:
:00422E8D B805000000 mov eax,
:00422E92 89542414 mov dword ptr [esp+14], edx
:00422E96 E87FE51100 call 0054141A ; HaspStatus
:00422E9B 8B442408 mov eax, dword ptr [esp+08] ; Parallel Port # (RetCode3)
:00422E9F 8B7C2404 mov edi, dword ptr [esp+04] ; Type of Hasp (Retcode2)
:00422EA3 A37CF65500 mov dword ptr [0055F67C], eax
:00422EA8 83FF01 cmp edi, 00000001 ; Is it a Memo-Hasp?
:00422EAB 740D je 00422EBA
:00422EAD B8FCFFFFFF mov eax, FFFFFFFC ; Bad_Guy
:00422EB2 83C410 add esp, 00000010
:00422EB5 5F pop edi
:00422EB6 5A pop edx
:00422EB7 59 pop ecx
:00422EB8 5B pop ebx
:00422EB9 C3 ret
* Referenced by a (C)onditional Jump at Address:00422EAB
:00422EBA 31C0 xor eax, eax ; Good_Guy
:00422EBC 83C410 add esp, 00000010
:00422EBF 5F pop edi
:00422EC0 5A pop edx
:00422EC1 59 pop ecx
:00422EC2 5B pop ebx
:00422EC3 C3 ret
No surprises yet: after checking if there
is a Hasp dongle connected, it checks its type (Memo-Hasp). It doesn't
care if it is a Memo-Hasp-1 or a Memo-Hasp-4 as Retcode1 is not verified.
The 3rd break:
mov eax, 00000002
:00422C13 E802E81100 call 0054141A ; HaspCode
:00422C18 5D pop ebp
:00422C19 5F pop edi
:00422C1A 5E pop esi
:00422C1B C20400 ret 0004
:00422B5B E864000000 call 00422BC4
:00422B60 8B1424 mov edx, dword ptr [esp] ; Store RetCode1 in Edx
:00422B63 81EACA190000 sub edx, 000019CA ; Edx-0x19CA
:00422B69 B905000000 mov ecx, 00000005
:00422B6E 89D0 mov eax, edx ; Store in Eax
:00422B70 C1FA1F sar edx, 1F
:00422B73 F7F9 idiv ecx ; Eax/5 and store result in Eax
:00422B75 3D982D0000 cmp eax, 00002D98 ; Is it correct?
:00422B7A 7405 je 00422B81 ; jmp over if OK
:00422B7C BE01000000 mov esi, 00000001 ; Set Bad_Guy#1 Flag discreetly so that stupid
; crackers will never find it!
:00422B81 817C24046DF60000 cmp dword ptr [esp+04],F66D ; Check RetCode2
:00422B89 0F8566FFFFFF jne 00422AF5 ; Bad_Guy#2 jump
:00422B8F 817C24086CD60000 cmp dword ptr [esp+08],D66C ; Check RetCode3
:00422B97 0F8558FFFFFF jne 00422AF5 ; Bad_Guy#2 jump
:00422B9D 817C240C973B0000 cmp dword ptr [esp+0C],3B97 ; Check RetCode4
:00422BA5 0F854AFFFFFF jne 00422AF5 ; Bad_Guy#2 jump
:00422BAB EB80 jmp 00422B2D ; JUMP if OK and make him believe everything
; is fine...
:00422B2D 85F6 test esi, esi ; ...and check Bad_Guy#1 Flag!
:00422B2F 7507 jne 00422B38 ; Bad_Guy_Jump.
RetCodes 2, 3 and 4 are displayed in the code (0xF66D, 0xD66C, 0x3B97). To check the RetCode1, the program uses simple mathematical expressions from offset 422B63 to offset 422B75.
Finding the RetCode1 value is simple.
0x2D98 = (RetCode1 - 0x19CA) / 5
RetCode1 = (0x2D98 * 5) + 0x19CA)
RetCode1 = 0xFDC2
You can see that if one of the 3 last RetCodes is wrong, it will clearly send you on the Bad_Guy#2.
But it will discreetly set the Bag_guy#1 flag (mov esi,1) if the first RetCode is wrong and will go ahead as if everything was fine before checking it later at offset 422B2F.
The 4th break:
This time, the program will read a block from the dongle, and check if no error occured (RetCode3)
:00422CE2 B832000000 mov
:00422CE7 31D2 xor edx, edx
:00422CE9 E82CE71100 call 0054141A ; ReadBlock
:00422CEE 807D02EA cmp byte ptr [ebp+02], EA ; Check correct value
:00422CF2 741F je 00422D13 ; jmp if OK
:00422CF4 837D7A00 cmp dword ptr [ebp+7A], 0 ; Check RetCode3 (status Code)
:00422CF8 7519 jne 00422D13 ; jmp if NOT correct as well
:00422CFA B801000000 mov eax, 00000001 ; Bad_Guy flag but make it looks
; like a Good_Guy Flag!
:00422CFF 8DA582000000 lea esp, dword ptr [ebp+82]
:00422D0A C3 ret ; Back to caller
:00422D13 8B457A mov eax, dword ptr [ebp+7A] ; store status code in Eax
:00422D16 8DA582000000 lea esp, dword ptr [ebp+82]
:00422D21 C3 ret ; Back to caller
:00422B22 E831030000 call 00422E58
:00422B27 89C6 mov esi, eax ; store in esi as well
:00422B29 85C0 test eax, eax ; Check if OK
:00422B2B 7418 je 00422B45 ; je Good_Guy
:00422B2D 85F6 test esi, esi ; Check again to confuse...
:00422B2F 7507 jne 00422B38 ; jne Bad_Guy
We could think that the mov eax,1 is our Good_Guy because right above, it checks the RetCode3 (equal to 0x0 if no error) and jump if an error was returned.
But it stores this RetCode into Eax (:422D13) and later will store it into Esi too, and will check both registers to see if it's OK. It is clear that, if the dongle was connected, the program should never reach offset :422CF4.
0xEA is probably a byte calculated somewhere depending on the dongle RetCode (it is not RetCode1, 2, 3 or 4). To crack this will have to store 0xEa into ebp+2 and to ensure that the RetCode3 will be equal to 0x0.
Now, Micro-Cap V seems to work fine but it still check for the dongle
depending on which key is pressed.
The 5th break:
Here, the program will check again Service#1 (IsHasp) but in another location.
The 6th break:
Now it calls again Service 2.
mov eax, 00000002
:00422C13 E802E81100 call 0054141A
:00422C18 5D pop ebp
:00422C19 5F pop edi
:00422C1A 5E pop esi
:00422C1B C20400 ret 0004
:00422D6A E855FEFFFF call 00422BC4
:00422D6F 6681FE8203 cmp si, 0382
:00422D74 7527 jne 00422D9D
:00422D76 813C24C7710000 cmp dword ptr [esp], 000071C7
:00422D7D 75C8 jne 00422D47
:00422D7F 817C2404935B0000 cmp dword ptr [esp+04], 00005B93
:00422D87 75BE jne 00422D47
:00422D89 817C2408E1BF0000 cmp dword ptr [esp+08], 0000BFE1
:00422D91 75B4 jne 00422D47
:00422D93 817C240C900D0000 cmp dword ptr [esp+0C], 00000D90
:00422D9B 75AA jne 00422D47
:00422D9D 6681FEE486 cmp si, 86E4
:00422DA2 752B jne 00422DCF
:00422DA4 813C248BF60000 cmp dword ptr [esp], 0000F68B
:00422DAB 759A jne 00422D47
:00422DAD 817C2404D3B40000 cmp dword ptr [esp+04], 0000B4D3
:00422DB5 7590 jne 00422D47
:00422DB7 817C2408FE0E0000 cmp dword ptr [esp+08], 00000EFE
:00422DBF 7586 jne 00422D47
:00422DC1 817C240CD43F0000 cmp dword ptr [esp+0C], 00003FD4
:00422DC9 0F8578FFFFFF jne 00422D47
:00422DCF 6681FE9907 cmp si, 0799
:00422DD4 7537 jne 00422E0D
:00422DD6 813C2411560000 cmp dword ptr [esp], 00005611
:00422DDD 0F8564FFFFFF jne 00422D47
:00422DE3 817C2404BB6E0000 cmp dword ptr [esp+04], 00006EBB
:00422DEB 0F8556FFFFFF jne 00422D47
:00422DF1 817C2408925C0000 cmp dword ptr [esp+08], 00005C92
:00422DF9 0F8548FFFFFF jne 00422D47
:00422DFF 817C240C8EB60000 cmp dword ptr [esp+0C], 0000B68E
:00422E07 0F853AFFFFFF jne 00422D47
:00422E0D 6681FE3E05 cmp si, 053E
:00422E12 7537 jne 00422E4B
:00422E14 813C24EB6F0000 cmp dword ptr [esp], 00006FEB
:00422E1B 0F8526FFFFFF jne 00422D47
:00422E21 817C2404945D0000 cmp dword ptr [esp+04], 00005D94
:00422E29 0F8518FFFFFF jne 00422D47
:00422E2F 817C24087D200000 cmp dword ptr [esp+08], 0000207D
:00422E37 0F850AFFFFFF jne 00422D47
:00422E3D 817C240CCEAE0000 cmp dword ptr [esp+0C], 0000AECE
:00422E45 0F85FCFEFFFF jne 00422D47
:00422E4B 31C0 xor eax, eax ; Good_Guy
:00422E4D 83C410 add esp, 00000010
:00422E50 5E pop esi
:00422E51 5A pop edx
:00422E52 59 pop ecx
:00422E53 5B pop ebx
:00422E54 C3 ret
:00422D47 B8B13A0000 mov eax, 00003AB1 ; Bad_Guy
:00422D4C 83C410 add esp, 00000010
:00422D4F 5E pop esi
:00422D50 5A pop edx
:00422D51 59 pop ecx
:00422D52 5B pop ebx
:00422D53 C3 ret
Depending on the value of Esi ( 0x0382, 0x86E4, 0x0799 or 0x053E) the program will check for different RetCodes (they all are shown in the code) and if it's OK, will clear Eax (Good_Guy) otherwise will make you jump to offset :422D47.
If Esi has a different value (this shouldn't happen) the program will get to the Good_Guy as well.
To crack this, we will simply xor Ecx (on the stack as it is saved there before the call to the Hasp routine) during a call to Service 2 and therefore we will always reach our Good_Guy. Clearing Ecx will not affect the call to Service 2 I described before this one as it is unused (saved on the stack).
There is a last break when exiting the program:
The 7th break:
mov eax, 00000006
:00422F3D EBDC jmp 00422F1B
:00422F1B E8FAE41100 call 0054141A
:00422F20 8B45F8 mov eax, dword ptr [ebp-08]
:00422F23 85C0 test eax, eax
:00422F25 7418 je 00422F3F
Here, the program just check if any error occured.
There are still few xrefs to the main Hasp routine (services 1, 6...) but it doesn't matter as we will 'emulate' the dongle and this will work for thoses xrefs as well. However, one of them is a call to service 0x29 (HaspID) at offset :422BF6 that apparently the program doesn't reach. We will not crack it.
As there's not enough room in the main Hasp routine to write our
own one, we will do it mostly at offset :514E4F0 that is called by this
All changes are shown in red:
.0514141B: 89E5 mov ebp,esp
.0514141D: 60 pushad
.0514141E: 88C7 mov bh,al ; bh=Hasp Service called
.05141420: 80FF02 cmp bh,02 ; Is it Service#2 ?
.05141423: 0F8510000000 jne .00141439 ; jump over if not
.05141429: 66C745240000 mov w,[ebp],00000 ; otherwise clear Esi
.0514142F: E905000000 jmp .000141439 ; Go ahead
.05141434: 8B7510 mov esi,[ebp] ; unused
.05141437: 8B36 mov esi,[esi] ; unused
.05141439: 55 push ebp ; back to original code
.0514143A: E8B1D00000 call .00514E4F0 ; call our new routine
.0514143F: 5D pop ebp
.05141440: 8B7D0C mov edi,[ebp][0000C]
.05141443: 8907 mov [edi],eax ; RetCode1
.05141445: 8B7D10 mov edi,[ebp]
.05141448: 891F mov [edi],ebx ; RetCode2
.0514144A: 8B7D14 mov edi,[ebp]
.0514144D: 890F mov [edi],ecx ; RetCode3
.0514144F: 8B7D18 mov edi,[ebp]
.05141452: 8917 mov [edi],edx ; RetCode4
; Is it Service#1 ?
.0514E4F3: 7505 jne .00014E4FA
.0514E4F5: B801000000 mov eax,000000001 ; RetCode1
.0514E4FA: 80FF02 cmp bh,002 ; Is it Service#2 ?
.0514E4FD: 7519 jne .00014E518
.0514E4FF: B8C2FD0000 mov eax,00000FDC2 ; RetCode1
.0514E504: BB6DF60000 mov ebx,00000F66D ; RetCode2
.0514E509: B96CD60000 mov ecx,00000D66C ; RetCode3
.0514E50E: BA973B0000 mov edx,000003B97 ; RetCode4
.0514E513: E925000000 jmp .00014E53D
.0514E518: 80FF05 cmp bh,005 ; Is it Service#5 ?
.0514E51B: 750C jne .00014E529
.0514E51D: BB01000000 mov ebx,000000001 ; RetCode2
.0514E522: B901000000 mov ecx,000000001 ; RetCode3
.0514E527: EB14 jmps .00014E53D
.0514E529: 80FF06 cmp bh,006 ; Is it Service#6 ?
.0514E52C: 740D je .00014E53B
.0514E52E: 80FF32 cmp bh,032 ; Is it Service#32 ?
.0514E531: 0F8504000000 jne .00014E53B
.0514E537: C6451CEA mov b,[ebp][0001C],0EA ; store our 0xEA
.0514E53B: 33C9 xor ecx,ecx ; clear RetCode3 (NO error)
.0514E53D: C3 retn ; back to Hasp main routine
.0514E53E: 8D3534FC5600 lea esi,[00056FC34] ; will never reach this part.
Everything works quite well but it may be safer not to forget the call to Service 0x29 that we didn't patch, just in case the program would reach it one of these days...
Vision XL/XXL v2.0
High performance image processing and image analysis system.
Dongle (parallel or serial key). Driver: Hardlock.vxd (c:\windows\system).
Run as a DEMO if no dongle detected (Save, save as, copy disabled, macros disabled after 30 program runs...).
Described as "seeing the invisible", this is a very sophisticated and extremely expensive soft. For those reasons, we could only expect a strong or at least, a good protection. Unfortunately, its protection is really stupid, and then, the most amazing is that we won't even have to care about the dongle to crack it!
During its installation, the program added the file Hardlock.vxd and told us that we need to restart Windows before running it (to load the dongle driver!).
Put a BPIO -H 378 with SoftICE and then run VisionXXL.
Nothing happens! The program doesn't seem to check the parallel port.
After a quick check at the huge documentation (25Mb is MS-Word format!),
I found this:
"The security key can be reversed to be used on a serial interface port...".
I read that there are some lines to add to your Autoexec.bat as well (SET HL_SEARCH=2f8s,...where 2f8 denotes the IO address of the serial port,and s denotes the serial port. The ellipsis ... is used to indicate that you can check several ports one after the other.).
OK, but let's just forget the dongle for now!
Re-run the program. You'll get the big nagscreen/bitmap telling you that the program is running in demo mode.
As the "Save" feature is disabled, press it in the target's toolbar. The following message box pops up:
"Sorry, this function is not available in demo mode"
Put a BPX MessageBoxA and press "Save" again.
SoftICE pops. Press <F11>, click 'OK' and press <F12> 3 times. You'll land here:
call .0001326D0 ;
Check if Full or Demo mode
.000CA437: 85C0 test eax,eax
.000CA439: 740A je .0000CA445 ; Good_Guy_Jump
.000CA43B: E840EBF4FF call .000018F80 ; Our MessageBoxA
.000CA440: E975040000 jmp .0000CA8BA ; Bad_Guy_Exit
.000CA445: E8127D0B00 call .00018215C ; Good_Guy_Go_Ahead
Those who are familiar with "disabled features"
cracking won't need to read my comments to understand this: this is a stupid
typical protection used so much often for this kind of program.
Let's have a look at the .0001326D0 routine:
001326D0: 8B81E8000000 mov
001326D6: 85C0 test eax,eax
001326D8: 740D je .0001326E7
001326DA: 8B4804 mov ecx,[eax]
001326DD: 85C9 test ecx,ecx
001326DF: 7406 je .0001326E7
001326E1: B801000000 mov eax,000000001 ; Bad_Guy_Flag
001326E6: C3 retn
001326E7: 33C0 xor eax,eax ; Good_Guy_Flag
001326E9: C3 retn
This routine is called as soon as you run
the program (to decide if it's a Demo or full working version) and each
time you'll press or try to use one of the disabled features.
Obviously, patching the first test eax,eax or changing the mov eax,1 will be enough to crack this dongle protection.
DDE (Dynamic Data Exchange) Server allowing other Windows application programs to access the data from the ABB Procontic CS31 automation system.
Dongle (parallel key). Driver: Hasp95.vxd (c:\windows\system).
Run as a time-limited DEMO if no dongle detected (will only run 1 hour).
At the end of the installation setup, we get a "reboot to activate HASP driver!" message. So we know where we are and where we going! The program added the file C:\Windows\System\Hasp95.vxd and the following line in the Registry: 'HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\HASP95'.
With HIEW5.66, we can quickly find the Hasp main routine located
in the Abbcs31.exe file (193Kb).
It starts at offset :00001AC9. Now we can BPX it with SoftICE (don't forget to add 0x400000 to the offset from Hiew to SoftICE ):
Running ABBCS32, we'll get 3 breaks. Callers are:
Here is the code (again from Hiew):
mov eax,[000420AC4] ;
.00001C9C: 50 push eax
.00001C9D: E827FEFFFF call .000001AC9 ; Hasp routine service #5
.00001CA2: 83C424 add esp,024
.00001CA5: 8B45CC mov eax,[ebp][-0034]
.00001CA8: A3A0204200 mov [0004220A0],eax
.00001CAD: 837DD000 cmp d,[ebp][-0030],0 ; Is it a Hasp-3 (RetCode2=0)?
.00001CB1: 0F850C000000 jne .000001CC3
.00001CB7: C745C401000000 mov d,[ebp][-003C],1 ; Yes: Good_Guy_Flag
.00001CBE: E907000000 jmp .000001CCA
.00001CC3: C745C400000000 mov d,[ebp][-003C],0 ; Bad_Guy_Flag
.00001CCA: 837DC400 cmp d,[ebp][-003C],0 ; Is it OK?
.00001CCE: 0F8446000000 je .000001D1A ; No, send_Him_Away...
.00001CD4: C705C40A420001000000 mov d,[000420AC4],1 ; otherwise Go_Ahead
.00001D06: A1C40A4200 mov eax,[000420AC4] ; eax=0x01
.00001D0B: 50 push eax
.00001D0C: E8B8FDFFFF call .000001AC9 ; Hasp routine service #1
.00001D11: 83C424 add esp,024
.00001D14: 8B45D4 mov eax,[ebp][-002C]
.00001D17: 8945C4 mov [ebp][-003C],eax
.00001D1A: 837DC400 cmp d,[ebp][-003C],0 ; Is it a Hasp Dongle (RetCode1=1)?
.00001D1E: 0F84E7000000 je .000001E0B ; Bad_Guy_Jump...
.00001D24: C705C40A420002000000 mov d,[000420AC4],2 ; otherwise Go_Ahead
.00001D84: A1C40A4200 mov eax,[000420AC4] ; eax=0x02
.00001D89: 50 push eax
.00001D8A: E83AFDFFFF call .000001AC9 ; Hasp routine service #2
.00001D8F: 83C424 add esp,024
.00001D92: C705C00A420000000000 mov d,[000420AC0],0
.00001D9C: A1AC204200 mov eax,[0004220AC]
.00001DA1: C1E004 shl eax,004
.00001DA4: 8B4DD4 mov ecx,[ebp][-002C]
.00001DA7: 398818204200 cmp [eax],ecx; Is RetCode1=0x7A17 ?
.00001DAD: 0F8551000000 jne .000001E04 ; Bad_Guy_Jump
.00001DB3: A1AC204200 mov eax,[0004220AC]
.00001DB8: C1E004 shl eax,004
.00001DBB: 8B4DD0 mov ecx,[ebp][-0030]
.00001DBE: 39881C204200 cmp [eax][00042201C],ecx; Is RetCode2=0x768A ?
.00001DC4: 0F853A000000 jne .000001E04 ; Bad_Guy_Jump
.00001DCA: A1AC204200 mov eax,[0004220AC]
.00001DCF: C1E004 shl eax,004
.00001DD2: 8B4DCC mov ecx,[ebp][-0034]
.00001DD5: 398820204200 cmp [eax],ecx; Is RetCode3=0x554C ?
.00001DDB: 0F8523000000 jne .000001E04 ; Bad_Guy_Jump
.00001DE1: A1AC204200 mov eax,[0004220AC]
.00001DE6: C1E004 shl eax,004
.00001DE9: 8B4DC8 mov ecx,[ebp][-0038]
.00001DEC: 398824204200 cmp [eax],ecx; Is RetCode4=0xE6EB ?
.00001DF2: 0F850C000000 jne .000001E04 ; Bad_Guy_Jump
.00001DF8: C745C401000000 mov d,[ebp][-003C],1 ; Good_Guy_Flag
.00001DFF: E907000000 jmp .000001E0B
.00001E04: C745C400000000 mov d,[ebp][-003C],0 ; Bad_Guy_Flag
.00001E0B: 837DC400 cmp d,[ebp][-003C],0
.00001E0F: 0F8515000000 jne .000001E2A ; Dongle_OK
.00001E15: 837DC002 cmp d,[ebp][-0040],2 ; No_Dongle
This routine is INCREDIBLY STUPID!!
As I said at the very beginning of this essay, the programmer just forgot to read the Hasp documentation shipped with his dongle:
Usually, you first check if there is a Hasp dongle connected to the parallel port (Service #1) and then, if there is one, the type of Hasp (Service #5).
We can see here that the program check the type of Hasp before verifying if there is a dongle connected.
The only problem is that we can see that ABBCS32 is expecting a Hasp-3 dongle (RetCode2=0). But, after a call to Service #5, if you don't have any dongle connected the RetCode2 will be equal to... 0x00 as well!
This just means that if you have the correct dongle or nothing at all, the program will just assume that you have the right Hasp-3! Unbelievable...
Fortunately, it checks Service #1 later.
There are a lot of different ways to crack this crap (patching the
Bad_Guy_Flag...) but let's emulate the dongle by reverse engineering the
main Hasp routine again:
Offsets changed are shown in red :
.00001AC9: 55 push
.00001ACA: 8BEC mov ebp,esp
.00001ACC: 50 push eax
.00001ACD: 53 push ebx
.00001ACE: 51 push ecx
.00001ACF: 52 push edx
.00001AD0: 57 push edi
.00001AD1: 56 push esi
.00001AD2: 8B751C mov esi,[ebp][0001C]
.00001AD5: 8B3E mov edi,[esi]
.00001AD7: B900000000 mov ecx,000000000 ; Clear ecx.
.00001ADC: 8B5D08 mov ebx,[ebp] ; bl=Service called.
.00001ADF: 80FB02 cmp bl,002 ; Is it Service #2?
.00001AE2: 7512 jne .000001AF6
.00001AE4: 66B8177A mov ax,07A17 ; correct RetCode#1
.00001AE8: 66BB8A76 mov bx,0768A ; correct RetCode#2
.00001AEC: 66B94C55 mov cx,0554C ; correct RetCode#3
.00001AF0: 66BAEBE6 mov dx,0E6EB ; correct RetCode#4
.00001AF4: EB0F jmps .000001B05
.00001AF6: 80FB01 cmp bl,001 ; Is it Service #1?
.00001AF9: 7506 jne .000001B01
.00001AFB: 66B80100 mov ax,00001 ; correct RetCode#1
.00001AFF: EB04 jmps .000001B05
.00001B01: 33DB xor ebx,ebx ; Xor unused registers
.00001B03: 33C0 xor eax,eax ; just in case.
.00001B05: 8B7D1C mov edi,[ebp][0001C] ; Back to original code.
.00001B08: 8907 mov [edi],eax
.00001B0A: 8B7D20 mov edi,[ebp]
.00001B0D: 891F mov [edi],ebx
.00001B0F: 8B7D24 mov edi,[ebp]
.00001B12: 890F mov [edi],ecx
.00001B14: 8B7D28 mov edi,[ebp]
.00001B17: 8917 mov [edi],edx
.00001B19: 5E pop esi
.00001B1A: 5F pop edi
.00001B1B: 5A pop edx
.00001B1C: 59 pop ecx
.00001B1D: 5B pop ebx
.00001B1E: 58 pop eax
.00001B1F: 5D pop ebp
.00001B20: C3 retn
Abbcs31 is cracked.
Searching for the main Hasp routine, we easily find it at offset
:44D528 in the main program (wellcad.exe 1.42Mb). It has 2 X-refs and then,
the 14 X-refs (called several times) calling the Hasp services.
Here are two of them:
; Service #1
:0049ED00 E87B080000 call 0049F580 ; Is_It_A_Hasp_Dongle ?
:0049ED05 8B442408 mov eax, dword ptr [esp+08]
:0049ED09 8D4C2410 lea ecx, dword ptr [esp+10]
:0049ED0D 48 dec eax
:0049ED0E 8D54240C lea edx, dword ptr [esp+0C]
:0049ED12 83F801 cmp eax, 00000001
:0049ED15 8D442414 lea eax, dword ptr [esp+14]
:0049ED19 1BFF sbb edi, edi
:0049ED1B 50 push eax
:0049ED1C 8D44240C lea eax, dword ptr [esp+0C]
:0049ED20 51 push ecx
:0049ED21 52 push edx
:0049ED22 8BCE mov ecx, esi
:0049ED24 F7DF neg edi
:0049ED26 50 push eax
:0049ED27 6868200000 push 00002068
:0049ED2C 6A02 push 00000002 ; Service # 2
:0049ED2E E84D080000 call 0049F580 ; Get_Hasp_Code
:0049ED33 817C2408A5F70000 cmp dword ptr [esp+08], 0000F7A5;Is RetCode1 OK ?
:0049ED3B 7529 jne 0049ED66 ; Bad_Guy jump
:0049ED3D 817C240C8E420000 cmp dword ptr [esp+0C], 0000428E;Is RetCode2 OK ?
:0049ED45 751F jne 0049ED66 ; Bad_Guy jump
:0049ED47 817C2410E54F0000 cmp dword ptr [esp+10], 00004FE5;Is RetCode3 OK ?
:0049ED4F 7515 jne 0049ED66 ; Bad_guy jump
:0049ED51 817C24144E470000 cmp dword ptr [esp+14], 0000474E;Is RetCode4 OK ?
:0049ED59 750B jne 0049ED66 ; Bad_Guy jump
:0049ED5B 83E701 and edi, 00000001
:0049ED5E 8BC7 mov eax, edi ; Set Good_Guy flag (eax=0x01)
:0049ED60 5F pop edi
:0049ED61 5E pop esi
:0049ED62 83C410 add esp, 00000010
:0049ED65 C3 ret
* Referenced by a (C)onditional:0049ED3B(C), :0049ED45(C), :0049ED4F(C),
:0049ED66 33FF xor edi, edi
:0049ED68 8BC7 mov eax, edi ; Bad_Guy (clear eax)
:0049ED6A 5F pop edi
:0049ED6B 5E pop esi
:0049ED6C 83C410 add esp, 00000010
:0049ED6F C3 ret
Let's crack it:
:0049ED66 66B80100 mov ax,00001
Now if you run the program, it will ask you for your name and company
name to type in. Then, it will take about 12 seconds on a P233 before WellCAD
main window appears on your screen. Let's solve this problem.
As there a too many checks and comparisons occuring even before the calls to the dongle, with SoftICE, BPX the main Hasp routine (:44D528) and try to find some interesting cross references that we'll lead us to the fatal(s) jnz_Bad_Guy.
Without any problem, we find several of them but only 2 seem very interesting:
:004C01E7 E8684A0200 MFC40.MFC40:NoName0713
:004C01EC 8D8BC8000000 lea ecx, dword ptr [ebx+000000C8]
:004C01F2 E829E6FDFF call 0049E820 ; Verify_Dongle (+ Misc routines)
:004C01F7 85C0 test eax, eax ; Is_Dongle_OK ?
:004C01F9 0F8455FDFFFF je 004BFF54 ; Bad_Guy jump
:004C01FF 68C8030000 push 000003C8 ; Good_Guy go ahead
:004C025F E8E4490200 MFC40.MFC40:NoName0711
:004C0264 8D8BC8000000 lea ecx, dword ptr [ebx+000000C8]
:004C026A E881F0FDFF call 0049F2F0 ; Verify_Dongle (+ Misc routines)
:004C026F 85C0 test eax, eax ; Is_Dongle_OK ?
:004C0271 0F84DDFCFFFF je 004BFF54 ; Bad_Guy jump
:004C0277 8D4DC8 lea ecx, dword ptr [ebp-38] ; Good_Guy go ahead
Just get rid of the two Verify_Dongle calls and replace them with mov eax,1.
This will considerabely speed up the program (just 1 little second
to start) and the crack is done.
OK, it seems very easy to crack but it takes longer that you may think. The protection is not too bad: a lot of calls to sub-routines that will call other sub-routines etc.. and then comparisons in one of them with the conditional jump in another one... It may fool or confuse you during a Live approach, but could not resist a good Dead listing.