• 标 题:Windows优化大师5.35
  • 作 者:trw2000
  • 时 间:2003/05/31 10:54pm 
  • 链 接:http://bbs.pediy.com

我不是高手,只是把自己的一点经验写出来与大家一起分享。
   制做注册机,关键是要找到加密运算的逆运算。破解一个程序时,反汇编代码是极容易得到的,而且我们必须通过分析反汇编代码来了解程序用了什么算法。当我们弄清了它的算法的时候,这些反汇编代码往往已经被我们熟知了。这时我们要求它的逆运算,我看还是修改反汇编代码最为直接。这样那些利用了寄存器特性的指令也可以很方便地求出逆运算。对原程序的成熟代码要尽可能利用,如果原代码太繁琐,在了解了其功能以后也可以自编代码。
   要想把反汇编代码修改成注册机源代码,首先必须获得加密运算中用到的所有代码包括所有子程序。然后要把反汇编代码分析透彻,知道它是一种什么算法,才能有针对性地求逆运算。这很重要,因为有的算法是无法直接得到逆运算的,如RSA,它的特点是,加密和解密可以用同一个函数,但所用的密钥不同,我们要求出解密密钥。
   Windows优化大师对申请码和第二、六注册码的计算及比较如下:
0167:0061422E  LEA      EAX,[EBP-04]<- 申请码
0167:00614231  MOV      EDX,00614394<- '1234567'的地址
0167:00614236  CALL     00612F7C<- 通过跟踪观察,可知这个子程序是把两个字符串相连接。
0167:0061423B  MOV      EAX,[EBP-04]
0167:0061423E  CALL     00612F74<- 执行完后eax=d,可见此call是求字符串长度
0167:00614243  TEST     EAX,EAXcall 612f74是求字符串长度
0167:00614245  JNS      0061424A<- 跳
0167:00614247  ADD      EAX,BYTE +07
0167:0061424A  SAR      EAX,03<- 右移三位得1
0167:0061424D  MOV      EDX,EAX
0167:0061424F  SHL      EDX,03<- 左移三位得8
0167:00614252  LEA      EAX,[EBP-04]<- [ebp-04]为2240020,这个地址处是'9787811234567'
0167:00614255  CALL     00613008<- 联系上下文,可知这个子程序是把字符串截成8位
0167:0061425A  XOR      ESI,ESI
0167:0061425C  LEA      EAX,[EBP-04]<- [ebp-04]为2240020,这个地址处'97878112'
0167:0061425F  CALL     00612FD0        <- 意义不明,但无影响
   通过分析可知,优化大师把申请码用"1234567"的前几位补成成8位,这一段再加上子程序会很长,在我们的注册机中不必完全照抄这些代码,自编出代码完成此功能即可,我编的代码如下,也可以完成此功能:
lea eax,APPH;申请码的地址
bits:inc ecx;
mov bl,BYTE ptr [eax+ecx]
test bl,bl
jnz bits;这段循环查看申请码的位数
cmp ecx,8;位数是否8?
jge app_cal
mov bl,31h;不足8位,用“1234567”的前几位来补足8位
add_bit:mov BYTE ptr [eax+ecx],bl
inc bl
inc ecx
cmp ecx,8
jl add_bit

   继续向下,主要的计算及比较如下:

0167:0061427F  MOV      EDX,EBX<- EBX中是“You are big pig”的地址,
0167:00614281  LEA      EAX,[EBP-1C]<- 这就是刚移出的“申请号97878112”
0167:00614284  CALL     00614170<- 根据“申请号”计算
...........
0167:006142B8  MOV      EAX,[EBP-10]<- 由第二注册码变来的16进制数
0167:006142BB  XOR      EDX,EDX
0167:006142BD  PUSH     EDX<- 0
0167:006142BE  PUSH     EAX<- 由第二注册码变来的16进制数
0167:006142BF  PUSH     DWORD [006150D0]<- 0
0167:006142C5  PUSH     DWORD [006150CC]<- 常数3b442af9
0167:006142CB  PUSH     DWORD [006150D8]<- 0
0167:006142D1  PUSH     DWORD [006150D4]<- 常数69aaa0e3
0167:006142D7  CALL     006140B8<- 进行rsa计算
0167:006142DC  SUB      EAX,BYTE +02<- 结果减2
0167:006142DF  MOV      [EBP-24],EAX<- 存入内存,设为数2

