IDA反汇编学习-转

2017-01-11 15:23:40来源:oschina作者:LUIS1983人点击

IDA Pro是一款强大的反汇编软件,特有的IDA视图和交叉引用,可以方便理解程序逻辑和快速定位代码片断,以方便修改。


ida-1


IDA视图


示例程序


下面会通过修改示例程序的输出字符串,来讲解如何使用IDA Pro。


#include
main()
{
int n;
scanf ("%d",&n);
if (n > 0)
printf("a > 0");//后面会用IDA Pro把'a'改成'n'
else
printf("n < 0");
}

编译后的程序下载:demo


运行IDA Pro


运行IDA Pro,并使用PE文件的方式打开示例的test.exe文件。IDA Pro会新建一个工程,并开始反汇编程序。反汇编完成后,在[IDA-View]窗口中,可以看到程序逻辑的树形图,如下:


ida-2ida-3


树形图把条件分支清晰地显示出来了,绿色线连着的表示条件为true时执行的逻辑,而红色线表示条件为false时执行的逻辑。右下角有IDA视图的缩略图,在上面点击可以快速定位到视图的指定位置。 IDA的工具栏有几个按钮对定位代码很重要,如下图所示:


ida-4


从左到右分别是:Open exports window:打开导出窗口Open import window:打开导入窗口 *Open names window:函数和参数的命名列表 *Open functions window:程序调用的所有函数窗口 *Open strings window: 打开字符串显示窗口,会列出程序中的所有字符串,该窗口有助于你通过程序的运行输出逆向找出对应的代码片断。


定位代码片断


假设我们现在接到个任务,需修正程序,把输出“a > 0”修正为“n > 0”。示例程序比较简单,直接看IDA视图我们就能找到需修改的代码片断,但实际处理时,可能程序有几m大,通过一个个看IDA视图已没法有效找到相关的执行代码片断,这时怎么办? 使用字符串窗口和IDA强大的交叉引用! 点击工具栏的[Open strings windows]按钮,可以看到如下的程序字符串:


ida-5


程序的字符串较少,可以很快地看到我们需要的字符串“a > 0”在数据段00403003位置。假如字符串多到已不能肉眼定位查找,因为字符串窗口是没有查找功能的,这时需要借助其他的文本编辑器,如notepad,editplus等。在字符串窗口内右键,选择菜单[copy]命令,会把字符串窗口的所有内容复制到剪贴板,再粘贴到记事本中查找就可以了。双击字符串窗口的该行字符串,会跳转到IDA视图的00403003位置,如下图所示:


ida-6


该位置的字符串后面会注释有DATA XREF的字样,这是程序中引用到该字符串的代码片断的地址!在该行上右键,选择[Jump to cross reference...]项,会立即跳转到引用该字符串的代码片断位置!


ida-7


ida-8


最后定位的代码片断 上图显示的汇编指令即是我们要找的代码片断,这时点击[Hex View-A]窗口,会切换到二进制浏览模式,并高亮了汇编代码的二进制格式指令,如下图所示:


ida-9


已找到需修改的代码片断,剩下的只需把a改成n。


修改程序文件


在IDA中,可以在[Hex View-A]窗口右键选择[Edit]来修改二进制指令。修改后通过右键选择[Commit Change]可以看到修改后的IDA视图。但需要注意的是,这种方式的修改并不会更新原始程序文件,实际只是修改了IDA的项目文件!IDA中只适合做一些验证性的修改,确保正确后再使用其他工具修改原始程序文件。 在IDA中验证修改正确后,可以使用UltraEdit或Hex Workshop来修改原始程序文件。下面会以UltraEdit为例来说明如何修改。


ida-10


用UltraEdit直接打开程序文件,UltraEdit会以16进制模式显示程序文件。UltraEdit显示的地址和IDA显示的地址是不同的,为了找到对应代码片断在UltraEdit中的实际地址,需要使用到UltraEdit的查找功能。在IDA中复制需修改的16进制模式显示的指令,在UltraEdit中打开查找,粘贴并查找该16进制字符串,UltrEdit会很快定位到该指令处,如下图所示:


ida-11


在IDA中使得右键来复制


ida-12


在UltraEdit打开查找功能


ida-13


找到了UltraEdit的对应位置 现在我们要把“a > 0”改成“n > 0”,a对应的ASCII码是61,而n对应的ASCII码是6E,只需把61改成6E就可以了,修改后保存。


ida-14


再次运行,可以看到结果已改变!


ida-15


