首页
社区
课程
招聘
[旧帖] 《用16进制编辑器编写一个DLL文件》大作的思想来查证在Adobe Reader应用开发时,DLL执行异常 0.00雪花
发表于: 2009-8-13 10:12 1417

[旧帖] 《用16进制编辑器编写一个DLL文件》大作的思想来查证在Adobe Reader应用开发时,DLL执行异常 0.00雪花

2009-8-13 10:12
1417
近日,在下想在Adobe Reader上做点应用开发,可怎想遇到了,不能解决的难题,也

曾试着用了些方法,但是都不奏效。所以恳请看雪牛人给予指点,在下不胜感激。
   
   事情的起因:应朋友之邀,为其做个生成pdf文件的后台程序。我选用了微软的VC++

6.0作为开发环境。按照以前的开发经验,只要能找到实现生成pdf文件相应DLL、Lib、以

及头文件,即可。经Google查之,Adobe公司只对付费购买了Reader用户才提供相应的

DLL,经与朋友确认,他没有付费版本的Reader。那就再Google,最后还是在国内某网

站,下载到了免费的AdobePDFL.dll文件。但就是它,给我带来了若干问题。

    调试步骤:1、虽然是拿到了免费的DLL,但我心里还是有点不放心。我先用VC++6.0

自带的Depends工具查了一下AdobePDFL.dll,该有的接口函数都有,相关的DLL也能找

到。嗯,可以开始了。

       2、像往常一样,编写代码如下:
        <a> HINSTANCE hInst;
        <b> hInst        = LoadLibrary( "AdobePDFL.dll" );
        <c> typedef ASText (*AddressFunction)(const char *);
        <d> FARPROC                        proc  = GetProcAddress(hInst, "ASAtomFromString");
        <e> AddressFunction pFunc = reinterpret_cast<AddressFunction>(proc);
        <f> pFunc("df");

      问题如期而至,代码运行到<b>、<d>、<e>时,均能正确返回,执行<f>时,调试器

报程序访问非法空间,程序跑飞。那就开始调试吧,先看<b>执行,我在<b>执行前后,

观察Windows任务管理器对应的本程序内存使用情况,的确有增加,大小也相仿。hInst

返回值非零。结论:暂且通过。再查装载地址是否正确?当跟踪到<d>、<e>两步时,与

Depends的分析结果中ASAtomFromString函数偏址作比较,结果是分毫不差。pFunc地

址非零。结论:暂且通过。执行<f>,反汇编,函数调用的前期执行正确,进入

AdobePDL.dll空间,程序跑飞。
   
    3、原因猜想:碰到此种事情,还是静下心来,好好分析一下,先预估一下有哪些可能

原因会导致代码失效:原因a,对DLL库装载流程,理解有误,导致根本不具备执行的可

能。原因b,对Adobe Reader接口函数理解不清,导致入口参数或返回值格式不匹配,进

而导致程序跑飞。原因c,Adobe把持着对AdobePDFL.dll的使用权控制,对于未授权的开

发一律封杀。
  
   4、逐一排查:排查原因a,我用如下代码:

        hInst        = LoadLibrary( "msvcrt.dll" );
        typedef int (*Example)(const char *format, ...);
        FARPROC                        where  = GetProcAddress(hInst, "printf");
        Example                        fire   = reinterpret_cast<Example>(where);
        fire("a");

      我找了最常用的printf函数所在的msvcrt.dll,嗯,完美通过。原因a,排除嫌疑。

排查原因b,我还是要先表扬一下Adobe,他们写的函数指南,全免费,超大容量。在他们

的Reader V9.0中居然有五千多页。我一共找了四类函数用来实验入口参数和返回值的情

况:分别是既无入口参数又无返回值;返回值为普通int型、入口参数无;返回为void型、

出口参数为int型;入口参数和返回值都是地址型。很遗憾,四类情况,不下数十个函数,

均歇在最后一步的函数执行上。我不可能将这数十个函数调用的调用都搞错吧,况且还有

入口参数和返回均无的简单情况,也不能执行。所以,我的结论是:原因b,排除嫌疑。

排查原因c,这对我就有点勉为其难。无从追踪,反汇编,逐步跟吧,功力不够,也查不出

一个所以然。所以,恳请看雪大牛,不吝赐教一二。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (8)
雪    币: 19
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
莫非是我没有将问题讲清楚,还是我取的这个主题,入不了大家的法眼?

