Undocumented HASP Part II
"xDEAD:xBEEF: extending HASP manufacturer's services"
advanced
Advanced
12 March 1998
by bajunny
Courtesy of Fravia's page of reverse engineering
slightly edited
by fravia+
fra_00F3
980312
bajunni
0010
AD
P3
Another great contribution by bajunny. Hasp misteries and vagaries are tackled and resolved. A must reading for all dongle interested serious researchers! This is definitely not for beginners, either you know how to send and check bytes from your PC ports, or you don't (and you better know it :-) If you are a beginner, leave this stuff for a while and delve inside +HCU's project 3until you have at least a rough global knowledge of dongle reversing.
project3
Dongle
There is a crack, a crack in everything That's how the light gets in
Rating
( )Beginner ( )Intermediate (x)Advanced ( )Expert

Second and most probably the final part of MemoHASP reversing saga.
Undocumented HASP - Part II
"xDEAD:xBEEF: extending HASP manufacturer's services"
Written by bajunny


Introduction

Second part of the text deals primarily with accessing HASP memory. Some aspects of software protection are also included (not very organised, though).

Tools required
Brains (obligatory). C compliler (quite optional). JavaScript manual (to land the teapot on).

Program History
See Part I for the first part of the text.

Essay

                              Open mind for a different view

                              And nothing else matter..

          

                                      an old song by Metallica

--------------------------------------------------------------



                    Undocumented HASP - Part II

                              by -bajunny





    4. Memo-  ..stands for memory!

    ------------------------------



  The HASP documentation says that MemoHASP-I has a total incredible 

amount of 112 bytes of memory ready for programmer use, while all happy 

buyers of NetHASP and MemoHASP-IV (which are essentially the same thing 

I believe) can take even more - 496 bytes. 

One can immediately realize, that in both cases HASP had reserved 16 bytes for 

its own use,  because 112 +16 == 128 and 496 +16 == 512 and memory 

manufacturers enjoy power_of_2_numbers. This fact was further

acknowledged by the following fragments of disassembled HASP

driver code:



; API_service#6



. . . 

mov word ptr ds:[bp + 0ea], fff9; 

call 6496

. . .

mov word ptr ds:[bp + 0ea], fff8; 

call 6496

. . .

mov ax, ds:[bp + si + 0d3]       ; HASP memory access commands

. . .

add ax, word ptr ds:[bp + 0ea]   ; reasons for ADD will follow

add ax, 8                        ; !

. . .



  So real addressing for user-accessible memory begins from 

offset 8, while in offsets 0 and 1 resides the "unique HASP ID". 

In fact, the following 6 words are never user by any HASP

