利用打补丁技术不仅可以修改已有程序中的Bug,还可以向程序中添加新功能。打补丁的对象可以是文件、内存,还可以是程序中的代码、数据等。本实例中,我们将使用打补丁技术把程序消息窗口提示的字符串更改为其他字符串。之前已查找到调用MessageBox W的部分和字符串的地址,这已经算是成功一半了。

修改字符串的两种方法

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

MessageBox W函数的字符串参数保存在地址4092A0处的一段缓冲区,只要修改这段内容就可以修改MessageBox W函数显示出的字符串。在Dump窗口中按Ctrl+G快捷键执行Go to命令,在弹出窗口中输入4092A0进入字符串缓冲区。然后使用鼠标选中4092A0地址处的字符串,按Ctrl+E快捷键打开编辑窗口,Unicode形式的“Hello World!”字符串占据的区域为4092A0~4092B0(Unicode编码中用2个字节表示1个罗马字母)。用新字符串覆写该区域。
在弹出的编辑窗口UNICODE文本框中输入“Hello Reversing”字符串,注意,Unicode字符串必须以NULL结束,它占据两个字节(添加NULL时不能直接在UNICODE文本框中进行,而要在HEX项目中添加)。
提示:更改后的字符串比原字符串更长一些。原字符串后一般会存在某些有意义的数据,使用更长的字符串覆盖原字符串时,某些数据可能会遭到损坏,这是十分危险的。本例中之所以采用更长的字符串覆盖仅仅是为了更好地向大家演示,实际操作中不建议这样做。
这种方法的优点是使用时非常简单,但缺点是它对新字符串的长度有限制,新字符串不应比原字符串长。

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

401007地址处有一条PUSH 004092A0命令,它把4092A0地址处的“Hello World”字符串以参数形式传递给MessageBox W()函数。
向MessageBox W()函数传递字符串是,传递到是字符串所在区域的首地址。如果改变了字符串地址,消息框就会显示变更后的字符串。在内存的某个区域昔年一个长字符串,并把新字符串的首地址传递给MessageBox W()函数,可以认为传递的是完全不同的字符串地址。
我们在方法1中修改的字符串地址的为4092A0,下面再用Dump窗口查看该部分。向下拖动滑动条,相应内存区域由NULL填充(NULL padding)结束。这就是程序中未使用的NULL填充区域。
提示:应用程序被加载到内存时有一个最小的内存分配大小,一般为1000.及时程序运行时只占用100的内存,它被加载到内存时仍然会被分到1000左右的内存,这些内存一部分被程序占用,其余部分为空余区域,全部被填充为NULL。
最好将此处用作字符串缓冲区并传递给MessageBox W()函数,用快捷键Ctrl+E想结尾部分适当位置(409F50)写入新字符串(“Hello Reversing World!!!”)即可。
仅进行上述操作无法更改消息框中的字符串。既然已经新建了缓冲区,接下来就应该把新的缓冲区地址(409F50)作为参数传递给MessageBox W()函数。为此我们需要在代码窗口中会使用汇编命令修改代码。在地址401007处,按空格键打开Assemble窗口。
在打开的Assemble窗口中输入“PUSH 409F50”指令,地址409F50为新字符串“Hello Reversing World!!!”的首地址。修改完成。
提示:若把修改后的代码重新保存为程序文件,可以发现程序无法正常运行,这是由409F50这一地址引起的。可执行文件被加载到内存并以进程形式运行时,文件并非原封不动的被载入内存,而是要遵循一定的规则进行。这一过程中,通常进程的内存是存在的,但是相应的文件偏移(offset)并不存在。上面示例中,与内存409F50对应的文件偏移就不存在,所以修改后的程序无法正常运行。