• 标 题:mIRC V5.71分析 (9千字)
  • 作 者:kanxue
  • 时 间:2000-8-19 22:49:49
  • 链 接:http://bbs.pediy.com

目标程序: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———