示例只是修改了字符串,只需更改数据段内容就可以了,不用更改指令。假如需要更改指令,需要参考< a href="http://courses.engr.illinois.edu/ece390/resources/opcodes.html#Main">8086指令操作表写出对应指今的16进制形式,再修改。


参考资料:


http://blog.csdn.net/liquanhai/article/details/5479141


http://www.youtube.com/watch?v=Gl2S0YPRb9s


http://www.woodmann.com/crackz/Tutorials/Flores1.htm


http://courses.engr.illinois.edu/ece390/resources/opcodes.html


http://faydoc.tripod.com/cpu/conventions.htm


=============================================================


2 边写变学IDA

http://hi.baidu.com/onepc/blog/item/bb217259aa539a212834f0f1.html源码



发觉若是没源码看着来还真的不知是啥意思。PAGE:0001048E MyUnloadproc near; DATA XREF: DriverEntry+9 o PAGE:0001048E;不过这个IDA怎么参数都没有显示?不是很明白。明明写有参数的。 PAGE:0001048E var_8= dword ptr -8 PAGE:0001048E var_4= dword ptr -4 PAGE:0001048E arg_0= dword ptr 8 PAGE:0001048E PAGE:0001048Epushebp PAGE:0001048Fmovebp, esp PAGE:00010491subesp, 8 PAGE:00010494moveax, [ebp+arg_0] ;ebp+8刚好是在参数1的位置。PAGE:00010497movecx, [eax+4] ;参数1偏移4的值传给ecx ;不能动态调试只能猜了。 lkd> dt _DRIVER_OBJECT nt!_DRIVER_OBJECT +0x000 Type: Int2B +0x002 Size: Int2B +0x004 DeviceObject: Ptr32 _DEVICE_OBJECT ;eax+4这里刚好是驱动对象里存放设备地址的地方 PAGE:0001049Amov[ebp+var_4], ecx;传给变量1ebp-4 ;这句 pDeviceObject=pDriverObject->DeviceObject; 变量1是设备对象指针。下面[变量1=pDeviceObject]表示 PAGE:0001049D PAGE:0001049D loc_1049D:; CODE XREF: MyUnload+40 j PAGE:0001049Dcmp[ebp+var_4], 0 ;变量与0比较 PAGE:000104A1jzshort loc_104D0 ;即是退出 等于0时跳 pushoffset Format; "Driver Exit!/n" PAGE:000104D5call_DbgPrint PAGE:000104DAaddesp, 4 PAGE:000104DDmovesp, ebp PAGE:000104DFpopebp PAGE:000104E0retn4 PAGE:000104E0 MyUnloadendpPAGE:000104A3movedx, [ebp+var_4];pDeviceObject的地址传给edx,PAGE:000104A6moveax, [edx+28h];地址偏移28h地方正是扩展设备存放地方的地方。 lkd> dt _DEVICE_OBJECT nt!_DEVICE_OBJECT +0x000 Type: Int2B +0x002 Size: Uint2B +0x004 ReferenceCount: Int4B +0x008 DriverObject: Ptr32 _DRIVER_OBJECT +0x00c NextDevice: Ptr32 _DEVICE_OBJECT +0x010 AttachedDevice: Ptr32 _DEVICE_OBJECT +0x014 CurrentIrp: Ptr32 _IRP +0x018 Timer: Ptr32 _IO_TIMER +0x01c Flags: Uint4B +0x020 Characteristics : Uint4B +0x024 Vpb: Ptr32 _VPB +0x028 DeviceExtension : Ptr32 Void PAGE:000104A9mov[ebp+var_8], eax ;扩展设备地址传给变量8,即是pDeviceS=(PDevice_Save)pDeviceObject->DeviceExtension;这句代码 ;这里的(PDevice_Save)地址转换在汇编里直接透明。 PAGE:000104ACmovecx, [ebp+var_8] PAGE:000104AFaddecx, 0Ch typedef struct _Device_Save { PDEVICE_OBJECT pDeviceSave; 4位 UNICODE_STRING uDeviceNameSave;8位 UNICODE_STRING uSysmbolicLinkNameSave; }Device_Save,*PDevice_Save; addecx, 0Ch结构地址加上0ch这里正好是指向uSysmbolicLinkNameSave地址 PAGE:000104B2pushecx; SymbolicLinkName PAGE:000104B3callds:__imp__IoDeleteSymbolicLink@4 ; IoDeleteSymbolicLink(x) PAGE:000104B9movedx, [ebp+var_4];pDeviceObject地址 PAGE:000104BCmoveax, [edx+0Ch];+0x00c NextDevice: Ptr32 _DEVICE_OBJECT PAGE:000104BFmov[ebp+var_4], eax;就是说把下一个设备地址传给变量1 PAGE:000104C2movecx, [ebp+var_8] ;这个是扩展设备地址 PAGE:000104C5movedx, [ecx] ;也是在扩展设备第一个结构成员的地址,即DeviceObject PAGE:000104C7pushedx; DeviceObject PAGE:000104C8callds:__imp__IoDeleteDevice@4 ; IoDeleteDevice(x) PAGE:000104CEjmpshort loc_1049D ; 无条件回跳GE:0001049Dcmp[ebp+var_4], 0到这里。所以可以看出这是一个死循环,若是没有jz 这个语句的话,所以可以看出这是一个while(x){......} x为真是循环。 PAGE:000104D0 ; --------------------------------------------------------------------------- PAGE:000104D0 PAGE:000104D0 loc_104D0:; CODE XREF: MyUnload+13 j PAGE:000104D0pushoffset Format; "Driver Exit!/n" PAGE:000104D5call_DbgPrint PAGE:000104DAaddesp, 4 PAGE:000104DDmovesp, ebp PAGE:000104DFpopebp PAGE:000104E0retn4 PAGE:000104E0 MyUnloadendp/////////////////////////////////////////////////////偶的分割线//////////////////////////////////////////////////////////////////////////