自己继续调,赐教也继续等!
2009-8-13 18:01
0
雪    币: 33
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
帮忙顶一下,虽然我不明白,呵呵
2009-8-14 15:47
0
雪    币: 19
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
近日,本人不敢懈怠,终日思索如何解决上述问题。幸好看到曾健生的大作《用16进
制编辑器编写一个DLL文件》(以下简称:大作),认真拜读,希望能找到解决问题的方法。我现将这几日的调试过程记录如下,请大家指点(大家可以无需顾忌,所有方面都能点评,从分析思路、调试方法、甚至于文笔和排版,不过我还是希望大家更多就问题给出点评,致谢!)
       
        对于出问题的AdobePDFL.dll(以下简称:AP.dll)的调试,先用Depends查了它的相关dll的包容情况,我都一一将相关dll拷贝至调试目录。

        然后,对照《大作》,逐字分析AP.dll文件。现将结果及我的理解记录如下:《大作》中提到_IMAGE_DOS_HEADER.elfanew的大小为00000090H,AP.dll的对应值为00000110H,该项数据虽与《大作》说明有异,但我有找了几个操作系统库中的dll,发现都与《大作》说明有异,但是他们都有一个共同特点,只要在_IMAGE_DOS_HEADER.elfanew记录的地址能找到_IMAGE_NT_HEADERS.Signature的“PE”值,即可。通过AP.dll的_IMAGE_DOS_HEADER.elfanew==00000110H的位置找到了“PE”,那说明AP.dll的此项内容正确。

        _IMAGE_OPTIONAL_HEADER对应的关键数据项,说明如下:SizeOfCode = = 2EA000H、SizeOfInitializedData = = 185000H、SizeOfUninitializedData = = 0H、SizeOfHead = = 1000H。这几项的加和为470000H,和我点击文件属性查的大小一致,那说明AP.dll的这几项数据也正确。以下是另外几项,我认可的数据:BaseOfCode = = 1000H、BaseOfData = = 2EB000H、SizeOfImage = = 475000H。对于AddressOfEntryPoint = = 12DEH数据,我严重怀疑其正确性,但是我按《大作》讲解的,将其改为与BaseOfCode一致,程序也无法正确运行。对于ImageBase = = 10,00,00,00H,与《大作》讲解有距离,《大作》说:该值可填全零,由系统自行在装载时,决定其内容,但是我的实验结果是,将该值改为除10,00,00,00H外的所有值,那么程序连着以前能正确执行的<b> hInst        = LoadLibrary( "AdobePDFL.dll" )(请见1楼),也不能执行。所有到现在,我还是怀疑,AP.dll动态装载执行不成功,就是源于,执行位置,具体是如何引起的,我还在调试…

        接下来,我来说区块表,一共五块,分别为:.text、.rdata、.data、.rsrc、.reloc。具体说明如下:.text的VirturalSize = = 2E946BH,VirtualAddress = = 1000H,SizeOfRawData = = 2EA000H,PointToRawData = = 1000H
. rdata的VirturalSize = = CE12AH,VirtualAddress = = 2EB000H,SizeOfRawData = = CF000H,PointToRawData = = 2EB000H
. data的VirturalSize = = 47B58H,VirtualAddress = = 3BA000H,SizeOfRawData = = 43000H,PointToRawData = = 3BA000H
. rsrc的VirturalSize = = 3A28CH,VirtualAddress = = 402000H,SizeOfRawData = = 3B000H,PointToRawData = = 3FD000H
. reloc的VirturalSize = = 37ECCH,VirtualAddress = = 43D000H,SizeOfRawData = = 38000H,PointToRawData = = 438000H
   上述数据,正好是一块接一块,上块的地址加(+)上块的大小,正好等于下一块的起始地址,但是也有纰漏(请自查),但我认为不会带来影响,可以放过。

        好了,有上述的分析数据,再对照《大作》的讲解,我就来分析
<a> HINSTANCE hInst;
        <b> hInst        = LoadLibrary( "AdobePDFL.dll" );
        <c> typedef ASText (*AddressFunction)(const char *);
        <d> FARPROC                        proc  = GetProcAddress(hInst, "ASAtomFromString");
        <e> AddressFunction pFunc = reinterpret_cast<AddressFunction>(proc);
        <f> pFunc("df");
        到底的是在什么地方,导致程序跑飞。

