freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

逆向分析教程(四)——打补丁
2022-01-05 10:23:52
所属地 上海

该系列文章以《逆向工程核心原理》为原型,调整其中对于新手需要耗费大量时间解决之处,更方便于新手入门。也同时解决互联网上扫描件电子书版本的阅读障碍(如截图模糊等)。

前言

代码逆向分析中,“打补丁”操作是不可或缺的重要主题。利用“打补丁”技术不仅可以修复已有程序的BUG,还可以向程序中添加新功能。“打补丁”的对象可以是文件、内存,还可以是程序的代码、数据等。本示例中,我们将使用“打补丁”技术把HelloWorld.exe程序消息窗口显示的“Hello World!”字符串更改为其他字符串。

我们后面会经常用到“打补丁”技术

请记住,我们的目标是把消息对话框中显示的“Hello World!”字符串更改为其他字符串。前面我们已经查找到了调用MessageBoxW的部分和“Hello World!”字符串的地址,这已经算成功了一半。

按Ctrl+F2快捷键重新调试,并使调试流运行到main函数的起始地址处(401000)。在401000地址处按F2键设置断点,再按F9执行程序。main()函数的地址401000被用作“大本营”(40104F)后第一个“前进营”。

修改字符串的两种方法

我们先介绍2种简单的修改字符串的方法。

1.直接修改字符串缓冲区(buffer)

2.在其他内存区域生成新字符串并传递给消息函数。

这两种方法各有优缺点,我们详细的来了解一下。

1.直接修改字符串缓冲区

MessageBoxW函数的字符串参数“Hello World!”保存在地址4092A0处的一段缓冲区,只要修改这段内容,就可以修改MessageBoxW函数显示出的字符串。在Dump窗口中按Ctrl+G快捷键执行Go to命令,在弹出窗口中输入4092A0进入字符串缓冲区。然后使用鼠标选中4092A0地址处的字符串,按Ctrl+E快捷键打开编辑窗口。

从图中可以看出,Unicode形式的“Hello World!”字符串占据的区域为4092A0~4092B0 (Unicode编码中用2个字节表示1个字罗马母)。用新字符串覆盖写该区域。

如果新字符串大于原有字符串,执行覆盖操作时可能损坏字符串后面的数据,所以一定要小心。特别是字符串后面有非常重要的数据时,覆盖操作导致数据损坏就会引发程序内存引用错误。

在弹出的编辑器窗口Unicode文本框中输入“Hello bylibrary!”字符串

unicode字符串必须以NULL结束,它占据2个字节(添加NULL时不能直接在unicode文本框中进行,而要在HEX项目中添加)。

更改后的字符串“Hello bylibrary!”的长度要比原字符串“Hello World!”更长一些。原字符串后一般会存在某些有意义的数据,使用更长的字符串覆盖原字符串时,数据可能会遭到损坏,这是十分危险的。之所以上面我们要采用更长的字符串覆盖,一方面是为了打广告,一方面是为了更好的向大家演示,实际操作中不建议这样做。

我们再返回main()函数,(还记得第一个前进营吧。)

虽然指令保持不变,但原字符串已经被新字符串取代,用作MessageBoxW()函数的参数,并且参数的地址仍为4092A0,只是该地址空间中的内容(字符串)发生了改变。按F9运行程序后,将弹出消息窗口,可以看到显示出新字符串。

以上就是直接更改字符串缓冲区来修改的方法。这种方法的优点就是使用起来十分简单,但缺点是它对新字符串的长度有限制,新字符串的长度不应比原字符串长。

可执行文件保存字符串时一般会给字符串多留出一些空间,第二张图中的HelloWorld.exe程序就是如此。所以,如果你的运气足够好,使用更长的字符串覆盖原字符串时,即使原字符串后面的部分空间被侵占,程序仍然能正常运行。但是我们不建议大家这样做,随着这些不安定因素逐渐增多,整个系统的稳定性最终会遭到破坏。请记住,我们是解决问题的人,而不是制造麻烦的。


保存更改到可执行文件

上面的调试中,我们通过修改字符串缓冲区更改了程序显示的消息内容,但是这种更改只是暂时的,终止调试(结束Hello World进程)后,程序中的原字符串仍然没有改变,如果想把这种更改永久保存下来,就要把更改后的程序另保存为一个可执行文件。

我们选中更改后的“Hello bylibrary”字符串,单机鼠标右键,在弹出的菜单中选择Copy to execuable 菜单,打开如下所示的HEX窗口

在弹出的Hex窗口中单机鼠标右键,选择Save file菜单,在Save file as对话框中输入文件名“Hello Reversing.exe”后保存为.exe可执行文件。然后运行该文件,弹出消息窗口,显示的字符串已经变为“Hello bylibrary”。

