目标程序:mIRC V5.71 32Bit
程序下载:http://ilike.myrice.com/soft_chat/mirc_2.html
使用工具:TRW2000,Turbo c++3.0 编译器
保护方式:注册码
难易程度:易,适合初学者练习写注册机。
最近申请了一个IRC聊天(202.96.137.64 频道:#Crack),当然选用mRIC这个最流行的 IRC 客户程序,这是一个十分优秀的共享软件,不注册有时间限制。刚好今天闲着没事,好久没为新手写东西了,故以这软件为例,谈谈如何写注册机。
拿到这个软件,首先运行一遍,看看功能是否有限制,然后再看看注册方式,还好,这是一个常用的注册保护方式,不注册还有NAG跳出,在Help处输入注册码,当然我们从输入注册码方式来下手了。
在破解序列号有多种方式,我们这次采用常用的方法,就是根据出错的对话框,反推找到注册码比较核心。
注册不成功时,会跳出一对话框。因此我们用bpx messagboxa设断来拦截这个对话框。
0167:004A33A8 PUSH DWORD 00531B23 -- -序列号进栈
0167:004A33AD PUSH DWORD 0053173C--- - ID进栈
0167:004A33B2 CALL 004A2F9C—————重点!!!跟进看何处使EAX可不为0
0167:004A33B7 TEST EAX,EAX ————— 试着下 EAX=0注册失败(这是以EAX为旗帜)
0167:004A33B9 JZ NEAR 004A345A———这里也可跳过
..........................................................
..........................................................
0167:004A3450 MOV EAX,01
0167:004A3455 JMP 004A351A——————这里可跳过
..........................................................
..........................................................
0167:004A34AA PUSH EAX
0167:004A34AB MOV EAX,[EBP+08]
0167:004A34AE PUSH EAX
0167:004A34AF CALL `USER32!MessageBoxA`—出错的对话框,然后向上分析何处跳过此处。
========================================
跟进0167:004A33B2 CALL 004A2F9C后:
0167:004A2FBD MOV EAX,EDI
0167:004A2FBF MOV EDX,ECX
0167:004A2FC1 SHR ECX,02
0167:004A2FC4 REP MOVSD --------- 如在TRW2000里按F10,会马上带过下面代码(因此在这里用F8)
0167:004A2FC6 MOV ECX,EDX----而在SOFTICE里就没这种情况。
0167:004A2FC8 AND ECX,BYTE +03
0167:004A2FCB REP MOVSB ---------这里用TRW2000时,按f8
0167:004A2FCD POP ESI
0167:004A2FCE PUSH ESI
0167:004A2FCF MOV EDI,ESI
0167:004A2FD1 MOV ESI,005425DC
0167:004A2FD6 XOR EAX,EAX
0167:004A2FD8 OR ECX,BYTE -01
0167:004A2FDB REPNE SCASB ---------这里用TRW2000时,按f8
0167:004A2FDD NOT ECX
0167:004A2FDF SUB EDI,ECX
0167:004A2FE1 XCHG ESI,EDI
0167:004A2FE3 MOV EAX,EDI
0167:004A2FF3 POP ESI
0167:004A2FF4 PUSH DWORD 005425DC-----序列号进栈
0167:004A2FF9 PUSH DWORD 005424DC ----ID进栈
0167:004A2FFE CALL 004A2EA4----------------重点!!!跟进看何处使EAX可不为0
0167:004A3003 TEST EAX,EAX------------------EAX=0失败
0167:004A3005 JZ 004A300E
========================================
按F8跟进0167:004A2FFE CALL 004A2EA4里,如下:
0167:004A2EB9 POP ECX
0167:004A2EBA CMP EAX,BYTE +05---------判断输入的姓名字符个数是否大于或等于5
0167:004A2EBD JNC 004A2EC6
0167:004A2EBF XOR EAX,EAX
0167:004A2EC1 JMP 004A2F90
0167:004A2EC6 PUSH BYTE +2D
0167:004A2EC8 PUSH ESI
0167:004A2EC9 CALL 00401278-------------------判断注册码中有无短线符号“-"
0167:004A2ECE ADD ESP,BYTE +08
0167:004A2ED1 MOV EBX,EAX
0167:004A2ED3 TEST EBX,EBX
0167:004A2ED5 JNZ 004A2EDE
(NO JUMP)
0167:004A2ED7 XOR EAX,EAX
0167:004A2EEE INC EBX
0167:004A2EEF CMP BYTE [EBX],00-判断注册码的短线是否在最后,如:123234-
0167:004A2EF2 JNZ 004A2EFB
0167:004A2EF4 XOR EAX,EAX
0167:004A2F16 MOV EDX,03
0167:004A2F1B MOV ECX,[EBP+08]
0167:004A2F1E ADD ECX,BYTE +03
0167:004A2F21 CMP EDX,[EBP-0C]
0167:004A2F24 JNL 004A2F42
以下就是注册码比较核心:
0167:004A2F26 MOVZX ESI,BYTE [ECX]———此处将姓名字符ASCII码给ESI,初值是从姓名第四个字符开始
0167:004A2F29 IMUL ESI,[EAX*4+0052158C]—EAX的初值=0;
这里程序将是取表(D 52158C)的值,每次取一值,结果赋值给ESI
0167:004A2F31 ADD EBX,ESI-———————EBX的初值=0
0167:004A2F33 INC EAX—————————EAX+1
0167:004A2F34 CMP EAX,BYTE +26-————比较是否超过字符表的范围(EAX初值是0)
0167:004A2F37 JNG 004A2F3B
0167:004A2F39 XOR EAX,EAX———————如姓名超过了39(27H)字符,则重新从表的开始处查表。
0167:004A2F3B INC EDX—————————EDX+1 循环计数+1
0167:004A2F3C INC ECX—————————ECX+1准备取下一个字数
0167:004A2F3D CMP EDX,[EBP-0C]————比较姓名字符是否计算结束
0167:004A2F40 JL 004A2F26
(JUMP)—没有跳到:004A2F26继续计算下一个字符。
0167:004A2F42 CMP EBX,[EBP-04]————————比较核心,在此:
①? EBX 显示:DEC 1405 ;HEX 57D 这里十进制1405就是注册码的前半部分
②下命令:DD EBP-4 此时在数据区显示:00003039;
再次下命令:? 3039 显示:DEC 12345 ;HEX 3039这就是我们输入的注册码。
********************************************************************************************
在这里我们稍微仔细地把刚才的流程数据处理过程写一下:
①我们输入的ID:toye1 serial:1234-56789
②查看表格数据,DD 0052158C显示:
0030:0052158C 0000000B 00000006 00000011 0000000C
................
0030:0052159C 0000000C 0000000E 00000005 0000000C
................
0030:005215AC 00000010 0000000A 0000000B 00000006
................
0030:005215BC 0000000E 0000000E 00000004 0000000B
................
0030:005215CC 00000006 0000000E 0000000E 00000004
................
0030:005215DC 0000000B 00000009 0000000C 0000000B
................
0030:005215EC 0000000A 00000008 0000000A 0000000A
................
0030:005215FC 00000010 00000008 00000004 00000006
................
0030:0052160C 0000000A 0000000C 00000010 00000008
................
0030:0052161C 0000000A 00000004 00000010 00000000
................
③每次循环执行[EAX*4+0052158C]一次,依次从数据表中取值:B、6、11、C等;
首先将ID中的第四个字符e(ASCII是65)乘以数据表的第一个数字“B“,然后再循环一次将ID的第五个字符“1”(ASCII是31)乘以数据表中的第二个数“6",由于ID就是5个字符,计算完成,最后生成的数字为:
65*B+31*6=57D 转换成十进制为1405,这个数就是注册码的前半部分。
********************************************************************************************
我们继续跟踪下半部分的注册码:
此时填上:ID为toye1 serial为1405-xxxxx(后面的任意)
0167:004A2F5F MOVZX ESI,BYTE PTR [ECX] ———首先将第四个字符赋给ESI
0167:004A2F62 MOVZX EDI,BYTE PTR [ECX-01] ——首先将第三个字符赋给EDI
0167:004A2F66 IMUL ESI,EDI -——————————ESI*EDI并将值放到ESI
0167:004A2F69 IMUL ESI,[EAX*4+0052158C] -———ESI乘以数据表中的第一数据
0167:004A2F71 ADD EBX,ESI ——————————EBX初值是0
0167:004A2F73 INC EAX
0167:004A2F74 CMP EAX,26 -——判断ID是否超过了39字符,以决定是否重复调用数据表
0167:004A2F77 JLE 004A2F7B
0167:004A2F79 XOR EAX,EAX
0167:004A2F7B INC EDX ————EDX+1 循环计数+1
0167:004A2F7C INC ECX ————ECX+1准备取下一个字数
0167:004A2F7D CMP EDX,[EBP-0C] ————比较姓名字符是否计算结束
0167:004A2F80 JL 004A2F5F
0167:004A2F82 CMP EBX,[EBP-08] ————————比较核心,在此:
?EBX将看到正确的注册码,DD EBP-8将看到我们输入的注册码的十六进制
注册码的后半部的算法分析和前半部分类似,所不同的每次取ID的两个字符。
以toye1姓名为例:计算关系式:字符"e"乘以字符"y",再乘以B。再次循环字符"1"乘以字符"e",再乘以6:
65*79*B+31*65*6=2811D 换算成十进制为164125;
因此注册码就是1405-164125 ID:toye1
==========================================
注册机:
#include <stdio.h>
#include <string.h>
void main(void)
{
unsigned long code1=0,code2=0,temp;
int i,j;
char name[80];
unsigned char Table[39] =
{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};
printf("mIRC_v5.71 32bit Keymaker (c) by toye(看雪)\n");
printf("【看雪学苑】http://toye.yeah.net\n\n\n");
printf("Input your name:");
scanf("%s",name);
while (strlen(name)<5)
{
printf("you must input your name above 5 letters.\n");
printf("please entry your name again:");
scanf("%s",name);
}
for(i=3,j=0;name[i]!='\0';i++)
{if(j>38) j=0;
code1=name[i]*Table[j]+code1;
j++;
}
for(i=3,j=0;name[i]!='\0';i++)
{if(j>38) j=0;
temp=name[i]*name[i-1];
code2=temp*Table[j]+code2;
j++;}
printf("\n");
printf("Registration code =%ld-%ld\n",code1,code2);
}
名亦我所欲也,利亦我所欲也;
若为破解故,二者皆可抛!
———end———
- 标 题:mIRC V5.71分析 (9千字)
- 作 者:kanxue
- 时 间:2000-8-19 22:49:49
- 链 接:http://bbs.pediy.com