调试Adobe Reader DC的一些记录
最近研究了Adobe PDF阅读器(Acrobat Reader DC)以下简称Acrobat,但是它没有符号,调试起来异常的痛苦,这里就记录下本人查阅资料在加上动态调试后的相关内容,这里得感谢360的大佬们在安全客上发的一篇PDF调试技巧剖析
Windbg命令
这里列出经常使用的命令:
sxe ld escript
,在加载escript.api的时候抛出异常,这样就能断在windbg里!heap -p -a addr
,如果addr是一个堆里的地址,那就能显示出该chunk的具体信息s -d 0 l?7fffffff value
,在内存中搜索value,通常用来定位js对象的地址.hh
,弹出帮助文档lm m ES*
,查看模块地址(支持通配符),列出全部模块可以用lmf
命令gu
,执行到返回,ga addr
,执行到addr$$>< script_path
,运行脚本dd/du/dc addr
,显示内存
文档下载
这是Acrobat的官方API文档:https://opensource.adobe.com/dc-acrobat-sdk-docs/acrobatsdk/documentation.html ,里面其实也就公开了一些API,但是总好过没有
API ref:https://opensource.adobe.com/dc-acrobat-sdk-docs/acrobatsdk/pdfs/acrobatsdk_jsapiref.pdf ,这个建议下载拿来对照着看,当作参考书来查对象的属性或者方法
寻找this对象
根据PDF调试技巧剖析里的讲解,我自己总结出的寻找this对象的步骤为:
也就是1003100e地址的那一句
- 接着顺藤摸瓜向上找到pc的值,如图中就是[ebp-28h],具体原因可以看360大佬的那篇文章
- 在找到fp的地址,通过他来获取this对象的地址:
寻找到了this对象后,再用脚本打印出this的属性,这样就能查看js代码中所有变量的值了,脚本为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29r @$t0 = 0fc29cb8 ; // <---这里替换为前面找到的this对象地址
r @$t1 = poi(@$t0) ;
r @$t2 = poi(@$t0 + 0x8 );
r @$t8 = poi(@$t1 + 0x10);
.for(; @$t8 != 0; r @$t1 = @$t8;r @$t8 = poi(@$t1 + 0x10)) {
r @$t3 = poi(@$t1 + 0x4);
r @$t9 = 0;
.catch {
du poi(@$t3 + 0x4);
r @$t9 = 0xaa
};
.if (@$t9 != 0xaa) {
r @$t3
};
r @$t3 = poi(@$t1 + 0x8);
r @$t4 = @$t3 >> 0n27;
r @$t5 = @$t3 & 0x00ffffff;
r @$t4, @$t5;
.if(@$t5 < @$t4) {
dd @$t0+0x18+@$t5*8 L0x2;
}.else {
r @$t5 = @$t5-@$t4;
dd @$t2+@$t5*8 L0x2;
};
.echo --------------------;
}脚本用前面提到过的
$$><
命令来加载
寻找函数地址
由于Acrobat没有符号,本着能重命名一个函数是一个的原则,我就介绍一些能找到的,相对比较准确的一些函数地址的寻找方法或者特点
js对应api的native实现
就如大佬文章中所说的,大部分的native实现都可以通过在EScript.api模块中的字符串的交叉引用来寻找到,以app.alert
来举例:
但是其实也只是找到了该函数的地址,你如果跟进去看,就会发现这都是些啥啊。。。。。
有一些方法并不在escript.api中,而在其它插件模块中,其中比较常见的是Acroform.api
,一般对象的属性都能找到的,而且这种函数由很明显的特征,就是一个对象的全部属性都会向上面alert函数那样,由一个函数注册(那个应该是个注册函数)
内存分配函数的封装
这些函数由很明显的二进制特征,比如calloc:
1 | // 这些函数我已经重新命名过了 |
一般这个calloc最好找也最明显,找到这个后,给函数重命名,接着就把那个全局变量命名为memobj,就是(void *)(*(int (__cdecl **)(size_t))(memobj + 4))(Size);
这一句,后面在逆向的时候如果看见用到了memobj,你可以猜测那就是个内存分配相关的函数,根据参数来猜,比如这个malloc:
1 | int __cdecl malloc_(wchar_t *a1) |
这个不一定准确,还需要具体动态调试,看他最后到底是不是调用到vcruntime.dll里的内存分配函数了
一些其它对象的表示
我只在别人发的cve分析文章里看见,看一个学一个,我也不知道作者他们咋知道这些个对象是怎么个表示法和对应的处理函数在哪,orz
pdf库
我们要能构建一个任意的pdf,最简单的办法就是利用别人写好的库,其中pyPDF2拿来构建自定义pdf和添加js代码都比较简单,项目地址为:https://github.com/mstamy2/PyPDF2
当然还有好多库,能用就行
参考链接
PDF调试技巧剖析 https://www.anquanke.com/post/id/188138