适合对象:想进阶的菜鸟,初次接触算法的同志。
使用工具:ollydbg,vc++(编写注册机)


个人觉得算法分析有2个难点
1.定位-那里是关键算法
2.算法的复杂程度

对于第1点,我们发现F8走过0059A1B9的call之后出现了注册码,而此前没有看到,故推测此call为
关键算法call。这样就定位了。
对于第2点就要慢慢看代码了。

暴破Word文档资料管理系统比较简单,这里节省篇幅就不说了(话外:如果你还不会暴破,请跳过这篇文章)
废话少说了,直接开始分析代码:

0059A199  |.  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]             ;  eax指向输入的注册码
0059A19C  |.  50            PUSH EAX                                 ;  保存指向注册码的指针
0059A19D  |.  8D55 F4       LEA EDX,DWORD PTR SS:[EBP-C]
0059A1A0  |.  A1 A06F5A00   MOV EAX,DWORD PTR DS:[5A6FA0]
0059A1A5  |.  8B00          MOV EAX,DWORD PTR DS:[EAX]
0059A1A7  |.  E8 FC0B0000   CALL DMS.0059ADA8                        ;  取机器码
0059A1AC  |.  8B55 F4       MOV EDX,DWORD PTR SS:[EBP-C]             ;  edx指向机器码
0059A1AF  |.  8D4D F8       LEA ECX,DWORD PTR SS:[EBP-8]
0059A1B2  |.  A1 A06F5A00   MOV EAX,DWORD PTR DS:[5A6FA0]
0059A1B7  |.  8B00          MOV EAX,DWORD PTR DS:[EAX]
0059A1B9  |.  E8 B20C0000   CALL DMS.0059AE70                        ;  产生注册码,随后进入分析
0059A1BE  |.  8B55 F8       MOV EDX,DWORD PTR SS:[EBP-8]
0059A1C1  |.  58            POP EAX
0059A1C2  |.  E8 A5ABE6FF   CALL DMS.00404D6C                        ;  关键比较call
0059A1C7  |.  0F85 B1000000 JNZ DMS.0059A27E                         ;  跳到注册码出错处理部分!


进入0059A1B9处的CALL DMS.0059AE70    

0059AE91  |.  BB 9F860100   MOV EBX,1869F                            ;  注意这里MOV EBX,1869F, 1869F是固定的
0059AE96  |.  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
0059AE99  |.  E8 829DE6FF   CALL DMS.00404C20                        ;  返回注册码长度
0059AE9E  |.  85C0          TEST EAX,EAX           ;  嘿嘿,没有输入  ?
0059AEA0  |.  7E 19         JLE SHORT DMS.0059AEBB         ;  跳就牺牲了
0059AEA2  |.  BA 01000000   MOV EDX,1             ;  初始化
0059AEA7  |>  8B4D FC       /MOV ECX,DWORD PTR SS:[EBP-4]            ;  ecx指向机器码
0059AEAA  |.  0FB64C11 FF   |MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]       ;  取一位机器码的asc码
0059AEAF  |.  03D9          |ADD EBX,ECX                             ;  逐位加上机器码的asc码
0059AEB1  |.  81C3 06020000 |ADD EBX,206                             ;  求和(加上0x206),结果保存在EBX
0059AEB7  |.  42            |INC EDX             ;  指向下一位
0059AEB8  |.  48            |DEC EAX                                 ;  长度减1,即循环次数减1
0059AEB9  |.^ 75 EC         \JNZ SHORT DMS.0059AEA7         ;  还没有完?继续循环
0059AEBB  |>  8BD6          MOV EDX,ESI
0059AEBD  |.  8BC3          MOV EAX,EBX                              ;  保存结果



以下我是用c++写的注册机,仅供研究之用,请勿非法传播,研究完,请删除。
请支持共享软件。

//Word文档资料管理系统 注册机
//vc++ 6.0, windows xp sp2编译通过
#include <iostream>