GE:000105D0 AllIrpComplete proc near; DATA XREF: DriverEntry+2E o PAGE:000105D0 PAGE:000105D0 var_4= dword ptr -4 ;第一个变量 PAGE:000105D0 arg_4= dword ptr 0Ch ;第二个参数 PAGE:000105D0 PAGE:000105D0pushebp PAGE:000105D1movebp, esp PAGE:000105D3pushecx PAGE:000105D4mov[ebp+var_4], 0 ;第一个变量设值为0 PAGE:000105DBmoveax, [ebp+arg_4] ;第二个参数传的值传给eax [这里是pIrp的地址] PAGE:000105DEmovecx, [ebp+var_4] PAGE:000105E1mov[eax+18h], ecx lkd> dt _IRP nt!_IRP +0x000 Type: Int2B +0x002 Size: Uint2B +0x004 MdlAddress: Ptr32 _MDL +0x008 Flags: Uint4B +0x00c AssociatedIrp: __unnamed +0x010 ThreadListEntry : _LIST_ENTRY +0x018 IoStatus: _IO_STATUS_BLOCK lkd> dt _IO_STATUS_BLOCK nt!_IO_STATUS_BLOCK +0x000 Status: Int4B +0x000 Pointer: Ptr32 Void +0x004 Information: Uint4B 把IRP的状态设为0即是成功的状态 PAGE:000105E4movedx, [ebp+arg_4] PAGE:000105E7movdword ptr [edx+1Ch], 0 lkd> dt _IRP -r1 nt!_IRP +0x000 Type: Int2B +0x002 Size: Uint2B +0x004 MdlAddress: Ptr32 _MDL +0x000 Next: Ptr32 _MDL +0x004 Size: Int2B +0x006 MdlFlags: Int2B +0x008 Process: Ptr32 _EPROCESS +0x00c MappedSystemVa: Ptr32 Void +0x010 StartVa: Ptr32 Void +0x014 ByteCount: Uint4B +0x018 ByteOffset: Uint4B +0x008 Flags: Uint4B +0x00c AssociatedIrp: __unnamed +0x000 MasterIrp: Ptr32 _IRP +0x000 IrpCount: Int4B +0x000 SystemBuffer: Ptr32 Void +0x010 ThreadListEntry : _LIST_ENTRY +0x000 Flink: Ptr32 _LIST_ENTRY +0x004 Blink: Ptr32 _LIST_ENTRY +0x018 IoStatus: _IO_STATUS_BLOCK +0x000 Status: Int4B +0x000 Pointer: Ptr32 Void +0x004 Information: Uint4B;这里正是1ch的地方 18h+4h=1ch PAGE:000105EExordl, dl PAGE:000105F0movecx, [ebp+arg_4] PAGE:000105F3callds:__imp_@IofCompleteRequest@8; IofCompleteRequest(x,x) PAGE:000105F9moveax, [ebp+var_4] ;return 0; PAGE:000105FCmovesp, ebp PAGE:000105FEpopebp PAGE:000105FFretn8 PAGE:000105FF AllIrpComplete endp



