首页 电脑 电脑学堂 查看内容

从算法到注册机步步进阶

2011-2-14 11:22 620 0

摘要:   要想在破解的道路上走得远点,单靠爆破是不行的。爆破熟练到一定程度后,应该学会算法分析,然后学着做出注册机。只有这样,才能在各式各样的软件算法面前游刃有余。但是,这样的进阶顺序却有一个突变,即从爆破...
关键词: nbsp 00494 00493 dword eax mov ptr ebp 字符串 push

  要想在破解的道路上走得远点,单靠爆破是不行的。爆破熟练到一定程度后,应该学会算法分析,然后学着做出注册机。只有这样,才能在各式各样的软件算法面前游刃有余。但是,这样的进阶顺序却有一个突变,即从爆破到算法分析这样一个质的飞跃。要应付好这个飞跃,对于算法新手来说,是比较困难的。也就是说,新手朋友往往面对一个软件的海量代码不知所措,不能有效地选择好关键代码进行分析,从而导致算法分析或者注册机编写的失败。  下面,我们就一起研究一款软件,我将力求用通俗易懂的语言来讲解算法分析和注册机编写,相信大家,特别是对于想要从爆破转到算法分析上的新手朋友来说,将会有不错的收获。  认识软件  “知己知彼,百战不殆”。我们在进行软件破解的时候,自然要对我们的破解对象有个宏观的认识。  “4U WMA MP3 Converter”是一款能将WMA格式转换为MP3格式的软件,我们研究的版本“6.0.2”。软件有没有加壳呢?用PEiD侦测可以知道,并没加壳,而且是用Borland Delphi编写的。  现在我们总结一下。要破解软件,应该先收集软件信息。那么,我们需要什么信息呢?我个人认为,应该包括这些方面:软件用法,有没加壳,用何种语言编译等。只有这些信息收集完后,我们才能方便地进行下一步的工作。  算法分析  上面我们已经收集到足够的信息了,现在进入下一步工作。用OD载入,下断点“bp MessageBoxA”可以定位到以下位置。  0049494D  |.  E8 3E02F7FF  call  00404B90  00494952  |.  50  push  eax  00494953  |.  68 CC494900  push  004949CC  ; |Text = "Invalid Registration Code! ",CR,LF,"Please enter an available Registration Code."  00494958  |.  A1 ECEF4B00  mov  eax, dword ptr [4BEFEC]  0049495D  |.  8B00  mov  eax, dword ptr [eax]  再往上看,我们可以知道,上面有个关键跳转。由此我们可以大胆断定,这里便是关键代码处。在上面靠前的地方下个断点,我选择在0049488C处下断点。F9运行,会跳出一个注册窗口要求注册。不用管它,我们随便输入注册名“hokkien”,注册码为“12345abcde”,点注册按扭后被断,然后F8单步跟踪,可以发现以下的关键位置。  004948E4  call  00494A18  我们F7步入00494A18,来到下面的关键处。  00494A3F  |.  55  push  ebp  00494A40  |.  68 734B4900  push  00494B73  00494A45  |.  64:FF30  push  dword ptr fs:[eax]  00494A48  |.  64:8920  mov  dword ptr fs:[eax], esp  00494A4B  |.  8D45 FC  lea  eax, dword ptr [ebp-4]  00494A4E  |.  BA 8C4B4900  mov  edx, 00494B8C  ;ASCII "Lb)a6Fcw9K9"  004947747.net3  |.  E8 48FFF6FF  call  004049A0  ;用固定字符串和注册名连接,返回固定字符串的长度  004947747.net8  |.  8B45 FC  mov  eax, dword ptr [ebp-4]  004947747.netB  |.  E8 38FFF6FF  call  00404998  ;连接后的字符串的长度  00494A60  |.  8BF0  mov  esi, eax  00494A62  |.  D1FE  sar  esi, 1  ;ESI是连接注册名和固定字符串形成的新字符串的长度,然后进行运算,即长度值除2,结果记为N  00494A64  |.  79 03  jns  short 00494A69  00494A66  |.  83D6 00  adc  esi, 0  00494A69  |>  8D45 F0  lea  eax, dword ptr [ebp-10]  00494A6C  |.  50  push  eax  00494A6D  |.  8BCE  mov  ecx, esi  00494A6F  |.  BA 01000000  mov  edx, 1  00494A74  |.  8B45 FC  mov  eax, dword ptr [ebp-4]  00494A77  |.  E8 7401F7FF  call  00404BF0  ;返回指定的前N个字符,所得字符串记为str1  00494A7C  |.  8B45 F0  mov  eax, dword ptr [ebp-10]  00494A7F  |.  50  push  eax  00494A80  |.  8D45 EC  lea  eax, dword ptr [ebp-14]  00494A83  |.  50  push  eax  00494A84  |.  8B45 FC  mov  eax, dword ptr [ebp-4]  00494A87  |.  E8 0CFFF6FF  call  00404998  00494A8C  |.  8BC8  mov  ecx, eax  00494A8E  |.  8D56 01  lea  edx, dword ptr [esi+1]  ;edx=N+1  00494A91  |.  8B45 FC  mov  eax, dword ptr [ebp-4]  00494A94  |.  E8 5701F7FF  call  00404BF0  ;返回从N+1个位置开始的后面所有字符串,所得字符串记为str2  00494A99  |.  8B55 EC  mov  edx, dword ptr [ebp-14]  00494A9C  |.  8D45 FC  lea  eax, dword ptr [ebp-4]  00494A9F  |.  59  pop  ecx  00494AA0  |.  E8 3FFFF6FF  call  004049E4  ;合并字符串,即 str3=str2+str1,注意顺序!  00494A7747.net  |.  8D45 F8  lea  eax, dword ptr [ebp-8]  00494AA8  |.  50  push  eax  00494AA9  |.  B9 0A000000  mov  ecx, 0A  00494AAE  |.  BA 01000000  mov  edx, 1  00494AB3  |.  8B45 FC  mov  eax, dword ptr [ebp-4]  00494AB6  |.  E8 3501F7FF  call  00404BF0  ;取str3的前10个字符,结果记为str4  00494ABB  |.  8D45 F4  lea  eax, dword ptr [ebp-C]  00494ABE  |.  50  push  eax  00494ABF  |.  8B45 FC  mov  eax, dword ptr [ebp-4]  00494AC2  |.  E8 D1FEF6FF  call  00404998  00494AC7  |.  8BC8  mov  ecx, eax  00494AC9  |.  BA 06000000  mov  edx, 6  00494ACE  |.  8B45 FC  mov  eax, dword ptr [ebp-4]  00494AD1  |.  E8 1A01F7FF  call  00404BF0  ;从第6位置取str3后的所有字符串,结果记为str5  00494AD6  |.  837D F4 00  cmp  dword ptr [ebp-C], 0  00494ADA  |.  75 10  jnz  short 00494AEC  00494ADC  |.  8D45 F4  lea  eax, dword ptr [ebp-C]  00494ADF  |.  BA 8C4B4900  mov  edx, 00494B8C  ;ASCII "Lb)a6Fcw9K9"  00494AE4  |.  8B4D F8  mov  ecx, dword ptr [ebp-8]  00494AE7  |.  E8 F8FEF6FF  call  004049E4  00494AEC  |>  53  push  ebx  00494AED  |.  8B4D F4  mov  ecx, dword ptr [ebp-C]  00494AF0  |.  8B55 F8  mov  edx, dword ptr [ebp-8]  00494AF3  |.  8BC7  mov  eax, edi  00494AF5  |.  E8 92F0FFFF  call  00493B8C  ;关键,等下将用到这个函数  上面这些代码是对注册名进行一定处理,我们以注册名“hokkien”进行具体的说明。首先,“hokkien”和“Lb)a6Fcw9K9”合并为“hokkien Lb)a6Fcw9K9”,然后取N个字符(本注册名是N=9),即“hokkienLb”,和剩下的字符倒过来又组成新的字符串,即“)a6Fcw9K9 hokkienLb”,然后再取前10位字符,即“)a6Fcw9K9h”,接着,从6个字符开始取后面的所有字符,有“w9K9hokkienLb”。其中,字符串“)a6Fcw9K9h”和“w9K9hokkienLb”是关键,后面将用于注册码的生成。  那么,上面对注册名进行这样复杂的处理有什么用呢?我们继续下去会发现“00494AF5 |. E8 92F0FFFF call 00493B8C”是关键,F7步入00493B8C,来到下面的代码处。  00493B8C  /$  55  push  ebp  00493B8D  |.  8BEC  mov  ebp, esp  00493B8F  |.  83C4 E0  add  esp, -20  00493B92  |.  53  push  ebx  00493B93  |.  56  push  esi  00493B94  |.  57  push  edi  00493B95  |.  33DB  xor  ebx, ebx  00493B97  |.  895D E0  mov  dword ptr [ebp-20], ebx  00493B9A  |.  895D F0  mov  dword ptr [ebp-10], ebx  00493B9D  |.  894D F8  mov  dword ptr [ebp-8], ecx  00493BA0  |.  8955 FC  mov  dword ptr [ebp-4], edx  00493BA3  |.  8B45 FC  mov  eax, dword ptr [ebp-4]  00493BA6  |.  E8 D50FF7FF  call  00404B80  00493BAB  |.  8B45 F8  mov  eax, dword ptr [ebp-8]  00493BAE  |.  E8 CD0FF7FF  call  00404B80  00493BB3  |.  33C0  xor  eax, eax  00493BB5  |.  55  push  ebp  00493BB6  |.  68 A83C4900  push  00493CA8  00493BBB  |.  64:FF30  push  dword ptr fs:[eax]  00493BBE  |.  64:8920  mov  dword ptr fs:[eax], esp  00493BC1  |.  8B45 F8  mov  eax, dword ptr [ebp-8]  00493BC4  |.  E8 CF0DF7FF  call  00404998 ;长度  00493BC9  |.  8945 F4  mov  dword ptr [ebp-C], eax  00493BCC  |.  837D F4 00  cmp  dword ptr [ebp-C], 0  00493BD0  |.  75 0D  jnz  short 00493BDF  00493BD2  |.  8D45 F8  lea  eax, dword ptr [ebp-8]  00493BD5  |.  BA C03C4900  mov  edx, 00493CC0  ;ASCII "Think Space"  00493BDA  |.  E8 990BF7FF  call  00404778  00493BDF  |>  33F6  xor  esi, esi  00493BE1  |.  BB 00010000  mov  ebx, 100  00493BE6  |.  8D45 F0  lea  eax, dword ptr [ebp-10]  00493BE9  |.  50  push  eax   ; /Arg1  00493BEA  |.  C745 E4 00010>mov  dword ptr [ebp-1C], 100;|  00493BF1  |.  C645 E8 00  mov  byte ptr [ebp-18], 0;|  00493BF5  |.  8D55 E4  lea  edx, dword ptr [ebp-1C];|  00493BF8  |.  33C9  xor  ecx, ecx;|  00493BFA  |.  B8 D43C4900  mov  eax, 00493CD4  ;|ASCII "%1.2x"  00493BFF  |.  E8 0461F7FF  call  00409D08  ; \WMAMP3Co.00409D08  看了这些代码后,似乎没有什么重要信息。但仔细跟踪后发现,数字0X100是很关键的。如何关键我们等下进行说明,现在我们F7继续下去。  00493C19  |> /8B45 FC  /mov  eax, dword ptr [ebp-4]  ;“)a6Fcw9K9h”  00493C1C  |. |8B55 EC  |mov  edx, dword ptr [ebp-14]  ;计数器  00493C1F  |. |0FB64410 FF  |movzx  eax, byte ptr [eax+edx-1]  ;取“)a6Fcw9K9h”相应位字符的ASCII  00493C24  |. |03C3  |add  eax, ebx  ;与上次运算结果相加  00493C26  |. |B9 FF000000  |mov  ecx, 0FF  00493C2B  |. |99  |cdq  00493C2C  |. |F7F9  |idiv  ecx  00493C2E  |. |8BDA  |mov  ebx, edx ;%模  00493C30  |. |3B75 F4  |cmp  esi, dword ptr [ebp-C]  00493C33  |. |7D 03  |jge  short 00493C38  00493C35  |. |46  |inc  esi  ;另一个计数器  00493C36  |. |EB 05  |jmp  short 00493C3D  00493C38  |> |BE 01000000  |mov  esi, 1  00493C3D  |> |8B45 F8  |mov  eax, dword ptr [ebp-8]  ;字符串“w9K9hokkienLb”  00493C40  |. |0FB64430 FF  |movzx  eax, byte ptr [eax+esi-1]  00493C45  |. |33D8  |xor  ebx, eax  00493C47  |. |8D45 E0  |lea  eax, dword ptr [ebp-20]  00493C4A  |. |50  |push  eax ; /Arg1  00493C4B  |. |895D E4  |mov  dword ptr [ebp-1C], ebx;|  00493C4E  |. |C645 E8 00  |mov  byte ptr [ebp-18], 0;|  00493C52  |. |8D55 E4  |lea  edx, dword ptr [ebp-1C];|  00493C55  |. |33C9  |xor  ecx, ecx;|  00493C57  |. |B8 D43C4900  |mov  eax, 00493CD4  ; |ASCII "%1.2x"  00493C5C  |. |E8 A760F7FF  |call  00409D08  00493C61  |. |8B55 E0  |mov  edx, dword ptr [ebp-20]  00493C64  |. |8D45 F0  |lea  eax, dword ptr [ebp-10]  00493C67  |. |E8 340DF7FF  |call  004049A0  00493C6C  |. |FF45 EC  |inc  dword ptr [ebp-14]  00493C6F  |. |4F  |dec  edi ;减1  00493C70  |.^\75 A7  \jnz  short 00493C19  上面的代码是注册码生成的关键!我们现在进行详细分析。首先取出“)a6Fcw9K9h”的相应位的ASCII,记为A1。然后(A1+上次运算的结果)%0XFF(特别的,第一次运算时,第一次结果设为0X100),所得结果为A2;接着,取出“w9K9hokkienLb”的相应位的ASCII,记为B1;最后,B1异或A2,所得的结果为本次运算的新结果。这样说估计比较难理解,那我们现在就用前几位运算来说明一下。  第一次运算:“)a6Fcw9K9h”的“)”的ASCII为0X29,0X29+0X100==0X129,然后,0X129%0XFF=0X2A。“w9K9hokkienLb”的w的ASCII为0X77,然后,0X77 XOR 0X2A=0X5D,则0X5D就是本次的运算结果。  第二次运算:“)a6Fcw9K9h”的“a”的ASCII为0X61,0X61+0X5D==0XBE,然后,0XBE%0XFF=0XBE。“w9K9hokkienLb”的9的ASCII为0X39,然后,0XBE XOR 0X39=0X87,则0X87就是本次的运算结果。  其他位的运算类似,我就不再细说了。最后我们得到由“)a6Fcw9K9h”和“w9K9hokkienLb”运算出来的16进制数字“5D87F64FE948F85BA6”,然后跟“100”合并为“1005D87F64FE948F85BA6”。那么这个字符串有什么作用呢?我们继续。  00494AFD  |.  50  push  eax  00494AFE  |.  8B03  mov  eax, dword ptr [ebx]  00494B00  |.  B9 05000000  mov  ecx, 5  00494B05  |.  BA 01000000  mov  edx, 1  00494B0A  |.  E8 E100F7FF  call  00404BF0  00494B0F  |.  FF75 E8  push  dword ptr [ebp-18]  00494B12  |.  68 A04B4900  push  00494BA0  00494B17  |.  8D45 E4  lea  eax, dword ptr [ebp-1C]  00494B1A  |.  50  push  eax  00494B1B  |.  8B03  mov  eax, dword ptr [ebx]  00494B1D  |.  B9 05000000  mov  ecx, 5  00494B22  |.  BA 06000000  mov  edx, 6  00494B27  |.  E8 C400F7FF  call  00404BF0  00494B2C  |.  FF75 E4  push  dword ptr [ebp-1C]  00494B2F  |.  68 A04B4900  push  00494BA0  00494B34  |.  8D45 E0  lea  eax, dword ptr [ebp-20]  00494B37  |.  50  push  eax  00494B38  |.  8B03  mov  eax, dword ptr [ebx]  00494B3A  |.  B9 05000000  mov  ecx, 5  00494B3F  |.  BA 0B000000  mov  edx, 0B  00494B44  |.  E8 A700F7FF  call  00404BF0  00494B49  |.  FF75 E0  push  dword ptr [ebp-20]  00494B4C  |.  8BC3  mov  eax, ebx  00494B4E  |.  BA 05000000  mov  edx, 5  00494B53  |.  E8 00FFF6FF  call  004047747.net8  00494B58  |.  33C0  xor  eax, eax  00494B5A  |.  5A  pop  edx  00494B5B  |.  59  pop  ecx  00494B5C  |.  59  pop  ecx  00494B5D  |.  64:8910  mov  dword ptr fs:[eax], edx  00494B60  |.  68 7A4B4900  push  00494B7A  00494B65  |>  8D45 E0  lea  eax, dword ptr [ebp-20]  00494B68  |.  BA 08000000  mov  edx, 8  00494B6D  |.  E8 92FBF6FF  call  00404704  00494B72  \.  C3  retn  看到上面这些代码,我们就明白了,这里还要进行进一步处理,即“1005D87F64FE948F85BA6”五个一组进行分组,分隔符为“-”,且注册码的形式为“XXXXX-XXXXX-XXXXX”,所以,我们可以得出注册名“hokkien”的注册码为“1005D-87F64-FE948”。赶紧注册下,呵呵,当然成功了。  注册机代码的编写  下面我们用C语言编写一个注册机。首先,应该进行运算准备,即获取类似“)a6Fcw9K9h”和“w9K9hokkienLb”的字符串。  char regcode[100]={0};  char str1[50];  char  str2[50];  char str3[50];  char str4[50];  char str5[50];  char len;  char retlen;  char newstr[50];  charregname[50];  char* strconst="Lb)a6Fcw9K9";  char *codecon="100";  printf("请输入你需要注册的用户名:");  scanf("%s",regname);  strcpy(newstr,regname);  strcat(newstr,strconst);  len=strlen(newstr);  retlen=len>>1;  strncpy(str1,newstr,retlen);//取回前retlen个字符  str1[retlen]='\0';  get_n_str(retlen,str2,newstr,len);  strcpy(str3,str2);  strcat(str3,str1);  strncpy(str4,str3,0x0a);  str4[0x0a]='\0';  get_n_str(6-1,str5,str3,len);  其中的函数get_n_str的原型是“void get_n_str(char n,char str[],char* constr,char strlen);”,功能是从字符串constr的第n位置开始把后面的字符全部复制给str。其实现代码如下:  void get_n_str(char n,char str[],char* constr,char strlen)// strlen是constr,的长度  {  for(int i=n;i<=strlen;i++)  str[i-n]=constr[i];  }  经过上面的代码,我们可以得到str4和str5,这是注册码生成的关键。下面的代码是对str4和str5进行运算从而生成注册码。  str4len=strlen(str4);  str5len=strlen(str5);  if(str4len<=str5len)  _strlen=str4len;  else  _strlen=str5len;  strcpy(regcode,codecon);  charstring[12];  unsigned char regtemp=((str4[0]+0x100)%0xFF)^(str5[0]);  char ctemp=0;  ultoa(regtemp,string,16);  strcat(regcode,string);  for(int i=1;i<_strlen;i++)  {  regtemp= ((regtemp+str4[i])%0xff)^(str5[i]);  ultoa(regtemp,string,16);  strcat(regcode,string);  }  printf(" ^_^恭喜你,你的注册码为:");  for(int n=0;n<15;n++)  {  printf("%C",(toupper(regcode[n])));  if(((n+1)%5==0)&(n+1)<15)  printf("-");  }  经过上面这段代码后,我们就可以得到注册码了。编译连接后运行,输入hokkien,得到的注册码正好是“1005D-87F64-FE948”,如图1所示。   图1  总结  新手朋友如果要顺利的进行算法分析,除了耐心外,最好掌握一门编程语言,并且善于应用,只有这样,算法分析和注册机的编写才能游刃有余。好了,就到这里,祝大家学习愉快
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部