1、IDA实例教程详解IDA实例教程详解作者:笨笨雄(转载)1 软件环境 静态分析有很多好处,例如加壳的程序(尽管对于高手来说这并不会耗费太多时间),我们不需要寻找OEP,也不需要解除自校验,只要修复IAT,DUMP下来就可以动手分析了。假如你需要修改程序,可以使用内存补丁技术。动态与静态,调试器与反汇编器结合可以简化分析任务,帮助我们理解代码。因此掌握一种反汇编器是非常必要的。IDA可以说是这方面的首选工具,它为我们提供了丰富的功能,以帮助我们进行逆向分析。这从IDA复杂的工作界面便可以知道。种类繁多的工具栏 在分辨率不高的情况,这些工具栏与反汇编窗口挤在小屏幕里,看起来不爽。我一般把它关闭(查
2、看=工具栏=主工具栏)以获得更好的视觉效果。当我们需要这些功能的时候,直接使用快捷键就可以了。下面是常用快捷键的清单:快捷键功能注释C转换为代码一般在IDA无法识别代码时使用这两个功能整理代码D转换为数据A转换为字符N为标签重命名方便记忆,避免重复分析。;添加注释R把立即值转换为字符便于分析立即值H把立即值转换为10进制Q把立即值转换为16进制B把立即值转换为2进制G跳转到指定地址X交叉参考便于查找API或变量的引用SHIFT+/计算器ALT+ENTER新建窗口并跳转到选中地址这四个功能都是方便在不同函数之间分析(尤其是多层次的调用)。具体使用看个人喜好ALT+F3关闭当前分析窗口ESC返回前
3、一个保存位置CTRL+ENTER返回后一个保存位置 在工具栏下面的便是工作窗口。主要的窗口分页有“IDA View-A”、“Name”、“Strings”、“Exports”和“Imports”。对于后面3项相信大家都不会陌生了,它们分别是字符参考,输出函数参考和输入函数参考。Name是命名窗口,在那里可以看到我们命名的函数或者变量。这四个窗口都支持索引功能,可以通过双击来快速切换到分析窗口中的相关内容,使用起来十分方便。简单输入几个字符即可定位目标 IDA View-A是分析窗口,支持两种显示模式,除了常见的反汇编模式之后,还提供图形视图以及其他有趣的功能。IDA的反汇编窗口一般我们在分析的
4、时候,并不关心程序的机械码,所以IDA为我们自动隐藏了这些信息。如果你有需要,可以通过以下步骤来设置:选项=常规=反汇编=显示反汇编行部分=机械码字节数=修改为你允许显示的大小 现在让我们以论坛脱壳版块置顶帖的那个经典为例,看看图形视图的表现。首先我们到以下连接下载:你能通过图形视图及其缩略图快速找到壳的出口吗 如图所示,标签40EA0E便是壳的出口代码的地址。在OD中直接跳到该地址,下断点,然后运行到该处,再单步便能看到OEP了。假如希望通过跳转法找OEP,相信图形视图比你在OD一个一个跳转跟随,要快得多。 再来看看这个壳的另类脱法。直接运行该程序, DUMP下来,再使用IMPORTREC的
5、IAT AutoSearch功能修复输入表。用IDA打开修复了输入表的DUMP文件。在IMPORT窗口随便选一个API,随便通过交叉参考跳转到一个函数的代码。此处为文件输入表的位置 我选了RegQueryValueExA,通过交叉参考,来到Sub_402488处的函数代码。 用鼠标拖动缩略图中的虚线框到上方,便能看到该CALL的头部了。然后按下图指示操作:在函数标记上点击鼠标右键 处于最上层的函数,便是OEP了,使用PE工具修改文件入口为10CC。现在函数可以正常工作了。这个方法的原理是通常我们写程序都有如下流程:Main proc ,打开IAT符号文件);CustEa = AskAddr(0
6、,目标IAT地址);filehandle = fopen(fileName,r);for (ea = CustEa; zcount 2; ea = ea + 4) if (Dword(ea) !=0) Sbuffer = readstr(filehandle); if(strlen(Sbuffer) 2) 00404C2C00404C2C00404C00404C404C6A00404C00404C00404C00404C00404C00404C00404C00404C00404C4A00404C00404C4F00404C4F00404C00404C00404C404C4560F0F0F0A0
7、C8 F5A5A83 C0A0C8 F5A5A83 C0a0a0045639F004563A004563A004563A004563A004563C004563C004563C4563C4563C004563C004563F004563F4563F004563F004563F004563F004563F4563F0045640A0045640A45640A0045640Aseg005:0045640A ; Resend the last transmissionseg005:0045640Aseg005:0045640D ; seg005:0045640D修复之后的代码除了“sub eax,
8、esp-8+arg_4”(实际上是sub eax,esp)看起来有点怪之后,一切正常。作为一个壳,在解决了花指令之后,剩下的问题便只有反调试代码和解密(解压缩)代码了。例如上面列出的代码是通过时间校验检查调试器,一旦检查到,便使用特权级指令,让程序发生异常,无法继续运行下去。当然,我们在静态的环境下,反调试技巧对于我们来说,毫无意义。尽管如此,我们仍然需要知道程序会在什么时候运行到什么地方,最常见的利用系统的机制莫过于SEH了,现在来看看下面代码:seg005:00456A9B call $+5seg005:00456AA0 add dword ptr esp+0, 136Fhseg005:0
9、0456AA7 push large dword ptr fs:0seg005:00456AAE mov large fs:0, esp设置SEH的代码“call $+5”指令后堆栈里的内容便是它的下一条指令在内存中的地址。这是病毒常用的重定位技巧。shift+/输入0x00456AA0+0x136F便能计算出异常处理函数的地址(457E0F)了。seg005:0045745C xor eax, eaxseg005:0045745E movzx eax, byte ptr eax产生异常的代码现在我们应该跳到457E0F继续分析。我想你已经了解如何在静态环境下跟踪程序的流程,现在就让我们跟着程
10、序的流程把解密相关的代码找出来。seg005:00459191 push ecxseg005:00459192 xor ecx, ecxseg005:00459194 call $+5seg005:00459199 pop ediseg005:0045919A add edi, 9C4hseg005:004591A0 pop edxseg005:004591A1 add edx, 15hseg005:004591A4 loc_4591A4: ; CODE XREF: sub_459149+6Bjseg005:004591A4 movzx eax, byte ptr ecx+ediseg005:
11、004591A8 xor eax, edxseg005:004591AA mov ecx+edi, alseg005:004591AD inc ecxseg005:004591AE cmp ecx, 93hseg005:004591B4 jb short loc_4591A4解密代码 容易看出这就是解密代码,在循环之中,且有修改内存的指令。至于解密的KEY,其实就是00459191处ECX的值+15h。我希望你还记得到达这里之前曾经看过下面代码:seg005:004587B6 mov eax, esp+0Chseg005:004587BA xor ecx, ecxseg005:004587BC
12、 xor ecx, eax+4seg005:004587BF xor ecx, eax+8seg005:004587C2 xor ecx, eax+0Chseg005:004587C5 xor ecx, eax+10h 这一段是检查硬件断点的代码,假如没有设置硬件断点,那么ECX的结果应该是0。假如你不能理解为什么,我建议你看看SEH以及关于反硬件断点的一些文章。 在知道解密代码的所有关键要素之后,就可以开始动手写脚本了。#include static main() auto StartAddr,cKey,Cbuffer,Counter;StartAddr = 0x00459199 + 0x9
13、c4;cKey = 0x15;for (Counter = 0 ; Counter 0x93; Counter +)Cbuffer = Byte(StartAddr) cKey; 00461F00461F00461F0046200F0046204C0046206A0046206F0046207A0046206A00461F9C0046206Flse语句。if (CF=1)CF=0;while (ECX !=0)PatchByte(DeCodeAddr,Byte(EDX);EDX +;DeCodeAddr +;ECX -; elsewhile(Counter != 1)PatchDword(De
14、CodeAddr,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; Higt
15、Bitflat = EBX & 0x;EBX = EBX + EBX;EBX = EBX + CF;CF = 0; 至此,我们成功将004528D0到004529A1处的代码转换成C代码。在完成如此复杂的代码还原之后,004529A6到004529D8处的反汇编代码只是小菜一碟。里面的代码也很好理解,将符合E8 01和E9 01的机械码解密。位移指令可以通过借用程序中的一个闲置的Dword,使用IDC提供的Pactch系列指令来模拟,详见。在完成最后的解密代码后,便是IAT的修复了。现在看看下面代码:004529DA lea edi, esi+50000h004529E0 loc_4529E0
16、: 004529E0 mov eax, edi004529E2 or eax, eax004529E4 jz short loc_452A22004529E4004529E6 mov ebx, edi+4004529E9 lea eax, eax+esi+549B0h004529F0 add ebx, esi004529F2 push eax004529F3 add edi, 8004529F6 call dword ptr esi+54A3Ch004529FC xchg eax, ebp004529FD loc_4529FD: 004529FD mov al, edi004529FF inc
17、 edi00452A00 or al, al00452A02 jz short loc_4529E000452A0200452A04 mov ecx, edi00452A06 push edi00452A07 dec eax00452A08 repne scasb00452A0A push ebp00452A0B call dword ptr esi+54A40h00452A11 or eax, eax00452A13 jz short loc_452A1C00452A1300452A15 mov ebx, eax00452A17 add ebx, 400452A1A jmp short lo
18、c_4529FD在分析该处代码之前,显然应该先把ESI的值计算出来。鼠标点击ESI,以高亮显示该寄存器,向上滚动反汇编窗口,发现从004529A6 pop esi处开始,ESI便没有被修改过,而该处对应于:seg005:0046206F mov esi, offset unk_447000seg005:00462074 lea edi, esi-46000hseg005:0046207A push edi 可见ESI=0x401000,容易计算出004529F6和00452A0B处CALL的地址分别为455A3Ch和455A40h。跳转到该地址: 显然,这里便是壳填充IAT的地方了。那么004
19、529DA 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,cBu
20、ffer,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 (Count
21、er != 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简易教程:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1