PAGE:00010503 ; Attributes: bp-based frame PAGE:00010503 PAGE:00010503 ConExeToSysproc near; DATA XREF: DriverEntry+3B o PAGE:00010503 PAGE:00010503 var_28= dword ptr -28h ;8 PAGE:00010503 var_24= dword ptr -24h ;7 PAGE:00010503 SourceString= dword ptr -20h ;6 PAGE:00010503 var_1C= dword ptr -1Ch ;5 PAGE:00010503 UnicodeString= UNICODE_STRING ptr -18h ;变量4=>这里可以看出占8字节变量 PAGE:00010503 DestinationString= STRING ptr -10h ;变量3=>同上 PAGE:00010503 var_8= dword ptr -8 ;变量2 PAGE:00010503 var_4= dword ptr -4 ;变量1 PAGE:00010503 arg_4= dword ptr 0Ch ;参数 PAGE:00010503 这个是主要的分发例程,看变量有N个。 PAGE:00010503pushebp PAGE:00010504movebp, esp PAGE:00010506subesp, 28h ;变量所需的空间 PAGE:00010509mov[ebp+var_24], 0 ;这个是NTSTATUS变量 PAGE:00010510moveax, [ebp+arg_4] ;IRP地址 PAGE:00010513movecx, [eax+60h] ; +0x040 Tail: __unnamed +0x000 Overlay: __unnamed +0x000 DeviceQueueEntry : _KDEVICE_QUEUE_ENTRY +0x000 DriverContext: [4] Ptr32 Void +0x010 Thread: Ptr32 _ETHREAD +0x014 AuxiliaryBuffer : Ptr32 Char +0x018 ListEntry: _LIST_ENTRY +0x020 CurrentStackLocation : Ptr32 _IO_STACK_LOCATION 上面是dt _IRP -r得出的信息 60h偏移处是 _IO_STACK_LOCATION结构的地址 PAGE:00010516mov[ebp+var_8], ecx var_8这个变量就是pIoStackLocation=IoGetCurrentIrpStackLocation(pIrp); PAGE:00010519movedx, [ebp+var_8] ;IO栈的地址传给edx PAGE:0001051Cmoveax, [edx+0Ch] 这个结构太难看了,windbg及ddk定义的结构,太多共用体之类的了。 共用体的最大存储字节是其中的元素最大的那个为准。 PAGE:0001051Fmov[ebp+var_1C], eax var_1C =>uControlCode PAGE:00010522movecx, [ebp+var_8] PAGE:00010525movedx, [ecx+8] PAGE:00010528mov[ebp+var_4], edx ebp+var_4=>uInBufferLength; PAGE:0001052Bmoveax, [ebp+var_1C] var_1C =>uControlCode PAGE:0001052Emov[ebp+var_28], eax 控制码传给var_28变量 PAGE:00010531cmp[ebp+var_28], 222000h 用这个变量与222000h比较 [这个即是应用层传来的控制码] PAGE:00010538jzshort loc_1053C 相等跳到 PAGE:0001053Ajmpshort loc_10594不相等跳 PAGE:0001053C ; --------------------------------------------------------------------------- PAGE:0001053C相等跳到这里 PAGE:0001053C loc_1053C:; CODE XREF: ConExeToSys+35 j PAGE:0001053Cmovecx, [ebp+arg_4] ;IRP地址 PAGE:0001053Fmovedx, [ecx+0Ch]; +0x00c AssociatedIrp: __unnamed PAGE:00010542mov[ebp+SourceString], edx +0x00c AssociatedIrp: __unnamed +0x000 MasterIrp: Ptr32 _IRP +0x000 IrpCount: Int4B +0x000 SystemBuffer: Ptr32 Void 传给sourcestring pIrp->AssociatedIrp.SystemBuffer;PAGE:00010545moveax, [ebp+SourceString] PAGE:00010548pusheax; SourceString PAGE:00010549leaecx, [ebp+DestinationString] PAGE:0001054Cpushecx; DestinationString PAGE:0001054Dcallds:__imp__RtlInitAnsiString@8; RtlInitAnsiString(x,x) PAGE:00010553push1; AllocateDestinationString PAGE:00010555leaedx, [ebp+DestinationString] PAGE:00010558pushedx; SourceString PAGE:00010559leaeax, [ebp+UnicodeString] PAGE:0001055Cpusheax; DestinationString PAGE:0001055Dcallds:__imp__RtlAnsiStringToUnicodeString@12; RtlAnsiStringToUnicodeString(x,x,x) RtlAnsiStringToUnicodeString转换状态在eax中 PAGE:00010563mov[ebp+var_24], eax PAGE:00010566cmp[ebp+var_24], 0 PAGE:0001056Ajgeshort loc_1057B ;若大于等于则跳 =>成功 PAGE:0001056Cpushoffset aConverUnsucces ; "conver unsuccess!/n" PAGE:00010571call_DbgPrint PAGE:00010576addesp, 4 PAGE:00010579jmpshort loc_1059B ;这里退出 break PAGE:0001057B ; --------------------------------------------------------------------------- PAGE:0001057B PAGE:0001057B loc_1057B:; CODE XREF: ConExeToSys+67 j PAGE:0001057Bmovecx, [ebp+UnicodeString.Buffer] PAGE:0001057Epushecx PAGE:0001057Fmovedx, dword ptr [ebp+UnicodeString.Length] PAGE:00010582pushedx PAGE:00010583callSetReg PAGE:00010588leaeax, [ebp+UnicodeString] PAGE:0001058Bpusheax; UnicodeString PAGE:0001058Ccallds:__imp__RtlFreeUnicodeString@4 ; RtlFreeUnicodeString(x) PAGE:00010592jmpshort loc_1059B ==>break PAGE:00010594 ; --------------------------------------------------------------------------- PAGE:00010594不相等跳到这里 PAGE:00010594 loc_10594:; CODE XREF: ConExeToSys+37 j PAGE:00010594mov[ebp+var_24], 0C0000232h #define STATUS_INVALID_VARIANT((NTSTATUS)0xC0000232L) PAGE:0001059B这里是流程语句结束。[这个各种流程若是没优化编译的话都是有一定的特征的] PAGE:0001059B loc_1059B:; CODE XREF: ConExeToSys+76j PAGE:0001059B; ConExeToSys+8F j PAGE:0001059Bmovecx, [ebp+arg_4] PAGE:0001059Emovedx, [ebp+var_24] PAGE:000105A1mov[ecx+18h], edx PAGE:000105A4moveax, [ebp+arg_4] PAGE:000105A7movdword ptr [eax+1Ch], 0 PAGE:000105AExordl, dl PAGE:000105B0movecx, [ebp+arg_4] PAGE:000105B3callds:__imp_@IofCompleteRequest@8; IofCompleteRequest(x,x) PAGE:000105B9moveax, [ebp+var_24] PAGE:000105BCmovesp, ebp PAGE:000105BEpopebp PAGE:000105BFretn8 PAGE:000105BF ConExeToSysendp PAGE:000105BF 总结:反汇编的主要是一些变量分配及堆栈平衡及一些结构成员的赋值。多看应会慢慢熟悉。还有各种流程控制语句要多练。PAGE:0001057Bmovecx, [ebp+UnicodeString.Buffer] PAGE:0001057Epushecx PAGE:0001057Fmovedx, dword ptr [ebp+UnicodeString.Length] PAGE:00010582pushedx PAGE:00010583callSetReg ;这里设SetReg有一个UnicodeString参数 这里可以看到,当压入一个UnicodeString字符时,会把缓冲区及长度分别压入,所以这种字符串不用以0为标志作为结尾。

