文章标题】: pdf2word1.6算法分析
【文章作者】: tjszlqq
【软件名称】: pdf2word1.6
【下载地址】: http://www.download.com/PDF2Word/3000-6675_4-10250723.html
【加壳方式】: 无壳
【保护方式】: 序列号
【编写语言】: vc6.0
【使用工具】: dfx.exe,immunity debugger
【操作平台】: 正版windowsxp
【软件介绍】: 把pdf转换成rtf
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2008年02月23日 22:39:56
看雪老大不让分析国内的软件,那我就分析国外的,应该没问题,学了几十年的破解,终于找到一个超简单的让我破解了,太高兴
了!
这个软件是共享软件,不注册只能试用一百次,运行时会弹出注册窗口,有错误提示“Series number error, please check it
and try again."用dfx.exe 查出pdf2word1.6为vc6.0编写,然后用immunity debugger载入,用ccdebuger教我们的字串参考,等
这个软件载入后,在代码的某个地方右击,选所有参考字符串。在这个程序中一个有所有字符串的新窗口弹了出来,往上翻屏并且
再次右击。然后选择搜索文本,再把“Series number error, please check it and try again."写进去。不过要记得勾上“区分
大小写”,然后按ok.
你将会来到下面这里:
代码:
00429F6F | PUSH pdf2rtf.00468270 | ASCII "Series number error, please check it and try again."
现在按F2把这行设一个断点,在这一行的上面你会看到其它的一些字符串,也许有用,所以也把它们下断点,如下:
"Thank you registered" and "Thank you registered VeryPDF PDF2Word v1.6."
现在双击代码的某一行,按F9运行这个程序。
注册窗口又再次弹出来,然后填上一个电子邮件地址,一个假码,然后点ok.
返回到od,你会看到停在下面这行:
00429F6F . 68 70824600 PUSH pdf2rtf.00468270 ; |Text = "Series number error, please check it and try again."
这是那条错误消息,这个程序在显示它之前停了下来。
你会看到这条错误消息是call MessageBoxA的一部分,这是调用API函数显示这条消息,如果在这之
用所有参考字串里面看过另外一条字符串,你会知道另外一个MessageBoxA和"Thank you registered VeryPDF PDF2Word v1.6."
在一块。
这就意味着如我们输入正确的注册码,会显示"Thank you registered VeryPDF PDF2Word v1.6."这条消息。
这个程序会按照你的输入来显示那条信息,来做这事事的代码一般在这条消息的不远处,往上翻屏,你会看到一条包含JNE,JE,JNZ
or jz的代码.这会跳转会发生在遇到一些事的时候。
一般测试条件就直接在跳转的上面,
你会看到如下代码:
00429F2E . 85C0 TEST EAX,EAX
00429F30 . 74 39 JE SHORT pdf2rtf.00429F6B
如eax为0,就跳,
如果我们跟踪这个跳转,发现跳过了"Thank you registered VeryPDF PDF2Word v1.6.",这样我们就知道eax为0就会显示错误消
息。
我们可以用nop把 JE SHORT pdf2rtf.00429F6B 代替,让程序总显示正确消息,不过重启这个程序会继续要我们注册,
所以我们需要继续搜索,我们需要找出EAX的值是什么时候得到的,
在TEST EAX,EAX上面二条指令我们可以看到
00429F26 . E8 F5F7FFFF CALL pdf2rtf.00429720
这是一个call调用这个程序某一处的子程序,你可以用生命来打赌一定是这个子程序设定了这个EAX的值,
所以我们需要找出这个子程序到底是怎么设的这个值,为了达到目的,我们按F2在 CALL pdf2rtf.00429720 上我们要设另外一个
断点。
现在我们要再次重新载入这个程序,使它中断在这个CALL上,按快捷键<CTRL>+<F2>就可达到,当程序要退出的时候(另可以按左
方向键和enter键)选是然后这个程序就重起了。
现在再次按<F9>让程序跑起来。
你会看到注册框会再次跳出来,所以你要把电子邮件地址和注册码填上,然后按ok.
就像你看到的那样程序中断在 CALL pdf2rtf.00429720 这条批令上了,
现在按 <F7>进入到这个call里面。
前面四条指令我们不感兴趣,所以我们从00429725开始分析,
下面就是我们看到的代码:
00429725 |. 8B7424 3C MOV ESI,DWORD PTR SS:[ESP+3C]
00429729 |. 57 PUSH EDI
0042972A |. 8A06 MOV AL,BYTE PTR DS:[ESI]
0042972C |. 8A4E 01 MOV CL,BYTE PTR DS:[ESI+1]
0042972F |. 8A56 0E MOV DL,BYTE PTR DS:[ESI+E]
00429732 |. 884424 18 MOV BYTE PTR SS:[ESP+18],AL
00429736 |. 32C0 XOR AL,AL
00429738 |. 884C24 30 MOV BYTE PTR SS:[ESP+30],CL
0042973C |. 8A4E 0F MOV CL,BYTE PTR DS:[ESI+F]
0042973F |. 884424 19 MOV BYTE PTR SS:[ESP+19],AL
00429743 |. 884424 31 MOV BYTE PTR SS:[ESP+31],AL
00429747 |. 884424 25 MOV BYTE PTR SS:[ESP+25],AL
0042974B |. 884424 0D MOV BYTE PTR SS:[ESP+D],AL
0042974F |. 8A46 02 MOV AL,BYTE PTR DS:[ESI+2]
00429752 |. 3C 24 CMP AL,24
00429754 |. 885424 24 MOV BYTE PTR SS:[ESP+24],DL
00429758 |. 884C24 0C MOV BYTE PTR SS:[ESP+C],CL
0042975C |. 75 52 JNZ SHORT pdf2rtf.004297B0
我已经把到开始检查字串以上的整个块都放到上面了,现在开始分析。
第一行-->把我们输入的注册移到esi
第二行-->不重要
第三行-->把我们的注册码第一个字符移al
第四行-->把我们的注册码第二个字符移cl
第五行-->把我们的注册码第十五个字符移dl
第六行-->把al中的内容送[esp+18]
第七行-->清除al中的内容
第八行-->把cl中的内容移[esp+30]
第九行-->把第十六个字符移到cl
第十,十一,十二,十三行-->当al还是空的时候把[ESP+19],[ESP+31],[ESP+25] & [ESP+D]中的内容清空
第十四行-->把我们输入的第三个字节移到al
第十五行-->把AL的内容和0x24比较
第十六行-->把第十五个字节移至[ESP+24]
第十七行-->把第十六个字节移至 [ESP+C]
第十八行-->如果AL不等于0x24就跳到004297B0
如果你跟踪十八行的跳转你会看到它会跳到下面的代码:
004297B0 |> 5F POP EDI
004297B1 |. 5E POP ESI
004297B2 |. 33C0 XOR EAX,EAX
004297B4 |. 5D POP EBP
004297B5 |. 83C4 30 ADD ESP,30
004297B8 \. C3 RETN
可以看到恢复被保存的值,把eax的值搞为0,然后返回到我们调用这个子程序的地方。
如果我们让它这么发生的话,那么eax会是0也就会给我们错误的提示框。
现在我们从上面这些代码可以知道什么?
-al必须等于0x24要不然就会得到错误提示框
-在等于0x24之前程序把第三个字符搞到al中
-这个程序把第十六个字节搞到cl
从上面的结论我可以得出第三个字符必须为$还有我们的注册码必有十六个字符好让我们把到搞到cl中去,
所以我们的注册码应该像这样 :..$.............
现在是接着的一片代码:
0042975E |. 8B3D 4C964400 MOV EDI,DWORD PTR DS:[<&MSVCRT.atoi>] ; msvcrt.atoi
00429764 |. 8D5424 0C LEA EDX,DWORD PTR SS:[ESP+C]
00429768 |. 52 PUSH EDX ; /s
00429769 |. FFD7 CALL EDI ; \atoi
0042976B |. 8BE8 MOV EBP,EAX
0042976D |. 8D4424 1C LEA EAX,DWORD PTR SS:[ESP+1C]
00429771 |. 50 PUSH EAX
00429772 |. FFD7 CALL EDI
00429774 |. 03E8 ADD EBP,EAX
00429776 |. 83C4 08 ADD ESP,8
00429779 |. 83FD 0A CMP EBP,0A
0042977C |. 75 32 JNZ SHORT pdf2rtf.004297B0
我们来分析它吧:
第一行-->把函数MSVCRT.atoi的地址搞到edi中
第二行-->把第十六个字符搞到edx中
第三行-->把edx做为参数关起来
第四行-->来到系统区做运算,结果会算到eax中
第五行-->把eax中的内容搞到ebp中
第六行-->把我们的第一个码码搞到eax中
第七行-->把这次关eax
第八行-->把我们的码码搞到系统区做运算,最后再搞回来,
第九行-->加法运算,
第十行-->不重要
第十一行-->把ebp减去0A如果结果不是0就让jnz实现
第十二行-->见风使舵
现在我们从上面的代码得到什么了?
-第十六个字符搞到atoi,说明这个字符的值在0-9之中取
-第一个字符也被关过,说明也要在0-9中取
-第十六个加第一个要等于0xa。
所以我们得到下面的注册码:1.$............9
你可以想像,第一个字符各第十六个字符可以为任何东西只要它们都有是数字,还有它们加
起来等于十进制的十,
到了看下一片代码的时候了:
0042977E |. 8D4C24 24 LEA ECX,DWORD PTR SS:[ESP+24]
00429782 |. 51 PUSH ECX
00429783 |. FFD7 CALL EDI
00429785 |. 8D5424 34 LEA EDX,DWORD PTR SS:[ESP+34]
00429789 |. 8BE8 MOV EBP,EAX
0042978B |. 52 PUSH EDX
0042978C |. FFD7 CALL EDI
0042978E |. 03E8 ADD EBP,EAX
00429790 |. 83C4 08 ADD ESP,8
00429793 |. 83FD 0A CMP EBP,0A
00429796 |. 75 18 JNZ SHORT pdf2rtf.004297B0
还是让我们来分析一下:
第一条-->第十五个字符搞进ecx
第二条-->关起来
第三条-->用系统区的代码来搞ecx,最后把结果搞到eax
第四条-->第二个字符搞到edx
第五条-->被系统区搞过的ecx再搞到ebp中
第六条-->再把ebp关起来
第七条-->把ebp放出来,放到eax中
第八条-->第十五和第二个字符结婚,
第九条-->分析不出来
第十条-->生出来是不是男的,
第十一条-->不是男的,就丢了,
就像你看到的那样,这片代码跟上面分析的很类似,所以就不更一步分析了
。
现在我们可以得到下面的代码:12$...........89
为了到达某个地方,我们还要分析一些代码:
最后要分析的一片代码:
00429798 |. 807E 03 24 CMP BYTE PTR DS:[ESI+3],24
0042979C |. 75 12 JNZ SHORT pdf2rtf.004297B0
0042979E |. 8A4E 05 MOV CL,BYTE PTR DS:[ESI+5]
004297A1 |. 33C0 XOR EAX,EAX
004297A3 |. 80F9 23 CMP CL,23
004297A6 |. 5F POP EDI
004297A7 |. 5E POP ESI
004297A8 |. 5D POP EBP
004297A9 |. 0F94C0 SETE AL
004297AC |. 83C4 30 ADD ESP,30
004297AF |. C3 RETN
分析:
第一排-->第四个字符和0x24比较
第二排-->不相等就到004297B0
第三排-->送第六个字符到cl
第四排-->检查第六个字符是不是等于0x23
第五,六,七排-->不重要
第八行-->上面相等就把al设成1
第九行-->不重要
第十行-->回到调用的地方 得出第四节必须为0x24还有第六字节必须为0x23
如果都成立的话al就会设为1也就意谓着eax不必为零了,也就会使程序给我们正确的提示
概括:
-check if 3th == $
-check if 1st + 16th == 10
-check if 15th + 2nd == 10
-check if 4th == $
-check if 6th == #
其它的字符对建造一个有效的注册码来说不重要了,所以我们的注册码可以是这样:
12$$.#........89
你可以把点号的地方填入任何你想填的,只要你把第一个,第二个,第十五个还有十六个填对。
注册机源码:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{ char serial[50],name[50];
int len,l1,l2,l15,l16;
printf("please input you email:");
scanf("%s",name);
printf("please input you series:");
scanf("%s",serial );
len=strlen(serial);
if (len<16)
printf("serial must more than 15 characters!");
else
{ if(serial[0]<58&&serial[0]>48&&serial[1]<58&&serial[1]>48)
{l1=serial[0];
l1=l1-48;
l2=serial[1];
l2=l2-48;
l15=10-l2;
l16=10-l1;
printf("serial is:%d%d$$%C#%C%C%C%C%C%C%C%C%d%d",l1,l2,serial[4],serial[6],serial[7],serial[8],serial[9],serial[10],serial[11],serial[12],serial[13],l15,l16);
}
else
{
serial[2]='$';serial[3]='$';serial[5]='#';
printf("serial is:37%c%c%c#%c%c%c%c%c%c%c%c37",serial[2],serial[3],serial[5],serial[6],serial[7],serial[8],serial[9],serial[10],serial[11],serial[12],serial[13]);}
}}
大家可以提出意见骂我,我这个人很好,不会生气!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)