software (I didn't look for Net- and Time- devices, though)

so you will be able to place something even more _unique_ here.. 

But you need more details on HASP memory access indeed 

before...



  As we already have seen in the first part of this essay, HASP 

wouldn't give anything useful without proper activation. 

 Memory access is no exception, and this is the sad news. 

The good news is that we actually have already acquired all

necessary items for this activation. I mean the opening combination

that we have found in the first part of this text. But we should stop at

the correct moment: in fact we need to know that after the 15th 

outbyte() is issued, one of  HASP's internal flip-flops 

switches output to query its booleans..

The moment after 14th outbyte() is right. It's amazing, but if

you will try to retrieve Boolean at that moment HASP returns 

only zeros to you - it definitely indicates some change in HASP 

internal state! Change for some memory work! 



  Technically speaking, all memory ops are issued through 

appropriate commands. These commands along with their arguments

and subsequent results are passed to HASP serially - that is

bit by bit by signalling specific bits just like bit0 was

signalled in the outbyte function, forcing HASP to parse its input

as command bytes. 14th byte of opening sequence was used as a 

background for this. - This is the reason why this byte was set

to certain value (x9C) irrelevant of  all other password related 

fiddlings.



  Command length is 10 bit. HASP driver provides the 7 following

values as command ops (all presented as bit strings, x's stand

for address values):

0110xxxxxx - read word from address specified

0101xxxxxx - write word to  -------//--------

0111xxxxxx - erase word at  -------//--------

0100110000 - enable write ops

0100000000 - disable write ops

0100100000 - ? unknown, apparently no effect on Memo-'s

0100000000 - ? the same.. 



So, to read word from address 9, one should send the following

10 bits to MemoHASP: 0110001001. Sending are performed by

signalling bit6, along with bit5 alterations (see my code at 

appendix). Do not forget to begin and end all memory operations by 

signalling bit1.. Resulting word is received also in a serial

manner, see below the code inside hasp_read_word()..



If you happen to torture MemoHASP-IV, just expend these 

command strings by two more bits, allowing full 256 words

address space (and of course call hasp_send_cmd( ..., 12 )!:)



Writing is analogous, but first one must enable write using a 

special command. HASP driver also issues obligatory erase 

before each write, but it's not really necessary: write 

successfully sets both 1s and 0s. One feature for erasure 

and writing: HASP driver has a specific code that waits for 

state change after each of those two operations, I put something 

analogous to wait_till_burned() routine below, though no actual 

wait was ever detected during my own experiments...



If you dare to use my routines to read/write some HASP memory, 

you won't see any expected values, because once again HASP

designers used  some silly obfuscating schemes to conceal 

their data. 

So you need first of all a password number to correctly decipher it. 

I already warned you there could be some ambiguities in password

detection, well, here is the place where they can be encountered.



But in fact this obfuscation CAN HELP to get the right 

password: many areas inside HASP memory holds initial

xFFFF's (you see, erasure sets bits this way) - and this

is especially true for all hidden words at 2..7! They are set

to xFFFF.





Obfuscation algorithm is presented inside the code fragments in 

appendix, it uses simple XOR of 1st word of the password, 

address of word and constant of xFF00 for addresses 0..7 

(well, actually xFFF8..xFFFF inside the HASP driver). 



I played a little with command opcodes, hoping to fish something

interesting, but without success. Maybe you will be more

successful... if so write about it.





    5. HASP ID story.

    -----------------



  The extremely vague HASP documentation warns you that: 

"You cannot order HASP keys with specific ID Numbers. These are 

assigned pseudo-randomly during manufacturing and are 

guaranteed not to repeat".. So if your HASP has some ugly ID

like xA60D:x12F7 you have to live with it?? 

No, no,no! 

Bajunny CAN help you to change it to something "prominent" 

like xDEAD:xBEEF or x1234:x5678 (as in all my HASPs) or 

whatever you like... extending thus the manufacturer's services, 

power of good cracking ;)



  Of course everything is already prepared: HASP ID lives at

the very beginning of memory, words at _0 and _1, this area

is accessible and is not write protected.. You already have all

necessary information to carne your own HASP ID. Nothing much 

to be added to the ID story except to mention that ID is 

checked sometimes by the envelope routines.. But for other crucial 

HASP parts: password and booleans I have no way to modify by 

means of software (but who knows.. what if... we will see ;) 

my wish to invent some mechanism to make one HASP start mocking 

another failed... So end of the story... for now ;)



    6. Conclusion (again too long).

    -------------------------------  

  When writing these words I have to admit to you I finally

got awfully bored of all this HASP super protection. Well, once

more we have to observe the old banal truth, so common in our 

cryptography intense world: security through obscurity is worse than 

no security at all. So what we have in these "ultrastrong" HASP

dongles? What's inside them? Almost nothing interesting. 

In fact, today already exist more decent dongles, documentally presenting 

strong algorithms inside (or I'm still dreaming, are they as easy to 

reverse?) having at least PIC-complexity rather than a simple set 

of flip-flops and memory cells.. 



Well, the HASP people can and will surely argue that they have 

at least implemented a strong software protection. 

It's complete bullshit - all info I have given to you in my essay 

has been gathered by myself through disassembling and experimenting 

with software. No ion-beams or layer etching intervention. 

Nothing in my hands! 

And I didn't encounter _any_ cool anti-debugging tricks! Well, some 

folks say they implemented anti-softicing like disabling 

breakpoints and firing something like "hboot" to your debugger's 

command line.. I don't know.. In fact, I've used winice only to 

get rid of HASP for the InscriberVMP program... and it was my first 

experience with windoze debugging.. Yeah, I use windoze only 

to format something to print on laser or to browse those great pages 

of fravia+ :) - all other experimenting still in good old doze.. 

Where else can one find such a well documented, inexpensive, 

_true_ real-time OS ? :))



  Maybe in the future I will present a  more comprehensive survey of

HASP software protection. All this enveloping stuff, and the like. 

Right now I'm not sure it will ever materialise. Not because

its difficult, but because its very boring, and I've almost spent my

strategic supply of Homeric laughters looking at something like:

"FAS - Full Authorization System" 



This seller's hypo stands for some feature in enveloping: you can assign 

a number to a program and specify a maximum number of activations. 



Sounds good? In fact, this FAS system eats half of your MemoHASP cell 