0167:006142E2  MOV      EAX,[EBP-0C]<- 由第六注册码变来的16进制数
0167:006142E5  XOR      EDX,EDX
0167:006142E7  PUSH     EDX<- 0
0167:006142E8  PUSH     EAX<- 由第六注册码变来的16进制数
0167:006142E9  PUSH     DWORD [006150D0]<- 0
0167:006142EF  PUSH     DWORD [006150CC]<- 常数3b442af9
0167:006142F5  PUSH     DWORD [006150D8]<- 0
0167:006142FB  PUSH     DWORD [006150D4]<- 常数69aaa0e3
0167:00614301  CALL     006140B8<- 进行rsa计算
0167:00614306  SUB      EAX,BYTE +02<- 结果减2
0167:00614309  MOV      [EBP-20],EAX<- 存入内存

0167:0061430C  SHL      DWORD [EBP-24],02<- 数2左移2位
0167:00614310  LEA      ECX,[EBP-24]<- 数2的地址
0167:00614313  MOV      EAX,[ECX]<- 取出数2
0167:00614315  MOV      EDX,[ECX+04]<- 取出数3
0167:00614318  SHRD     EAX,EDX,02<- 数2、数3联合移位,数2改变,数3不变
0167:0061431C  SHR      EDX,02<- 数3右移2位
0167:0061431F  MOV      [ECX],EAX<- 数2放入内存
0167:00614321  MOV      [ECX+04],EDX<- 数3放入内存
0167:00614324  MOV      EAX,[EBP-24]<- 取出数2
0167:00614327  CMP      EAX,[EBP-1C]<- 与根据申请码计算的数1的低32位比较
0167:0061432A  JZ       00614330<- 相等时跳转,去取出数3的低16位存在一个地方(83f30a)
0167:0061432C  XOR      EBX,EBX;移位结果可使第二注册码结果的最低两位替换第一注册码结果的最高两位,第二注册码结果右移两位,高位补0
0167:0061432E  JMP      SHORT 00614341
0167:00614330  MOV      AX,[EBP-20]<- 取出数3的低16位,返回上一级子程序后比较它是否14H。
   通过分析,这一段求逆不是很困难,我编的逆运算如下:
app_cal:lea eax,APPH;装入申请码的地址
call appcode;对申请码计算,结果存在申请码处

mov eax,APPH;申请码计算结果的高32位
mov edx,14h
shld edx,eax,2;联合左移,edx变,eax不变,eax的最高两位移到edx的最低两位,edx中原数顺次左移两位
shl eax,2;
shr eax,2;先左移1位,再右移1位也行,目的是把最高位即符号位清0

add eax,2
add edx,2
mov DWORD ptr REG2,eax;这两个数再进行rsa计算就是注册码了
mov DWORD ptr REG6,edx;

MOV EAX,DWORD PTR REG2    ;由申请码算出的未进行rsa计算的第二注册码
XOR EDX,EDX
PUSH EDX
PUSH EAX
PUSH 0
PUSH 2C86F9h;解密密钥d;加密密钥为3b442af9h
PUSH 0;解密密钥是另外编程求出的。
PUSH 69aaa0e3h;密钥n
CALL rsa;进行rsa计算
MOV DWORD PTR REG2,EAX;保存第一注册码

MOV EAX,DWORD PTR REG6;由申请码算出的未进行rsa计算的第六注册码
XOR EDX,EDX
PUSH EDX
PUSH EAX
PUSH 0
PUSH 2C86F9h;解密密钥d;加密密钥为33b442af9h
PUSH 0
PUSH 69aaa0e3h;密钥n
CALL rsa;进行rsa计算
MOV DWORD PTR REG6,EAX;保存第二注册码

   Windows优化大师对跟进申请码进行计算的子程序,直接dump出的代码如下:

