当前位置:文档之家› IDA实例教程详解

IDA实例教程详解

IDA实例教程详解作者:笨笨雄(转载)1 软件环境静态分析有很多好处,例如加壳的程序(尽管对于高手来说这并不会耗费太多时间),我们不需要寻找OEP,也不需要解除自校验,只要修复IAT,DUMP下来就可以动手分析了。

假如你需要修改程序,可以使用内存补丁技术。

动态与静态,调试器与反汇编器结合可以简化分析任务,帮助我们理解代码。

因此掌握一种反汇编器是非常必要的。

IDA可以说是这方面的首选工具,它为我们提供了丰富的功能,以帮助我们进行逆向分析。

这从IDA复杂的工作界面便可以知道。

种类繁多的工具栏在分辨率不高的情况,这些工具栏与反汇编窗口挤在小屏幕里,看起来不爽。

我一般把它关闭(查看=>工具栏=>主工具栏)以获得更好的视觉效果。

当我们需要这些功能的时候,直接使用快捷键就可以了。

下面是常用快捷键的清单:快捷键功能注释C转换为代码一般在IDA无法识别代码时使用这两个功能整理代码D转换为数据A转换为字符N为标签重命名方便记忆,避免重复分析。

;添加注释在工具栏下面的便是工作窗口。

主要的窗口分页有“IDA View-A”、“Name”、“Strings”、“Exports”和“Imports”。

对于后面3项相信大家都不会陌生了,它们分别是字符参考,输出函数参考和输入函数参考。

Name是命名窗口,在那里可以看到我们命名的函数或者变量。

这四个窗口都支持索引功能,可以通过双击来快速切换到分析窗口中的相关内容,使用起来十分方便。

简单输入几个字符即可定位目标IDA View-A是分析窗口,支持两种显示模式,除了常见的反汇编模式之后,还提供图形视图以及其他有趣的功能。

IDA的反汇编窗口一般我们在分析的时候,并不关心程序的机械码,所以IDA为我们自动隐藏了这些信息。

如果你有需要,可以通过以下步骤来设置:选项=>常规=>反汇编=>显示反汇编行部分=>机械码字节数=>修改为你允许显示的大小现在让我们以论坛脱壳版块置顶帖的那个经典为例,看看图形视图的表现。

首先我们到以下连接下载:你能通过图形视图及其缩略图快速找到壳的出口吗如图所示,标签40EA0E便是壳的出口代码的地址。

在OD中直接跳到该地址,下断点,然后运行到该处,再单步便能看到OEP了。

假如希望通过跳转法找OEP,相信图形视图比你在OD一个一个跳转跟随,要快得多。

再来看看这个壳的另类脱法。

直接运行该程序,DUMP下来,再使用IMPORTREC的IAT AutoSearch功能修复输入表。

用IDA打开修复了输入表的DUMP文件。

在IMPORT窗口随便选一个API,随便通过交叉参考跳转到一个函数的代码。

此处为文件输入表的位置我选了RegQueryValueExA,通过交叉参考,来到Sub_402488处的函数代码。

用鼠标拖动缩略图中的虚线框到上方,便能看到该CALL的头部了。

然后按下图指示操作:在函数标记上点击鼠标右键处于最上层的函数,便是OEP了,使用PE工具修改文件入口为10CC。

现在函数可以正常工作了。

这个方法的原理是通常我们写程序都有如下流程:Main proc修复之后的代码除了“sub eax, [esp-8+arg_4]”(实际上是sub eax,[esp])看起来有点怪之后,一切正常。

作为一个壳,在解决了花指令之后,剩下的问题便只有反调试代码和解密(解压缩)代码了。

例如上面列出的代码是通过时间校验检查调试器,一旦检查到,便使用特权级指令,让程序发生异常,无法继续运行下去。

当然,我们在静态的环境下,反调试技巧对于我们来说,毫无意义。

尽管如此,我们仍然需要知道程序会在什么时候运行到什么地方,最常见的利用系统的机制莫过于SEH了,现在来看看下面代码:设置SEH的代码“call $+5”指令后堆栈里的内容便是它的下一条指令在内存中的地址。

这是病毒常用的重定位技巧。

shift+/输入0x00456AA0+0x136F便能计算出异常处理函数的地址(457E0F)了。

产生异常的代码现在我们应该跳到457E0F继续分析。

我想你已经了解如何在静态环境下跟踪程序的流程,现在就让我们跟着程序的流程把解密相关的代码找出来。

解密代码容易看出这就是解密代码,在循环之中,且有修改内存的指令。

至于解密的KEY,其实就是00459191处ECX的值+15h。

我希望你还记得到达这里之前曾经看过下面代码:这一段是检查硬件断点的代码,假如没有设置硬件断点,那么ECX的结果应该是0。

