某输入通1.34注册算法分析
软件网站:http://openinput.126.com/
破解工具:TRW
作者:Maomao[CCG]
日期:2002-7-15
软件介绍:
**输入通是一个综合性的、能够满足用户多种输入要求的软件,用户即可以挂接任意的形码方案作为形码输入法,如五笔输入,也可以用作拼音输入法,拼音输入支持字、词、句间的无缝转换,系统会根据用户输入的拼音由一定的算法自动选出最可能的汉字,免去用户逐字逐词进行选择的麻烦,提高了拼音输入的效率。
声明:
这款软件是国产软件输入法中比较优秀的软件之一,注册费用也比较合理,希望大家支持国产软件。本人写此文的目的仅在于帮助大家提高程序分析的能力,希望大家理解支持配合.
打开此输入法,选择注册,任意输入29位注册码,下断点bpx hmemcpy,然后按“注册”,程序中断,按几次F12和F10(用pmodule会失败),会来到Zwsrt的领空,这时会看到下面的代码:
0177:00C0E95F PUSH BYTE +01
0177:00C0E961
PUSH EAX <=====假码
0177:00C0E962 CALL
00C0E3A0<======注册算法的call
0177:00C0E967 LEA
ECX,[ESP+0C]
0177:00C0E96B MOV [00C2B33A],EAX
<===EAx是返回值
0177:00C0E970 PUSH ECX
0177:00C0E971
PUSH DWORD 80000002
0177:00C0E976 CALL 00C014C0
0177:00C0E97B TEST EAX,EAX <=====这里比较
0177:00C0E97D JZ 00C0E994 <=====跳走就完了
用F8跟进C0E962 的call,一路无话,来到这里:
0177:00C0E431 MOV
AX,[EBP+00]<====EBP开始的内存中存放的就是机器码了,每四位一段,共六段,十六进制,这里取第一段的四位数
0177:00C0E435 SHL EAX,1 2 <====左移一位,相当于乘以2
0177:00C0E437 MOV [ESP+10],EAX
0177:00C0E43B
MOV [EBP+00],AX<====低四位放回
0177:00C0E43F XOR
EAX,EAX
0177:00C0E441 MOV AX,[EBP+02]
<====取第二段
0177:00C0E445 LEA EAX,[EAX+EAX*2]<====乘以3
0177:00C0E448 SHL EAX,1<====再左移一位(乘以2)
0177:00C0E44A MOV [ESP+10],EAX
0177:00C0E44E
MOV [EBP+02],AX<====低四位放回(相当于乘以6,取低四位)
0177:00C0E452
XOR EAX,EAX
0177:00C0E454 MOV
AX,[EBP+04]<====取第三段
0177:00C0E458 LEA EAX,[EAX+EAX*4]<====乘以5
0177:00C0E45B MOV [ESP+10],EAX
0177:00C0E45F
MOV [EBP+04],AX<====低四位放回
0177:00C0E463 XOR
EAX,EAX
0177:00C0E465 MOV AX,[EBP+06]<====取第四段
0177:00C0E469 SHL EAX,02<====再左移二位(乘以4)
0177:00C0E46C MOV [ESP+10],EAX
0177:00C0E470
MOV [EBP+06],AX<====低四位放回
0177:00C0E474 XOR
EAX,EAX
0177:00C0E476 MOV AX,[EBP+08]<====取第五段
0177:00C0E47A LEA EAX,[EAX+EAX*8]<====乘以9
0177:00C0E47D MOV [ESP+10],EAX
0177:00C0E481
MOV [EBP+08],AX<====低四位放回
0177:00C0E485 XOR
EAX,EAX
0177:00C0E487 MOV AX,[EBP+0A]<====取第六段
0177:00C0E48B LEA ECX,[EAX*8+00000000]<====乘以8
0177:00C0E492 SUB ECX,EAX<====再减去自己(相当于完成乘以7)
0177:00C0E494 XOR EAX,EAX
0177:00C0E496
MOV [ESP+10],ECX
0177:00C0E49A MOV
AX,[EBP+00]<====取第一段运算结果
0177:00C0E49E MOV
[EBP+0A],CX <====低四位放回
0177:00C0E4A2 MOV ECX,EAX
0177:00C0E4A4 MOV EAX,[ESP+10]
0177:00C0E4A8
AND EAX,FFFF <====取得第六段运算结果
0177:00C0E4AD
LEA EDX,[EAX+EAX*2]<====第六段*3
0177:00C0E4B0
LEA EAX,[EDX+ECX*2]<==== 加 第一段*2
0177:00C0E4B3
MOV [ESP+10],EAX
0177:00C0E4B7 MOV
[EBP+0A],AX<====低四位放回第六段
0177:00C0E4BB XOR
EAX,EAX
0177:00C0E4BD XOR ECX,ECX
0177:00C0E4BF
MOV AX,[EBP+04]<====取第三段运算结果
0177:00C0E4C3 MOV
CX,[EBP+08]<====取第五段运算结果
0177:00C0E4C7 LEA
EAX,[ECX+EAX*2]<====第五段+第三段*2
0177:00C0E4CA MOV
[ESP+10],EAX
0177:00C0E4CE MOV [EBP+08],AX<====低四位放回第五段
0177:00C0E4D2 CMP [ESP+80],EBX
0177:00C0E4D9
JZ NEAR 00C0E5EA
小结:
假设我的机器码是:38DF-F3D0-D5CE-C4C4-7D81-5874
从左往右依次为第 ① ② ③ ④ ⑤ ⑥ 段保存于EBP中,上面这段程序完成以下的运行:
①=(①*2)&0xffff
②=(②*6)&0xffff
③=(③*5)&0xffff
④=(④*4)&0xffff
⑤=((⑤*9)&0xffff+③*2)&0xffff
⑥=((⑥*7)&0xffff+①*2)&0xffff
这样六段合起来就是注册码了,但没有任何迹像表明这就是注册码,因为下面还有一大段代码,比较有意思,是校验:
0177:00C0E5FA
MOV EDX,[ESP+18]
0177:00C0E5FE LEA
EDI,[ESP+40]
0177:00C0E602 OR ECX,BYTE -01
0177:00C0E605 XOR EAX,EAX
0177:00C0E607
LEA ESI,[ESP+2C]
0177:00C0E60B REPNE SCASB
0177:00C0E60D NOT ECX
0177:00C0E60F SUB
EDI,ECX
0177:00C0E611 MOV [ESP+20],ESI
0177:00C0E615 MOV EAX,ECX
0177:00C0E617
MOV ESI,EDI
0177:00C0E619 MOV
EDI,[ESP+20]
0177:00C0E61D SHR ECX,02
0177:00C0E620
REP MOVSD
0177:00C0E622 MOV ECX,EAX
0177:00C0E624
AND ECX,BYTE +03
0177:00C0E627 CMP
EBX,BYTE +02<======EBX是计数器,记录上次操作的段
0177:00C0E62A REP MOVSB
0177:00C0E62C JNL 00C0E63C<===========如果当前操作的段>2,则跳到下面转换
0177:00C0E62E LEA ECX,[ESP+24]
0177:00C0E632
XOR EAX,EAX
0177:00C0E634 MOV
AX,[EDX]<==========不转换(1、2段)
0177:00C0E637 PUSH BYTE
+10
0177:00C0E639 PUSH ECX
0177:00C0E63A JMP
SHORT 00C0E653
0177:00C0E63C MOV
AX,[EDX] <==========3-6段需要转换
0177:00C0E63F LEA
ECX,[ESP+24]
0177:00C0E643 IMUL AX,AX,BYTE +39<============乘以0x39
0177:00C0E647 AND EAX,FFFF<============取低四位
0177:00C0E64C PUSH BYTE +10
0177:00C0E64E MOV
[ESP+14],EAX
0177:00C0E652 PUSH ECX
0177:00C0E653 PUSH EAX
0177:00C0E654 CALL
`MSVCRT!_ltoa`<============转成字符串
0177:00C0E65A OR
ECX,BYTE -01
0177:00C0E65D LEA EDI,[ESP+30]
0177:00C0E661 XOR EAX,EAX
0177:00C0E663
ADD ESP,BYTE +0C
0177:00C0E666 REPNE SCASB
0177:00C0E668 NOT ECX
0177:00C0E66A DEC
ECX
0177:00C0E66B LEA EDI,[ESP+45]
0177:00C0E66F MOV EDX,ECX
0177:00C0E671
OR ECX,BYTE -01
0177:00C0E674 REPNE SCASB
0177:00C0E676 NOT ECX
0177:00C0E678 SUB
EDI,ECX
0177:00C0E67A LEA ESI,[ESP+EDX+24]
0177:00C0E67E MOV EAX,ECX
0177:00C0E680
MOV [ESP+20],ESI
0177:00C0E684 MOV
ESI,EDI
0177:00C0E686 MOV EDI,[ESP+20]
0177:00C0E68A SHR ECX,02
0177:00C0E68D REP
MOVSD
0177:00C0E68F MOV ECX,EAX
0177:00C0E691
MOV EAX,04
0177:00C0E696 AND
ECX,BYTE +03
0177:00C0E699 SUB EAX,EDX
0177:00C0E69B
REP MOVSB
0177:00C0E69D MOV [ESP+10],EAX
0177:00C0E6A1
LEA EDX,[ESP+EAX+2C]
0177:00C0E6A5 LEA
EDI,[ESP+24]
0177:00C0E6A9 OR ECX,BYTE -01
0177:00C0E6AC XOR EAX,EAX
0177:00C0E6AE
REPNE SCASB
0177:00C0E6B0 NOT ECX
0177:00C0E6B2
SUB EDI,ECX
0177:00C0E6B4 MOV
EAX,ECX
0177:00C0E6B6 MOV ESI,EDI
0177:00C0E6B8
MOV EDI,EDX
0177:00C0E6BA SHR
ECX,02
0177:00C0E6BD REP MOVSD
0177:00C0E6BF MOV
ECX,EAX
0177:00C0E6C1 XOR EAX,EAX
0177:00C0E6C3
AND ECX,BYTE +03
0177:00C0E6C6 REP MOVSB
0177:00C0E6C8
LEA EDI,[ESP+2C]
0177:00C0E6CC OR
ECX,BYTE -01
0177:00C0E6CF REPNE SCASB
0177:00C0E6D1
MOV EAX,[ESP+1C]
0177:00C0E6D5 NOT
ECX
0177:00C0E6D7 SUB EDI,ECX
0177:00C0E6D9
MOV EDX,ECX
0177:00C0E6DB MOV
ESI,EDI
0177:00C0E6DD MOV EDI,EAX
0177:00C0E6DF
ADD EAX,BYTE +05
0177:00C0E6E2 SHR
ECX,02
0177:00C0E6E5 REP MOVSD
0177:00C0E6E7 MOV
ECX,EDX
0177:00C0E6E9 MOV [ESP+1C],EAX
0177:00C0E6ED AND ECX,BYTE +03
0177:00C0E6F0
INC EBX
0177:00C0E6F1 REP MOVSB
以上这些代码完成各段的变换(3-6段*0x39),再转成字符串,不足四位高位补0,并连接
0177:00C0E6F3
MOV ECX,[ESP+18]
0177:00C0E6F7 ADD
ECX,BYTE +02
0177:00C0E6FA CMP EBX,BYTE
+06
0177:00C0E6FD MOV [ESP+18],ECX
0177:00C0E701
JL NEAR 00C0E5FA<============取下一段进行运算
0177:00C0E707
LEA EAX,[ESP+54]
0177:00C0E70B MOV
BYTE [ESP+71],00
0177:00C0E710 PUSH EAX<============全部转换好的SN(小写)
0177:00C0E711 MOV DWORD [00C291C0],1234
0177:00C0E71B
CALL `USER32!CharUpperA`<============转成大写
如果你到这里看到注册码,以为成功,那就大错特错了!这是作者的高明之处。暂且把这里
得到串叫做校验码1。
接下来这段将得到的正确注册进行如下变换,得到校验码2。
0177:00C0E759
MOV EAX,EBP
0177:00C0E75B MOV
ECX,06
0177:00C0E760 ADD WORD [EAX],BYTE +34<====每段+0x34
0177:00C0E764 ADD EAX,BYTE +02
0177:00C0E767
DEC ECX
0177:00C0E768 JNZ 00C0E760
0177:00C0E7A8 MOV EAX,EBP
0177:00C0E7AA
MOV ECX,06
0177:00C0E7AF ADD
WORD [EAX],0200<====每段+0x200
0177:00C0E7B4 ADD
EAX,BYTE +02
0177:00C0E7B7 DEC ECX
0177:00C0E7B8
JNZ 00C0E7AF
这里开始校验了:
0177:00C0E7BA
MOV EBX,[00C211D8]
0177:00C0E7C0 XOR
ESI,ESI
0177:00C0E7C2 MOV EDI,EDX
0177:00C0E7C4
MOV AX,[EBP+00]<=======校验码2
0177:00C0E7C8 ADD
AX,1000<=======加0x1000
0177:00C0E7CC CMP
ESI,BYTE +02<=======第1、2段不比较
0177:00C0E7CF MOV
[EBP+00],AX
0177:00C0E7D3 JNL 00C0E7E5<=======跳到校验
0177:00C0E7D5 AND EAX,FFFF
0177:00C0E7DA
IMUL EAX,ESI<=======乘以(当前段数-1)
0177:00C0E7DD SHL
EAX,1<=======乘以2
0177:00C0E7DF MOV
[ESP+10],EAX<=======留到下次使用
0177:00C0E7E3 JMP
SHORT 00C0E81E
0177:00C0E7E5 MOV EAX,[EDI]
0177:00C0E7E7 LEA ECX,[ESP+10]
0177:00C0E7EB
PUSH ECX
0177:00C0E7EC LEA EDX,[ESP+28]
0177:00C0E7F0 PUSH DWORD 00C2384C
0177:00C0E7F5
PUSH EDX
0177:00C0E7F6 MOV BYTE [ESP+34],00
0177:00C0E7FB MOV [ESP+30],EAX
0177:00C0E7FF
CALL EBX
0177:00C0E801 MOV EAX,[ESP+1C]
0177:00C0E805 MOV ECX,[00C291C0]
0177:00C0E80B
ADD EAX,ECX <=======校验码1加0x1234
0177:00C0E80D
XOR ECX,ECX
0177:00C0E80F MOV
[ESP+1C],EAX
0177:00C0E813 MOV CX,[EBP+00]
0177:00C0E817 ADD ESP,BYTE +0C
0177:00C0E81A
CMP EAX,ECX <=======与校验码2比较
0177:00C0E81C JNZ
00C0E851 <=======跳走说明校验失败!
0177:00C0E81E INC
ESI
0177:00C0E81F ADD EDI,BYTE +05
0177:00C0E822 ADD EBP,BYTE +02
0177:00C0E825
CMP ESI,BYTE +06
0177:00C0E828 JL
00C0E7C4 <=====继续下一位校验
作者这一段看似无用的校验,却非常有用,既是障眼法又增加了跟踪的难度,让你搞不清他的比较方法,如果你在上面看到工某寄存器中有注册码,自以为成功,那你就上当了。只有多观察分析比较思考(有点像说教),相信你能很快成为高手。
如果本文能对你学习破解有所帮助,我的目的就达到了:)
Maomao[CCG]
2002-7-15
- 标 题:五笔输入通1.x注册算法分析 (10千字)
- 作 者:Maomao[CCG]
- 时 间:2002-7-15
12:11:59
- 链 接:http://bbs.pediy.com