00614170  PUSH EBX
00614171  PUSH ESI
00614172  PUSH EDI
00614173  PUSH ECX
00614174  MOV DWORD PTR SS:[ESP],EAX
00614177  MOV EAX,20
0061417C  MOV ECX,DWORD PTR SS:[ESP]
0061417F  MOV ECX,DWORD PTR DS:[ECX]
00614181  MOV EBX,DWORD PTR SS:[ESP]
00614184  MOV EBX,DWORD PTR DS:[EBX+4]
00614187  XOR ESI,ESI
00614189  DEC EAX
0061418A  ADD ESI,DWORD PTR DS:[6150C8]
00614190  MOV EDI,EBX
00614192  SHL EDI,4
00614195  ADD ECX,EDI
00614197  MOV EDI,DWORD PTR DS:[EDX]
00614199  XOR EDI,EBX
0061419B  ADD ECX,EDI
0061419D  MOV EDI,EBX
0061419F  SHR EDI,5
006141A2  XOR EDI,ESI
006141A4  ADD ECX,EDI
006141A6  ADD ECX,DWORD PTR DS:[EDX+4]
006141A9  MOV EDI,ECX
006141AB  SHL EDI,4
006141AE  ADD EBX,EDI
006141B0  MOV EDI,DWORD PTR DS:[EDX+8]
006141B3  XOR EDI,ECX
006141B5  ADD EBX,EDI
006141B7  MOV EDI,ECX
006141B9  SHR EDI,5
006141BC  XOR EDI,ESI
006141BE  ADD EBX,EDI
006141C0  ADD EBX,DWORD PTR DS:[EDX+C]
006141C3  TEST EAX,EAX
006141C5  JA SHORT 00614189
006141C7  MOV EAX,DWORD PTR SS:[ESP]
006141CA  MOV DWORD PTR DS:[EAX],ECX
006141CC  MOV EAX,DWORD PTR SS:[ESP]
006141CF  MOV DWORD PTR DS:[EAX+4],EBX
006141D2  POP EDX
006141D3  POP EDI
006141D4  POP ESI
006141D5  POP EBX
006141D6  RETN

   这段代码不用求逆,其是0061418A行用到了直接寻址方式,我们把它改作立即数,修改后的代码如下:

appcode:PUSH EBX
PUSH ESI
PUSH EDI
PUSH ECX
lea edx,STRING;"You are big pig."的地址
MOV DWORD PTR SS:[ESP],EAX
MOV EAX,20h
MOV ECX,DWORD PTR SS:[ESP];申请码地址放入ecx
MOV ECX,DWORD PTR DS:[ECX];申请码前4位放入ecx
MOV EBX,DWORD PTR SS:[ESP];申请码地址放入ebx
MOV EBX,DWORD PTR DS:[EBX+4];申请码后4位放入ebx
XOR ESI,ESI
j614189:DEC EAX
ADD ESI,9e3779b9h;DWORD PTR DS:[6150C8]
MOV EDI,EBX
SHL EDI,4
ADD ECX,EDI
MOV EDI,DWORD PTR DS:[EDX]
XOR EDI,EBX
ADD ECX,EDI
MOV EDI,EBX
SHR EDI,5
XOR EDI,ESI
ADD ECX,EDI
ADD ECX,DWORD PTR DS:[EDX+4]
MOV EDI,ECX
SHL EDI,4
ADD EBX,EDI
MOV EDI,DWORD PTR DS:[EDX+8]
XOR EDI,ECX
ADD EBX,EDI
MOV EDI,ECX
SHR EDI,5
XOR EDI,ESI
ADD EBX,EDI
ADD EBX,DWORD PTR DS:[EDX+0Ch]
TEST EAX,EAX
JA j614189
MOV EAX,DWORD PTR SS:[ESP]
MOV DWORD PTR DS:[EAX],ECX
MOV EAX,DWORD PTR SS:[ESP]
MOV DWORD PTR DS:[EAX+4],EBX
POP EDX
POP EDI
POP ESI
POP EBX
RETN
   
   对注册码使用了RSA算法,它有个特点,加密和解密可以用同一个函数。这样实现RSA算法的代码我们就不用编了,直接“以子之矛,攻子之盾”,我们只需把关键的密钥算出来代入即可。因此RSA运算的代码完全取自Windows优化大师,只做标号和个别语法的修改即可。(代码较长,此处略)
   对另四个码的运算如下:
