HappyEO 2.40.2 算法分析
作者:bbbsl
使用工具:trw v1.23
分析平台:盗版Win98se
软件介绍:HappyEO是一款用声卡模拟电子琴的软件。有了它,您可以用计算机的键盘奏出美妙的乐曲。还有录音、自动伴奏和效果等功能。假如您没有声卡,您仍然可以用计算机内部的扬声器来发音。
(不是我说的,是作者说的,不过确实挺好玩的,只可惜我不识谱,唉,只能瞎弹!^_*)
分析过程:
先运行trw及该软件,然后选注册后,会出现注册窗口,依次填入姓名,公司名及注册码,作者很细心,如果填错位数他会提醒你的,然后下断点
bpx hmemcpy,填getwindowtexta及getdlgitemtexta均不行,那样就过了关键地方了!:-P,不过在Win2000下怎么设断点呢?有那位大虾能告诉我吗?谢谢!
废话不多说了,回到注册界面点击确定按钮,然后程序会断下,然后F10,经过N个ret后,我们来到这里:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
第一个程序段
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
0167:51098C40 LEA EDX,[EBP-04]
0167:51098C43 MOV EAX,[EBX+02D0]
0167:51098C49 CALL 510312E0
==>我们从这里出来停在下一行!
0167:51098C4E
MOV EAX,[EBP-04] ==>Name
0167:51098C51 CALL 51003F28
==>这里计算长度
0167:51098C56
CMP EAX,BYTE +04 ==>Name<4?报错:继续
0167:51098C59 JL NEAR 51098DB0
0167:51098C5F LEA
EDX,[EBP-08]
0167:51098C62 MOV EAX,[EBX+02EC]
0167:51098C68 CALL 510312E0
==>经过这个call取公司名
0167:51098C6D MOV
EAX,[EBP-08] ==>Corporation
0167:51098C70 CALL 51003F28
==>计算长度
0167:51098C75
CMP EAX,BYTE +0C ==>Corporation<12?报错:继续
0167:51098C78 JL NEAR 51098DB0
0167:51098C7E LEA EDX,[EBP-0C]
0167:51098C81 MOV EAX,[EBX+02D4]
0167:51098C87 CALL
510312E0 ==>在这里取注册码
0167:51098C8C MOV EAX,[EBP-0C]
==>我们输入的注册码
0167:51098C8F
CALL 51003F28 ==>计算长度
0167:51098C94 CMP EAX,BYTE +06
==>长度<6?报错:继续
0167:51098C97
JNZ NEAR 51098DB0
0167:51098C9D LEA
EDX,[EBP-10]
0167:51098CA0 MOV
EAX,[EBX+02D4]
0167:51098CA6 CALL
510312E0
0167:51098CAB MOV EAX,[EBP-10]
==>再取一遍?
0167:51098CAE PUSH
EAX ==>注册码进栈
0167:51098CAF LEA EDX,[EBP-18]
0167:51098CB2 MOV EAX,[EBX+02EC]
0167:51098CB8 CALL
510312E0
0167:51098CBD MOV EAX,[EBP-18]
0167:51098CC0 PUSH
EAX ==>Corp进栈
0167:51098CC1 LEA EDX,[EBP-1C]
0167:51098CC4 MOV EAX,[EBX+02D0]
0167:51098CCA CALL 510312E0
0167:51098CCF MOV
EAX,[EBP-1C] ==>eax<--Name
0167:51098CD2 LEA ECX,[EBP-14]
==>用来存放地址的一个指针
0167:51098CD5
POP EDX ==>edx<--Corp
0167:51098CD6 CALL 510980B4
==>关键,跟进!
0167:51098CDB MOV EDX,[EBP-14]
==>这里D edx可得注册码
0167:51098CDE POP
EAX ==>假注册码
0167:51098CDF CALL 51004038
==>比较是否正确,就不看怎么比较的了吧!
0167:51098CE4
JNZ NEAR 51098D9A
0167:51098CEA MOV EAX,51098E00
0167:51098CEF CALL 51056968
0167:51098CF4
CALL 51009688
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
这里是刚才我说的关键call
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
0167:510980B4 PUSH EBP
0167:510980B5 MOV EBP,ESP
0167:510980B7 ADD ESP,BYTE -10
0167:510980BA PUSH EBX
0167:510980BB
XOR EBX,EBX
0167:510980BD MOV
[EBP-10],EBX ==>相当于四个变量
0167:510980C0 MOV [EBP-0C],ECX
0167:510980C3 MOV [EBP-08],EDX
0167:510980C6 MOV [EBP-04],EAX
0167:510980C9 MOV EAX,[EBP-04]
0167:510980CC CALL 510040DC
0167:510980D1
MOV EAX,[EBP-08]
0167:510980D4 CALL 510040DC
0167:510980D9 XOR
EAX,EAX
0167:510980DB PUSH EBP
0167:510980DC PUSH
DWORD 5109814A
0167:510980E1 PUSH DWORD [FS:EAX]
0167:510980E4 MOV [FS:EAX],ESP
0167:510980E7 MOV
EAX,[EBP-0C]
0167:510980EA CALL 51003CA8
0167:510980EF MOV EAX,[EBP-04]
==>又来了,判断名字长度
0167:510980F2
CALL 51003F28
0167:510980F7 CMP EAX,BYTE +04
0167:510980FA JL
51098127
0167:510980FC MOV EAX,[EBP-08]
==>判断公司名长度
0167:510980FF
CALL 51003F28
0167:51098104 CMP
EAX,BYTE +0C
0167:51098107
JL 51098127
0167:51098109 LEA EAX,[EBP-10]
0167:5109810C MOV
ECX,[EBP-08] ==>公司名
0167:5109810F MOV EDX,[EBP-04]
==>Name
0167:51098112 CALL 51003F74
==>这里用来合并姓名和公司名
0167:51098117 MOV EAX,[EBP-10]
==>eax<--合并后的字符串
0167:5109811A CALL
51097F9C ==>用这个字符串来算一个重要数!跟进!
0167:5109811F MOV EDX,[EBP-0C]
==>通过运算得到一个数
0167:51098122
CALL 51098024 ==>用这个数求最后的六位注册码
0167:51098127 XOR EAX,EAX
0167:51098129 POP
EDX
0167:5109812A POP ECX
0167:5109812B POP
ECX
0167:5109812C MOV [FS:EAX],EDX
0167:5109812F PUSH DWORD 51098151
0167:51098134 LEA
EAX,[EBP-10]
0167:51098137 CALL 51003CA8
0167:5109813C
LEA EAX,[EBP-08]
0167:5109813F MOV
EDX,02
0167:51098144 CALL
51003CCC
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
算注册码的CALL一
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
0167:51097F9C PUSH EBP
0167:51097F9D MOV EBP,ESP
0167:51097F9F ADD ESP,BYTE -10
0167:51097FA2
MOV [EBP-04],EAX
0167:51097FA5 MOV
EAX,[EBP-04]
0167:51097FA8 CALL
510040DC
0167:51097FAD XOR EAX,EAX
0167:51097FAF PUSH EBP
0167:51097FB0 PUSH DWORD 51098016
0167:51097FB5
PUSH DWORD [FS:EAX]
0167:51097FB8 MOV
[FS:EAX],ESP
0167:51097FBB MOV
DWORD [EBP-08],FFFFFFFF ==>设[ebp-8]为tempvar
0167:51097FC2 MOV EAX,[EBP-04]
==>那串字符串设为str[]
0167:51097FC5 CALL
51003F28
0167:51097FCA TEST EAX,EAX
0167:51097FCC JNG
51097FF5
0167:51097FCE MOV [EBP-10],EAX
==>设[ebp-10]为lenofnc
0167:51097FD1
MOV DWORD [EBP-0C],01 ==>设[ebp-c]为i
0167:51097FD8 MOV EAX,[EBP-04]
==>字符串地址addrofstr<--[ebp-4]
0167:51097FDB
MOV EDX,[EBP-0C] ==>用edx来从字符串定位字符
0167:51097FDE MOV AL,[EAX+EDX-01]
==>一次取一个字符
0167:51097FE2
MOV EDX,[EBP-08] ==>edx<--tempvar,初值为-1
0167:51097FE5 CALL 51097F48
==>中间为查表过程,过会详细看看
0167:51097FEA
MOV [EBP-08],EAX ==>得到的结果放入tempvar
0167:51097FED INC DWORD [EBP-0C]
==>i++
0167:51097FF0 DEC
DWORD [EBP-10] ==>lenofnc--
0167:51097FF3 JNZ 51097FD8
==>lenofnc==0?往下走:循环
0167:51097FF5 MOV EAX,[EBP-08]
0167:51097FF8 CALL 51097F80
==>得到的最终结果取反
0167:51097FFD MOV [EBP-08],EAX
0167:51098000 XOR EAX,EAX
0167:51098002
POP EDX
0167:51098003 POP
ECX
0167:51098004 POP ECX
0167:51098005 MOV [FS:EAX],EDX
0167:51098008 PUSH DWORD 5109801D
0167:5109800D LEA EAX,[EBP-04]
0167:51098010 CALL 51003CA8
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
注册码从call
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
0167:51097F48
PUSH EBP
0167:51097F49 MOV
EBP,ESP
0167:51097F4B ADD
ESP,BYTE -0C
0167:51097F4E MOV [EBP-08],EDX
==>tempvar
0167:51097F51
MOV [EBP-01],AL ==>所取字符
0167:51097F54 MOV AL,[EBP-08]
0167:51097F57 XOR
AL,[EBP-01] ==>tempvar^str[i]
0167:51097F5A AND EAX,FF
==>temp<--tempvar^str[i]&0xff
0167:51097F5F MOV EAX,[EAX*4+510DFEB4]
==>用temp查表送往eax
0167:51097F66 MOV
EDX,[EBP-08]
0167:51097F69
SHR EDX,08 ==>tempvar>>=8
0167:51097F6C AND EDX,00FFFFFF
==>tempvar&=0xffffff
0167:51097F72
XOR EAX,EDX ==>eax<--tempvar^[temp*4+510dfeb4]
0167:51097F74 MOV [EBP-0C],EAX
0167:51097F77 MOV
EAX,[EBP-0C]
0167:51097F7A MOV
ESP,EBP
0167:51097F7C POP
EBP
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
在这里面,刚才的最终数被取反
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
0167:51097F80 PUSH EBP
0167:51097F81 MOV EBP,ESP
0167:51097F83 ADD ESP,BYTE -08
0167:51097F86
MOV [EBP-04],EAX
0167:51097F89 MOV
EAX,[EBP-04]
0167:51097F8C XOR
EAX,BYTE -01 ==>It's here!!!
0167:51097F8F MOV [EBP-08],EAX
0167:51097F92 MOV EAX,[EBP-08]
0167:51097F95 POP ECX
0167:51097F96
POP ECX
0167:51097F97 POP
EBP
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
最后一个call,用来算六位注册码
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
0167:51098024 PUSH EBP
0167:51098025 MOV EBP,ESP
0167:51098027 ADD ESP,BYTE -14
0167:5109802A
XOR ECX,ECX
0167:5109802C MOV
[EBP-14],ECX
0167:5109802F MOV
[EBP-08],EDX
0167:51098032 MOV
[EBP-04],EAX
0167:51098035 XOR EAX,EAX
0167:51098037 PUSH EBP
0167:51098038 PUSH DWORD 510980A6
0167:5109803D
PUSH DWORD [FS:EAX]
0167:51098040 MOV
[FS:EAX],ESP
0167:51098043 MOV
EAX,[EBP-08]
0167:51098046 CALL 51003CA8
0167:5109804B XOR EAX,EAX
0167:5109804D MOV [EBP-0C],EAX
0167:51098050 MOV EAX,[EBP-04]
==>刚才求得的那个数字
0167:51098053
MOV ECX,24
==>除数为0x24
0167:51098058 XOR
EDX,EDX
0167:5109805A DIV ECX
==>edx=eax%0x24
0167:5109805C MOV DL,[EDX+510E02B5]
==>用余数来查表
0167:51098062
LEA EAX,[EBP-14]
==>这里的地址用来存放注册码
0167:51098065 CALL
51003E50
==>存注册码
0167:5109806A MOV
EDX,[EBP-14]
0167:5109806D MOV EAX,[EBP-08]
0167:51098070 CALL
51003F30
0167:51098075 MOV
EAX,[EBP-08]
0167:51098078 MOV EAX,[EBP-04]
0167:5109807B MOV ECX,24
0167:51098080 XOR EDX,EDX
0167:51098082 DIV ECX
0167:51098084
MOV [EBP-04],EAX
==>将除完了的数放回ebp-4
0167:51098087 INC
DWORD [EBP-0C] ==>循环计数器
0167:5109808A CMP DWORD [EBP-0C],BYTE
+06 ==>是否已经六位了?
0167:5109808E
JNZ 51098050
0167:51098090 XOR
EAX,EAX
0167:51098092 POP
EDX
0167:51098093 POP ECX
0167:51098094 POP ECX
0167:51098095 MOV [FS:EAX],EDX
0167:51098098 PUSH DWORD 510980AD
0167:5109809D
LEA EAX,[EBP-14]
0167:510980A0 CALL
51003CA8
##############################################################
我认为我分析的挺详细了,有什么地方不对谢谢指教!其实就是这么简单,不过我的注册机放2000下了,没法帖出来,见谅,不过到这里,大家也能自己写出来了吧!
- 标 题:HappyEO算法分析 (11千字)
- 作 者:bbbsl
- 时 间:2002-6-30
12:26:27
- 链 接:http://bbs.pediy.com