Log in

View Full Version : Hardlock Alladin without dongle


Kova78
June 30th, 2011, 05:54
Hi
I'm studying an "old" program that use an Alladin Hardlock Protection (09-Feb-1997*V3.65 version).
I read some tute on the net (specially the tute "What's behind the Hardl*ck by MaV3Ri*k" but I haven't reversing this application yet.
These are the things that I know:
- The modad is 0x773
- I know the HL_LOGIN (00402ED7) and HL_READBL (00402F63) function call (thanks to root).
- After the HL_LOGIN I forced the eax = 0 and the dongle was recognized like connected but nothing happen.
- I used some emulator like multikey 10.8 with an example hardlock .reg file (I changed only the modad with mine) and the program doesn't show me any error message (like "Hardlock not present" ecc.) but it terminates.

Have I some hopes to reverse this application?

This is the program if you want to look inside

http://ifile.it/9meojna
password: zanzaremaledettefatemidormire



Thanks, bye all

sapu
July 4th, 2011, 11:20
Quote:
[Originally Posted by Kova78;90582]- I used some emulator like multikey 10.8 with an example hardlock .reg file (I changed only the modad with mine) and the program doesn't show me any error message (like "Hardlock not present" ecc.) but it terminates.

The program code is encrypted, and without the correct Seed1/2/3 values, there is no way it can work.

Anyway, Seed values can be recovered in a few hours by brute-forcing the ID_Ref[8] / ID_Verify[8] values from Hardlock Login request (ID_Verify[] = encrypted ID_Ref[]) .

In your case, if i am not wrong, the correct Seed1/2/3 values should be: c68e, b389, 4e87.

This should allow you to bypass the encrypted .exe wrapper, but do not espect the program to run: you still need to figure out what the hardlock memory contains (and this cannot be guessed without the dongle).

FoxB
July 5th, 2011, 09:11
memory context for 0x773 also ciphered...

@sapu: all seed's is wrong...

sapu
July 6th, 2011, 01:17
Quote:
[Originally Posted by FoxB;90605]memory context for 0x773 also ciphered...

@sapu: all seed's is wrong...


You are right, i was too fast into my conclusion.

Recovering seeds from login request return multiple results, and i just assumed the first one that caused the program to display a different message was the right one... but since seeds are used to decrypt memory content (that i left all zero on my test), there is no way this can work.

Just for reference, i'll post here the code i wrote to recover the seeds... i guess it should not hurt, since there are lots of better and faster tools available now (althought they require a dump to work).

Kova78
July 6th, 2011, 09:24
Thank you guys for the help.
I don't understand very well the utility of these seeds without the memory content
Now I'm working to bypass the checks between the bytes read from the key (in my case all 00s) and the right constants that the program should read.
I received an help from an user of another forum and he told me that it's possible to bypass some check and run the program fully without to rebuild the content of the dongle.

Are 2 days that I'm working to do this

Thanks!
Bye

sapu
July 6th, 2011, 12:14
Quote:
[Originally Posted by Kova78;90609]Thank you guys for the help.
I don't understand very well the utility of these seeds without the memory content
Now I'm working to bypass the checks between the bytes read from the key (in my case all 00s) and the right constants that the program should read.
I received an help from an user of another forum and he told me that it's possible to bypass some check and run the program fully without to rebuild the content of the dongle.

Are 2 days that I'm working to do this

Thanks!
Bye


Since you don't have the dongle memory content, the seeds are completely useless (except for login verification), sorry.

Anyway, for your purpose i'll suggest you to bypass all the functions that are used to decrypt the memory, understand what the program is espected to find on memory data, and set in your dump the dongle memory as espected.

The relevant hardlock api calls that you need to know are:
00554A02 = HL_LOGIN (login to hardlock)
00554CE9 = HL_READBL (read hardlock memory, 128 bytes)
00554994 = HL_CODE (decrypt a block of memory, 8 bytes)
0055457B = HL_LOGOUT (logout from hardlock)

Kova78
July 7th, 2011, 08:09
Quote:
[Originally Posted by sapu;90611]Since you don't have the dongle memory content, the seeds are completely useless (except for login verification), sorry.

Anyway, for your purpose i'll suggest you to bypass all the functions that are used to decrypt the memory, understand what the program is espected to find on memory data, and set in your dump the dongle memory as espected.

The relevant hardlock api calls that you need to know are:
00554A02 = HL_LOGIN (login to hardlock)
00554CE9 = HL_READBL (read hardlock memory, 128 bytes)
00554994 = HL_CODE (decrypt a block of memory, 8 bytes)
0055457B = HL_LOGOUT (logout from hardlock)


Thanks sapu for the help.
Are 3 days, my eyes are in flame but there aren't big results

I studied the Hardlock Api Guide (downloaded from this site) and thanks to you I reversed step by step each function (HL_LOGIN ecc.) included the HL_AVAIL that I suppose is at 00402F4E address.

I don't have any hardlock drivers installed (and also I removed the multikey32 tool) but I noticed a strange thing:
When I put a breakpoint at 00554A02 (HL_LOGIN) and one at the next instruction 00402EDC and olly breaks here the value in EAX is 13 and ECX is 7.
Well, when I put a write memory bp at the byte that contains the "API Status Value" and olly breaks at 0055878F address, in the 00402EDC breakpoint the value in EAX is 00690000 (so AX = 0) and ECX is 1
(EAX should contain the Api status value)

What's up?!?!?!?
I didn't modify anything !!!

After 30 hours of work I'm not able to understand what the program expect from the memory dump.
Boh!!

Thanks sapu, have a nice day!
Bye.

P.S.
Another question: "How I can identify all the hardlock api calls?"

Kova78
July 13th, 2011, 05:46
Hi all,
after many hours of study I'm beginning to understand something about the protection (but the solution is so far).
First of all an user has sent to me a screen with the program fully executed and then I believe that the dongle is simply bypassable but I'm a newbie so I have to understand how

I begin to explain (I hope clearly) what the application does.
From the hardlock api guide and some C examples, the code begin with:

Code:
result = HL_LOGIN (29809,DONT_CARE,"HARDLOCK","@0=/&#s3";
IF (result == STATUS_OK)
IF (HL_AVAIL() == STATUS_OK)
eeprom = SPACE(128);
HL_READBL (eeprom);
ENDIF;
result = HL_LOGOUT();
ENDIF;


The API Status Values returned are:
STATUS_OK --> 0, NOT_INIT --> 1, ecc.

So after the HL_LOGIN and HL_AVAIL functions the returned value should be 0 and after it will be possible to execute the HL_READBL function.

(N.B. I have installed the Hardl*ck driver (file hl*rv32.zip downloaded from the official ftp).

In olly I will have:
Code:
00402ED7 CALL 00554A02 ; HL_LOGIN
00402EDC MOVZX EDI,AX ; EAX returned to me is 0x13 (19 dec) that isn't an API STATUS documented in the pdf


So I forced the EAX value to 0 (STATUS_OK)
And I stepped over until:

Code:
00402EDC MOVZX EDI,AX
00402EDF ADD ESP,10
00402EE2 CMP DI,BX
00402EE5 JE SHORT 00402EF6; IF EAX=0 jump the HL_LOGOUT
00402EE7 HL_LOGOUT


With EAX=0 the LOGOUT and Error msgbox (00402F38) will be bypassed.
After, there is the HL_AVAIL() function that I believe is here:
Code:
00402F4E CALL 00525590; HL_AVAIL()

Stepped over this call the status is 0 (EAX=0 STATUS_OK), so I stepped until the HL_READBL function (to "read" the dongle context):

Code:
00402F63 CALL 00426440 ; Call to HL_READBL


Inside the call:

Code:
00426440 MOV EAX,DWORD PTR SS:[ESP+4]
00426444 PUSH EAX
00426445 CALL 00554CE9; HL_READBL

In this piece of code the pointer is loaded and passed to the HL_READBL function.

If some breakpointers are set inside this function, error messages will be returned because there are calls to GetTickCount() function.

The only interesting part in this function is the pointer value to the memory structure (in my case is 00699D90 and inside the structure there is the ASCII DA*AKUST value).

Stepping with F8 I arrive at the HL_CODE function (that crypt/decrypt a block).

From the manual, the prototype is:
HL_CODE(DATAPTR, BCNT)
DATAPTR-->pointer
BCNT-->number of blocks to crypt/decrypt
Then:
Code:
result = HL_LOGIN (29809,DONT_CARE,"HARDLOCK","@0=/&#s3";
IF (result == STATUS_OK)
text = "Hello Hardlock !";
IF (HL_CODE(text, 2) == STATUS_OK))
PRINT "The encrypted data is: " + text;
ENDIF;
result = HL_LOGOUT();
ENDIF;


In olly:
Code:
00402F7D CALL 00426460; Call to HL_CODE
00402F82 ADD ESP,8


Entrando nella CALL:
Code:
00426460 PUSH EBP
00426461 MOV EBP,DWORD PTR SS:[ESP+8]
00426465 PUSH ESI
00426466 PUSH EDI
00426467 XOR EDI,EDI
00426469 LEA ESP,[LOCAL.2]
00426470 LEA EAX,[EBP+EDI]; Here begin the loop to read the structure
00426473 PUSH 1 ; Arg2 = 1
00426475 PUSH EAX ; Arg1 --> In my case is 0012FDB0 and the memory area is large 128 byte
00426476 CALL 00554994; HL_CODE
0042647B ADD ESP,8
0042647E MOV SI,AX
00426481 NEG SI
00426484 SBB ESI,ESI
00426486 ADD EDI,8
00426489 ADD ESI,1
0042648C CMP EDI,80
00426492 JB SHORT 00426470; Read loop


Step with F7 the HL_CODE call
Code:
00554994 PUSH EBP
00554995 MOV EBP,ESP
00554997 PUSH EBX
00554998 PUSH ESI
00554999 PUSH EDI
0055499A CMP DWORD PTR DS:[699E90],0; Verify that there is the 00699D90 value, otherwise set it
005549A1 JNE 005549B1
005549A7 MOV DWORD PTR DS:[699E90],OFFSET 00699D90
005549B1 MOV EAX,DWORD PTR SS:[ARG.1]; Move in EAX the 0012FDB0 pointer
005549B4 MOV ECX,DWORD PTR DS:[699E90]; Move in ECX the 00699D90 pointer
005549BA MOV DWORD PTR DS:[ECX+12],EAX
005549BD MOV AX,WORD PTR SS:[ARG.2]; AX = 1 and then EAX will be 00120001
005549C1 MOV ECX,DWORD PTR DS:[699E90]; ECX = 00699D90 (Not changed)
005549C7 MOV WORD PTR DS:[ECX+16],AX; ECX+16 = 1
005549CB MOV EAX,DWORD PTR DS:[699E90]; EAX = 00699D90
005549D0 MOV WORD PTR DS:[EAX+18],0B; EAX+18 = 0B
005549D6 MOV EAX,DWORD PTR DS:[699E90]; EAX = 00699D90 (Not changed)


In these instructions I believe that there is the call to the crypt/decrypt of a block function:
Code:
005549DB PUSH EAX; Arg1 = cna*2.699D90
005549DC CALL 00554520; Crypt/Decrypt
005549E1 ADD ESP,4
005549E4 MOV EAX,DWORD PTR DS:[699E90]; EAX = 00699D90
005549E9 MOV WORD PTR DS:[EAX+16],0
005549EF MOV EAX,DWORD PTR DS:[699E90]; EAX = 00699D90
005549F4 MOV AX,WORD PTR DS:[EAX+1A]; AX = 1 so EAX = 00690001
005549F8 JMP 005549FD; Jump to the next instruction
005549FD POP EDI
005549FE POP ESI
005549FF POP EBX
00554A00 LEAVE
00554A01 RETN; Read the next block


Inside the CALL

Code:
00554520 PUSH EBP; Crypt/Decrypt?!?!
00554521 MOV EBP,ESP; EBP = 0012FD04
00554523 SUB ESP,4; ESP = 0012FD00 --> ASCII 2EU
00554526 PUSH EBX; ESP = 0012FCFC --> 0
00554527 PUSH ESI; ESP = 0012FCF8 ---> 00701660
00554528 PUSH EDI; ESP = 0012FCF4 ---> 0
00554529 MOV EAX,DWORD PTR SS:[ARG.1]; EAX=00699D90 (Not changed)
0055452C PUSH EAX; ESP = 0012FCF0 ---> 00699D90
0055452D CALL 005586F5; I believe that in this call is verified if the crypt/decrypt procedure is well executed
00554532 ADD ESP,4;
00554535 MOV WORD PTR SS:[LOCAL.1],AX; Move 1 in 0012FD00
00554539 MOV AX,WORD PTR SS:[LOCAL.1]; Not changed
0055453D JMP 00554542; Jump to the next instruction
00554542 POP EDI; 0012FCF4=0
00554543 POP ESI; 0012FCF8=00701660
00554544 POP EBX; 0012FCF8=0
00554545 LEAVE; Release the stack
00554546 RETN


Inside the CALL 0055452D:
Code:
005586F5 PUSH EBP; ESP = 0012FCE8 --> 0012FD04
005586F6 MOV EBP,ESP
005586F8 PUSH EBX; ESP = 0012FCE4 --> 0
005586F9 MOV EBX,DWORD PTR SS:[ARG.1]; EBX = 00699D90
005586FC CALL 00558020; Interesting call, here are executed 3 CMPs
00558701 POP EBX; EBX = 0
00558702 POP EBP; EBP = 0012FD04
00558703 RETN


Inside the CALL 00558020 there are 3 interesting CMPs:

Code:
00558020 CMP WORD PTR DS:[EBX+6],0; DS:[EBX+6] = 2
00558025 JNE SHORT 0055803E; Not jump
00558027 CMP WORD PTR DS:[EBX+18],0B; DS:[EBX+18] = 0B
0055802C JNE SHORT 0055803E; Not jump
0055802E CMP WORD PTR DS:[EBX+16],0; DS:[EBX+16] = 1
00558033 JNE SHORT 00558040; Jump! Here, IMHO, set AX=1 when the Crypt/Dectrypt function fails
00558035 MOV AX,0
00558039 MOV WORD PTR DS:[EBX+1A],AX; [EBX+1A] = 1
0055803D RETN
0055803E JMP SHORT 00558086
00558040 CMP BYTE PTR DS:[EBX+0FE],0; [EBX+0FE] = 0
00558047 JNE SHORT 0055804F; Non salta
00558049 MOV AX,1; Imposta AX =1
0055804D JMP SHORT 00558039


At the return from the main HL_CODE function (00402F82) EAX is 0.

After this analysis I'm not able to understand when the program read the features and, in particular, what are these features!

Go ahead with the code, the HL_CODE is called for the 2nd time:

Code:
00403087 CALL 00426E40; Call to HL_CODE
0040308C CMP WORD PTR DS:[6A5E40],2; EAX = 00618F98


Step and I reach the call that run the program:

Code:
004030EF CALL 00404C20


Some info are loaded from an .ini file until this instruction:
Code:
00404E8B CALL EBP; \USER32.CreateWindowExA


And this messagebox appears:
Cannot find Ha*dlock(0).
Please check correct installation.


What I have to do?
Some advice?
I'm begin crazy because "I don't see the light" for a solution

Help guys
Thank you very much :wink:
Bye all