using std::cout;
using std::cin;
using std::endl;

int main()
{
  char code[20];

  cout << "please input the code: ";
  cin >> code;
  int sum = 0x1869f;    //对应程序的  MOV EBX,1869F

  int length = strlen(code);    //对应程序的 CALL 00404C20  ;返回注册码长度

  for (int i = 0; i < length; i++)
  {
    sum += code[i];      //对应  ADD EBX,ECX
    sum += 0x206;      //对应  ADD EBX,206 
  //  sum = sum + code[i] + 0x206;  //可以直接用这局代替
  }

/*上面的 for 循环对应如下的代码:请初学者仔细分析
      
      MOV EDX,1
      MOV ECX,DWORD PTR SS:[EBP-4]            ;  ecx指向机器码
      MOVZX ECX,BYTE PTR DS:[ECX+EDX-1]       ;  取一位机器码的asc码
      ADD EBX,ECX                             ;  逐位加上机器码的asc码
      ADD EBX,206                             ;  求和,结果保存在EBX
      INC EDX          ;  指向下一位机器码
      DEC EAX                                 ;  长度减 1即循环次数减 1
      JNZ SHORT DMS.0059AEA7      ;  不为 0 继续循环
*/
//      MOV EDX,ESI
//      MOV EAX,EBX        ;结果保存到EAX,一般是函数的返回值

  cout << endl;
  cout << "The register code is: " << sum << endl;
  system(" pause ");

  return 0;
}

运行注册机,输入机器码,看看计算结果吧:103410
输入103410看看,注册成功

程序将运行次数和注册码写入注册表,有兴趣请自行跟踪,部分代码如下:

0059A207  |>  BA E4A25900   MOV EDX,DMS.0059A2E4                     ;  ASCII "SOFTWARE\wjsh"
0059A20C  |.  8BC3          MOV EAX,EBX
0059A20E  |.  E8 019FEAFF   CALL DMS.00444114
0059A213  |.  B1 01         MOV CL,1
0059A215  |.  BA E4A25900   MOV EDX,DMS.0059A2E4                     ;  ASCII "SOFTWARE\wjsh"
0059A21A  |.  8BC3          MOV EAX,EBX
0059A21C  |.  E8 CF9FEAFF   CALL DMS.004441F0
0059A221  |.  B9 C3FFFFFF   MOV ECX,-3D
0059A226  |.  BA FCA25900   MOV EDX,DMS.0059A2FC                     ;  ASCII "run_times"
0059A22B  |.  8BC3          MOV EAX,EBX
0059A22D  |.  E8 B6A3EAFF   CALL DMS.004445E8
0059A232  |>  8D55 F0       LEA EDX,DWORD PTR SS:[EBP-10]
0059A235  |.  8B86 04030000 MOV EAX,DWORD PTR DS:[ESI+304]
0059A23B  |.  E8 C445ECFF   CALL DMS.0045E804
0059A240  |.  8B4D F0       MOV ECX,DWORD PTR SS:[EBP-10]
0059A243  |.  BA 10A35900   MOV EDX,DMS.0059A310                     ;  ASCII "regist_code"
0059A248  |.  8BC3          MOV EAX,EBX
0059A24A  |.  E8 F5A2EAFF   CALL DMS.00444544
0059A24F  |.  8BC3          MOV EAX,EBX
0059A251  |.  E8 2A9EEAFF   CALL DMS.00444080
0059A256  |.  8BC3          MOV EAX,EBX
0059A258  |.  E8 0F98E6FF   CALL DMS.00403A6C
0059A25D  |.  B8 24A35900   MOV EAX,DMS.0059A324
0059A262  |.  E8 3D0CEAFF   CALL DMS.0043AEA4                        ;  提示出错了


打开注册表对应位置可以找到找到:
[HKEY_LOCAL_MACHINE\SOFTWARE\wjsh]
"run_times"=dword:ffffffc7
"regist_code"="103410"

文章比较短,请我等菜鸟自己练习。