2.在其他内存区域新建字符串并传递给消息函数

如果要用“Hello bylibrary world!!!”替换原字符串“Hello World!”,上述方法就不适用了。此时我们就要换一个方法。

按ctrl+F2我们来重新调试,再按F9运行,由于之前我们在main()函数的起始位置处(401000)设置了断点,所以调试流自动转到main()函数处。再看一下main()函数。

401007处有一条PUSH 004092A0命令,它把4092A0地址处的“Hello World”字符串以参数形式传递给MessageBoxW()函数。

向MessageBoxW()函数传递字符串参数时,传递的是字符串所在区域的首地址。如果改变了字符串地址,消息框就会显示变更后的字符串。在内存的某个区域新建一个长字符串,并把新字符串的首地址传递给MessageBoxW()函数,可以认为传递的是完全不同的字符串地址

上面这样的做法看起来是没有问题的,但是我们需要考虑另外一个问题:“应该在哪块区域创建新字符串呢?”,要解决这个问题,我们又要留坑了,这个需要在后面了解到PE文件格式以及虚拟地址结构相关知识才行。

我们在方法1中修改的字符串地址为4092A0,我们在dump窗口查看该部分。向下拖动滑动条,相应内存区域由NULL填充(NULL padding)结束。

这部分就是程序中未使用的NULL填充区域。

如果找不到你肯定又忘了ctrl+G这玩意了,4092A0,往下拖

应用程序被加载到内存时有一个最小的内存分配大小,一般为1000。即使程序运行时只占用100内存,它被加载到内存时仍然会分到1000左右的内存,这些内存一部分被程序占用,其余部分为空余区域,全部被填充为NULL。

我们最好把这个地方当作字符串缓冲区并传递给MessageBoxW函数,用快捷键Ctrl+E向结尾部分适当位置(比如409F50)写入新字符串(“Hello bylibrary!!!”)即可。

但是如果只是进行上面的操作,我们时没有办法更改消息框中的字符串的。既然我们已经新建了缓冲区,接下来就应该把新的缓冲区地址(409F50)作为参数传递给MessageBoxW函数。所以,我们需要在代码窗口中使用汇编命令修改代码。

我们把光标移至401007处,按空格键或者双击打开Assemble窗口。

在打开的窗口中输入“push 409F50”,地址409F50为新字符串“Hello bylibrary!!!”字符串。

用户可以在Assemble窗口中输入任何想要输入的汇编指令,输入当时就能在代码中体现出来,也可以被执行。这种“在运行过程中动态修改进程代码”的方式正是调试最强大的功能之一。

在OllyDbg中我们按F9运行程序,弹出消息窗口,可以看到字符串已经被修改了。

如果我们把修改后的代码重新保存为程序文件,可以发现程序无法正常运行,这是由409F50这一地址引起的。可执行文件被加载到内存并以进程形式运行时,文件并非原封不动的被载入内存,而是要遵循一定的规则进行。在这个过程中,通常进程的内存是存在的,但是相应的文件偏移并不存在。比如,我们上面的例子中,与内存409F50对应的文件偏移就不存在,所以修改后的程序无法正常运行。如果还是有疑惑,还是因为我们还没有掌握PE文件格式的相关知识的原因,这些问题我们可以以后再解决。

Q&A

经过前面四章的学习,有三个问题需要顺便给大家解答一下。

A.快捷键F4与F9的区别

两个都是“运行”命令,F9为Run(运行),F4为Run to Cursor(运行到光标处),F9是运行整个程序的命令,而F4仅运行到当前光标所在位置,可以把F4看作断点与F9命令的组合。

B.什么是启动函数

启动函数(Stubcode)不是用户编写的代码,而是编译器任意添加的代码。编译程序时,不同编译器会根据自身特点添加不同启动函数,特别是EP代码区域中存在着许多启动函数,它们也被称为启动代码(StartUp code)。调试程序时,我们不需要仔细分析这些启动函数,但是初学者有必要分清程序中哪些是启动函数,哪些是用户代码。希望大家调试时多看一看这些代码,熟悉后就能轻松区分。

C.到底什么是PE文件,为什么要等到后面才讲解?如果不懂得PE文件是否就无法调试?

PE是Portable Executable的简称,它是Windows操作系统下的可执行文件的格式,主要包含了对文件规格的描述,代码逆向分析技术的初学者学习它会感到非常吃力、无趣。所以我们并没有在前面详细讲解,更重要的是先让大家感受到调试的乐趣,然后再一点点地学习。此外,如果不了解PE文件结构的相关知识,将无法进行高级调试。

# 逆向工程 # 逆向分析 # 逆向技术 # 逆向基础 # 逆向工程核心原理
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录