假如你不能理解为什么,我建议你看看SEH以及关于反硬件断点的一些文章。

在知道解密代码的所有关键要素之后,就可以开始动手写脚本了。

lse语句。

if (CF==1){CF=0;while (ECX !=0){PatchByte(DeCodeAddr,Byte(EDX));EDX ++;DeCodeAddr ++;ECX --;}}else{while(Counter != 1){PatchDword(DeCodeAddr,Dword(EDX));EDX = EDX + 4;DeCodeAddr = DeCodeAddr + 4;if (ECX <= 4){ECX= ECX -4;break;}ECX = ECX - 4;}DeCodeAddr = DeCodeAddr + ECX;}//反汇编代码的循环入口(4528DE)与我们转换的循环入口不同(4528E9)//跟开始的时候一样,入口之前的代码放到循环外面。

IsNotZero = EBX & 0x7FFFFFFF;if (IsNotZero == 0){CF=1;EBX = Dword(MyAddr);MyAddr = MyAddr + 4;至此,我们成功将004528D0到004529A1处的代码转换成C代码。

在完成如此复杂的代码还原之后,004529A6到004529D8处的反汇编代码只是小菜一碟。

里面的代码也很好理解,将符合E8 01和E9 01的机械码解密。

位移指令可以通过借用程序中的一个闲置的Dword,使用IDC提供的Pactch系列指令来模拟,详见。

在完成最后的解密代码后,便是IAT的修复了。

现在看看下面代码:004529FC xchg eax, ebp004529FD loc_4529FD:004529FD mov al, [edi]004529FF inc edi00452A00 or al, al00452A02 jz short loc_4529E000452A0200452A04 mov ecx, edi00452A06 push edi00452A07 dec eax00452A08 repne scasb00452A0A push ebp00452A0B call dword ptr [esi+54A40h]00452A11 or eax, eax00452A13 jz short loc_452A1C00452A1300452A15 mov [ebx], eax00452A17 add ebx, 400452A1A jmp short loc_4529FD在分析该处代码之前,显然应该先把ESI的值计算出来。

鼠标点击ESI,以高亮显示该寄存器,向上滚动反汇编窗口,发现从004529A6 pop esi处开始,ESI便没有被修改过,而该处对应于:seg005:0046206F mov esi, offset unk_447000seg005:00462074 lea edi, [esi-46000h]seg005:0046207A push edi可见ESI=0x401000,容易计算出004529F6和00452A0B处CALL的地址分别为455A3Ch 和455A40h。

跳转到该地址:显然,这里便是壳填充IAT的地方了。

那么004529DA lea edi, [esi+50000h]中,EDI 便是保存API名字的数据表。

做脱壳机的任务就留给读者作课后练习,正如前面介绍的那样,只需要API的名字为相关IAT地址重命名,便能分析了。

也就是说00452A0B处,调用GetProcAddress,跟踪它的参数lpProcName (00452A06 push edi),以及它的返回值(00452A15 mov [ebx], eax),当然这里的跟踪,可以象刚才那样手动确认,也可以通过与调试器配合快速得出结果。

不难得出下面脚本:#include ""static main() {auto ESI,EDI,EAX,EBX,Counter,cBuffer,BufLen,straa;ESI = 0x447000 - 0x46000;EDI = ESI + 0x50000;Counter = MaxEA() - MinEA();MakeUnknown(MinEA(),Counter,1); //将整个程序标记未分析AnalyzeArea (MinEA(),MaxEA()); //分析整个程序Counter = 0;while (Counter != 1){EAX = Dword(EDI);if (EAX == 0) break;EBX = Dword(EDI+4);EBX = EBX + ESI;EDI = EDI + 8;while (Counter != 1){EAX = Byte(EDI);EDI++;if (EAX == 0) break;cBuffer = GetString(EDI,-1,ASCSTR_C);straa = cBuffer + "_"; //IDA不允许重复命名,加上“_”避免重复MakeNameEx(EBX,straa,SN_AUTO);EBX = EBX + 4;EDI = EDI + strlen(cBuffer);EDI++;}}}注意解密后,必须将整个程序标记为未分析,并重新分析,然后才能进行重命名。

程序的OEP到此,静态脱壳完毕。

从这个例子也可以知道,对于掌握反汇编器的人来说,除非反调试机制与解密KEY关联,否则根本就没有强度可言。

然而,IDA博大精深,还有更多强大的功能,本文也只是抛砖引玉而已。

下面给出几个链接,方便大家更进一步学习:IDA的官方网站:看雪论坛9月翻译专题:&threadid=31023IDA Pro的插件开发SDK:&threadid=31441IDA逆向工程入门:&threadid=40765IDA简易教程:。

相关主题