跟踪到<f>步骤,反汇编:
Mov esi, esp
Push off string  “df”  ;                Address = = 41F058H
Call dword ptr [ebp-0ch] ;        预期调用pFunc("df"),即ASAtomFromString(“df”);
我在跟踪进入其中
1000F510 6A FF                push        0FFh
1000F512 68 D8 0B 2C 10       push        102C0BD8h
1000F517 64 A1 00 00 00 00    mov         eax,fs:[00000000]
1000F51D 50                   push        eax
1000F51E 83 EC 10             sub         esp,10h
1000F521 53                   push        ebx
1000F522 55                   push        ebp
1000F523 56                   push        esi
1000F524 57                   push        edi
1000F525 A1 10 AE 3B 10       mov         eax,[103BAE10]
1000F52A 33 C4                xor         eax,esp
1000F52C 50                   push        eax
1000F52D 8D 44 24 24          lea         eax,[esp+24h]
1000F531 64 A3 00 00 00 00    mov         fs:[00000000],eax
1000F537 8B 7C 24 34          mov         edi,dword ptr [esp+34h]
1000F53B 80 3F 00             cmp         byte ptr [edi],0
1000F53E 75 16                jne         1000F556
跳走
1000F540 33 C0                xor         eax,eax
1000F542 8B 4C 24 24          mov         ecx,dword ptr [esp+24h]
1000F546 64 89 0D 00 00 00 00 mov         dword ptr fs:[0],ecx
1000F54D 59                   pop         ecx
1000F54E 5F                   pop         edi
1000F54F 5E                   pop         esi
1000F550 5D                   pop         ebp
1000F551 5B                   pop         ebx
1000F552 83 C4 1C             add         esp,1Ch
1000F555 C3                   ret
1000F556 A1 3C F3 3F 10       mov         eax,[103FF33C]
1000F55B 50                   push        eax
1000F55C FF 15 38 B4 2E 10    call        dword ptr ds:[102EB438h]
正确返回,这就给我最大的疑惑,假如是AP.dll的文件结构加密或是做能什么手脚,那应该什么函数都不能执行(地址空间是从10000000H开始的,很明显是按照ImageBase定义的位置装载的),但是现在的事实是,不但执行了,还有返回,不解。唯一能解释的是:该处的函数调用不是AP.dll自身的,而是来自所包含的系统dll(纯猜测)。
1000F562 8B 58 20             mov         ebx,dword ptr [eax+20h]
1000F565 8D 4C 24 34          lea         ecx,[esp+34h]
1000F569 51                   push        ecx
1000F56A 8D 54 24 20          lea         edx,[esp+20h]
1000F56E 52                   push        edx
1000F56F 8B CB                mov         ecx,ebx
1000F571 89 5C 24 1C          mov         dword ptr [esp+1Ch],ebx
1000F575 E8 36 E7 FF FF       call        1000DCB0
到此处就Game Over,问题又留给大家了,同时,我也会继续努力的,未完,continued …
2009-8-17 11:46
0
雪    币: 19
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
恳请大家给出指导意见,致谢!
2009-8-17 16:24
0
雪    币: 19
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
一晃,调试几近十日。在此期间,本人好好拜读了“看雪”若干与DLL有关的大作,直至今日下午14时许,终于可以将问题理顺,特记录如下,还恳请大家指正,不甚感激!

    我在前面几贴中猜测的问题如下:1、我猜测:Adobe公司处于对其知识产权的保护,对未购买的客户所获得的相关DLL,做了手脚,导致我通过LoadLibrary和GetProcAddress获得的函数入口是镜中月、水中花,看是看得,但是一运行过程中有可能歇菜。2、在返回反汇编模式下,我在逐个函数排除过程中,发现动态装载完AdobePDFL.dll(以下,简称AP.dll)后,在运行中某些函数能用,而有些函数则会出故障;当时我的猜测是:能运行的是AP.dll中调用OS接口函数,不能运行的是AP.dll自身的函数。

        先讲结论,再讲调试过程。

结论是:大方的Adobe公司目前还为对AP.dll做任何手脚,无论该用户是否购买其产品,AP.dll提供的软件功能是完善的。而至于我先前遇到的软件问题,是另有文章。

        调试过程:刚开始的几日,是对照《用16进制编辑器编写一个DLL文件》、以及《【翻译】“PE文件格式”1.9版 完整译文(附注释)》(以下,合称《大作》),将AP.dll整理成文,以备在跟踪是查对。AP.dll有个特点,它将虚拟基址写得很大,然后各节数据内容装载的位置完全与内存装载位置平行一致,这样就有一个好处,省去了虚址与文件地址的转化。缺点也是显而易见的,耗费内存和磁盘空间(主要还是磁盘空间)。AP.dll的构成方式,巧妙的回避了《大作》中返回论述的内存地址、磁盘文件地址的转换(其实,两者的对应转换还是很重要的,正因为《大作》中的指点,我才能读懂AP.dll的两套地址的关系。假如大家有时间,好好看看AP.dll的编排,是会有有收获的)。做了这么多预备工作,开始具体工作:
        同样,也要选取一个程序片段,如下:
        <a>、handle = LoadLibrary(_T("AdobePDFL.dll"));
        <b>、typedef        PDDoc (*Address)( );
        <c>、Address func = (Address)GetProcAddress( handle, ("PDDocCreate") );
        <d>、func();
        代码出现故障的位置我在前面几贴已经做了详细说明,可以确定,是进入<d>后出现的故障,跟踪如下:(左列中的地址,是执行代码的执行地址)
