Hard Disk Sleeper v1.55
Tutorial by Lucifer48 [Immortal Descendants]
(23 july 1999)
Target Program: | Hard Disk Sleeper v1.55 |
Location: | http://www.mwso.com/ |
Protection: | Name/Serial |
Level: | Beginner (3/10) |
Getting a good serial isn't extremly difficult (the program is written in C (borland), the code is
clear), but it requires some calculations. As usual, we fill the Name & Serial boxes... When we
click on the OK button, there are only a comparison:
XXXX:00413A24 MOV EAX,[004205D0] ;checksum computed with the name and the serial
XXXX:00413A29 CMP EAX,[004205C0] ;comparison with the right value (19Eh)
XXXX:00413A2F JZ 00413A6C ;no jump = bad cracker!
The calculation of the dword in [004205D0] is done after each key pressed.
XXXX:004139DC CALL USER32!GetWindowTextA
XXXX:004139E1 CMP EAX,08 ;the serial must have 8 chars
...
XXXX:00413A08 CALL 00413C94 ;make 8 bytes
...
XXXX:00413A10 LEA EAX,[EBP-0C] ;our 8 precious bytes (C1, C2, ..., C8)
XXXX:00413A13 PUSH EAX
XXXX:00413A14 CALL 00413D13 ;calculation of the checksum (result eax)
XXXX:00413A19 POP ECX ;add esp,4
XXXX:00413A1A MOV [004205D0],EAX ;save to compare later
These 8 bytes (C1, C2, ..., C8) are computed with the name and the serial. This is (in a virtual
language, somewhere between C and Pascal) what the call 00413D13 does with these 8 bytes:
x={ C1, C2, C3, C4, C5, C6, C7, C8 }
checksum=0;
for i:=0 to 6 do
checksum:=checksum + ( (x[i]+i) mod $A ) * ( (x[i+1]+i+1) mod $A );
At the end of the loop, we must have: checksum=0x19E. How doing this ?
Brute force attack ?? Umm, not at all, 8 variables (from 0 to FF) it's too much. We will rather
uses the two mod instructions, indeed we can't exceed 9*9 (and at least 0*0) for one loop.
We will try to find in a first time 8 numbers between 0 to 9. I mean, we make a change of variable,
D1= (C1 + 0) mod 0xA, etc.. so the formula with the checksum will become:
y={ D1, D2, D3, D4, D5, D6, D7, D8 }
checksum=0;
for i:=0 to 6 do
checksum:=checksum + y[i] * y[i+1];
and more simply:
checksum = D1*D2 + D2*D3 + D3*D4 + D4*D5 + D5*D6 + D6*D7 + D7*D8
At this moment, the "brute force attack" will be easy (8 variables from 0 to 9, only
10^8 possibilities...).
This my source in C:
/*********************************************************/
#include
void main()
{
signed char x1, x2, x3, x4, x5, x6, x7, x8;
long a;
for(x1=0; x1<=9; x1++)
for(x2=0; x2<=9; x2++)
for(x3=0; x3<=9; x3++)
for(x4=0; x4<=9; x4++)
for(x5=0; x5<=9; x5++)
for(x6=0; x6<=9; x6++)
for(x7=0; x7<=9; x7++)
for(x8=0; x8<=9; x8++)
{
a=0;
a= x1*x2 + x2*x3 + x3*x4 + x4*x5 + x5*x6 + x6*x7 + x7*x8;
if (a==0x19E)
printf("%x %x %x %x %x %x %x %x\n",x1,x2,x3,x4,x5,x6,x7,x8);
} /* end of for */
}
/*********************************************************/
We find lots of solutions (2919 exactly) in few seconds. This is the last one:
a b c d e f g h
9 9 9 9 9 4 6 5
9 9 9 9 9 4 9 2
9 9 9 9 9 5 5 4
9 9 9 9 9 5 9 0
9 9 9 9 9 6 3 6
9 9 9 9 9 6 4 3
9 9 9 9 9 6 6 0
9 9 9 9 9 7 3 2
9 9 9 9 9 8 2 1
9 9 9 9 9 9 1 0
If i take the last combination as example, it means (with the source of the program):
Loop1: (C1 + 0 + 0) mod 10 = 9 et (C2 + 0 + 1) mod 10 = 9
Loop2: (C2 + 1 + 0) mod 10 = 9 et (C3 + 1 + 1) mod 10 = 9
Loop3: (C3 + 2 + 0) mod 10 = 9 et (C4 + 2 + 1) mod 10 = 9
Loop4: (C4 + 3 + 0) mod 10 = 9 et (C5 + 3 + 1) mod 10 = 9
Loop5: (C5 + 4 + 0) mod 10 = 9 et (C6 + 4 + 1) mod 10 = 9
Loop6: (C6 + 5 + 0) mod 10 = 9 et (C7 + 5 + 1) mod 10 = 1
Loop7: (C7 + 6 + 0) mod 10 = 1 et (C8 + 6 + 1) mod 10 = 0
We remove expressions which are twice times present:
(C1 + 0) mod 10 = 9 (= a)
(C2 + 1) mod 10 = 9 (= b)
(C3 + 2) mod 10 = 9 (= c)
(C4 + 3) mod 10 = 9 (= d)
(C5 + 4) mod 10 = 9 (= e)
(C6 + 5) mod 10 = 9 (= f)
(C7 + 6) mod 10 = 1 (= g)
(C8 + 7) mod 10 = 0 (= h)
So, it is easy to generate our 8 precious bytes (C1, C2, ..., C8). It is over for the call
00413D13.
Remark: Don't forget that these 8 bytes are computed with the name and the serial.
Ok, we know how getting 8 good bytes (C1...C8), now, let's study how the serial and the serial
are encoded to produce the 8 bytes. It is located in CALL 00413C94 (in XXXX:00413A08).
S1, S2, ..., S8 are the 8 bytes of the final (working) serial.
My name (Lucifer48) is coded like this (84 = 4C + 38) on 8 bytes:
XXXX:0068F464 84 75 63 69 66 65 72 34 .ucifer4
N1 N2 N3 N4 N5 N6 N7 N8
This is the encryption scheme:
C1 =S1 - [ (N1 mod 1Ah) + 41h ]
C2 =S2 - [ (N2 mod 1Ah) + 41h ]
...
C8 =S8 - [ (N8 mod 1Ah) + 41h ]
If Ck (k={1,2,...8} ) is negative (between 7F and FF), then Ck += 1Ah.
Each char of the serial is independent. So we could solve separately 8 equations.
Which are:
S1 = C1 + [ (N1 mod 1Ah) + 41h ]
S2 = C2 + [ (N2 mod 1Ah) + 41h ]
...
S8 = C8 + [ (N3 mod 1Ah) + 41h ]
It is true, assuming Sk > [ (Nk mod 1Ah) + 41h ]
(to remove the carry problem (+1A) ).
For my name:
S1 = C1 + 43
S2 = C2 + 4E
S3 = C3 + 56
S4 = C4 + 42
S5 = C5 + 59
S6 = C6 + 58
S7 = C7 + 4B
S8 = C8 + 41
To find C1, C2, ..., C8 i do:
C1 = 3*Ah + 9 - 0 = 27
C2 = 3*Ah + 9 - 1 = 26
...
C7 = 3*Ah + 1 - 6 = 19
C8 = 3*Ah + 0 - 7 = 17
I take this 3 because it is an ideal number which allow us to obtain printable
chars for the serial (not too high ascii value). I get this:
6A ; 74 ; 7B ; 66 ; 7C ; 7A ; 64 ; 58 (so: "jt{f|zdX")
The serial works, but there are two bad chars: {, | ;)
In fact the 3 is not so good... I will take 2, i think it will be better !
(same process as above):
C1 = 2*Ah + 9 - 0 = 1D
C2 = 2*Ah + 9 - 1 = 1C
...
C7 = 2*Ah + 1 - 6 = 0F
C8 = 2*Ah + 0 - 7 = 0D
I get:
60 ; 6A ; 71 ; 5C ; 72 ; 70 ; 5A ; 4E (so: "`jq\rpZN")
The second serial also works ! But the 2 is not very good too !
Finaly, i decide to mix the two serials to get my registration:
Name/ Lucifer48
Serial/ jjqfrzdX
Greetings: All ID members (Volatility, Torn@do, ...), Eternal Bliss, ACiD BuRN,
people on #cracking4newbies, french crackers, etc.
(c) Lucifer48. All rights reversed