【文章标题】闹钟和笑话Ver1.0 注册分析
【文章作者】jackozoo
【作者邮箱】jackozoo@163.com
【软件名称】闹钟和笑话
【软件大小】480K
【原版下载】http://catman.iglobalserver.com/
【保护方式】机器码-序列号
【软件简介】用于日常事务的提醒, 闹钟, 以及播放笑话的功能 .
【作者声明】本文仅供研究学习,本人对因这篇文章而导致的一切后果,不承担任何法律责任。本文中的不足之处请各位多多指教
------------------------------------------------------------------------
P.S : 我发现上面的原版下载地址有时打不开,所以我将原版安装程序放在续贴的附件中供需要的朋友下载. 同时为了便于阅读,分为上下帖.
【分析过程】
[大体简介]
这个软件结构比较简单, Delphi写的 . 注册机制是: 先是机器码自动生成, 然后我们输入注册码进行验证, 其中注册码还分试用版的注册码和正式版的注册码.
不过判断部分太失败了, 竟然是明码比较的方式, 当然为了不太扫兴, 我大概分析了下整个程序的算法.
[主要目标]
1.分析正式版注册码的生成.
2.分析试用版注册码的生成.
3.分析程序注册信息的保存.
4.分析程序的验证方式.
5.分析机器码的生成方式.
6.心得与体会
[详细过程]
0.初探门径
PEID之,ASPack,脱之.再PEID, Borland Delphi 4.0 - 5.0.
运行之, 窗口标题栏显示"闹钟与笑话(未注册)", 点击看笑话按钮, 发现可看的序号有限制.点注册按钮,
机器码已自动显示出来.我们只需输入序列号.随便输入ABCDEF.确定.弹错.
开始动手了:
DeDe载入, 切换到RegForm窗体. 得到注册按钮事件的VA. OD下断跟踪. 试炼码:ABCDEF
如下:
00482530 >/. 55 push ebp
00482531 |. 8BEC mov ebp, esp
00482533 |. 33C9 xor ecx, ecx
00482535 |. 51 push ecx
00482536 |. 51 push ecx
00482537 |. 51 push ecx ; 这里在开辟局部变量空间,和VC很不同.
00482538 |. 51 push ecx
00482539 |. 51 push ecx
0048253A |. 53 push ebx
0048253B |. 8BD8 mov ebx, eax ; 保存RegForm句柄至ebx
0048253D |. 33C0 xor eax, eax
0048253F |. 55 push ebp
00482540 |. 68 27264800 push dumped_.00482627
00482545 |. 64:FF30 push dword ptr fs:[eax]
00482548 |. 64:8920 mov fs:[eax], esp ; SEH, try 块.
0048254B |. 8D55 FC lea edx, [ebp-4] ; 缓冲区. 存放我们的注册码.
0048254E >|. 8B83 E0020000 mov eax, [ebx+2E0] ; Edit控件.
00482554 >|. E8 4F00FBFF call dumped_.004325A8 ; TControl.GetText(TControl):TCaption;
00482559 |. 8D55 F0 lea edx, [ebp-10] ; 存放机器码的缓冲区.
0048255C >|. 8B83 E8020000 mov eax, [ebx+2E8] ; 机器码的Edit控件
00482562 >|. E8 4100FBFF call dumped_.004325A8 ; TControl.GetText(TControl):TCaption;
00482567 |. 8B45 F0 mov eax, [ebp-10]
0048256A |. 8D55 F8 lea edx, [ebp-8]
0048256D >|. E8 1AFAFFFF call dumped_.00481F8C ; ->:TfrmSetAwake._PROC_00481F8C()
00482572 |. 8D55 EC lea edx, [ebp-14]
00482575 >|. 8B83 E8020000 mov eax, [ebx+2E8] ; *Edit2:TEdit
0048257B >|. E8 2800FBFF call dumped_.004325A8 ; ->controls.TControl.GetText(TControl):TCaption;
00482580 |. 8B45 EC mov eax, [ebp-14]
00482583 |. 8D55 F4 lea edx, [ebp-C]
00482586 >|. E8 69FAFFFF call dumped_.00481FF4 ; 这个call会得到一个注册码,但是是试用版的.
0048258B |. 8B45 FC mov eax, [ebp-4] ; 试炼码
0048258E |. 8B55 F8 mov edx, [ebp-8] ; 试用版注册码
00482591 >|. E8 5E19F8FF call dumped_.00403EF4 ; 比较
00482596 |. 75 28 jnz short dumped_.004825C0 ; 如果相等的话, 则为试用版.(概率太小..)
00482598 |. 8B55 FC mov edx, [ebp-4]
0048259B |. 8BC3 mov eax, ebx
0048259D >|. E8 5E010000 call dumped_.00482700 ; 这里是正式版的注册码生成call
004825A2 |. 84C0 test al, al
004825A4 |. 74 1A je short dumped_.004825C0
004825A6 |. B8 3C264800 mov eax, dumped_.0048263C ; 试用版提示信息.
004825AB |. E8 14D4FFFF call dumped_.0047F9C4 ; MessageBox
004825B0 |. C683 F4020000>mov byte ptr [ebx+2F4], 0
004825B7 |. 8BC3 mov eax, ebx
004825B9 >|. E8 5EAEFCFF call dumped_.0044D41C ; 关闭窗口.
004825BE |. EB 3F jmp short dumped_.004825FF
004825C0 |> 8B45 FC mov eax, [ebp-4]
004825C3 |. 8B55 F4 mov edx, [ebp-C]
004825C6 >|. E8 2919F8FF call dumped_.00403EF4 ; 这里才是和正式版的注册码进行比较.
004825CB |. 75 28 jnz short dumped_.004825F5
004825CD |. 8B55 FC mov edx, [ebp-4] ; 参数二为注册码.
004825D0 |. 8BC3 mov eax, ebx ; 参数一为Reg窗体的句柄.
004825D2 >|. E8 29010000 call dumped_.00482700 ; 到这里就是没跳,而软件要保持了注册信息,下面又无其他陌生call,所以这里就是写入注册信息.
004825D7 |. 84C0 test al, al
004825D9 |. 74 1A je short dumped_.004825F5 ; 写入失败,跳走.
004825DB |. C683 F4020000>mov byte ptr [ebx+2F4], 0
004825E2 |. B8 68264800 mov eax, dumped_.00482668
004825E7 |. E8 D8D3FFFF call dumped_.0047F9C4 ; 完成注册提示!
004825EC |. 8BC3 mov eax, ebx ; ebx保存的为Reg窗口的句柄.给eax作为参数.
004825EE >|. E8 29AEFCFF call dumped_.0044D41C ; 关闭窗口.
004825F3 |. EB 0A jmp short dumped_.004825FF
004825F5 |> B8 98264800 mov eax, dumped_.00482698
004825FA |. E8 C5D3FFFF call dumped_.0047F9C4 ; 弹错,窗口保留.
004825FF |> 33C0 xor eax, eax
00482601 |. 5A pop edx
00482602 |. 59 pop ecx
00482603 |. 59 pop ecx
00482604 |. 64:8910 mov fs:[eax], edx
00482607 |. 68 2E264800 push dumped_.0048262E
0048260C |> 8D45 EC lea eax, [ebp-14]
0048260F |. BA 02000000 mov edx, 2
00482614 >|. E8 6F15F8FF call dumped_.00403B88 ; 清理
00482619 |. 8D45 F4 lea eax, [ebp-C]
0048261C |. BA 03000000 mov edx, 3
00482621 >|. E8 6215F8FF call dumped_.00403B88
00482626 \. C3 retn
00482627 .^ E9 4C0FF8FF jmp dumped_.00403578
0048262C .^ EB DE jmp short dumped_.0048260C
0048262E . 5B pop ebx
0048262F . 8BE5 mov esp, ebp
00482631 . 5D pop ebp
00482632 . C3 retn
1.正式版注册码生成算法的分析.
00481FF4 /$ 55 push ebp ; 试用版注册码生成Call
00481FF5 |. 8BEC mov ebp, esp
00481FF7 |. 83C4 F8 add esp, -8
00481FFA |. 53 push ebx
00481FFB |. 33C9 xor ecx, ecx
00481FFD |. 894D F8 mov [ebp-8], ecx
00482000 |. 8BDA mov ebx, edx
00482002 |. 8945 FC mov [ebp-4], eax
00482005 |. 8B45 FC mov eax, [ebp-4]
00482008 |. E8 8B1FF8FF call dumped_.00403F98
0048200D |. 33C0 xor eax, eax
0048200F |. 55 push ebp
00482010 |. 68 4F204800 push dumped_.0048204F
00482015 |. 64:FF30 push dword ptr fs:[eax]
00482018 |. 64:8920 mov fs:[eax], esp
0048201B |. 8D4D F8 lea ecx, [ebp-8] ; 参数3:存放试用版注册码. (也即输出参数)
0048201E |. 66:BA 31D4 mov dx, 0D431 ; 参数2:常熟一个, 作为参数
00482022 |. 8B45 FC mov eax, [ebp-4] ; 参数1:机器码.
00482025 |. E8 32000000 call dumped_.0048205C ; call_1
0048202A |. 8B45 F8 mov eax, [ebp-8]
0048202D |. 8BD3 mov edx, ebx
0048202F |. E8 8C000000 call dumped_.004820C0 ; call_2
00482034 |. 33C0 xor eax, eax
00482036 |. 5A pop edx
00482037 |. 59 pop ecx
00482038 |. 59 pop ecx
00482039 |. 64:8910 mov fs:[eax], edx
0048203C |. 68 56204800 push dumped_.00482056
00482041 |> 8D45 F8 lea eax, [ebp-8]
00482044 |. BA 02000000 mov edx, 2
00482049 |. E8 3A1BF8FF call dumped_.00403B88
0048204E \. C3 retn
可以看到,就那两个call是关键. 一个个来:
//call_1
0048205C /$ 53 push ebx
0048205D |. 56 push esi
0048205E |. 57 push edi
0048205F |. 55 push ebp
00482060 |. 51 push ecx
00482061 |. 8BE9 mov ebp, ecx
00482063 |. 8BF2 mov esi, edx ; 这里把那个常数给esi.
00482065 |. 890424 mov [esp], eax
00482068 |. 8BC5 mov eax, ebp
0048206A |. 8B1424 mov edx, [esp]
0048206D |. E8 461BF8FF call dumped_.00403BB8
00482072 |. 8B0424 mov eax, [esp]
00482075 |. E8 6A1DF8FF call dumped_.00403DE4 ; 求字符串长度.
0048207A |. 8BF8 mov edi, eax
0048207C |. 85FF test edi, edi
0048207E |. 7E 39 jle short dumped_.004820B9 ; 空串则玩完.
00482080 |. BB 01000000 mov ebx, 1 ; 循环计数 i
00482085 |> 8BC5 /mov eax, ebp
00482087 |. E8 281FF8FF |call dumped_.00403FB4
0048208C |. 8B1424 |mov edx, [esp]
0048208F |. 8A541A FF |mov dl, [edx+ebx-1]
00482093 |. 0FB7CE |movzx ecx, si ; 到这里知道那个是加密key了.
00482096 |. C1E9 08 |shr ecx, 8
00482099 |. 32D1 |xor dl, cl
0048209B |. 885418 FF |mov [eax+ebx-1], dl ; 这里就是写入.
0048209F |. 8B45 00 |mov eax, [ebp]
004820A2 |. 0FB64418 FF |movzx eax, byte ptr [eax+ebx-1]
004820A7 |. 66:03F0 |add si, ax
004820AA |. 66:69C6 09CE |imul ax, si, 0CE09
004820AF |. 66:05 5B58 |add ax, 585B
004820B3 |. 8BF0 |mov esi, eax ; 这几句对key进行变化.
004820B5 |. 43 |inc ebx
004820B6 |. 4F |dec edi
004820B7 |.^ 75 CC \jnz short dumped_.00482085
004820B9 |> 5A pop edx
004820BA |. 5D pop ebp
004820BB |. 5F pop edi
004820BC |. 5E pop esi
004820BD |. 5B pop ebx
004820BE \. C3 retn
这个call_1比较简单. 就是一个简单变换,它生成的是一个同机器码相同长度的序列.记为machine ---> machine_e:
大致过程:
for (i=0;i<strlen((char*)machine);++i)
{
machine_e[i] = machine[i] ^ ((WORD)key >> 8);
key += (BYTE)machine_e[i];
key = (WORD)((WORD)(key * 0xCE09) + 0x585B);
}
再来看call_2:
004820C0 /$ 53 push ebx
004820C1 |. 56 push esi
004820C2 |. 57 push edi
004820C3 |. 55 push ebp
004820C4 |. 83C4 F4 add esp, -0C
004820C7 |. 891424 mov [esp], edx
004820CA |. 8BF0 mov esi, eax
004820CC |. 8BC6 mov eax, esi
004820CE |. E8 111DF8FF call dumped_.00403DE4 ; 得到machine_e长度
004820D3 |. 83C0 02 add eax, 2
004820D6 |. B9 03000000 mov ecx, 3
004820DB |. 99 cdq
004820DC |. F7F9 idiv ecx
004820DE |. 8BD0 mov edx, eax
004820E0 |. C1E2 02 shl edx, 2 ; 参数2: strlen(m)+2/3*4
004820E3 |. 8B0424 mov eax, [esp] ; 参数1:这里就是存放试用版注册码的部分.
004820E6 |. E8 2D20F8FF call dumped_.00404118 ; 设置长度, 忽略之.
004820EB |. 8BC6 mov eax, esi ; 变形后的机器码.
004820ED |. E8 F21CF8FF call dumped_.00403DE4 ; 求长度call.
004820F2 |. 83C0 02 add eax, 2
004820F5 |. B9 03000000 mov ecx, 3
004820FA |. 99 cdq
004820FB |. F7F9 idiv ecx
004820FD |. 8BF8 mov edi, eax ; 循环次数.
004820FF |. 85FF test edi, edi
00482101 |. 0F8E 00010000 jle dumped_.00482207
00482107 |. BB 01000000 mov ebx, 1 ; 循环计数.
0048210C |> 8BC6 /mov eax, esi
0048210E |. E8 D11CF8FF |call dumped_.00403DE4 ; 又求长度, 为8
00482113 |. 8D145B |lea edx, [ebx+ebx*2]
00482116 |. 3BC2 |cmp eax, edx
00482118 |. 7D 25 |jge short dumped_.0048213F ; strlen(machine_e) >= 3*i 则跳
0048211A |. 8BC6 |mov eax, esi
0048211C |. E8 C31CF8FF |call dumped_.00403DE4 ; 还是求长度call, 大家可以把这个弄个lable
00482121 |. 8BC8 |mov ecx, eax
00482123 |. 8BC3 |mov eax, ebx
00482125 |. 48 |dec eax
00482126 |. 8D0440 |lea eax, [eax+eax*2]
00482129 |. 2BC8 |sub ecx, eax ; Move函数的arg3 = strlen(machine_e) -3*(i-1)
0048212B |. 8D5424 04 |lea edx, [esp+4] ; 这个缓冲区暂记为temp[7]
0048212F |. 8BC3 |mov eax, ebx
00482131 |. 48 |dec eax
00482132 |. 8D0440 |lea eax, [eax+eax*2]
00482135 |. 8D0406 |lea eax, [esi+eax] ; 这是源串的起始地址.
00482138 |. E8 0307F8FF |call dumped_.00402840 ; 这个是Move. 大家可以当成是memcpy函数.
0048213D |. EB 17 |jmp short dumped_.00482156
0048213F |> 8D5424 04 |lea edx, [esp+4] ; 循环中的前面几次会到这里来的.
00482143 |. 8BC3 |mov eax, ebx
00482145 |. 48 |dec eax
00482146 |. 8D0440 |lea eax, [eax+eax*2]
00482149 |. 8D0406 |lea eax, [esi+eax]
0048214C |. B9 03000000 |mov ecx, 3 ; 这是这次的size为常数3.
00482151 |. E8 EA06F8FF |call dumped_.00402840 ; Move
00482156 |> 8A4424 04 |mov al, [esp+4] ; 取第一个字符.
0048215A |. 8BD0 |mov edx, eax
0048215C |. 80E2 FC |and dl, 0FC
0048215F |. 81E2 FF000000 |and edx, 0FF
00482165 |. C1EA 02 |shr edx, 2 ; edx 其实是作为偏移使用的.
00482168 |. B9 8C224800 |mov ecx, dumped_.0048228C ; ASCII "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
0048216D |. 8A1411 |mov dl, [ecx+edx]
00482170 |. 885424 07 |mov [esp+7], dl ; temp[3] 赋值. 注意:第一次循环的时候,temp[0]至temp[2]被Move函数赋值.
00482174 |. 24 03 |and al, 3
00482176 |. 8BE8 |mov ebp, eax
00482178 |. 81E5 FF000000 |and ebp, 0FF
0048217E |. C1E5 04 |shl ebp, 4
00482181 |. 8A5424 05 |mov dl, [esp+5]
00482185 |. 8BC2 |mov eax, edx
00482187 |. 24 F0 |and al, 0F0
00482189 |. 25 FF000000 |and eax, 0FF
0048218E |. C1E8 04 |shr eax, 4
00482191 |. 0BE8 |or ebp, eax ; 以上N行为生成新的偏移
00482193 |. B8 8C224800 |mov eax, dumped_.0048228C ; ASCII "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
00482198 |. 8A0428 |mov al, [eax+ebp]
0048219B |. 884424 08 |mov [esp+8], al ; temp[4]赋值.
0048219F |. 80E2 0F |and dl, 0F ; Ok, 下面的这些都差不多了.
004821A2 |. 8BEA |mov ebp, edx
004821A4 |. 81E5 FF000000 |and ebp, 0FF
004821AA |. C1E5 02 |shl ebp, 2
004821AD |. 8A4424 06 |mov al, [esp+6]
004821B1 |. 8BD0 |mov edx, eax
004821B3 |. 80E2 C0 |and dl, 0C0
004821B6 |. 81E2 FF000000 |and edx, 0FF
004821BC |. C1EA 06 |shr edx, 6
004821BF |. 0BEA |or ebp, edx
004821C1 |. BA 8C224800 |mov edx, dumped_.0048228C ; ASCII "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
004821C6 |. 8A142A |mov dl, [edx+ebp]
004821C9 |. 885424 09 |mov [esp+9], dl
004821CD |. 24 3F |and al, 3F
004821CF |. 25 FF000000 |and eax, 0FF
004821D4 |. BA 8C224800 |mov edx, dumped_.0048228C ; ASCII "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
004821D9 |. 8A0402 |mov al, [edx+eax]
004821DC |. 884424 0A |mov [esp+A], al
004821E0 |. 8B0424 |mov eax, [esp]
004821E3 |. E8 CC1DF8FF |call dumped_.00403FB4
004821E8 |. 8BD3 |mov edx, ebx
004821EA |. 4A |dec edx
004821EB |. C1E2 02 |shl edx, 2
004821EE |. 8D1410 |lea edx, [eax+edx] ; 这是目的地址,连接注册码: ®[4*(i-1)]
004821F1 |. 8D4424 07 |lea eax, [esp+7] ; 源地址,即&temp[3]
004821F5 |. B9 04000000 |mov ecx, 4 ; 这里是个关键了, ecx为copy的字节数.
004821FA |. E8 4106F8FF |call dumped_.00402840 ; Move.每次4个.
004821FF |. 43 |inc ebx
00482200 |. 4F |dec edi
00482201 |.^ 0F85 05FFFFFF \jnz dumped_.0048210C
00482207 |> 8BC6 mov eax, esi ; machine_e
00482209 |. E8 D61BF8FF call dumped_.00403DE4 ; 还是strlen
0048220E |. B9 03000000 mov ecx, 3
00482213 |. 99 cdq
00482214 |. F7F9 idiv ecx
00482216 |. 4A dec edx ; 除以3的余数来switch-case
00482217 |. 75 34 jnz short dumped_.0048224D
00482219 |. 8B0424 mov eax, [esp] ; 余数为1处理:
0048221C |. 8B00 mov eax, [eax]
0048221E |. E8 C11BF8FF call dumped_.00403DE4
00482223 |. 8BD8 mov ebx, eax
00482225 |. 8B0424 mov eax, [esp]
00482228 |. E8 871DF8FF call dumped_.00403FB4
0048222D |. C64418 FE 3D mov byte ptr [eax+ebx-2], 3D ; 就这个mov特殊点, 看到[eax+ebx-1]就知道是填充注册码的尾部了.
00482232 |. 8B0424 mov eax, [esp]
00482235 |. 8B00 mov eax, [eax]
00482237 |. E8 A81BF8FF call dumped_.00403DE4
0048223C |. 8BD8 mov ebx, eax
0048223E |. 8B0424 mov eax, [esp]
00482241 |. E8 6E1DF8FF call dumped_.00403FB4
00482246 |. C64418 FF 3D mov byte ptr [eax+ebx-1], 3D ; 同上个mov byte ptr ...
0048224B |. EB 2D jmp short dumped_.0048227A
0048224D |> 8BC6 mov eax, esi
0048224F |. E8 901BF8FF call dumped_.00403DE4 ; strlen
00482254 |. B9 03000000 mov ecx, 3
00482259 |. 99 cdq
0048225A |. F7F9 idiv ecx
0048225C |. 83FA 02 cmp edx, 2
0048225F |. 75 19 jnz short dumped_.0048227A
00482261 |. 8B0424 mov eax, [esp] ; 余数为2处理:
00482264 |. 8B00 mov eax, [eax]
00482266 |. E8 791BF8FF call dumped_.00403DE4
0048226B |. 8BD8 mov ebx, eax
0048226D |. 8B0424 mov eax, [esp]
00482270 |. E8 3F1DF8FF call dumped_.00403FB4
00482275 |. C64418 FF 3D mov byte ptr [eax+ebx-1], 3D ; 也是填尾巴的
0048227A |> 83C4 0C add esp, 0C ; 整除则不处理.
0048227D |. 5D pop ebp
0048227E |. 5F pop edi
0048227F |. 5E pop esi
00482280 |. 5B pop ebx
00482281 \. C3 retn
这个call_2有点长, 不过总的来说, 思路很清晰, 即为通过call_1得到的变形码来生成, 其中会有一个大循环.
在这个循环里面, 有个temp[7]. 每次循环进去的时候, 在machine_m中都复制3个字节到temp的内存中(不足则复制零头). 然后根据这三个字节的值计算出一个偏移地址, 然后用这个偏移地址加上一个常量字符串表的地址来得到一个字符.
字符表为:
const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
依次得到4个字符放入到temp剩余的缓冲区中. 最后用Move函数将这4个字节复制到注册码缓冲区中.
其中最为关键的代码为:
004821EE |. 8D1410 |lea edx, [eax+edx] ; 这是目的地址,连接注册码: ®[4*(i-1)]
004821F1 |. 8D4424 07 |lea eax, [esp+7] ; 源地址,即&temp[3]
004821F5 |. B9 04000000 |mov ecx, 4 ; 这里是个关键了, ecx为copy的字节数.
004821FA |. E8 4106F8FF |call dumped_.00402840 ; Move.每次4个.
这个call的功能类似于memcpy(souce,dest,size), 注意Delphi中常用eax,edx,ecx来传参 . 用C语言可以表示为:
strcpy((char*)®_code[4*(i-1)], &temp[3], 4);
索引生成大致过程:
mlen = strlen((char*)machine_e);
regLen = (mlen + 2) / 3 * 4;
for (i=0;i<regLen/4;i++)
{
if ((i+1)*3<mlen)
strncpy((char*)temp,(char*)&machine_e[3*i],3);
else
strncpy((char*)temp,(char*)&machine_e[3*i],mlen-3*i);
temp[3] = table[(temp[0] & 0xFC) >> 2];
temp[4] = table[((temp[0] & 0x3) << 4) | ((temp[1] & 0xF0) >> 4)];
temp[5] = table[((temp[1] & 0xF) << 2) | ((temp[2] & 0xC0) >> 6)];
temp[6] = table[temp[2] & 0x3F];
strncpy((char*)®[i*4],(char*)&temp[3],4);
}
2.试用版的注册码如何生成.
00481F8C /$ 55 push ebp ; 试用版注册码生成.
00481F8D |. 8BEC mov ebp, esp
00481F8F |. 83C4 F8 add esp, -8
00481F92 |. 53 push ebx
00481F93 |. 33C9 xor ecx, ecx
00481F95 |. 894D F8 mov [ebp-8], ecx
00481F98 |. 8BDA mov ebx, edx
00481F9A |. 8945 FC mov [ebp-4], eax
00481F9D |. 8B45 FC mov eax, [ebp-4]
00481FA0 |. E8 F31FF8FF call dumped_.00403F98
00481FA5 |. 33C0 xor eax, eax
00481FA7 |. 55 push ebp
00481FA8 |. 68 E71F4800 push dumped_.00481FE7
00481FAD |. 64:FF30 push dword ptr fs:[eax]
00481FB0 |. 64:8920 mov fs:[eax], esp
00481FB3 |. 8D4D F8 lea ecx, [ebp-8]
00481FB6 |. 66:BA 3930 mov dx, 3039 ; 看到这你吃惊了一下吗? 别慌继续.
00481FBA |. 8B45 FC mov eax, [ebp-4]
00481FBD |. E8 9A000000 call dumped_.0048205C
00481FC2 |. 8B45 F8 mov eax, [ebp-8]
00481FC5 |. 8BD3 mov edx, ebx
00481FC7 |. E8 F4000000 call dumped_.004820C0 ; 这里的两个call不是如此的熟悉吗? 回去看看正式版的.. . 啊 ?!原来真是那两个call了.
00481FCC |. 33C0 xor eax, eax
00481FCE |. 5A pop edx
00481FCF |. 59 pop ecx
00481FD0 |. 59 pop ecx
00481FD1 |. 64:8910 mov fs:[eax], edx
00481FD4 |. 68 EE1F4800 push dumped_.00481FEE
00481FD9 |> 8D45 F8 lea eax, [ebp-8]
00481FDC |. BA 02000000 mov edx, 2
00481FE1 |. E8 A21BF8FF call dumped_.00403B88
00481FE6 \. C3 retn
所以,现在我们明白, 其实正式版与试用版的区别只在于两者使用的加密key不同而已, 算法的call完全一样.
所以到了这里, 我们对于注册码的生成就分析完毕了.
3.分析程序注册信息的保存方式.
//这个也很简单了, 上面我标出了那个注册信息保存call.
00482700 $ 55 push ebp ; 注册信息保存call
00482701 . 8BEC mov ebp, esp
...... //无关信息
...... //
0048274D . 8D55 F0 lea edx, [ebp-10]
00482750 . A1 64624800 mov eax, [486264]
00482755 . 8B00 mov eax, [eax]
00482757 . E8 A4E4FCFF call dumped_.00450C00 ; 这个是GetModuleFileName类似的函数,得到完全路径.前面都是无关紧要的.
0048275C . 8B45 F0 mov eax, [ebp-10]
0048275F . 8D55 F4 lea edx, [ebp-C]
00482762 . E8 7566F8FF call dumped_.00408DDC ; 提取出文件名.
00482767 . 8B4D F4 mov ecx, [ebp-C]
0048276A . 8D45 F8 lea eax, [ebp-8]
0048276D . BA E4274800 mov edx, dumped_.004827E4 ; ASCII "\SoftWare\Microsoft\"
00482772 . E8 B916F8FF call dumped_.00403E30 ; 字符串连接
00482777 . 8B55 F8 mov edx, [ebp-8]
0048277A . B1 01 mov cl, 1
0048277C . 8BC3 mov eax, ebx
0048277E . E8 F545FFFF call dumped_.00476D78 ; 打开注册表.
00482783 . 8B4D FC mov ecx, [ebp-4] ; 这是参数3: 即我们的注册码
00482786 . BA 04284800 mov edx, dumped_.00482804 ; ASCII "Pwd"
0048278B . 8BC3 mov eax, ebx ; 句柄.
0048278D . E8 A247FFFF call dumped_.00476F34 ; 写入一个键值.
00482792 . 8BC3 mov eax, ebx
00482794 . E8 7F06F8FF call dumped_.00402E18 ; 释放资源.
00482799 . B3 01 mov bl, 1
0048279B . 33C0 xor eax, eax
// ......
所以, 程序是用最常用的手法以键值对的形式将注册码保存在注册表中的.
好了,到了这里为了避免此页过长影响大家阅读, 剩下的分析(4-7四个目标的实现)我帖在了下贴上:
下贴地址: http://bbs.pediy.com/showthread.php?p=609591
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课