SetRegproc near; CODE XREF: ConExeToSys+80 p INIT:00010938 INIT:00010938 var_54= dword ptr -54h INIT:00010938 var_50= dword ptr -50h INIT:00010938 var_4C= dword ptr -4Ch INIT:00010938 var_48= dword ptr -48h INIT:00010938 var_44= dword ptr -44h INIT:00010938 var_40= dword ptr -40h INIT:00010938 var_3C= dword ptr -3Ch INIT:00010938 DestinationString= UNICODE_STRING ptr -38h INIT:00010938 KeyHandle= dword ptr -30h INIT:00010938 ObjectAttributes= OBJECT_ATTRIBUTES ptr -2Ch INIT:00010938 ValueName= UNICODE_STRING ptr -14h INIT:00010938 Handle= dword ptr -0Ch INIT:00010938 Disposition= dword ptr -8 INIT:00010938 Data= dword ptr -4 INIT:00010938 arg_0= byte ptr 8 INIT:00010938 INIT:00010938pushebp INIT:00010939movebp, esp INIT:0001093Bsubesp, 54h INIT:0001093Epushoffset aRegistryMachin ; "//Registry//Machine//SOFTWARE//Microsoft//Wi"... INIT:00010943leaeax, [ebp+DestinationString] INIT:00010946pusheax; DestinationString INIT:00010947callds:__imp__RtlInitUnicodeString@8; RtlInitUnicodeString(x,x) INIT:0001094Dmov[ebp+ObjectAttributes.Length], 18h INIT:00010954mov[ebp+ObjectAttributes.RootDirectory], 0 INIT:0001095Bmov[ebp+ObjectAttributes.Attributes], 40h INIT:00010962leaecx, [ebp+DestinationString] INIT:00010965mov[ebp+ObjectAttributes.ObjectName], ecx INIT:00010968mov[ebp+ObjectAttributes.SecurityDescriptor], 0 INIT:0001096Fmov[ebp+ObjectAttributes.SecurityQualityOfService], 0 INIT:00010976leaedx, [ebp+ObjectAttributes] INIT:00010979pushedx; ObjectAttributes INIT:0001097Apush0F003Fh; DesiredAccess INIT:0001097Fleaeax, [ebp+KeyHandle] INIT:00010982pusheax; KeyHandle INIT:00010983callds:__imp__ZwOpenKey@12; ZwOpenKey(x,x,x) INIT:00010989mov[ebp+var_3C], eax INIT:0001098Ccmp[ebp+var_3C], 0 INIT:00010990jgeshort loc_109A4 INIT:00010992pushoffset aOpenNotSuccess ; "Open Not Success/n" INIT:00010997call_DbgPrint INIT:0001099Caddesp, 4 INIT:0001099Fjmploc_10A6C INIT:000109A4 ; --------------------------------------------------------------------------- INIT:000109A4 INIT:000109A4 loc_109A4:; CODE XREF: SetReg+58 j INIT:000109A4mov[ebp+var_54], 18h INIT:000109ABmovecx, [ebp+KeyHandle] INIT:000109AEmov[ebp+var_50], ecx INIT:000109B1mov[ebp+var_48], 40h INIT:000109B8leaedx, [ebp+arg_0] INIT:000109BBmov[ebp+var_4C], edx INIT:000109BEmov[ebp+var_44], 0 INIT:000109C5mov[ebp+var_40], 0 INIT:000109CCleaeax, [ebp+Disposition] INIT:000109CFpusheax; Disposition INIT:000109D0push0; CreateOptions INIT:000109D2push0; Class INIT:000109D4push0; TitleIndex INIT:000109D6leaecx, [ebp+var_54] INIT:000109D9pushecx; ObjectAttributes INIT:000109DApush0F003Fh; DesiredAccess INIT:000109DFleaedx, [ebp+Handle] INIT:000109E2pushedx; KeyHandle INIT:000109E3callds:__imp__ZwCreateKey@28 ; ZwCreateKey(x,x,x,x,x,x,x) INIT:000109E9mov[ebp+var_3C], eax INIT:000109ECcmp[ebp+var_3C], 0 INIT:000109F0jlshort loc_10A1A INIT:000109F2cmp[ebp+Disposition], 1 INIT:000109F6jnzshort loc_10A07 INIT:000109F8pushoffset aCreate ; "create/n" INIT:000109FDcall_DbgPrint INIT:00010A02addesp, 4 INIT:00010A05jmpshort loc_10A1A INIT:00010A07 ; --------------------------------------------------------------------------- INIT:00010A07 INIT:00010A07 loc_10A07:; CODE XREF: SetReg+BE j INIT:00010A07cmp[ebp+Disposition], 2 INIT:00010A0Bjnzshort loc_10A1A INIT:00010A0Dpushoffset aOpen; "Open/n" INIT:00010A12call_DbgPrint INIT:00010A17addesp, 4 INIT:00010A1A INIT:00010A1A loc_10A1A:; CODE XREF: SetReg+B8 j INIT:00010A1A; SetReg+CD j ... INIT:00010A1Apushoffset aDebugger ; "Debugger" INIT:00010A1Fleaeax, [ebp+ValueName] INIT:00010A22pusheax; DestinationString INIT:00010A23callds:__imp__RtlInitUnicodeString@8; RtlInitUnicodeString(x,x) INIT:00010A29mov[ebp+Data], offset aCWindowsNtll_e ; "C://WINDOWS//ntll.exe" INIT:00010A30movecx, [ebp+Data] INIT:00010A33pushecx; wchar_t * INIT:00010A34callds:__imp__wcslen INIT:00010A3Aaddesp, 4 INIT:00010A3Dleaedx, [eax+eax+2] INIT:00010A41pushedx; DataSize INIT:00010A42moveax, [ebp+Data] INIT:00010A45pusheax; Data INIT:00010A46push1; Type INIT:00010A48push0; TitleIndex INIT:00010A4Aleaecx, [ebp+ValueName] INIT:00010A4Dpushecx; ValueName INIT:00010A4Emovedx, [ebp+Handle] INIT:00010A51pushedx; KeyHandle INIT:00010A52callds:__imp__ZwSetValueKey@24 ; ZwSetValueKey(x,x,x,x,x,x) INIT:00010A58moveax, [ebp+Handle] INIT:00010A5Bpusheax; Handle INIT:00010A5Ccallds:__imp__ZwClose@4 ; ZwClose(x) INIT:00010A62movecx, [ebp+KeyHandle] INIT:00010A65pushecx; Handle INIT:00010A66callds:__imp__ZwClose@4 ; ZwClose(x) INIT:00010A6C INIT:00010A6C loc_10A6C:; CODE XREF: SetReg+67 j INIT:00010A6Cmovesp, ebp INIT:00010A6Epopebp INIT:00010A6Fretn8

