今天对第一个程序Acid burn.exe进行破解。此篇主要分爆破、寻找内置算法及密码两部分进行分析。
首先使用PEID对程序进行分析,可以知道程序是使用Delphi写的,且没有加壳。
进入程序,可以看到有两个输入密码的按钮,分别是“Serial/Name”和“Serial”,将它们分别作为入口1与入口2。下面先进入入口1,可以看到要求输入用户名以及对应的密码,在这里我分别输入123和456,可以看到程序出现了提示,说输入的有误:
在这里需要注意的是提示的标题以及内容!!!这在下面的分析中有用。
上面是入口1处的提示,下面我们来到入口2,看看那里是什么情况。可以看到进入入口2之后,程序要求输入字符串,在这里我输入123456,程序弹出相应的提示:
在这里可以看到这个提示的标题,与入口1处的提示是不同的!将提示的不同作为接下来分析的依据。
由于入口2的数据比入口1少,因此首先对入口2进行分析,主要分爆破、寻找内置算法及密码两部分分析。
首先对入口2处进行爆破。将入口2处提示标题“Failed”作为寻找的目标,使用IDA打开程序,在字符串窗口中找到相应的字符:
这样就可以找到这个字符串所在的位置:
可以看到这个字符串所在位置是经过跳转之后的地址,那么往上寻找,看一看跳转的位置。
可以看到,在E:0042F4D这个位置是跳转的语句,这就是爆破和寻找密码的关键所在。
只要更改它跳转的条件就可以实现爆破了。这里我使用OD将跳转的语句更改为NOP,
将修改后程序保存,再次运行,在入口2处输入123456,如我们所愿,成功爆破。
下面开始寻找入口2处的密码。
正如上面所说,在E:0042F4D这个位置是跳转的语句,这就是爆破和寻找密码的关键所在。要实现跳转,首先要对进行判断。那么判断是什么?在这里显然就是我们输入的字符与内置密码的比较判断。
在CODE:0042F4D5这个跳转位置的前面有一个call语句以及两个mov语句,这两个mov语句实际上是作为参数参与到call所在函数的运算中,我们使用OD进行动态调试看看到跳转语句的过程中发生了什么,在第一个mov语句即CODE:0042F4CA位置设置一个断点,开始调试。
当运行到call语句时,可以看一下eax和edx的值,可以看到eax的值是“123456”,edx的值是“Hello Dude!”,好了,这个 “Hello Dude!”是什么?这就是程序内置的密码!我们尝试使用“Hello Dude!”进行测试,看看我们找的这个对不对。
对啦!至此,对于入口2的处理就结束了。
下面对入口1分别进行爆破与注册码的处理。
上面说过,入口1与入口2处的提示存在明显的不同,这里我们将“Sorry,The serial is incorect!”作为处理的第一步, 使用IDA打开程序,并在字符串窗口中找到这个字符串
来到字符串相应的位置,并利用X找到调用字符串的位置,这里有两个对应的字符串位置,分别是CODE:0042FB1F和CODE:0042FA63。我们首先处理CODE:0042FB1F处。
可以看到,CODE:0042FB1F是一个跳转之后的一个位置,那么我们就循着这个跳转往上走
可以看到,CODE:0042FB03是跳转语句,它是实现是否正确提示的关键,这里首先对入口1进行爆破。
要实现爆破, 只需将CODE:0042FB03处的跳转语句修改为NOP就可以实现正确的提示了。
修改完成之后,我们再次在入口1处输入123和456,可以看到,出现了错误的提示,这是为什么?
在暂时找不到原因的情况下,看一看另一个字符串所在的位置,或许在那里会有收获。
我们来到CODE:0042FA63这个位置,
可以看到这也是在一个跳转语句的后面,往上看,“jge short loc_42FA79”,再往上看,有一个“cmp eax, 4”,这是什么?后面我们可以知道,这是判断字符串长度的语句。那先不管了,这里设置一个断点,另外在下面我们处理过的地方再次设置一个断点,看看到底是什么情况。
调试的过程中,依然使用123/456作为输入,程序运行到“cmp eax, 4”时,我们要注意寄存器的值,
可以看到,运行到CODE:0042FA57时,EAX= 1,这是什么情况?明明输入的是123啊!重新调试,输入12/354,再到这个断点看一下,EAX还是1!有问题。 那么输入4位以上的用户名是什么情况呢?再次调试并输入1234/5678,到达断点处,再看一下EAX,这次EAX=5,继续执行,看看怎么样,
这次对啦!原来这是对用户名还有长度的限制。那这样就好办了,将“CODE:0042FA5A 7D 1D jge short loc_42FA79”这里的jge改为jmp就可以绕过长度的限制了。
再次运行程序并在入口1处输入123/456,提示成功!
下面对入口1处的注册码进行寻找。
0042FA52 |. E8 D96EFDFF call Acid_bur.00406930
0042FA57 |. 83F8 04 cmp eax,0x4 ; 比较字符串的长度是否大于等于4
0042FA5A |. 7D 1D jge short Acid_bur.0042FA79
0042FA5C |. 6A 00 push 0x0
0042FA5E |. B9 74FB4200 mov ecx,Acid_bur.0042FB74 ; ASCII 54,"ry Again!"
0042FA63 |. BA 80FB4200 mov edx,Acid_bur.0042FB80 ; ASCII 53,"orry , The serial is incorect !"
0042FA68 |. A1 480A4300 mov eax,dword ptr ds:[0x430A48]
0042FA6D |. 8B00 mov eax,dword ptr ds:[eax] ; Acid_bur.00424090
0042FA6F |. E8 FCA6FFFF call Acid_bur.0042A170 ; 字符串长度小于4回到0042A170位置,输错错误对话框
0042FA74 |. E9 BE000000 jmp Acid_bur.0042FB37
0042FA79 |> 8D55 F0 lea edx,[local.4]
0042FA7C |. 8B83 DC010000 mov eax,dword ptr ds:[ebx+0x1DC]
0042FA82 |. E8 D1AFFEFF call Acid_bur.0041AA58
0042FA87 |. 8B45 F0 mov eax,[local.4]
0042FA8A |. 0FB600 movzx eax,byte ptr ds:[eax] ; 取出name字符串中的第一个字符
0042FA8D |. F72D 50174300 imul dword ptr ds:[0x431750] ; 乘以0x29(地址431750)
0042FA93 |. A3 50174300 mov dword ptr ds:[0x431750],eax
0042FA98 |. A1 50174300 mov eax,dword ptr ds:[0x431750]
0042FA9D |. 0105 50174300 add dword ptr ds:[0x431750],eax ; 再乘以2存在0x431750
0042FAA3 |. 8D45 FC lea eax,[local.1]
0042FAA6 |. BA ACFB4200 mov edx,Acid_bur.0042FBAC
0042FAAB |. E8 583CFDFF call Acid_bur.00403708
0042FAB0 |. 8D45 F8 lea eax,[local.2]
0042FAB3 |. BA B8FB4200 mov edx,Acid_bur.0042FBB8
0042FAB8 |. E8 4B3CFDFF call Acid_bur.00403708
0042FABD |. FF75 FC push [local.1] ; Acid_bur.0042FBAC
0042FAC0 |. 68 C8FB4200 push Acid_bur.0042FBC8 ; UNICODE "-"
0042FAC5 |. 8D55 E8 lea edx,[local.6]
0042FAC8 |. A1 50174300 mov eax,dword ptr ds:[0x431750]
0042FACD |. E8 466CFDFF call Acid_bur.00406718 ; 这个call函数中的内容就是生成serial中间数字串的部分
0042FAD2 |. FF75 E8 push [local.6] ; local.6是中间生成的password数字串
0042FAD5 |. 68 C8FB4200 push Acid_bur.0042FBC8 ; UNICODE "-"
0042FADA |. FF75 F8 push [local.2] ; Acid_bur.0042FBB8
0042FADD |. 8D45 F4 lea eax,[local.3]
0042FAE0 |. BA 05000000 mov edx,0x5
0042FAE5 |. E8 C23EFDFF call Acid_bur.004039AC ; 字符串拼接
0042FAEA |. 8D55 F0 lea edx,[local.4]
0042FAED |. 8B83 E0010000 mov eax,dword ptr ds:[ebx+0x1E0]
0042FAF3 |. E8 60AFFEFF call Acid_bur.0041AA58 ;得到正确的password
0042FAF8 |. 8B55 F0 mov edx,[local.4] ; 输入的Password:12345
0042FAFB |. 8B45 F4 mov eax,[local.3] ; 正确的password
0042FAFE |. E8 F93EFDFF call Acid_bur.004039FC ; 明显就是两个字符串比较喽
0042FB03 |. 75 1A jnz short Acid_bur.0042FB1F
算法就是name输入后先根据上面的结果生成数字字符串,然后再与其他的字母,符号拼接,生成成最后的serial。这就是这个name/serial算法的求算过程。
以下是注册机程序:
#include
#include
int main()
{
char buffer[200] = {0};
short int c;
while (1)
{
printf("please input name:\n");
scanf("%s",buffer);
if(strlen(buffer)<4) //判断序列号长度
printf("Too short!\n");
else
{
c=buffer[0]*0x29*2;
printf("Serial: CW-%4d-CRACKED\r\n",c);
}
}
return 0;
}