ExtractRes的破解
kflnig
一不小心就把黑客手册中的ExtractRes给破了。谁叫它躺在了《黑客手册》两周年生日的那张光盘上。《黑客手册》两周年了,也拖了我4篇文章的稿费了。心中感到由衷的高兴,于是产生了本文来给《黑客手册》贺寿。好像迟到了一点,但是不要紧,只要有这份心就行。
本文适合想学习破解知识的小鸟。很简单。本文中若无特殊说明都是16进制运算。
我用下列这些工具:OLLYDBG。假使你也使用这些。
输入用户名和伪码之后出现了,图1
图1
它都这么说了,我还有什么可说呢?典型的重启验证。
但是大家也要注意一点。不是所有的软件这样之后都会是在重启之后验证。有一部分是先处理好是否正确注册之后,然后写一个true或者false的标志到某个地方,重启的时候只是读取一下这个值而已。当然这个软件不是特例。
很不好意思的是这个软件又是半个明码比较。我们看看:
既然是重启验证,那么当然会有特定的手段了。
第一,它把注册信息写到了哪里?我猜多数是注册表。
验证,OLLYDBG载入。下断RegQueryValueA。然后F9,眼睛紧盯堆栈窗口。
图2
图3
看到图2,图3,你还有什么话说。
第二,亲爱的注册过程你在哪里。
如果有人愿意一步一步F7(步入)+F8(步过)等一步一步爬到关键的地方,我只能说佩服你的毅力。我没有毅力。
所以我要走捷径。
思考:因为它在取用户名和注册码,那么注册过程肯定在这个之后。
于是乎,在见到图3之后,粗跟踪一番。可是不顺,对注册过程的处理一无所获。
怎么办?但是得到一点有用的信息。
给大家看一下,我在粗跟踪中的成果。
0040F714 . E8 CD3A0300 CALL ExtractR.004431E6
0040F719 . A1 286B4800 MOV EAX,DWORD PTR DS:[486B28]
0040F71E . C68424 CC0100>MOV BYTE PTR SS:[ESP+1CC],10
0040F726 . 85C0 TEST EAX,EAX
0040F728 . 75 0E JNZ SHORT ExtractR.0040F738
0040F72A . 68 2C0E4800 PUSH ExtractR.00480E2C ; ASCII " [unregistered]"
0040F72F . 8D4C24 2C LEA ECX,DWORD PTR SS:[ESP+2C]
如果你要说0040F714处的call是关键call的话,那么我告诉你错了。关键是
0040F719 . A1 286B4800 MOV EAX,DWORD PTR DS:[486B28]
0040F726 . 85C0 TEST EAX,EAX
0040F728 . 75 0E JNZ SHORT ExtractR.0040F738
0040F72A . 68 2C0E4800 PUSH ExtractR.00480E2C ; ASCII " [unregistered]"
这里我们看到假如在正常情况下,eax不为0那么我们就不用破解了,也就是说要是我们不擅自改,那么只要注册成功,这里的eax就是0。因为这个[unregistered]是图3中的软件标题的一部分。
图3
^_^那么eax又来自哪里呢?MOV EAX,DWORD PTR DS:[486B28]这句话明确的告诉了我们它的来历!
到这里我们就好办了。
OD其实有很多功能,我们平时没有用到。现在我们就用“硬件访问断点”伺候。
OD从新载入。在命令框中输入d 486B28。然后如图4操作
图4
我们此时看“调试——>硬件断点”可以看到如图5所示
图5
假设你现在下好了断点。我们就可以运行了。
在RegQueryValueA和刚才的硬件访问断点,我们可以很容易的确定关键地点。我们可以忽略RegQueryValueA断下之前的硬件断点,只是这个软件这种情况没有发生。当然也可以忽略0040F719 . A1 286B4800 MOV EAX,DWORD PTR DS:[486B28]这个之后的硬件断点。
这个软件第一次断下后不远处就到了关键的地点。真善良,^_^
断在此处:0040F4B3 . E8 AEC30400 CALL ExtractR.0045B866
这是关键:0040F509 . E8 D2090000 CALL ExtractR.0040FEE0 ; \ExtractR.0040FEE0
进入……
第三,在第二步大功告成之后,我们就得真的和它硬碰了。这是考功力的一关。分析代码。
进入之后,显示100万行无用代码。众小鸟不要被这个气势压倒。之后是关键的东西。
先要讲不少预备知识
esp的值的改变:
push一次
esp=esp-4
pop一次
esp=esp+4
cdq和idiv指令
CDQ是符号扩展指令 ,D是dword(4字节),Q是qword(8字节) 。CDQ把EAX寄存器中的数视为有符号的数,将其符号位(即EAX的最高位)扩展到EDX寄存器,即若EAX的最高位是1,则执行后EDX的每个位都是1,结果EDX = FFFFFFFF;若EAX的最高位是0,则执行后EDX的每个位都是0,结果EDX = 00000000。这样就把EAX中的32位带符号的数变成了EDX:EAX中的64位带符号的数,以满足64位运算指令的需要,但转换后的值没变。
若是idiv ebp就是
eax=eax div ebp,edx=eax mod ebp。
<1>
0040FFD8 |> \8B9424 E40000>MOV EDX,DWORD PTR SS:[ESP+E4];edx指向用户名
0040FFDF |. 33C9 XOR ECX,ECX;这里ecx清零,在下面的循环中控制次数。
0040FFE1 |. 53 PUSH EBX
0040FFE2 |. C64424 08 68 MOV BYTE PTR SS:[ESP+8],68;注意这些初始化的值
0040FFE7 |. 8B72 F8 MOV ESI,DWORD PTR DS:[EDX-8];用户名长度
0040FFEA |. C64424 09 75 MOV BYTE PTR SS:[ESP+9],75
0040FFEF |. 85F6 TEST ESI,ESI
0040FFF1 |. C64424 0A 79 MOV BYTE PTR SS:[ESP+A],79
0040FFF6 |. C64424 0B 64 MOV BYTE PTR SS:[ESP+B],64
0040FFFB |. C64424 0C 6F MOV BYTE PTR SS:[ESP+C],6F
00410000 |. C64424 0D 6E MOV BYTE PTR SS:[ESP+D],6E
00410005 |. C64424 0E 67 MOV BYTE PTR SS:[ESP+E],67
0041000A |. C64424 0F 00 MOV BYTE PTR SS:[ESP+F],0
0041000F |. 7E 3F JLE SHORT ExtractR.00410050;这是和0040FFEF TEST ESI,ESI联系的,除非你没有输入用户名,否则就不会跳走
00410011 |. 55 PUSH EBP
00410012 |. 57 PUSH EDI
00410013 |. 8D7C34 17 LEA EDI,DWORD PTR SS:[ESP+ESI+17]
<2>
00410017 |> 8B8424 F00000>/MOV EAX,DWORD PTR SS:[ESP+F0];指向用户名的首地址
0041001E |. BD 07000000 |MOV EBP,7
00410023 |. 8A1C01 |MOV BL,BYTE PTR DS:[ECX+EAX];ecx将依次递增,所以就是依次指向用户名的一个个字符。
00410026 |. 8BC1 |MOV EAX,ECX
00410028 |. 99 |CDQ
00410029 |. F7FD |IDIV EBP
0041002B |. 0FBEC3 |MOVSX EAX,BL
0041002E |. 8BD9 |MOV EBX,ECX
00410030 |. 0FBE5414 10 |MOVSX EDX,BYTE PTR SS:[ESP+EDX+10]
00410035 |. 03DA |ADD EBX,EDX
00410037 |. 03C3 |ADD EAX,EBX
00410039 |. BB 09000000 |MOV EBX,9
0041003E |. 03C6 |ADD EAX,ESI
00410040 |. 99 |CDQ
00410041 |. F7FB |IDIV EBX
00410043 |. 80C2 30 |ADD DL,30
00410046 |. 41 |INC ECX
00410047 |. 8817 |MOV BYTE PTR DS:[EDI],DL;edi中最后指向真码
00410049 |. 4F |DEC EDI
0041004A |. 3BCE |CMP ECX,ESI
0041004C |.^ 7C C9 \JL SHORT ExtractR.00410017
<3>
0041004E |. 5F POP EDI
0041004F |. 5D POP EBP
00410050 |> 8D46 4D LEA EAX,DWORD PTR DS:[ESI+4D]
00410053 |. B9 09000000 MOV ECX,9
00410058 |. 99 CDQ
00410059 |. F7F9 IDIV ECX
0041005B |. 8B8424 EC0000>MOV EAX,DWORD PTR SS:[ESP+EC]
00410062 |. 80C2 30 ADD DL,30
00410065 |. 885434 10 MOV BYTE PTR SS:[ESP+ESI+10],DL
00410069 |. C64434 11 00 MOV BYTE PTR SS:[ESP+ESI+11],0
很长,但是可以分为三部分。前面在初始化一些有用的值,中间是用用户名生成序列号,后来是解决最后一位的取值问题。
再作一点疑难知识讲解:
0040FFE2和0041004C之间只有两条push语句。
所以第一部分的esp相当于循环中的esp+8。所以循环中的[ESP+EDX+10]事实上,相当于前面的[ESP+EDX+8]。从中我们就可以找出两部分之间的对应关系。至于其中的运算,希望你自己注意。慢慢分析。如果有必要自己可以列一张表,分析寄存器的值的变化。
最后第三部分
看
00410065 |. 885434 10 MOV BYTE PTR SS:[ESP+ESI+10],DL
00410069 |. C64434 11 00 MOV BYTE PTR SS:[ESP+ESI+11],0
很容易知道DL的来历,通过对ESP+ESI+10值的分析知道它是把DL的值添加到code尾。
比如说我原来生成的值是38 31 33 33 31 31 ,执行过00410065之后就是38 31 33 33 31 31 32。我们输入的用户名和注册码它都是当字符串在处理。但是你知道下面的一个0有什么意思吗?因为c字符串是以00结尾的。这里就是把用户名通过处理构建一个c字符串的解。cracker最终还是要看代码的,最后让我们用高级语言来实现一下上面我所说的。
#include <iostream.h>
#include <string.h>
void main()
{
int sz[8]={0x68,0x75,0x79,0x64,0x6F,0x6E,0x67,0x0};
char name[]="kflnig";
char code[10];//这个大小是我随便写的。
int zc=0,len,n,eax,edx,bl;
len=strlen(name);
for(n=0;n<len;n++)
{
bl=name[n];
edx=n % 7;
edx=sz[edx];
eax=bl;
eax=eax+edx+n+len;
edx=eax %9;
eax=eax /9;
edx=edx+0x30;
code[n+1]=edx;
}
eax=0x4d+len;
edx=eax % 9;
edx=edx+0x30;
code[0]=edx;
for (n=len;n>=0;n--)cout<<code[n];//不知道算不算是cout太聪明了,这里会输出的就是ancsii码值。
}
所以我
用户名:kflnig
序列号:8133112
下面就是一段比较。
00410072 |> /8A10 /MOV DL,BYTE PTR DS:[EAX];eax是伪码
00410074 |. |8A1E |MOV BL,BYTE PTR DS:[ESI];esi是真码
00410076 |. |8ACA |MOV CL,DL
00410078 |. |3AD3 |CMP DL,BL
0041007A |. |75 1E |JNZ SHORT ExtractR.0041009A;绝命的跳
0041007C |. |84C9 |TEST CL,CL
0041007E |. |74 16 |JE SHORT ExtractR.00410096
00410080 |. |8A50 01 |MOV DL,BYTE PTR DS:[EAX+1]
00410083 |. |8A5E 01 |MOV BL,BYTE PTR DS:[ESI+1]
00410086 |. |8ACA |MOV CL,DL
00410088 |. |3AD3 |CMP DL,BL
0041008A |. |75 0E |JNZ SHORT ExtractR.0041009A;绝命的跳
0041008C |. |83C0 02 |ADD EAX,2
0041008F |. |83C6 02 |ADD ESI,2
00410092 |. |84C9 |TEST CL,CL
00410094 |.^\75 DC \JNZ SHORT ExtractR.00410072
我之所以把这个代码贴出来是因为这个代码有点怪,用这种奇怪的方式一下子比较两个byte。
行文到此结束了,小鸟要努力看懂上面循环中一段运算的代码。找到注册码花了我2分钟,写这篇文章花了5个小时,值得!
最后,祝《黑客手册》生日快乐。
浙江省绍兴县柯桥中学高二(3)班李宁
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!