INIT:00010A6F SetRegends

=====================================================================

3 IDA反汇编工具初探

对于程序员来说,增长自己编程功力的一个好方法是阅读其它人开发的程序的源码,从而把别人的技术来消化成为自己知识,这是不是很象吸星大法?


  但开源的程序毕竟是在少数,大多数程序都只会分发可执行文件及相关文件,这时我们要想查看此程序的代码,就只有把它反汇编,当然这需要一定的汇编功底,但是一个好的反汇编工具能为你阅读反汇编出来的程序提供非常大的帮助。


  了解反汇编的朋友也一定知道WINDASM这个有名的反汇编工具,比如我们用WINDASM反汇编一个程序,在其程序入口点反汇编得到如下代码:


  //*********************** Program Entry Point *****************


  :00401000 6A00 push 00000000


  :00401002 E8FF050000 call 00401606


  :00401007 A316304000 mov [00403016], eax


  :00401007 E8EF050000 call 00401600


  :00401011 A30E304000 mov [0040300E], eax


  :00401016 6A0A push 0000000A


  :00401018 FF350E304000push dword ptr [0040300E]


  :0040101E 6A00 push 00000000


  :00401020 EF3516304000 push dword ptr [00403016]


  :00401026 E806000000 call 00401031


  :0040102B 50 push eax


  :0040102c E8C9050000 call 004015FA


  如果不联系上下文及知道这是程序入口的话,很难看出来这一段代码到底是干什么的,但IDA就不一样了,它不但会反汇编程序,并会尽量分析程序,并加上相应的注释(正因为这样,IDA反汇编一个大的程序会花非常长的时间),请看下面一段IDA反汇编出来的代码,是不是明了多了?


  .text:00401000 push 0 ;lpModuleName


  .text:00401002 call GetModuleHandleA


  .text:00401007 mov hInstance, eax


  .text:0040100C call GetCommandLineA


  .text:00401011 mov dword_0_40300E, eax


  .text:00401016 push 0Ah


  .text:00401018 push dword_0_40300E


  .text:0040101E push 0


  .text:00401020 push hInstance


  .text:00401026 call sub_0_401031


  .text:0040102B push eax ;uExitCode


  .text:0040102C call ExitProcess


  IDA反汇编程序后,会生成一个 .idb文件,里面保存了反汇编出来的代码及注释及IDA的一些其它相关数据,我们可以直接在IDA中写自己的分析结果和注释并保存,下次直接打开.idb文件就可以了,例如上面


  .text:00401000 push 0 ;lpModuleName


  .text:00401002 call GetModuleHandleA


  .text:00401007 mov hInstance, eax


  我们可以看出来实际上就是hInstance = GetModuleHandleA(nil);我们可以在后面直接加上注释,在.text:00401007这一行最后面的空白处点右键,在弹出的菜单中选择"注释",然后在弹出的窗口中填上"取得当前模块实例句柄",这一行就会变为


  .text:00401007 mov hInstance, eax ;取得当前模块实例句柄


  这样就为我们的反汇编出的代码增加了可读性.


  IDA不但可以在当前代码中加注释,还可以更改其默认的符号名,比如


  .text:00401011 mov dword_0_40300E, eax


  其中的dwrd_0_40300E可以看出来是存放取得的命令行的缓冲区指针(可以双击符号名,函数名跳到其定义处),在dword_0_40300E上面点右键,选取"重命名",然后在弹出的窗口中填入lpCommandline,点确定,这样程序中所有使用到了dword_0_40300E这个变量的地方都会将dword_0_40300E替换为lpCommandline.如下所示:


  .text:00401011 mov lpCommandline, eax


  .text:00401016 push 0Ah


  .text:00401018 push lpCommandline


  我们再来看.text:00401026 call sub_0_401031这一行


  可以从上面的代码看出来,这是调用的WinMain函数,在sub_0_401031上面点右键,选取"重命名",然这个函数命名为WinMain,这时IDA就将所有sub_0_401031符号变为WinMain, 并且自动加上函数定义,并会在函数调用时入栈的参数后面加上其对应的变量注释,这时我们反汇编出来的这一段代码就成了下面这个样子的了:


  .text:00401000 start proc near


  .text:00401000 push 0 ;lpModuleName


  .text:00401002 call GetModuleHandleA


  .text:00401007 mov hInstance, eax ;取得当前模块实例句柄


  .text:0040100C call GetCommandLineA


  .text:00401011 mov lpCommandline, eax


  .text:00401016 push 0Ah ;nShowCmd


  .text:00401018 push lpCommandline ;lpCmdLine


  .text:0040101E push 0 ;hPrevInstance


  .text:00401020 push hInstance ;hInstance


  .text:00401026 call WinMain


  .text:0040102B push eax ;uExitCode


  .text:0040102C call ExitProcess


  是不是一目了解了呢?


  当我们通过阅读源码,能确定某一个子函数的作用及传入的参数类型时,我们可以双击这个函数名,跳到函数定义处,在函数定义处点右键,使用"设置函数类型"功能来编辑函数定义(C++语法),这样所有调用到这个函数的地方都会在入栈的参数后面加上其对应的变量注释. 还可以通过在函数定义处后面空白处点右键加上"可重复注释",这样所有调用此函数的地方都会在后面加上这个重复的注释.


  如果想查看某个变量或函数被调用的情况,可以通过在函数或变量名上点右键,点击"查看操作数交叉索引处"功能,就可以在打开的窗口中查看到所有调用其的代码,并可通过双击跳到这段代码处.这是一个很有用的功能,能帮助你快速的搞清函数及变量的调用关系.


  按下F12还可以查看到程序的流程图,CTRL+12可以查看到函数的调用图.


  IDA还拥有符号调试技术,能识别常见编释器编释的程序,例如下面反汇编出的VC6.0的程序代码段:


  .text:00405427 push edx


  .text:00405428 call _swscanf


  .text:0040542D lea eax, [esp+38h+arg_40]


  .text:00405431 push offset unk_0_5DB1A4 ;const wchar_t *


  .text:00405436 push eax ;const wchar_t *


  .text:00405437 call _wcscmp


  .text:0040543C add esp, 1Ch


  .text:0040543F test eax, eax


  .text:00405441 jz short loc_0_405459


  .text:00405443 lea ecx, [esp+24h+arg_40]


  .text:00405447 push offset unk_0_5DB18C ;const wchar_t *


  .text:0040544C push ecx ;const wchar_t *


  .text:0040544D call _wcscmp


  就检查到了其调用了MFC类库中的函数,并把它们替换成了相应的函数名.


  还可以调用IDA导出.MAP文件,来配合其它动态调试工具如SOFT-ICE来进行代码分析.


  IDA是一个非常强大的反汇编工具,这里只是讨论了一下它的一些基本的应用,希望能起到抛砖引玉的作用

汇编语言里 eax, ebx, ecx, edx, esi, edi, ebp, esp这些都是什么意思啊?


eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 汇编语言中CPU上的通用寄存器的名称,是32位的寄存器。如果用C语言来解释,可以把这些寄存器当作变量看待。


比方说:add eax,-2 ;//可以认为是给变量eax加上-2这样的一个值。


这些32位寄存器有多种用途,但每一个都有“专长”,有各自的特别之处。


EAX是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。


EBX是"基地址"(base)寄存器, 在内存寻址时存放基地址。


ECX是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。


EDX则总是被用来放整数除法产生的余数。


ESI/EDI分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.


EBP是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer). 在破解的时候,经常可以看见一个标准的函数起始代码:      push ebp ;保存当前ebp   mov ebp,esp ;EBP设为当前堆栈指针   sub esp, xxx ;预留xxx字节给函数临时变量.   ...      这样一来,EBP 构成了该函数的一个框架, 在EBP上方分别是原来的EBP, 返回地址和参数. EBP下方则是临时变量. 函数返回时作mov esp,ebp/pop ebp/ret即可.


ESP专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。在32位平台上,ESP每次减少4字节。

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台