004E99C1  |.>MOV EAX,DWORD PTR DS:[EDI+CC]    8E4B1B2B
004E99C7  |.>SUB DWORD PTR SS:[ESP+C],EAX     第3码-8E4B1B2B
004E99CB  |.>MOV EAX,DWORD PTR DS:[EDI+C8]    AC0AF08E
004E99D1  |.>SUB DWORD PTR SS:[ESP+4],EAX     第1码-AC0AF08E
004E99D5  |.>MOV ESI,14     设定循环次数
004E99DA  |>>/MOV EBX,DWORD PTR SS:[ESP+4]  
004E99DE  |.>|MOV EAX,DWORD PTR SS:[ESP+10]  
004E99E2  |.>|MOV DWORD PTR SS:[ESP+4],EAX   第4码代替第1码
004E99E6  |.>|MOV EAX,DWORD PTR SS:[ESP+C]  
004E99EA  |.>|MOV DWORD PTR SS:[ESP+10],EAX  第3码代替第4码
004E99EE  |.>|MOV EAX,DWORD PTR SS:[ESP+8]  
004E99F2  |.>|MOV DWORD PTR SS:[ESP+C],EAX   第2码代替第3码
004E99F6  |.>|MOV DWORD PTR SS:[ESP+8],EBX   第1码代替第2码
004E99FA  |.>|MOV EAX,DWORD PTR SS:[ESP+10]
004E99FE  |.>|ADD EAX,EAX  第4码乘以2
004E9A00  |.>|INC EAX      再加1
004E9A01  |.>|IMUL DWORD PTR SS:[ESP+10] 再乘以第4码
004E9A05  |.>|MOV EDX,5
004E9A0A  |.>|CALL WIN优化?004E9744  带进位循环左移
004E9A0F  |.>|MOV EBP,EAX   结果暂存到ebp
004E9A11  |.>|MOV EAX,DWORD PTR SS:[ESP+8]
004E9A15  |.>|ADD EAX,EAX  第2码乘以2
004E9A17  |.>|INC EAX      再加1
004E9A18  |.>|IMUL DWORD PTR SS:[ESP+8] 再乘以第2码
004E9A1C  |.>|MOV EDX,5
004E9A21  |.>|CALL WIN优化?004E9744  带进位循环左移
004E9A26  |.>|MOV EBX,EAX   结果暂存到ebx
004E9A28  |.>|MOV EAX,ESI   循环次数
004E9A2A  |.>|ADD EAX,EAX   乘以2
004E9A2C  |.>|PUSH DWORD PTR DS:[EDI+EAX*4+24]
004E9A30  |.>|MOV EAX,DWORD PTR SS:[ESP+10]  第4码
004E9A34  |.>|POP EDX
004E9A35  |.>|SUB EAX,EDX
004E9A37  |.>|MOV EDX,EBX
004E9A39  |.>|CALL WIN优化?004E9758     带进位循环右移
004E9A3E  |.>|XOR EAX,EBP
004E9A40  |.>|MOV DWORD PTR SS:[ESP+C],EAX
004E9A44  |.>|MOV EAX,ESI
004E9A46  |.>|ADD EAX,EAX
004E9A48  |.>|PUSH DWORD PTR DS:[EDI+EAX*4+20]
004E9A4C  |.>|MOV EAX,DWORD PTR SS:[ESP+8]
004E9A50  |.>|POP EDX
004E9A51  |.>|SUB EAX,EDX
004E9A53  |.>|MOV EDX,EBP
004E9A55  |.>|CALL WIN优化?004E9758     带进位循环右移
004E9A5A  |.>|XOR EBX,EAX
004E9A5C  |.>|MOV DWORD PTR SS:[ESP+4],EBX
004E9A60  |.>|DEC ESI
004E9A61  |.>|TEST ESI,ESI
004E9A63  |.>\JNZ WIN优化?004E99DA  
004E9A69  |.>MOV EAX,DWORD PTR DS:[EDI+24]
004E9A6C  |.>SUB DWORD PTR SS:[ESP+10],EAX
004E9A70  |.>MOV EAX,DWORD PTR DS:[EDI+20]
004E9A73  |.>SUB DWORD PTR SS:[ESP+8],EAX   这一步执行后,结果就完全形成了
返回后检查第三、四注册码是否为:8AEB53C2-F137E07C

   这是RC6运算,仔细分析此程序,可以编出逆运算如下:

