ASLR影响下修复一dll的某个bug
00 前言:之前在使用某软件的报表组件时发现它导出文件时无法写入中文,最近闲了下来,尝试修复其bug;
本文涉及 OD 的导入库、用 LordPE 关闭 ASLR、添加 IAT、修补代码时对 ASLR 的处理等内容;
在叙述时,会把一些思路进行说明,所以有些啰嗦,请多多包涵,也希望给萌新们带来收获;
01 定位问题点:
测试用例就不细说了,就是简单的从数据库中查询记录显示到报表组件中,添加一按钮,实现报表导出为 csv 文件;
首先载入OD,F9 运行,因为是导出文件,所以下 WriteFile 断点
主程序界面上点击按钮,进行文件导出,此时 OD 停在 WriteFile 断点处,ALT+F9,返回到用户领空
此时发现用户领空中有一些 API 只有序号,没有函数名,这样很难分析,那首先要显示出函数名。
像图中使用的是 mfc100u.dll,那就需要 mfc100u.lib 文件,因为电脑里只安装了 VS2017,没有 2010,找不到该文件,然而翻遍了全网都没有找到直接下载的;
最后,还是在本论坛悬赏帖里找到了 冰若° 大佬 OD-2.0 ,里面有相当全的 lib 库文件,感谢 冰若° 大佬!(下载帖 https://www.52pojie.cn/thread-704349-1-1.html,下载后有报毒,没有分析过,冰若°大佬有篇帖子是说,程序加过 UPX 壳,杀软会误报;咱小白,啥都不懂,幸好是只需要里面的导入库 ^_^)
将导入库文件夹下的所有文件复制到 OD 目录下的 lib 文件夹下,而后 OD菜单栏“调试” - “选择导入库”,弹出框中点击“添加”,选择 OD/lib 目录下的所有文件(是的,可以多选,那直接 Ctrl+A,方便),点击“处理” 即可。
重新载入程序,按之前的操作,断下后回到用户领空,此时 API 已经能看到函数名称了。
向上翻,可以看到程序写入文件是用的 CStdioFile的WriteString,bd下该函数导出中文时需要 setlocale( LC_CTYPE, "chs" )。
Ctrl+N,查看该 dll 导入表,发现没有 setlocale,因此需要添加导入表。
而修补的时机选择在此处 的 push 0,因为该处刚好是下方 CStdioFile::Open 需要的三个参数,不会引起异常,再往下是循环写入文件,不适合;
另外因为是 __stdcall 的关系,之后修补代码时不需要关注寄存器的值,只需注意堆栈就行了。
整理下思路,要做的事情是:
1. 添加导入API setlocale;
2. 在 push 0 的地方 jmp 到 修补代码处;
3. 修补 setlocale( LC_CTYPE, "chs" );
4. 补全 push 0 之后被占用的原代码,jmp 回原代码;
02 修补
0201 去掉 ASLR
为了方便,先关闭 ASLR,去掉重定位带来的不便。。
如图,运行 LordPE,点击“PE编辑器”,选择 dll,点击“特征值”,勾选“重定位已分离”,“确定”,“保存”,“确定”,“退出”。
0201 添加 API
打开 StudyPE+,将 dll 拖入 StudyPE+,点击“导入”,右键,“添加导入函数”;选择文件 mvcr100.dll,选择 API setlocale,点击“添加”;记录下该 API 的 RVA,也就是 0x00055CDC。
0203 补代码
OD 载入 DLL,因为只有一小段新增代码,所以没有新增区段,直接在最后找一段全 0 的地方,用来补代码。
首先是字符串 "chs",再往下另找一段,补 setlocale,以及原代码处 jmp 下来
0204 测试
这样修改真的就好了吗?实践进行检验。
将修改的保存下来,替换原文件,测试后发现程序挂了...
什么原因呢?还是 ASLR 的问题,虽然 dll 关了,但 exe 没关,所以在使用字符串或是 API 时 还是受 ASLR 影响,会出问题。
03 处理ASLR
怎么处理 ASLR?
1. 啥都不管,把 exe 的 ASLR 关了;(嗯,也行,但有点暴力,实在没办法了再这么干)
2. dll 处理重定位表;(没有找到好用、能增、能改的 重定位处理工具,手动处理容易出错,主要是需要对PE有较深的理解,含泪舍去)
3. 绕过重定位,使修补的代码不受 ASLR 影响;
选择方案3,绕过重定位。
分析上图出错位置,发现在 push 字符串 和 调用外部 API 时,会受ASLR影响,而 jmp 下来和 jmp 回去都没事,差别是什么呢?
文件内部 call 或者 jmp 时,虽然 汇编代码看上去是 jmp XXXXXXX,但其实它二进制代码用的是相对地址,所以无论基址是多少,都没关系。
因此,需要把字符串和API的地址通过相对地址进行计算再获取,此时需要获取 EIP 的值。
EIP 的值是不能直接得到的,即 不能 mov eax, eip。
了解 call 和 ret 本质的同学就清楚了,在 call 时,会把下一句的指令地址入栈,此时只要 pop eax,那 eax 就能得到 eip 了。
把之前的代码进行修改,为了区分,我另开了一段,进行修补,再把原代码 jmp 到新的位置,修补代码如下:
保存修改,替换原dll,再次测试,功能OK;开启 dll 的 重定位,再测,OK;放到其他电脑中测试,功能也OK。
终于成功了,很有成就感!{:301_1000:}
04 结尾
篇幅略长,谢谢观看。
如有错误,请指出,我会及时修改,防止误认。
如有好的编辑重定位表的工具,请推荐。
gh0st_ 发表于 2020-4-29 14:15
修复重定位的工具还是有很多的
求大佬分享{:301_1003:}
之前搜了一些修复重定位表的工具,大多都是用在脱壳后的修复,原理好像是比对脱壳前后的重定位表;
而我这是本身不是脱壳,而是在原有基础上新导入了一个API,新加了个字符串,那需要在原有重定位表上增加几条规则;
论坛里有找到大佬分享的一个工具,https://www.52pojie.cn/thread-352725-1-1.html,但没有使用说明,我添加了地址后,用 LordPE 查看重定位表,发现新增的记录是 error,实际运行也是直接挂掉
因为找不到工具,之后才想到的用相对地址做偏移,绕过了重定位 总结的不错!偶尔我也干这事。看了文章,大意是原程序导出中文错误,为了正确导出中文,需要修补原程序增加执行setlocale( LC_CTYPE, "chs" ),再导出就OK了。这篇文章就是介绍 如何修改原程序加入汇编码的问题! 楼主的基础功底真的厉害。学习了 看完感觉楼主的思路很不错,居然利用了eip做偏移计算, 把软件发出来呀。。 学习技术来了 jixun66 发表于 2020-4-28 15:49
把软件发出来呀。。
软件就不发了,是某个商业软件
这里主要分享下思路{:301_1001:} pojie6 发表于 2020-4-28 19:28
总结的不错!偶尔我也干这事。看了文章,大意是原程序导出中文错误,为了正确导出中文,需要修补原程序增加 ...
对头,就是酱紫{:301_987:} 修复重定位的工具还是有很多的
页:
[1]
2