space - 2 words for each 16 possible program numbers, first word to 

check if corresponding  slot was occupied (xFFFF if not, any other value 

if yes, HASP... puts x0000) while the second word keeps the counter (xFFFF if 

unlimited activations..). Of course you can edit everything with my 

functions below or even using HASPEDIT. 



Well, what should I say? I sip a good cup of tea, observing this moronical 

hype once again and have decided to give up, my dear reader... it's too easy 

and too stupid... 

Even fighting windmills is better than fighting stupidity..



    APPENDIX

    --------

  Here are some fragments to be added to my little cracking

program  from the first part of this work of mine
// --------------------------------------------------- int hasp_answer(void) { return (inportb(PORT +1) & 0x20) ? 1 : 0; } int sticky = 0x9c; // hardcoded, HASP software always sets this value.. void memo_open(void) { int i; outportb( PORT +2, 0x0c); outbyte( 0xc6); for( i=0;i<14;i++) outbyte( tmp[i]); //sticky = tmp[13]; } void memo_close(void) { outbyte( 0xc6); } void tease_bit( int t, int b) { int teaser = 1<<b; if(t) sticky |= teaser; else sticky &= ~teaser; outportb( PORT, sticky); } void hasp_send_word( unsigned cmd, int len) { for( ; len; len--) { tease_bit( cmd & (1<<(len-1)), 6); tease_bit( 1, 5); tease_bit( 0, 5); } } unsigned hasp_read_word( void) { int i; unsigned res = 0; tease_bit(1,5); // a necessary "phase shift".. tease_bit(0,5); for( i=16; i>0; i--) { res |= hasp_answer() <I-1); tease_bit(1,5); tease_bit(0,5); } return res; } int wait_till_burned(void) { time_t t; t = time(0); tease_bit( 1, 1); for( ; time(0)-t<5;) { if(hasp_answer()) { tease_bit( 0, 1); return 0; } } return -1; } . . . void main() { int addr; unsigned short passwd1=0x347f, passwd2=0x13b3; // known from previous invocation of cracker.. . . . // read _all_ HASP memory memo_open(); for( i=0; i<0x40; i++) { tease_bit( 1, 1); hasp_send_word( 0x180 +i, 10); k = hasp_read_word(); tease_bit( 0, 1); printf("%04x ", k ^ passwd1 ^ (i-8) ^ ( i<8 ? 0xff00: 0) ); // obfuscator: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ if(0==(i+1)%8) printf("\n"); } memo_close(); . . . // read/erase/write _one_ word addr = 0x3f; memo_open(); tease_bit( 1, 1); hasp_send_word( 0x180 +addr, 10); k = hasp_read_word(); tease_bit( 0, 1); printf("original read: %04x\n", k); tease_bit( 1, 1); hasp_send_word( 0x130, 10); tease_bit( 0, 1); // erasure.. tease_bit( 1, 1); hasp_send_word( 0x1c0 +addr, 10); tease_bit( 0, 1); wait_till_burned(); tease_bit( 1, 1); hasp_send_word( 0x180 +addr, 10); k = hasp_read_word(); tease_bit( 0, 1); printf("after erasure read: %04x\n", k); // burn smth in.. tease_bit( 1, 1); hasp_send_word( 0x140 +addr, 10); hasp_send_word( 0x55aa, 16); tease_bit( 0, 1); wait_till_burned(); tease_bit( 1, 1); hasp_send_word( 0x180 +addr, 10); k = hasp_read_word(); tease_bit( 0, 1); tease_bit( 1, 1); hasp_send_word( 0x100, 10); tease_bit( 0, 1); memo_close(); printf("final read: %04x\n", k); } // ------------- end of transmission -----------------

Final Notes

The author encourages you always to look one level deeper,

of course if the time and patience would permit it... if you do, by all means, 

write and document and publicize your findings...



Ob Duh
I wont even bother explaining you that you should BUY any of your target programs if you intend to use them for a longer period than the allowed one or on a greater number of machines than the allowed one. Should you want to STEAL those buggy software instead, you don't need to crack its protection scheme at all: you'll certainly find it on most Warez sites, complete and already regged or undongled, farewell.

You are deep inside fravia's page of reverse engineering, choose your way out:

redhomepage redlinks redsearch_forms red+ORC redstudents' essays redacademy database
redreality cracking redhow to search redjavascript wars
redtools redanonymity academy redcocktails redantismut CGI-scripts redmail_fravia+
redIs reverse engineering legal?