首 页文章中心黑客软件黑客动画绿色软件私服技术私服下载本站论坛
您当前的位置:黑客之 家文章中心脱壳破解软件破解 → 文章内容 退出登录 用户管理
本类热门文章
相关文章
站内广告

11.4.1 逆向Defender的初始化程序(图)
作者:佚名  来源:不详  发布时间:2008-9-25 2:17:19

减小字体 增大字体

11.4.1  逆向Defender的初始化程序

因为程序显然没有直接调用任何API函数,所以你也就无法找到一个可以设置断点的API函数供你找到程序中输出“Sorry … Bad key, try again.”消息的代码。因此除了检查程序的入口点来碰碰运气,看能不能找到一些有所启示的代码外,你没有其他选择。让我们在IDA中加载这个程序,然后仔仔细细地分析它。现在你可以快速浏览一下这个程序入口点处的代码


 
 
                                      列表11.6  由IDA产生的Defender的入口函数的反汇编代码(待续)

 

 

 

 

 

 

列表11.6(续)

列表11.6给出了Defender的入口函数。快速地扫描一下这个函数,你会发现一个很重要的特征——这里的入口点并非一个普通的运行库初始化程序。即使你之前从来没见过运行库初始化程序,你也可以非常肯定它不可能以IsDebuggerPresent函数调用结尾。当程序执行到IsDebuggerPresent调用时,你可以看到函数一返回EAX就与自己做了一次异或操作(XORed)——其返回值居然被忽略了!在网址http://msdn.microsoft.com上快速搜索一下,我们可以得知IsDebuggerPresent函数应该根据当前是否存在调试器而返回一个布尔(Boolean)值。在这个API函数刚刚返回就对EAX做异或意味着这个调用没有任何的实际意义。

不管怎样,我们回到列表11.6中前边的代码,了解一些有关Defender的信息。我们来看看对402EA8处的调用做了些什么。

 

前面的程序以一段有趣的代码序列开始:从fs:30h中加载了一个值到EAX寄存器。一般来说,在基于NT的操作系统中,fs寄存器用于访问线程本地信息(thread local information)。对任一给定的线程,fs:0指向的都是本地线程环境块(Thread Environment Block,TEB)数据结构,这个数据结构中包含了大量在运行时系统所需的线程私有(thread- private)信息。在这里,函数访问了TEB中偏移地址+30处的信息。幸运的是,你可以得到详细的Windows的符号信息(symbolic information),通过这些符号信息你可以知道TEB中偏移地址+30处存放的是什么信息。通过在WinDbg中加载NTDLL的符号并使用DT命令你就可以得到这些符号信息(关于WinDbg和DT命令的更多信息你可以参考Microsoft Debugging Tools的网页,网址是:www.microsoft.com/whdc/devtools/debugging/default.mspx)。

TEB的结构列表非常长,所以在这里我只列出了其中的前边部分,一直到偏移地址+30处——也就是程序访问的那个偏移地址

 

 

很显然,.h3mf85n:00402EA9这一行是通过TEB访问进程环境块(Process Environment Block,PEB)。PEB是Windows中的进程信息数据结构,就像TEB是线程信息数据结构一样。在地址00402EB5处程序访问了PEB中偏移地址+c处的信息。让我们看看这里存放的是什么。同样,整个PEB的定义也非常长,所以这里我只列出了定义的开始部分。

 

在这里,偏移地址+c处是_PEB_LDR_DATA,也就是加载程序(loader)信息。我们来看一下这个数据结构,弄清楚它内部到底有些什么。

 

看起来这个数据结构是用来管理在当前进程中加载的可执行模块的。这个数据结构内有好几个模块列表,每个模块列表中都包含了当前进程加载的不同顺序的可执行模块。这个函数读取偏移地址+c处,也就是访问InLoadOrderModuleList模块。我们看一下模块数据结构LDR_DATA_TABLE_ENTRY,并试着理解这个函数在找什么东西。

下面关于LDR_DATA_TABLE_ENTRY的定义是在WinDbg中使用DT命令生成的。一些Windows的符号文件实际上都可以使用这个命令来转储其中所包含的数据结构定义。你只需键入“DT ModuleName!*”,就可以得到模块中所有名字的列表,然后再键入“DT ModuleName!StructureName”即可看到其成员的完美的列表。

 

在获取了指向InLoadOrderModuleList的指针后,函数好像读取了第一个模块中偏移地址+0处的信息。从这个结构中可以看出,这个偏移地址+0处是LIST_ENTRY数据结构的一部分。我们转储LIST_ENTRY,看看偏移地址+0处是什么内容。

 

