简单逆向分析修改软件标题

受人之托,替人办事,修改一个软件的标题。虽然修改一个标题比较简单,但是在简单的任务面前也有一些知识点是可以供我们学习的。我们此次要修改的软件的文件名为“RosettaStoneVersion3.exe”,是一款学习英语的软件。修改标题的要求是必须以该文件启动,也就是说不能以其他外挂式的软件启动(不能增加额外的启动文件)。仅此一个要求。当然了,除了这个要求外,就是要将原标题的“Rosetta Stone Version 3”修改为“MoNi YingYu XueXi XiTong”。我们来完成这个简单的任务,下面是我分析该软件的思路及详细步骤。

 

拿到一个可执行文件不要忙着放入OD或者IDA中,首先要查壳。否则直接放到OD中进行调试会晕死在外壳的“迷宫”当中。我们用PEID对“RosettaStoneVersion3.exe”进行查壳,查壳结果是“Microsoft Visual C++ 7.0[Debug] [Overlay]

 

从查壳结果中可以看出,该程序是VC++7.0编译链接生成的一个调试版的程序,该程序有附加数据。

 

小知识:

1 VC++编译生成的文件有两种版本,一种是调试版(Debug版),一种是发布版(Release版)。调试版本的程序中有大量的调试信息,且生成的二进制机器码没有经过任何的优化,由于代码没有进行优化故而方便通过反汇编的形式进行调试,因此该版本方便软件在未发布前进行测试调试使用。发布版本的程序中不存在调试信息,而且代码被编译器进行了大量的优化,因此发布版的运行效率要高,体积要小。

附加数据(Overlay),在PE文件所有节区后面的那部分文件,了解该内容需要了解PE文件格式,在此不做介绍。

 

既然该程序没有壳,那么PE格式中的资源我们可以通过各种资源编辑器进行修改编辑,我们这里使用的资源编辑工具是“Resource Hacker”。将“RosettaStoneVersion3.exe”拖拽到Resource Hacker中,查看Resource Hacker左边树形控件的“Dialog”节点中的内容。在Resource Hacker列出的三个对话框资源中查找我们要的对话框,但是在“Dialog”节点中并没有我们要找的资源。在ResourceHacker的“bin”节点中保存着3个二进制文件,并且通过查看3个二进制文件的机器码得知,3个二进制文件中的第一个和第三个文件是PE文件,也就是可执行文件。我们通过Resource Hacker将这三个二进制文件单独保存出来,然后继续用Resource Hacker查看资源,通过我的查看,同样也并没有找到我们需要的资源。

 

通过上面的分析,我们发现直接靠资源编辑器修改程序的标题可能已经不是最好的方法了,我们该改变思路了。该程序除了一个.EXE的可执行文件外,还有几个.DLL文件。也许我们需要的资源在某个DLL文件中,但是我们不应该再去那些DLL文件中寻找可修改的资源了,因为DLL文件较多,会减低我们的效率。

 

我们用OD打开“RosettaStoneVersion3.exe”,直接运行该程序。当程序启动以后我们搜索ASCII字符串,在搜索到的字符串中查找当前标题,可惜没有找到。继续使用UNICODE进行查找,同样也没有查找到。由于没有找到字符串,因此重新打开该程序并运行,发现当程序的标题栏和程序都出现以后,才会出现标题文字。我有了新的思路了,我再次重新打开该程序,然后设置API断点“bpSetWindowTextW”,也就是说我认为该软件的标题可能是使用SetWindowTextA或者SetWindowTextW设置上去的,而不是在编程时直接通过资源设置好的。设置好API断点后,运行程序。第一次中断在我们的SetWindowTextW函数处时,观察栈窗口,并不是我们要找的断点,让它继续运行。当第二次被中断到我们的SetWindowTextW函数处时,正是我们要找的地方,查看OD的栈窗口。从栈窗口中我们看到了我们要的标题字符串,我们显示“00E689B8”处的内存数据到OD的数据窗口中。在数据窗口中我们可以看出,字符串是以UNICODE形式保存的,只要我们直接修改程序文件中该位置的UNICODE字符串就可以达到我们修改标题的目的了。我们用LordPE查看该虚拟内存地址所对应的文件偏移地址。用LordPE打开“RosettaStoneVersion3.exe”,通过“位置计算器”进行计算“00E689B8”虚拟内存地址的文件偏移地址,但是却提示“超出范围”,这样说明在程序中没有与“00E689B8”所对应的文件偏移地址。我们回到OD中通过内存窗口查看“00E689B8”所属的位置,该虚拟内存地址应该是一块堆地址,堆是进程动态申请到的内存地址。因此,我们无法通过直接修改可以执行文件程序来修改该地址的字符串,因为文件中没有文件偏移地址与此地址对应;当然也同样无法通过直接修改该虚拟内存地址来修改该地址的字符串,因为修改后堆地址无法保存到程序文件中,下次启动时仍然无法显示我们修改后的标题。

 

既然上面的方法不行,我们就从只能从它的代码上做手脚了。我们按下ALT+F9返回对SetWindowTextW函数的调用,看对SetWindowTextW函数调用的反汇编代码,代码如下:

00404646    CC              INT3

00404647    CC              INT3

00404648    CC              INT3

00404649    CC              INT3

0040464A    CC              INT3

0040464B    CC              INT3

0040464C    CC              INT3

0040464D    CC              INT3

