• 标 题:KEYGENNING4NEWBIES #7破解过程+注册机 (6千字)
  • 作 者:伪装者[CCG]
  • 时 间:2001-8-21 6:22:43
  • 链 接:http://bbs.pediy.com

KEYGENNING4NEWBIES #7破解过程+注册机

前两天TAE!让我看看KEYGENNING4BEWBIES 的#3,那个东西很简单,做了它的注册机
后来看雪给了我一个代理服务器地址,使我能够到国外的一些破解站转转,于是我找
到了这个NUMBER 7

KEYGENNING4NEWBIES有7个KEYGENME(其中第二个有问题),这些KEYGENME的
作用就是让初学者练习写KEYGEN,其中有的是比较简单的(如#1,#3)
这次我要写的KEYGENME #7用了MD5算法(相应的资料可以在http://www.rsa.com找到)
下载地址:http://www.leelouonline.com/users/bofh/k4n/k4n7.zip
使用工具:TRW2000
难度    :5(10为最难,0为最易)
CRACKER :伪装者[BCG&&CCG]
目的    :学习破解一周年纪念
目标    : 做出这个的注册机,并且使初学者看完之后能有所收获
过程如下:
运行KEYGENNING4NEWBIES #7(以下简称"#7")
输入用户名,注册码
用户名:cracknow
注册码:121212
启动TRW2000
BPX HMEMCPY
按"OK"键,被拦截
一次PMODULE后来到0167:00401B8A这里
BC *并用F9在这里下新的断点
0167:00401B8A  CMP      EAX,BYTE +10 -------------->输入的注册码的位数和16比较
0167:00401B8D  JNZ      00401BA8                    不是16就跳(呵呵~~想起一位大客的口诀
0167:00401B8F  PUSH    BYTE +64                    "一条就死,九筒便和"不过如果这样的话
0167:00401B91  PUSH    DWORD 0040603C              就不能叫KEYGEN ME了~~)所以从新输入注
0167:00401B96  PUSH    DWORD 03E8                  册码,新注册码为:1212121212121212
0167:00401B9B  PUSH    ESI
0167:00401B9C  CALL    EDI                     
0167:00401B9E  CALL    00401D90------------------>将输入的注册码转成十六进制
0167:00401BA3  CALL    00401C70------------------>关键的CALL 了,一定要进去!
0167:00401BA8  POP      EDI
0167:00401BA9  XOR      EAX,EAX
0167:00401BAB  POP      ESI
0167:00401BAC  RET      10

***********************************************
0167:00401CAF  LEA      EAX,[EBP-78]-------------->进入之后不是到这里,但上面的我觉得             
0167:00401CB2  PUSH    EAX                        都不重要,所以没有U下来
0167:00401CB3  CALL    00401A10                  将用户名进行进行标准的MD5转换(不重要
0167:00401CB8  ADD      ESP,BYTE +08              不用跟,跟也看不明白~~呵呵~~~)
0167:00401CBB  MOV      EBX,[EBP-14]-------------->从这里开始你必须要集中精力了,因为如
0167:00401CBE  MOV      [EBP-04],EBX          |  果你要做这个的注册机,那么底下的每一       
0167:00401CC1  XOR      EBX,[EBP-0C]      |  行你都要明白是做什么用的!
0167:00401CC4  MOV      [00406CE4],EBX          |  我们设用户名经过MD5转换后的结果为S
0167:00401CCA  MOV      EBX,[EBP-10]            | S[0]~~S[3]分别表示S的4个部分,这些
0167:00401CCD  MOV      [EBP-18],EBX            | 行的作用就是使[ebp-4]=[ebp-14]=s[0]
0167:00401CD0  MOV      EBX,[EBP-0C]            |  [ebp-10]=[ebp-18]=s[1],[ebp-c]=[ebp-
0167:00401CD3  MOV      [EBP-1C],EBX            |  1c]=s[2],[ebp-8]=[ebp-20]=s[3],另外
0167:00401CD6  MOV      EBX,[EBP-08]            | 再设一个N,N=S[0]^S[2];
0167:00401CD9  MOV      [EBP-20],EBX-------------
0167:00401CDC  MOV      EBX,[004060A0]----->注册码的前8个和后8个分别放入ebp-80,ebp-7c
0167:00401CE2  MOV      [EBP-7C],EBX      | 这时你会发现如果注册码用1212121212121212这
0167:00401CE5  MOV      EBX,[004060A4]    | 样前后相同的数回造成不方便观察,所以退出,将
0167:00401CEB  MOV      [EBP-80],EBX------->注册码改成1212121234343434 继续
0167:00401CEE  MOV      ECX,[EBP-7C]------------->从这里开始是关键中的关键!!!!!!
0167:00401CF1  SHL      ECX,04                  | 最好用笔抄下来慢慢分析
0167:00401CF4  ADD      ECX,[EBP-1C]            | 这些行将输入的注册码和字符串s做
0167:00401CF7  MOV      EDX,[EBP-7C]            | 运算,最后的结果分别和0x6779656b
0167:00401CFA  ADD      EDX,[00406CE4]          | 0x656d6e65比较(呵呵~~就是keygenme)
0167:00401D00  XOR      ECX,EDX                |
0167:00401D02  MOV      EAX,[EBP-7C]            |
0167:00401D05  SHR      EAX,05                  |
0167:00401D08  ADD      EAX,[EBP-20]            |
0167:00401D0B  XOR      ECX,EAX                |
0167:00401D0D  MOV      EDX,[EBP-80]            |
0167:00401D10  SUB      EDX,ECX                |
0167:00401D12  MOV      [EBP-80],EDX            | ********注意这里!!!********
0167:00401D15  MOV      EAX,[EBP-80]            |
0167:00401D18  SHL      EAX,04                  |
0167:00401D1B  ADD      EAX,[EBP-04]            |
0167:00401D1E  MOV      ECX,[EBP-80]            |
0167:00401D21  ADD      ECX,[00406CE4]          |
0167:00401D27  XOR      EAX,ECX                |
0167:00401D29  MOV      EDX,[EBP-80]            |
0167:00401D2C  SHR      EDX,05                  |
0167:00401D2F  ADD      EDX,[EBP-18]            |
0167:00401D32  XOR      EAX,EDX                |
0167:00401D34  MOV      ECX,[EBP-7C]            |
0167:00401D37  SUB      ECX,EAX                |
0167:00401D39  MOV      [EBP-7C],ECX------------->
0167:00401D3C  CMP      DWORD [EBP-7C],6779656B-->跳就死!
0167:00401D43  JNZ      00401D69                |
0167:00401D45  CMP      DWORD [EBP-80],656D6E65 |
0167:00401D4b JNZ      00401D69----------------->跳就死!
现在开始对那个"关键中的关键"分析
比较的是[ebp-7c]与0x6779656B,[ebp-80]与0x656D6E65,所以如果注册码正确那么这两处在比较的时候
就分别应该为0x6779656B,0x656D6E65,看看上面的这行0167:00401D12  MOV      [EBP-80],EDX
将edx放入[ebp-80]中,那么这个EDX就应该等于0x656D6E65,并且这行0167:00401D12以后的[ebp-80]
都要等于0x656D6E65!利用这点我们可以反推出401D34行中的ecx,它就是正确的注册码的第二部分,
然后再利用这个反推出401D0D中的edx,这个就是正确注册码的第一部分
得到结果
用户名:cracknow
注册码:f7afdc2f25d32e18

注册机如下(VC)

#include <stdio.h>
#include <stdlib.h>
#include "md5lib.h"
void main()
{unsigned long s[4],k[2],ea,eb,ec,ed,n,sn1,sn2;
  char *text;
  int i,j;
  int tmp[16],d[2];
printf("*********KEYGENME #7*********\nThis keygen is made by Pretender\nPlease input your name : ");
k[0]=0x656d6e65;k[1]=0x6779656b;
gets(text);
text=MDString(text);                                                //用户名做MD5
for(i=0;i<16;i++)                                                  //将结果分为s[0]~s[3]
{d[0]=text[i*2];d[1]=text[i*2+1];                                  //四个部分
for(j=0;j<2;j++)
  {if(d[j]>47&&d[j]<58) d[j]=d[j]-48;
  if(d[j]>64&&d[j]<71) d[j]=d[j]-55;
  if(d[j]>96&&d[j]<103) d[j]=d[j]-87;
  }
  tmp[i]=d[0]*16+d[1];
  if(i%4==3)
  s[i/4]=tmp[i]*65536*256+tmp[i-1]*65536+tmp[i-2]*256+tmp[i-3];
}

n=s[0]^s[2];                            
//printf("%lx\n",n);                        //反推的过程
ea=k[0];
ea<<=4;
ea+=s[0];
ec=k[0];
ec+=n;
//printf("%lx",ea);
ea^=ec;
ed=k[0];
ed>>=5;
ed+=s[1];
ea^=ed;
ec=ea+k[1];
sn2=ec;
ec<<=4;
ec+=s[2];
ed=sn2;
ed+=n;
ec^=ed;
ea=sn2;
//printf("%lx",ea);
ea/=32;
ea+=s[3];
ec^=ea;
ed=ec+k[0];
printf("Your Register code is  : %08lx%08lx",ed,sn2);      //输出结果
  printf("\n *****************************      ---    ---    ---\n *Welcome to WWW.CRACKNOW.COM*      /      /      / --\n *****************************      ---    ---    --/\n");

}