anonymouse187
09-09-2006, 12:54 PM
. . . . . . . . . . . . . . . . .
. .
. KeyGen Tutorial on mIRC 5.41 .
. - .
. (c) 1998 by Dynamite .
. .
. . . . . . . . . . . . . . . . .
( )Beginner (X)Intermediate ( )Advanced ( )Expert
In this tut, we will get the information to write a keygen for the IRC client mIRC 5.41. The
first time I worked on mIRC 5.41 I wondered, because the code was so clearly written. It was
really fun to crack it :-) Because of the clearly written code (Thanks to Khaled Mardam-Bey) it
is a nice target for a tut. Only one thing is very bad on mIRC. One time registered, you can't
un-register it. I tried to delete it, but the registration was allready there. Maybe it keeps
the registration info in the registry or in a file in the win95 dir. I don't know...
For this tut you will need Soft-Ice 3.0+ and W32Dasm (I'm using v8.9).
Run mIRC and select Register in the Help menu. Enter anything you want and press the register
button. You're noting a msgbox poping up, which tells you, that your registration info was
wrong. So let's set a BPX at MessageBoxA. Repeat the whole crap and you are in SIce, where
the msgbox pops up. It is at :0043D29C. Write this address down and load MIRC32.EXE into
W32Dasm. Once in W32Dasm, goto :0043D29C and then scroll up, until you find the next reference
to a conditional jump. You'll find it at :0043D257. It comes from :0043D1C6. At :0043D1C6 you
can see the following piece of code:
:0043D1B5 68701E4D00 push 004D1E70 ; the s/n is pushed
:0043D1BA 68B41B4D00 push 004D1BB4 ; the name is pushed
:0043D1BF E844140500 call 0048E608 ; that's the check_function
:0043D1C4 85C0 test eax, eax ; valid s/n entered?
:0043D1C6 0F848B000000 je 0043D257 ; jump, when s/n was wrong
Okay. Now we know where to search. We have to set a BPX at :0048E608. When I worked on mIRC, I
traced through the whole check_function and all its sub-functions. Here follows the whole
check_function well commented:
* Referenced by a CALL at Addresses:
|:0043D1BF , :0048E7CA
|
:0048E608 55 push ebp
:0048E609 8BEC mov ebp, esp
:0048E60B 53 push ebx
:0048E60C 56 push esi
:0048E60D 57 push edi
:0048E60E 8B750C mov esi, dword ptr [ebp+0C]
:0048E611 8B5D08 mov ebx, dword ptr [ebp+08]
:0048E614 53 push ebx ; push name
:0048E615 E8AE530200 call 004B39C8 ; get length of name
:0048E61A 59 pop ecx
:0048E61B 83F805 cmp eax, 00000005 ; the min. of chars is 5
:0048E61E 7304 jnb 0048E624 ; if name consist of 5 or more
chars, jump. else leave func
:0048E620 33C0 xor eax, eax
:0048E622 EB6D jmp 0048E691 ; jump to end of function
If you entered a name with 4 or less chars, then restart the whole process and enter a name
with minimal 5 chars.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E61E(C)
|
:0048E624 56 push esi
:0048E625 53 push ebx
:0048E626 E8FDFEFFFF call 0048E528
Here follows the function :0048E528. This is the main function of the whole protection, because
it validates the s/n with the username.
* Referenced by a CALL at Addresses:
|:0048E626 , :0048E66E
|
:0048E528 55 push ebp
:0048E529 8BEC mov ebp, esp
:0048E52B 83C4F4 add esp, FFFFFFF4
:0048E52E 53 push ebx
:0048E52F 56 push esi
:0048E530 57 push edi
:0048E531 8B750C mov esi, dword ptr [ebp+0C] ; move s/n to esi
:0048E534 6A2D push 0000002D
:0048E536 56 push esi ; push s/n
:0048E537 E838540200 call 004B3974 ; check, if there is a "-" in
the s/n
:0048E53C 83C408 add esp, 00000008
:0048E53F 8BD8 mov ebx, eax
:0048E541 85DB test ebx, ebx
:0048E543 7507 jne 0048E54C ; jump if there is a "-" else
leave function
:0048E545 33C0 xor eax, eax
:0048E547 E9B2000000 jmp 0048E5FE ; leave function
You see, that your s/n have to contain a "-". If you didn't enter a "-" in your s/n then enter
it now and restart the whole process.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E543(C)
|
:0048E54C C60300 mov byte ptr [ebx], 00 ; replace the "-" in the s/n with
a '00' byte
:0048E54F 56 push esi ; push s/n
:0048E550 E807A80200 call 004B8D5C ; check if the s/n consists of
numbers
:0048E555 59 pop ecx
:0048E556 8945FC mov dword ptr [ebp-04], eax
:0048E559 C6032D mov byte ptr [ebx], 2D
:0048E55C 43 inc ebx
:0048E55D 803B00 cmp byte ptr [ebx], 00
:0048E560 7507 jne 0048E569
:0048E562 33C0 xor eax, eax
:0048E564 E995000000 jmp 0048E5FE
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E560(C)
|
:0048E569 53 push ebx
:0048E56A E8EDA70200 call 004B8D5C
:0048E56F 59 pop ecx
:0048E570 8945F8 mov dword ptr [ebp-08], eax
:0048E573 8B4508 mov eax, dword ptr [ebp+08]
:0048E576 50 push eax ; push name
:0048E577 E84C540200 call 004B39C8 ; get length of name
:0048E57C 59 pop ecx
:0048E57D 8945F4 mov dword ptr [ebp-0C], eax
:0048E580 33C0 xor eax, eax
:0048E582 33DB xor ebx, ebx
:0048E584 BA03000000 mov edx, 00000003
:0048E589 8B4D08 mov ecx, dword ptr [ebp+08] ; move name to ecx
:0048E58C 83C103 add ecx, 00000003
:0048E58F 3B55F4 cmp edx, dword ptr [ebp-0C]
:0048E592 7D1C jge 0048E5B0
Okay. Here follows a very interesting part of the protection. All chars of the name (excluded the
first three chars) are multiplicated with special digits out of a table. The outcome is added to
a checksum in EBX. You can look into the actual position of the table, if you enter
'D 4*eax+004CCB30' in SIce. To ease your cracking work, I'll give you the table.
Num_of_char Digit
---------------------
4 0B
5 06
6 11
7 0C
8 0C
9 0E
10 05
11 0C
12 10
13 0A
14 0B
15 06
16 0E
17 0E
18 04
19 0B
20 06
21 0E
22 0E
23 04
24 0B
25 09
26 0C
27 0B
28 0A
29 08
30 0A
31 0A
32 10
33 08
34 04
35 06
36 0A
37 0C
38 10
39 08
40 0A
41 04
42 10
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5AE(C)
|
:0048E594 0FB631 movzx esi, byte ptr [ecx] ; move next char of name
to esi
:0048E597 0FAF348530CB4C00 imul esi, dword ptr [4*eax+004CCB30] ; multiplicate the char
with one digit out of
the table
:0048E59F 03DE add ebx, esi ; add the outcome to EBX
:0048E5A1 40 inc eax ; next char
:0048E5A2 83F826 cmp eax, 00000026
:0048E5A5 7E02 jle 0048E5A9
:0048E5A7 33C0 xor eax, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5A5(C)
|
:0048E5A9 42 inc edx
:0048E5AA 41 inc ecx
:0048E5AB 3B55F4 cmp edx, dword ptr [ebp-0C] ; end of string?
:0048E5AE 7CE4 jl 0048E594 ; jump if not end of str
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E592(C)
|
:0048E5B0 3B5DFC cmp ebx, dword ptr [ebp-04] ; compare checksum (ebx)
with the first part of
the s/n.
:0048E5B3 7404 je 0048E5B9 ; jump when they match
:0048E5B5 33C0 xor eax, eax
:0048E5B7 EB45 jmp 0048E5FE ; else leave function
At :0048E5B0 the checksum (EBX) is compared with the first part of the s/n. The first part of the
s/n is the part before the "-". Here follows an example:
If you entered "Dynamite" in the name box, you have to calculate as follows:
----------------------------------------
| Name: D y n a m i t e |
| Number: 1 2 3 4 5 6 7 8 |
| Digits: 0B 06 11 0C 0C |
----------------------------------------
CheckSum = (61 * 0B) + (6D * 06) + (69 * 11) + (74 * 0C) + (65 * 0C)
CheckSum = 0x17DE
Now you only have to convert 0x17DE to decimal number.
0x17DE ==> 6110
So the first part of your serial is '6110-'. The second part of the serial is calculated some
lines below.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5EE(C)
|
:0048E5CD 0FB631 movzx esi, byte ptr [ecx] ; move one char to esi
:0048E5D0 0FB679FF movzx edi, byte ptr [ecx-01] ; move one char before to
edi
:0048E5D4 0FAFF7 imul esi, edi ; multiplicate the 2 chrs
:0048E5D7 0FAF348530CB4C00 imul esi, dword ptr [4*eax+004CCB30] ; multiplicate the
outcome with the
numbers out of the
table
:0048E5DF 03DE add ebx, esi ; add outcome to checksum
in EBX
:0048E5E1 40 inc eax
:0048E5E2 83F826 cmp eax, 00000026
:0048E5E5 7E02 jle 0048E5E9
:0048E5E7 33C0 xor eax, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5E5(C)
|
:0048E5E9 42 inc edx
:0048E5EA 41 inc ecx
:0048E5EB 3B55F4 cmp edx, dword ptr [ebp-0C] ; end of string?
:0048E5EE 7CDD jl 0048E5CD ; jump if not end of str
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5CB(C)
|
:0048E5F0 3B5DF8 cmp ebx, dword ptr [ebp-08] ; compare checksum with
second part of the s/n
:0048E5F3 7404 je 0048E5F9 ; jump when they match
:0048E5F5 33C0 xor eax, eax
:0048E5F7 EB05 jmp 0048E5FE ; else leave
This second calculation multiplicates every char of the name with the char before the char. The
outcoming of this multiplication is multiplicated with a number out of the tabel. To get the
second part of the s/n you have to calculate as follows:
----------------------------------------
| Name: D y n a m i t e |
| Number: 1 2 3 4 5 6 7 8 |
| Digits: 0B 06 11 0C 0C |
----------------------------------------
CheckSum = (('a' * 'n') * 0B) + (('m' * 'a') * 06) + (('i' * 'm') * 11) +
(('t' * 'i') * 0C) + (('e' * 't') * 0C)
CheckSum = 0xA1A6D
Just convert it to a decimal number and you get 662125. Now you have to put the two parts
together and you got the valid s/n for 'Dynamite'.
name: Dynamite
s/n: 6110-662125
I think you got all information to write a keygen for mIRC 5.41. I hope you enjoyed this tut by
me. Sorry for my bad english :]
Greetz are going to he +HCU and to NiKai ;-)
(c) 1998 by Dynamite
Private Sub ShowKey()
'Text1.Text = Username | Min 4 chars |
Static Already As Boolean, MyTable(&H26)
If Already = False Then
MyTable(0) = 11: MyTable(1) = 6: MyTable(2) = 17: MyTable(3) = 12
MyTable(4) = 12: MyTable(5) = 14: MyTable(6) = 5: MyTable(7) = 12
MyTable(8) = 16: MyTable(9) = 10: MyTable(10) = 11: MyTable(11) = 6
MyTable(12) = 14: MyTable(13) = 14: MyTable(14) = 4: MyTable(15) = 11
MyTable(16) = 6: MyTable(17) = 14: MyTable(18) = 14: MyTable(19) = 4
MyTable(20) = 11: MyTable(21) = 9: MyTable(22) = 12: MyTable(23) = 11
MyTable(24) = 10: MyTable(25) = 8: MyTable(26) = 10: MyTable(27) = 10
MyTable(28) = 16: MyTable(29) = 8: MyTable(30) = 4: MyTable(31) = 6
MyTable(32) = 10: MyTable(33) = 12: MyTable(34) = 16: MyTable(35) = 8
MyTable(36) = 10: MyTable(37) = 4: MyTable(38) = 16
End If
If Len(Text1.Text) < 4 Then Text2.Text = "": Exit Sub
CL = 0
For C = 4 To Len(Text1.Text)
Valore = Asc(Mid$(Text1.Text, C, 1)) * MyTable(CL)
FirstPart = FirstPart + Valore
CL = CL + 1
If CL > &H26 Then CL = 0
Next
CL = 0: Valore = 0
For C = 4 To Len(Text1.Text)
Valore = Asc(Mid$(Text1.Text, C - 1, 1)) * Asc(Mid$(Text1.Text, C, 1))
SecondPart = SecondPart + Valore * MyTable(CL)
CL = CL + 1
If CL > &H26 Then CL = 0
Next
Text2.Text = LTrim$(Str$(FirstPart)) + "-" + LTrim$(Str$(SecondPart))
End Sub
Private Sub Text1_Change()
ShowKey
End Sub
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(){
const char lookup_table[]={0xB, 0x6 ,0x11 ,0xC ,0xC ,0xE ,0x5 ,0xC ,0x10
,0xA ,0xB ,0x6 ,0xE ,0xE ,0x4 ,0xB ,0x6 ,0xE
,0xE ,0x4 ,0xB ,0x9 ,0xC ,0xB ,0xA ,0x8 ,0xA
,0xA ,0x10 ,0x8 ,0x4 ,0x6 ,0xA ,0xC ,0x10 ,0x8
,0xA, 0x4, 0x10, 00};
cout << "KeyGen for mIRC 5.82t (32-bit version) by Rith.\n\n";
cout << "Please enter your name exactly as you wish it to appear in mIRC.\n"
<< "Due to a program requirement, the name must be between 5 and 80 characters long.\n"
<< flush;
char name[81];
long int code1=0, code2=0;
int lookup_index=0;
cin.getline(name,80,'\n');
if(strlen(name)<5){
cout << "Error: name must be at least 5 characters long." << endl << flush;
}
for(int name_index=3; name_index<strlen(name); name_index++){
code1+=name[name_index]*lookup_table[lookup_index];
lookup_index++;
if(lookup_index>38) //hex 26
lookup_index=0;
}
lookup_index=0;
for(name_index=3; name_index<strlen(name); name_index++){
code2+=name[name_index]*name[name_index-1]*lookup_table[lookup_index];
lookup_index++;
if(lookup_index>38) //hex 26
lookup_index=0;
}
printf("Your code is: %i-%i\n",code1,code2);
cout << "\nEnjoy yet another fine release from Rith!\n" << flush;
return 0;
}
. .
. KeyGen Tutorial on mIRC 5.41 .
. - .
. (c) 1998 by Dynamite .
. .
. . . . . . . . . . . . . . . . .
( )Beginner (X)Intermediate ( )Advanced ( )Expert
In this tut, we will get the information to write a keygen for the IRC client mIRC 5.41. The
first time I worked on mIRC 5.41 I wondered, because the code was so clearly written. It was
really fun to crack it :-) Because of the clearly written code (Thanks to Khaled Mardam-Bey) it
is a nice target for a tut. Only one thing is very bad on mIRC. One time registered, you can't
un-register it. I tried to delete it, but the registration was allready there. Maybe it keeps
the registration info in the registry or in a file in the win95 dir. I don't know...
For this tut you will need Soft-Ice 3.0+ and W32Dasm (I'm using v8.9).
Run mIRC and select Register in the Help menu. Enter anything you want and press the register
button. You're noting a msgbox poping up, which tells you, that your registration info was
wrong. So let's set a BPX at MessageBoxA. Repeat the whole crap and you are in SIce, where
the msgbox pops up. It is at :0043D29C. Write this address down and load MIRC32.EXE into
W32Dasm. Once in W32Dasm, goto :0043D29C and then scroll up, until you find the next reference
to a conditional jump. You'll find it at :0043D257. It comes from :0043D1C6. At :0043D1C6 you
can see the following piece of code:
:0043D1B5 68701E4D00 push 004D1E70 ; the s/n is pushed
:0043D1BA 68B41B4D00 push 004D1BB4 ; the name is pushed
:0043D1BF E844140500 call 0048E608 ; that's the check_function
:0043D1C4 85C0 test eax, eax ; valid s/n entered?
:0043D1C6 0F848B000000 je 0043D257 ; jump, when s/n was wrong
Okay. Now we know where to search. We have to set a BPX at :0048E608. When I worked on mIRC, I
traced through the whole check_function and all its sub-functions. Here follows the whole
check_function well commented:
* Referenced by a CALL at Addresses:
|:0043D1BF , :0048E7CA
|
:0048E608 55 push ebp
:0048E609 8BEC mov ebp, esp
:0048E60B 53 push ebx
:0048E60C 56 push esi
:0048E60D 57 push edi
:0048E60E 8B750C mov esi, dword ptr [ebp+0C]
:0048E611 8B5D08 mov ebx, dword ptr [ebp+08]
:0048E614 53 push ebx ; push name
:0048E615 E8AE530200 call 004B39C8 ; get length of name
:0048E61A 59 pop ecx
:0048E61B 83F805 cmp eax, 00000005 ; the min. of chars is 5
:0048E61E 7304 jnb 0048E624 ; if name consist of 5 or more
chars, jump. else leave func
:0048E620 33C0 xor eax, eax
:0048E622 EB6D jmp 0048E691 ; jump to end of function
If you entered a name with 4 or less chars, then restart the whole process and enter a name
with minimal 5 chars.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E61E(C)
|
:0048E624 56 push esi
:0048E625 53 push ebx
:0048E626 E8FDFEFFFF call 0048E528
Here follows the function :0048E528. This is the main function of the whole protection, because
it validates the s/n with the username.
* Referenced by a CALL at Addresses:
|:0048E626 , :0048E66E
|
:0048E528 55 push ebp
:0048E529 8BEC mov ebp, esp
:0048E52B 83C4F4 add esp, FFFFFFF4
:0048E52E 53 push ebx
:0048E52F 56 push esi
:0048E530 57 push edi
:0048E531 8B750C mov esi, dword ptr [ebp+0C] ; move s/n to esi
:0048E534 6A2D push 0000002D
:0048E536 56 push esi ; push s/n
:0048E537 E838540200 call 004B3974 ; check, if there is a "-" in
the s/n
:0048E53C 83C408 add esp, 00000008
:0048E53F 8BD8 mov ebx, eax
:0048E541 85DB test ebx, ebx
:0048E543 7507 jne 0048E54C ; jump if there is a "-" else
leave function
:0048E545 33C0 xor eax, eax
:0048E547 E9B2000000 jmp 0048E5FE ; leave function
You see, that your s/n have to contain a "-". If you didn't enter a "-" in your s/n then enter
it now and restart the whole process.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E543(C)
|
:0048E54C C60300 mov byte ptr [ebx], 00 ; replace the "-" in the s/n with
a '00' byte
:0048E54F 56 push esi ; push s/n
:0048E550 E807A80200 call 004B8D5C ; check if the s/n consists of
numbers
:0048E555 59 pop ecx
:0048E556 8945FC mov dword ptr [ebp-04], eax
:0048E559 C6032D mov byte ptr [ebx], 2D
:0048E55C 43 inc ebx
:0048E55D 803B00 cmp byte ptr [ebx], 00
:0048E560 7507 jne 0048E569
:0048E562 33C0 xor eax, eax
:0048E564 E995000000 jmp 0048E5FE
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E560(C)
|
:0048E569 53 push ebx
:0048E56A E8EDA70200 call 004B8D5C
:0048E56F 59 pop ecx
:0048E570 8945F8 mov dword ptr [ebp-08], eax
:0048E573 8B4508 mov eax, dword ptr [ebp+08]
:0048E576 50 push eax ; push name
:0048E577 E84C540200 call 004B39C8 ; get length of name
:0048E57C 59 pop ecx
:0048E57D 8945F4 mov dword ptr [ebp-0C], eax
:0048E580 33C0 xor eax, eax
:0048E582 33DB xor ebx, ebx
:0048E584 BA03000000 mov edx, 00000003
:0048E589 8B4D08 mov ecx, dword ptr [ebp+08] ; move name to ecx
:0048E58C 83C103 add ecx, 00000003
:0048E58F 3B55F4 cmp edx, dword ptr [ebp-0C]
:0048E592 7D1C jge 0048E5B0
Okay. Here follows a very interesting part of the protection. All chars of the name (excluded the
first three chars) are multiplicated with special digits out of a table. The outcome is added to
a checksum in EBX. You can look into the actual position of the table, if you enter
'D 4*eax+004CCB30' in SIce. To ease your cracking work, I'll give you the table.
Num_of_char Digit
---------------------
4 0B
5 06
6 11
7 0C
8 0C
9 0E
10 05
11 0C
12 10
13 0A
14 0B
15 06
16 0E
17 0E
18 04
19 0B
20 06
21 0E
22 0E
23 04
24 0B
25 09
26 0C
27 0B
28 0A
29 08
30 0A
31 0A
32 10
33 08
34 04
35 06
36 0A
37 0C
38 10
39 08
40 0A
41 04
42 10
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5AE(C)
|
:0048E594 0FB631 movzx esi, byte ptr [ecx] ; move next char of name
to esi
:0048E597 0FAF348530CB4C00 imul esi, dword ptr [4*eax+004CCB30] ; multiplicate the char
with one digit out of
the table
:0048E59F 03DE add ebx, esi ; add the outcome to EBX
:0048E5A1 40 inc eax ; next char
:0048E5A2 83F826 cmp eax, 00000026
:0048E5A5 7E02 jle 0048E5A9
:0048E5A7 33C0 xor eax, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5A5(C)
|
:0048E5A9 42 inc edx
:0048E5AA 41 inc ecx
:0048E5AB 3B55F4 cmp edx, dword ptr [ebp-0C] ; end of string?
:0048E5AE 7CE4 jl 0048E594 ; jump if not end of str
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E592(C)
|
:0048E5B0 3B5DFC cmp ebx, dword ptr [ebp-04] ; compare checksum (ebx)
with the first part of
the s/n.
:0048E5B3 7404 je 0048E5B9 ; jump when they match
:0048E5B5 33C0 xor eax, eax
:0048E5B7 EB45 jmp 0048E5FE ; else leave function
At :0048E5B0 the checksum (EBX) is compared with the first part of the s/n. The first part of the
s/n is the part before the "-". Here follows an example:
If you entered "Dynamite" in the name box, you have to calculate as follows:
----------------------------------------
| Name: D y n a m i t e |
| Number: 1 2 3 4 5 6 7 8 |
| Digits: 0B 06 11 0C 0C |
----------------------------------------
CheckSum = (61 * 0B) + (6D * 06) + (69 * 11) + (74 * 0C) + (65 * 0C)
CheckSum = 0x17DE
Now you only have to convert 0x17DE to decimal number.
0x17DE ==> 6110
So the first part of your serial is '6110-'. The second part of the serial is calculated some
lines below.
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5EE(C)
|
:0048E5CD 0FB631 movzx esi, byte ptr [ecx] ; move one char to esi
:0048E5D0 0FB679FF movzx edi, byte ptr [ecx-01] ; move one char before to
edi
:0048E5D4 0FAFF7 imul esi, edi ; multiplicate the 2 chrs
:0048E5D7 0FAF348530CB4C00 imul esi, dword ptr [4*eax+004CCB30] ; multiplicate the
outcome with the
numbers out of the
table
:0048E5DF 03DE add ebx, esi ; add outcome to checksum
in EBX
:0048E5E1 40 inc eax
:0048E5E2 83F826 cmp eax, 00000026
:0048E5E5 7E02 jle 0048E5E9
:0048E5E7 33C0 xor eax, eax
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5E5(C)
|
:0048E5E9 42 inc edx
:0048E5EA 41 inc ecx
:0048E5EB 3B55F4 cmp edx, dword ptr [ebp-0C] ; end of string?
:0048E5EE 7CDD jl 0048E5CD ; jump if not end of str
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0048E5CB(C)
|
:0048E5F0 3B5DF8 cmp ebx, dword ptr [ebp-08] ; compare checksum with
second part of the s/n
:0048E5F3 7404 je 0048E5F9 ; jump when they match
:0048E5F5 33C0 xor eax, eax
:0048E5F7 EB05 jmp 0048E5FE ; else leave
This second calculation multiplicates every char of the name with the char before the char. The
outcoming of this multiplication is multiplicated with a number out of the tabel. To get the
second part of the s/n you have to calculate as follows:
----------------------------------------
| Name: D y n a m i t e |
| Number: 1 2 3 4 5 6 7 8 |
| Digits: 0B 06 11 0C 0C |
----------------------------------------
CheckSum = (('a' * 'n') * 0B) + (('m' * 'a') * 06) + (('i' * 'm') * 11) +
(('t' * 'i') * 0C) + (('e' * 't') * 0C)
CheckSum = 0xA1A6D
Just convert it to a decimal number and you get 662125. Now you have to put the two parts
together and you got the valid s/n for 'Dynamite'.
name: Dynamite
s/n: 6110-662125
I think you got all information to write a keygen for mIRC 5.41. I hope you enjoyed this tut by
me. Sorry for my bad english :]
Greetz are going to he +HCU and to NiKai ;-)
(c) 1998 by Dynamite
Private Sub ShowKey()
'Text1.Text = Username | Min 4 chars |
Static Already As Boolean, MyTable(&H26)
If Already = False Then
MyTable(0) = 11: MyTable(1) = 6: MyTable(2) = 17: MyTable(3) = 12
MyTable(4) = 12: MyTable(5) = 14: MyTable(6) = 5: MyTable(7) = 12
MyTable(8) = 16: MyTable(9) = 10: MyTable(10) = 11: MyTable(11) = 6
MyTable(12) = 14: MyTable(13) = 14: MyTable(14) = 4: MyTable(15) = 11
MyTable(16) = 6: MyTable(17) = 14: MyTable(18) = 14: MyTable(19) = 4
MyTable(20) = 11: MyTable(21) = 9: MyTable(22) = 12: MyTable(23) = 11
MyTable(24) = 10: MyTable(25) = 8: MyTable(26) = 10: MyTable(27) = 10
MyTable(28) = 16: MyTable(29) = 8: MyTable(30) = 4: MyTable(31) = 6
MyTable(32) = 10: MyTable(33) = 12: MyTable(34) = 16: MyTable(35) = 8
MyTable(36) = 10: MyTable(37) = 4: MyTable(38) = 16
End If
If Len(Text1.Text) < 4 Then Text2.Text = "": Exit Sub
CL = 0
For C = 4 To Len(Text1.Text)
Valore = Asc(Mid$(Text1.Text, C, 1)) * MyTable(CL)
FirstPart = FirstPart + Valore
CL = CL + 1
If CL > &H26 Then CL = 0
Next
CL = 0: Valore = 0
For C = 4 To Len(Text1.Text)
Valore = Asc(Mid$(Text1.Text, C - 1, 1)) * Asc(Mid$(Text1.Text, C, 1))
SecondPart = SecondPart + Valore * MyTable(CL)
CL = CL + 1
If CL > &H26 Then CL = 0
Next
Text2.Text = LTrim$(Str$(FirstPart)) + "-" + LTrim$(Str$(SecondPart))
End Sub
Private Sub Text1_Change()
ShowKey
End Sub
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main(){
const char lookup_table[]={0xB, 0x6 ,0x11 ,0xC ,0xC ,0xE ,0x5 ,0xC ,0x10
,0xA ,0xB ,0x6 ,0xE ,0xE ,0x4 ,0xB ,0x6 ,0xE
,0xE ,0x4 ,0xB ,0x9 ,0xC ,0xB ,0xA ,0x8 ,0xA
,0xA ,0x10 ,0x8 ,0x4 ,0x6 ,0xA ,0xC ,0x10 ,0x8
,0xA, 0x4, 0x10, 00};
cout << "KeyGen for mIRC 5.82t (32-bit version) by Rith.\n\n";
cout << "Please enter your name exactly as you wish it to appear in mIRC.\n"
<< "Due to a program requirement, the name must be between 5 and 80 characters long.\n"
<< flush;
char name[81];
long int code1=0, code2=0;
int lookup_index=0;
cin.getline(name,80,'\n');
if(strlen(name)<5){
cout << "Error: name must be at least 5 characters long." << endl << flush;
}
for(int name_index=3; name_index<strlen(name); name_index++){
code1+=name[name_index]*lookup_table[lookup_index];
lookup_index++;
if(lookup_index>38) //hex 26
lookup_index=0;
}
lookup_index=0;
for(name_index=3; name_index<strlen(name); name_index++){
code2+=name[name_index]*name[name_index-1]*lookup_table[lookup_index];
lookup_index++;
if(lookup_index>38) //hex 26
lookup_index=0;
}
printf("Your code is: %i-%i\n",code1,code2);
cout << "\nEnjoy yet another fine release from Rith!\n" << flush;
return 0;
}