func();
0040105A   mov         esi,esp
0040105C   call        dword ptr [ebp-8]
0040105F   cmp         esi,esp
00401061   call        __chkesp (004010b0)
没什么好商量的,进入0040105C的call调用,代码如下:
100B3620   push        ebp
100B3621   mov         ebp,esp
100B3623   push        ecx
100B3624   push        ecx
100B3625   and         dword ptr [ebp-4],0
100B3629   lea         eax,[ebp-8]
100B362C   push        eax
100B362D   mov         dword ptr [ebp-8],8
100B3634   call        100B3376

让我们来看看:100B3620   push        ebp,我就关心它的地址,100B3620 = 10000000 + B3620;10000000是ImageBase,而B3620就是PDDocCreate函数在AP.dll通过 IMAGE_DIRECTORY_ENTRY_EXPORT 索引到的地址位置。到目前,好像可以相信Adobe没有对AP.dll做什么手脚。我们再跟踪,看看后面的情况。

100B3634   call        100B3376,又有调用,这次我们关心,call的地址,100B3376 = 10000000 + B3376。B3376也是能通过 IMAGE_DIRECTORY_ENTRY_EXPORT索引到的函数地址,而且这个函数名更加可以使我们确信,B3376对应的函数是PDDocCreateWithParams。跟踪,进入100B3376,代码如下:
100B3376   push        ebp
100B3377   sub         esp,70h
100B337A   lea         ebp,[esp-4]
100B337E   mov         eax,[103BAE10]
100B3383   xor         eax,ebp
100B3385   mov         dword ptr [ebp+70h],eax
100B3388   push        24h
100B338A   mov         eax,102CBE78h
100B338F   call        102958BF

终于出现要思考的地方了,call        102958BF是哪个函数,导出函数的名称、地址、序号三者看是的地址分别为:3ADDF8、3AF5C0、3B0D88,各个地址间正好相差5F2(导出函数个数)乘以4(每个地址字长)的长度。2958BF会是什么呢?刚开始,我也怀疑是不是Adobe使了手段,后来一想,这么大一个AP.dll就没有一些支撑型函数,况且2958BF所指的地址也不在IMAGE_DIRECTORY_ENTRY_EXPORT指引返回内。嗯,102958BF就是一支撑型函数。

继续跟进,此后一路,就是进进出出函数,让我们到将出现故障的程序片段附近吧!

10057420   mov         eax,[103FF33C]10057425   push        eax
10057426   call        dword ptr ds:[102EB438h]
1005742C   mov         ecx,dword ptr [esp+4]
10057430   push        ecx
10057431   mov         ecx,dword ptr [eax+9Ch]
10057437   call        10057280

[103FF33C]是AP.dll定义的数据区,取变量了?这个与AP.dll有关的变量在我的程序中没有直接操作或通过函数间接操作过,由此再做计算,哪有不跑飞程序的道理?就在 mov         ecx,dword ptr [eax+9Ch]语句中,访问到了非法地址,程序“完美”跑飞!

感激和收获就留到下回再说吧!

来“看雪”,我很希望每次都有,“雪后初晴”的心情。今天是有的!
2009-8-26 22:04
0
雪    币: 63
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
这样的文章很好,支持lz
2009-8-27 10:40
0
雪    币: 19
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
“三人行,必有我师”。看雪中的大师很多,值得我学习的地方更是不胜枚举。

我在注册后的这一个月里,几乎是逐贴过眼、过心,唯恐自己会错过精彩的章节。今日,在IDA环境中也试着爆破了一个共享软件,但是这不是我今天想谈的重点。我很想说说:看雪给我们带了什么?我们可以为看雪贡献什么?

说来实在惭愧,与软件打交道也有些年头了,若不是因为前些日子,在开发中遇到了与PE有关的难题,可能认识看雪的日子还得往后拖。正是在这段日子里,看到了大师们将PE知识点讲得透彻,很明显这是看雪给我们带来的。然后,继续学习,看到了大师们将code如庖丁解牛般逐一拆开,然后又按照自己的目的(破解,杀毒)逐一修复,一场场酣畅淋漓的智力盛宴就展示在了大家面前。但是,在我心里总觉得还缺少点什么。那就是,我学完后,能给看雪做点什么呢?我看到了有许多人,将破解成功后的喜悦和收获,都反馈给看雪。首先,这毫无疑问,这是可以值得肯定和赞扬的。但是,除此之外,一个优秀的软件从业人员,还能做点什么呢?大师们也给了我们做了榜样:出书和杀毒(软件攻防),或者就是为了寻找破解后的一种精神上的愉乐。

很遗憾,我现在回答不出来,我能为看雪贡献什么?而且我很想知道,我们能为看雪贡献什么?
2009-9-10 16:42
0
雪    币: 19
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
再没人来,就只能练“左右手互搏术”啦!
2009-9-11 18:54
0
游客
登录 | 注册 方可回帖
返回
//