MOV EAX,DWORD PTR DS:[EDI+24H]
add DWORD PTR SS:[ESP+10H],EAX
MOV EAX,DWORD PTR DS:[EDI+20H]
add DWORD PTR SS:[ESP+8],EAX  
MOV ESI,14H;设定循环次数
E99DA:
MOV EAX,DWORD PTR SS:[ESP+10H]
ADD EAX,EAX;第4码乘以2
INC EAX;再加1
IMUL DWORD PTR SS:[ESP+10H];再乘以第4码
ROL EAX,5;带进位循环左移
MOV EBP,EAX;结果暂存到ebp

MOV EAX,DWORD PTR SS:[ESP+8]
ADD EAX,EAX;第2码乘以2
INC EAX;再加1
IMUL DWORD PTR SS:[ESP+8];再乘以第2码
ROL EAX,5;带进位循环左移
MOV EBX,EAX;结果暂存到ebx

MOV EAX,DWORD PTR SS:[ESP+0cH];第3码
XOR EAX,EBP;与第四码的结果异或
MOV ECX,EBX;第二码的结果
ROL EAX,CL;带进位循环右移
MOV DWORD PTR SS:[ESP+0CH],EAX;存回第三码处
mov eax,15h
sub EAX,ESI;循环次数
add eax,eax;乘以2
mov edx,DWORD PTR DS:[EDI+EAX*4+24H]
MOV EAX,DWORD PTR SS:[ESP+0cH];第3码
add EAX,EDX
MOV DWORD PTR SS:[ESP+0CH],EAX;存回第三码处

MOV EAX,DWORD PTR SS:[ESP+04h];第一码
XOR EAX,EBX;与第二码的结果异或
MOV ECX,EBP;第四码的结果
ROL EAX,CL;带进位循环右移
MOV DWORD PTR SS:[ESP+04h],EaX  ;存回第一码处
mov eax,15h
sub eax,esi
add eax,eax
mov edx, DWORD PTR DS:[EDI+EAX*4+20H]
MOV EAX,DWORD PTR SS:[ESP+04h];第一码
add EAX,EDX
MOV DWORD PTR SS:[ESP+04h],EaX  ;存回第一码处

MOV EBX,DWORD PTR SS:[ESP+4]    ;a
MOV EAX,DWORD PTR SS:[ESP+8H]   ;b
MOV DWORD PTR SS:[ESP+4],EAX;a=b
MOV EAX,DWORD PTR SS:[ESP+0CH]  
MOV DWORD PTR SS:[ESP+8H],EAX;b=c
MOV EAX,DWORD PTR SS:[ESP+10h]  
MOV DWORD PTR SS:[ESP+0CH],EAX;c=d
MOV DWORD PTR SS:[ESP+10h],EBX;d=a

DEC ESI
TEST ESI,ESI
JNZ E99DA  

MOV EAX,DWORD PTR DS:[EDI+0CCH];从一个表里取数,8E4B1B2B
add DWORD PTR SS:[ESP+0CH],EAX;第3码-8E4B1B2B
MOV EAX,DWORD PTR DS:[EDI+0C8H];AC0AF08E
add DWORD PTR SS:[ESP+4],EAX;第1码-AC0AF08E

   到此,关键的算法已经获得,然后要把密码表写到注册机源代码中去。以下要找一个汇编语言的开发系统和一个注册机模板。我用的开发系统是Masm for EditPlus,模板是KeyMake的注册机模板,这个模板用EditPlus来编译时需要修改一些地方。
   用汇编语言写注册机涉及的环节很多,在这里不能一一列举,读者如遇到困难可以问我,我会给予答复的。