0040464E    CC              INT3

0040464F    CC              INT3

00404650    8B4424 04       MOV EAX,DWORD PTR SS:[ESP+4]

00404654    8378 18 08      CMP DWORD PTR DS:[EAX+18],8

00404658    72 11           JB SHORT 0040466B

0040465A    8B40 04         MOV EAX,DWORD PTR DS:[EAX+4]

0040465D    50              PUSH EAX

0040465E    8B41 60         MOV EAX,DWORD PTR DS:[ECX+60]

00404661    50              PUSH EAX

00404662    FF15 44F44B00   CALL DWORD PTRDS:[<&USER32.SetWindowTex>; user32.SetWindowTextW

00404668    C2 0400         RETN 4

 

SetWindowTextW函数有两个参数,该函数的第二个参数是用来指向字符串的指针。从反汇编代码中看,调用SetWindowTextW函数时,第二个参数入栈的地址为0040465D,也就是push eax这句代码,也就是说eax这个地址中保存的是标题的UNICODE字符串,只要我们将eax中保存的地址进行改变,并且改变后的地址中保存的是我们要更改的标题字符串就可以了。既然有了新的思路,那么我们就在程序中找一处空白的地方添加我们要修改的字符串。可是,SetWindowTextW需要的是一个UNICODE字符串,而不是普通的ASCII字符串,我们如何得到“MoNi YingYu XueXi XiTong”的UNICODE字符串编码呢?我们打开文本编辑器我们输入“MoNi YingYu XueXi XiTong”字符串,在保存文本的时候,在通用对话框的最下面选择编码方式为“UNICODE”,然后用C32ASM打开该文本,就可以获得该字符串的UNICODE编码了

 

我们在哪个位置保存字符串呢,在PE文件中有很多地方供我们保存字符串,我们用LordPE来打开该程序,查看该软件的区段,我们选择在“.rdata”段中保存字符串,为了方便找到.rdata段中的空白位置我们从.data的起始位置处向上找。用C32ASM打开我们的可执行程序,来到.data段处的文件偏移处000EF000,我们看到该地址的上方就有空白位置,我们在程序的文件偏移000EEFB0处插入字符串的UNICODE编码并保存。我们用LordPE打开我们的添加过字符串后的文件,计算文件偏移地址对应的虚拟内存地址,文件偏移地址“000EEFB0”对应的虚拟内存文件地址为“004EEFB0”。

 

我们既然有了字符串的虚拟内存地址,那么我们就可以改变前面提到的eax中保存的地址了。用OD打开我们的添加过字符串的可执行文件,来到00404646地址处,修改反汇编代码,修改后的代码如下:

00404646    B8 B0EF4E00     MOV EAX,004EEFB0

0040464B    90              NOP

0040464C    EB 0F           JMP SHORT 0040465D

0040464E    CC              INT3

0040464F    CC              INT3

00404650    8B4424 04       MOV EAX,DWORD PTR SS:[ESP+4]

00404654    8378 18 08      CMP DWORD PTR DS:[EAX+18],8

00404658    72 11           JB SHORT 0040466B

0040465A  ^ EB EA           JMP SHORT 00404646

0040465C    90              NOP

0040465D    50              PUSH EAX

0040465E    8B41 60         MOV EAX,DWORD PTR DS:[ECX+60]

00404661    50              PUSH EAX

00404662    FF15 44F44B00   CALL DWORD PTRDS:[<&USER32.SetWindowTex>; user32.SetWindowTextW

00404668    C2 0400         RETN 4

 

我们将原来对eax进行赋值的位置修改为了JMP指令,然后跳转到上面的00404646地址处,这里原来都是INT3指令,这些指令在程序中并不被执行,因此我们在这里添加了我们的代码,首先是moveax,004EEFB0,执行这句会让我们的字符串的地址赋值给eax,然后在JMPpush eax的地址处,也就是字符串入栈的地址处。修改后直接保存修改过的反汇编代码,我们直接运行程序。发现程序的标题处已经成为新的标题了。

 

通过我们反复的分析,我们完成了对该软件标题的修改,在此分析的过程中,我们涉及到一些关于逆向方面的知识,也涉及到一些PE文件格式的知识,但是本文并没有对其进行深入的讲解,因为这些内容超出了本文的范围,如果铺开讲内容会很多,大家可以自己进行学习和了解。我将所涉及的知识进行整理,方便大家自行参考学习相关知识。

首先,应该掌握SetWindowText函数的使用,在了解了该函数的使用后应该了解和熟悉SetWindowTextASetWindowTextW的区别,来了解ASCIIUNICODE字符编码的区别;

其次,要熟悉和掌握反汇编当中的函数调用方式的约定,几乎所有的WindowsAPI函数(除了几个变参函数外)的函数调用约定都为stdcall方式,也就是所有的Windows API函数的参数都是从右往左依次入栈,平衡栈的操作在被调函数体内完成;

最后,要熟悉和掌握PE文件格式的三种地址的转换计算方式,三种地址分别是虚拟地址(VA),相对虚拟地址(RVA)和文件偏移地址(FileOffset)

 

本文可能写的长了些,重点部分在后半篇,但是前半篇也是整个分析思路过程的一部分,希望本文能起到抛砖引玉的作用,给读者一定的启发与帮助。

posted on 2013-09-11 20:51  新一  阅读(3998)  评论(0编辑  收藏  举报

导航