偏移地址+0处是Flink,它可能是指的是“前向链接(foreward link)”。这就是说函数通过硬编码的方式跳过第一个入口,而不管这个入口中是什么。这很异乎寻常,因为对一个链表(linked list)来说你会想着应该有个循环才对——这里却没有循环,函数通过硬编码的方式跳过第一个入口。在这之后,函数只是简单地返回第二个入口中偏移地址+18处的值给主调函数。_LDR_DATA_TABLE_ENTRY中偏移地址+18处是DllBase。所以,看上去函数所做的只是为了寻找某个DLL的基地址。这时,用WinDbg加载Defender.EXE是明智之举,我们查看一下加载程序的信息,看看第二个模块是什么。为此,我们使用了“!dlls”命令,“!dlls”可以转储得到一个界面友好的(相对而言)加载程序数据结构的视图。选“-l”参数,命令会以加载顺序转储模块,实际上就是你刚才从PEB_LDR_DATA中取InloadOrderModuleList所遍历的列表。

  

 

好了,看来第二个模块就是NTDLL.DLL。00402EA8处函数的作用只是用来获取NTDLL.DLL在内存中的地址。这有很多用处,因为我前面曾经说过,程序如果不使用任何与操作系统的接口的话是不可能与用户进行通信的。显然,获得NTDLL.DLL的地址是创建与操作系统的接口的第一步。

如果再回到列表11.6,可以看到00402EA8处这个函数的返回值直接传给了004033D1,004033D1处这个函数正是下一个被调用的函数。我们来看看004033D1处这个函数。


 

 

 

 

 

 

 

 

 

表11.7  由IDA Pro生成的Defender中4033D1处这个函数的反汇编代码

这个函数开头的部分看起来很熟悉,是吧?但在后面却有一处有些奇怪。看一下在指令“JMP EBX”之后地址004034DD处的代码。看上去好像IDA将它看作是数据,而不是代码。这些数据从地址004034DD开始一直延续到地址4041FD(为了节省版面,我在列表中省略掉了大部分的数据)。为什么在程序的中间部分会出现这么一段数据呢?这在拷贝保护代码中是一种常见的情景——子程序在加密后都以二进制的形式存储,并在运行时再将其解密。很可能这些不能识别的数据就是加密后的程序代码,它们会在运行时被解密。

让我们对函数开头部分中未加密的代码做个简单的分析。我们很快就可以确定出这部分“可读的”代码区大体上被分为两大块,很可能是用if语句分开的。在00403405内的条件跳转指令决定了程序接下来要执行哪一个块,但需要注意的是,00403401处的CMP指令将[ebp-8]与0进行比较,尽管[ebp-8]在前一行被置为了1。在循环中这种序列非常常见——修改变量、然后再执行一次代码。通观IDA中的反汇编代码你会发现,这个函数中根本就找不到这种构成循环的跳转。

既然找不到理由让我们相信40346D中的代码曾经被执行过(因为[ebp-8]中存放的变量被硬编码为1),那么现在我们就可以把精力全部放在第一种情况了。简单地说,现在我们看的是一个循环,这个循环在对一块数据区进行迭代处理(将迭代到一个数就将它与常数2BCA6179h做异或运算)。回到指针被第一次初始化的位置,即地址004033E3,就是在这里通过堆栈将[ebp-20h]初始化为4034DD。[ebp-20h]后来被用作开始异或(XOR)运算的起始地址。如果你在看列表11.7的话,可以看出地址4034DD处于这个函数的中间位置——正好是代码部分结束而数据部分开始的地方。

所以,不出意外的话这段代码应该是实现了某个解密算法。加密了的数据就放在这个函数的中间——4034DD处。这个时候,一个好的办法是将调试器中代码切换到现场调试中,看看解密过程的输出结果。要做到这一点,你可以在OllyDbg中运行这个程序,并在解密过程结束的地方(即0040346B处)设置一个断点。在OllyDbg运行到0040346B地址的时候,起初4034DD中的数据看起来好像还不知道是什么数据,因为Olly输出的结果是这样的:

 

不管怎样,你只能让Olly重新分析这段内存,看能不能找到一些有意义的东西。通过按“Ctrl+A”进行重新分析。显然,情况立即发生了变化。那些无意义的字节变成了汇编语言代码。往下翻几页你就会发现代码可真不少——实际上有好几十页的代码。这其实才是正在研究的函数4033D1真正的函数体。列表11.7中所列出的只是这个解密函数序言(prologue)。函数4033D1完整的解密代码很长,如果全列出来会占很多页,所以这里就不列出来了,我试着介绍一下这个函数的总体结构以及它所完成的功能。当然,我会对其中一些值得研究的关键代码段作进一步的分析。最好是不要关闭OllyDbg,让程序对自己进行解密,这样你就可以一边看书,一边看OllyDbg中解密后的代码了(译注:书上要是列出这些代码你就不用这么费劲了)——这个函数中确实有不少有趣的代码。你一定要知道的是,对于这么大的一个函数,你想要理解其中的每一行是不大现实的,而且也没有那个必要。相反,你必须要尝试着找出代码中的关键区域,并试着理解这些代码的用途。

上一页 1 2 

[] [返回上一页] [打 印]
关于本站 - 网站帮助 - 广告合作 - 下载声明 - 友情连接 - 网站地图 - 文章投稿 - 软件发布 - 购物资讯网 - _