Target :- Trace.exe (included with Cimagrafi v5.07+).
The HASP DLL Cracking Technique
If you are at all au fait with HASP you will know that the protection takes 2 forms, the API through which hasp() services are actioned and Aladdin's fully blown PE encryptor known as the envelope which relies on response codes from the dongle to do the decryption. I chose Trace.exe for 2 reasons, firstly its an enveloped target as good as any other, and secondly we are here to learn about reverse engineering as opposed to stealing Cimagrafi (a rather good design program imho which is sadly protected by a HASP). HASP's envelope checks for the presence of SoftICE using a very familiar trick, CreateFileA for the video driver //./SIWVID, however before we start delving into vast amounts of code I recommend that you PEDump the target just to look at what your up against.
Note the _TEXT_HA which is the HASP API section, we'll see this later, and .protect the actual envelope, sometimes these sections have their names changed (e.g. .protectzz) yet the Win32 envelope always equates to something around 160k. As you might expect the envelope is heavily encrypted (disassembling will give you about 300h of the initial round of decryption which works on the principal of sliding an XOR key through many small rounds of code and then calling the newly decrypted routines, as you might imagine, studying this is not for the faint hearted.
The decryption is pretty messy and there is nothing to be really gained in studying it, in fact tracing it too low in SoftICE will result in a horrid crash (I think this is SEH related). What the envelope subsequently does is call its own decrypted hasp() routine to check for a specific dongle before using the response codes to decrypt and hand control to the original program. The first step is to kill the anti-SoftICE trick I described above, after which you should bpx for FreeEnvironmentStringsA which is called in most 32-bit HASP protections immediately after the CALL to the main hasp() routine. Here's how it looks :-
:00546AC5 CALL [EBP+00] <-- This is hasp() for real.
:00546AC8 PUSHAD <-- Save all registers.
:00546AC9 LEA ESI,[0054A395]
:00546ACF PUSH DWORD PTR [ESI]
:00546AD1 LEA ESI,[KERNEL32!FreeEnvironmentStringsA]
:00546AD7 CALL [ESI]
:00546AD9 POPAD <-- Restore registers (you break here).
:005449C4 PUSH EBP <-- Now set a bpx here.
:005449C5 CALL 0054691F <-- Highest level hasp().
:005449CA POP EBP
When you return the hasp() envelope routine has just been executed for its first time, its always IsHasp(), so set EAX=1 and bpx for the next service. Sure enough the next service is 2 (in BH), ECX holds vendor password 1, EDX vendor password 2 & EAX the seed code. In this case we have EAX=512D, ECX=2459 & EDX=2CF3, after the call to hasp() again EAX through EDX = 0, they should actually be filled with the required response codes for the given seed. In all Win32 envelopes I've seen its been possible to recover these responses by simple tracing (not that we actually need to).
Using the HaspCode algorithm we can find the desired responses, so patch in EB0E, 6D3B, 19FA & BF33, now F5 and you'll get the check repeated, patch in the responses once again. The 3rd check decrements the seed code 1 so you need to patch in 904C, 5CD5, DAEE & 30BE (returns for seed 512C, these responses can't be recovered without knowing the HaspCode() algorithm). It is these values that will be used for the decryption after the hash function of course :-). I recommend you now disable all the breakpoints and bpx for VirtualAlloc, in different versions of the envelope WriteProcess Memory is also extensively used. After this breaks, place the data window at the RVA of the first section (its usually 401000) and watch slowly, there are probably only 2 quick techniques for finding the original entry point.
One of the best ways is to use combinations of bpx's on VirtualAlloc/WriteProcessMemory & GetProcAddress, then try and trace intuitively, another way (perhaps easier), do map32 and get the address range of the first section, then set a bpr for the entire section range, you'll either break here during some fixups or at the OEP :-). In the case of Trace.exe 2 breaks on VirtualAlloc and the bpr I describe above will find you the O.E.P (RVA 0xAF790), as soon as you reach here, dump all the sections, maybe you can even use ProcDump Bhrama or IceDump or TRW to make a valid PE :-).
Here are the details if you choose to do this by hand :-
Section RVA Size Raw Location Size in bytes ---------------------------------------------------------- .text x401000 xAE9E4 x1000 715,236 .data x4B0000 x112AC xAEE00 70,316 .reloc x4CA000 xB6FC xC2A00 46,844
You can now paste these decrypted dumps over the original bytes, but go very careful when translating the RVA into a raw offset in the actual file (I've done this part for you), note also that .rsrc is not encrypted in this example by the HASP envelope. If you are doing this part with UltraEdit, I advise you take it very slowly to avoid errors, also note that you can kill the .protect section completely as we'll no longer need it.
This will be the important stage before we can run our rebuilt file. At offset 0x128 we need to update our entry point (0xAF790 as identified earlier). Next we need to fix our import RVA and size (round the size up to the file alignment), this again is easy to find (set a breakpoint for GetProcAddress and then a bpr for anywhere in the .idata section), here's the code :-
:bpr 004c5000 004c5000+250c rw
Break due to BPR #0167:004C5000 #0167:004C750C RW
:0053C800 MOV EAX,[EBP-0C] <-- VA of import table (4C5000).
:0053C803 CMP DWORD PTR [EAX+0C],00
:0053C807 JZ 0053C860
Finally fix the BASRELOC & Size entries in the data directory, 0xCA000 (RVA of .reloc) & B800 (size) in this case. Did I also mention that you should delete the .protect section from the PE header and update the number of sections. Now of course you must crack Cimagrafi's HASP protection in the usual manner :-).
I should point out that I'm not the pioneer of this technique and it only really has advantages if you have many files protected by HASP and want to bpx just a single location to examine all of the checks, its also a technique that can be used using just finger movements inside your HEX editor. I've given you a hasp.dll (actually this is a dll HASP provide to developers that has been edited somewhat for our purposes). Please beware that this dll won't always work and when it doesn't your system is likely to be trashed ..... it certainly doesn't work 'as is' with Cimagrafi, the stack needs to be corrected). I won't explain any further how this works (I tested only with MAYA Fusion v2.51b), HASP watchers will figure the rest on their own :-
1. Locate the HASP trademark 'cmp bh, 32' inside your target.
2. Trace below the next CALL. Change the PUSHAD 4 lines into the CALL (i.e. the 2nd instance) into a NOP and note the address ESI is pointing too (2 lines above).
3. Change the CALL to GetModuleHandleA (about 10 lines below) to LoadLibraryA.
4. Locate the next CALL following what was GetModuleHandleA and trace below. The first CALL to GetProcAddress should save EAX to the location of ESI you noted in part 2. The line immediately afterwards should be changed to point ESI at this address.
5. Locate the string 'KERNEL32.DLL' and change to the name of our new dll, be sure to change only the HASP reference (look for HASP names like HASPUT16.DLL nearby).
6. Load your program, bpx for the 'cmp bh, 32' reference, trace and figure, edit the dll to your needs.