IDA反汇编学习-转

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

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

ida-2ida-3

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

 ida-4

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

定位代码片断

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

ida-5

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

ida-6 

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

ida-7

ida-8

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

ida-9

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

修改程序文件

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

示例只是修改了字符串,只需更改数据段内容就可以了,不用更改指令。假如需要更改指令,需要参考< ahref="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:0001048EMyUnload       procnear              ; DATA XREF: DriverEntry+9 o
PAGE:0001048E   ;不过这个IDA怎么参数都没有显示?不是很明白。明明写有参数的。
PAGE:0001048Evar_8          = dword ptr -8
PAGE:0001048Evar_4          = dword ptr -4
PAGE:0001048Earg_0          = dword ptr 8
PAGE:0001048E
PAGE:0001048E                push   ebp
PAGE:0001048F                mov    ebp, esp
PAGE:00010491                sub    esp, 8
PAGE:00010494                mov    eax, [ebp+arg_0] ;ebp+8刚好是在参数1的位置。PAGE:00010497                mov    ecx, [eax+4] ;参数1偏移4的值传给ecx;不能动态调试只能猜了。
lkd> dt _DRIVER_OBJECT
nt!_DRIVER_OBJECT
   +0x000Type            : Int2B
   +0x002Size            : Int2B
   +0x004DeviceObject    : Ptr32 _DEVICE_OBJECT ;eax+4这里刚好是驱动对象里存放设备地址的地方
PAGE:0001049A                mov    [ebp+var_4], ecx ;传给变量1 ebp-4
;这句pDeviceObject=pDriverObject->DeviceObject;变量1是设备对象指针。下面[变量1=pDeviceObject]表示
PAGE:0001049D
PAGE:0001049Dloc_1049D:                             ; CODE XREF: MyUnload+40 j
PAGE:0001049D                cmp    [ebp+var_4], 0 ;变量与0比较
PAGE:000104A1                jz     short loc_104D0 ;即是退出
等于0时跳
push    offsetFormat   ; "DriverExit!\n"
PAGE:000104D5                call   _DbgPrint
PAGE:000104DA                add    esp, 4
PAGE:000104DD                mov    esp, ebp
PAGE:000104DF                pop    ebp
PAGE:000104E0                retn   4
PAGE:000104E0MyUnload       endp


PAGE:000104A3                mov    edx, [ebp+var_4];pDeviceObject的地址传给edx,PAGE:000104A6                mov    eax, [edx+28h];地址偏移28h地方正是扩展设备存放地方的地方。
lkd> dt_DEVICE_OBJECT
nt!_DEVICE_OBJECT
   +0x000Type            : Int2B
   +0x002Size            : Uint2B
   +0x004ReferenceCount   :Int4B
   +0x008DriverObject    : Ptr32 _DRIVER_OBJECT
   +0x00cNextDevice      : Ptr32 _DEVICE_OBJECT
   +0x010AttachedDevice   : Ptr32_DEVICE_OBJECT
   +0x014CurrentIrp      : Ptr32 _IRP
   +0x018Timer           : Ptr32 _IO_TIMER
   +0x01cFlags           : Uint4B
   +0x020 Characteristics :Uint4B
   +0x024Vpb             : Ptr32 _VPB
   +0x028 DeviceExtension : Ptr32Void

PAGE:000104A9                mov    [ebp+var_8], eax 
;扩展设备地址传给变量8,即是pDeviceS=(PDevice_Save)pDeviceObject->DeviceExtension;这句代码
;这里的(PDevice_Save)地址转换在汇编里直接透明。
PAGE:000104AC                mov    ecx, [ebp+var_8]
PAGE:000104AF                add    ecx, 0Ch
typedef struct_Device_Save 
{
   PDEVICE_OBJECT pDeviceSave;4位
   UNICODE_STRINGuDeviceNameSave;8位
   UNICODE_STRINGuSysmbolicLinkNameSave;
}Device_Save,*PDevice_Save;
add    ecx, 0Ch结构地址加上0ch这里正好是指向uSysmbolicLinkNameSave地址
PAGE:000104B2                push   ecx            ; SymbolicLinkName 
PAGE:000104B3                call   ds:__imp__IoDeleteSymbolicLink@4 ;IoDeleteSymbolicLink(x)
PAGE:000104B9                mov    edx, [ebp+var_4];pDeviceObject地址
PAGE:000104BC                mov    eax, [edx+0Ch];  +0x00cNextDevice      : Ptr32 _DEVICE_OBJECT
PAGE:000104BF                mov    [ebp+var_4], eax;就是说把下一个设备地址传给变量1
PAGE:000104C2                mov    ecx, [ebp+var_8] ;这个是扩展设备地址
PAGE:000104C5                mov    edx, [ecx] ;也是在扩展设备第一个结构成员的地址,即DeviceObject 
PAGE:000104C7                push   edx            ; DeviceObject 
PAGE:000104C8                call   ds:__imp__IoDeleteDevice@4 ; IoDeleteDevice(x)
PAGE:000104CE                jmp    short loc_1049D ;
无条件回跳GE:0001049D                cmp    [ebp+var_4], 0到这里。所以可以看出这是一个死循环,若是没有jz这个语句的话,所以可以看出这是一个while(x){......} x为真是循环。
PAGE:000104D0 ;---------------------------------------------------------------------------
PAGE:000104D0
PAGE:000104D0loc_104D0:                             ; CODE XREF: MyUnload+13 j
PAGE:000104D0                push    offsetFormat   ; "DriverExit!\n"
PAGE:000104D5                call   _DbgPrint
PAGE:000104DA                add    esp, 4
PAGE:000104DD                mov    esp, ebp
PAGE:000104DF                pop    ebp
PAGE:000104E0                retn   4
PAGE:000104E0MyUnload       endp

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\偶的分割线\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

GE:000105D0AllIrpComplete procnear              ; DATA XREF: DriverEntry+2E o
PAGE:000105D0
PAGE:000105D0var_4          = dword ptr -4 ;第一个变量
PAGE:000105D0arg_4          = dword ptr 0Ch ;第二个参数
PAGE:000105D0
PAGE:000105D0                push   ebp
PAGE:000105D1                mov    ebp, esp
PAGE:000105D3                push   ecx
PAGE:000105D4                mov    [ebp+var_4], 0 ;第一个变量设值为0
PAGE:000105DB                mov    eax, [ebp+arg_4] ;第二个参数传的值传给eax [这里是pIrp的地址]
PAGE:000105DE                mov    ecx, [ebp+var_4]
PAGE:000105E1                mov    [eax+18h], ecx
lkd> dt_IRP
nt!_IRP
   +0x000Type            : Int2B
   +0x002Size            : Uint2B
   +0x004MdlAddress      : Ptr32 _MDL
   +0x008Flags           : Uint4B
   +0x00cAssociatedIrp   : __unnamed
   +0x010 ThreadListEntry :_LIST_ENTRY
   +0x018IoStatus        : _IO_STATUS_BLOCK
lkd> dt_IO_STATUS_BLOCK
nt!_IO_STATUS_BLOCK
   +0x000Status          : Int4B
   +0x000Pointer         : Ptr32 Void
   +0x004Information     : Uint4B
把IRP的状态设为0即是成功的状态
PAGE:000105E4                mov    edx, [ebp+arg_4]
PAGE:000105E7                mov    dword ptr [edx+1Ch], 0
lkd> dt _IRP-r1
nt!_IRP
   +0x000Type            : Int2B
   +0x002Size            : Uint2B
   +0x004MdlAddress      : Ptr32 _MDL
     +0x000Next            : Ptr32 _MDL
     +0x004Size            : Int2B
     +0x006MdlFlags        : Int2B
     +0x008Process         : Ptr32 _EPROCESS
     +0x00c MappedSystemVa   : Ptr32Void
     +0x010StartVa         : Ptr32 Void
     +0x014ByteCount       : Uint4B
     +0x018ByteOffset      : Uint4B
   +0x008Flags           : Uint4B
   +0x00cAssociatedIrp   : __unnamed
     +0x000MasterIrp       : Ptr32 _IRP
     +0x000IrpCount        : Int4B
     +0x000SystemBuffer    : Ptr32 Void
   +0x010 ThreadListEntry :_LIST_ENTRY
     +0x000Flink           : Ptr32 _LIST_ENTRY
     +0x004Blink           : Ptr32 _LIST_ENTRY
   +0x018IoStatus        : _IO_STATUS_BLOCK
     +0x000Status          : Int4B
     +0x000Pointer         : Ptr32 Void
     +0x004Information     : Uint4B   ;这里正是1ch的地方 18h+4h=1ch

PAGE:000105EE                xor    dl, dl
PAGE:000105F0                mov    ecx, [ebp+arg_4]
PAGE:000105F3                call   ds:__imp_@IofCompleteRequest@8 ;IofCompleteRequest(x,x)
PAGE:000105F9                mov    eax, [ebp+var_4] ;return0;
PAGE:000105FC                mov    esp, ebp
PAGE:000105FE                pop    ebp
PAGE:000105FF                retn   8
PAGE:000105FF AllIrpComplete endp


PAGE:00010503 ; Attributes: bp-based frame
PAGE:00010503
PAGE:00010503ConExeToSys    procnear              ; DATA XREF: DriverEntry+3B o
PAGE:00010503
PAGE:00010503var_28         = dword ptr -28h ;8
PAGE:00010503var_24         = dword ptr -24h ;7
PAGE:00010503SourceString   = dword ptr -20h ;6
PAGE:00010503var_1C         = dword ptr -1Ch ;5
PAGE:00010503 UnicodeString   =UNICODE_STRING ptr -18h ;变量4=>这里可以看出占8字节变量
PAGE:00010503 DestinationString= STRING ptr -10h;变量3=>同上
PAGE:00010503var_8          = dword ptr -8 ;变量2
PAGE:00010503var_4          = dword ptr -4 ;变量1
PAGE:00010503arg_4          = dword ptr 0Ch ;参数
PAGE:00010503
这个是主要的分发例程,看变量有N个。
PAGE:00010503                push   ebp
PAGE:00010504                mov    ebp, esp
PAGE:00010506                sub    esp, 28h ;变量所需的空间
PAGE:00010509                mov    [ebp+var_24], 0 ;这个是NTSTATUS变量
PAGE:00010510                mov    eax, [ebp+arg_4] ;IRP地址
PAGE:00010513                mov    ecx, [eax+60h] ;
+0x040Tail            : __unnamed
     +0x000Overlay         : __unnamed
        +0x000 DeviceQueueEntry : _KDEVICE_QUEUE_ENTRY
        +0x000DriverContext   : [4] Ptr32 Void
        +0x010Thread          : Ptr32 _ETHREAD
        +0x014 AuxiliaryBuffer : Ptr32 Char
        +0x018ListEntry       : _LIST_ENTRY
        +0x020 CurrentStackLocation : Ptr32 _IO_STACK_LOCATION
上面是dt_IRP -r得出的信息 60h偏移处是 _IO_STACK_LOCATION结构的地址
PAGE:00010516                mov    [ebp+var_8], ecx
var_8这个变量就是pIoStackLocation=IoGetCurrentIrpStackLocation(pIrp);
PAGE:00010519                mov    edx, [ebp+var_8] ;IO栈的地址传给edx
PAGE:0001051C                mov    eax, [edx+0Ch] 
这个结构太难看了,windbg及ddk定义的结构,太多共用体之类的了。
共用体的最大存储字节是其中的元素最大的那个为准。
PAGE:0001051F                mov    [ebp+var_1C], eax
var_1C =>uControlCode
PAGE:00010522                mov    ecx, [ebp+var_8]
PAGE:00010525                mov    edx, [ecx+8]
PAGE:00010528                mov    [ebp+var_4], edx
ebp+var_4=>uInBufferLength;
PAGE:0001052B                mov    eax, [ebp+var_1C]
var_1C=>uControlCode
PAGE:0001052E                mov    [ebp+var_28], eax
控制码传给var_28变量
PAGE:00010531                cmp    [ebp+var_28], 222000h
用这个变量与222000h比较[这个即是应用层传来的控制码]
PAGE:00010538                jz     short loc_1053C
相等跳到
PAGE:0001053A                jmp    short loc_10594 不相等跳
PAGE:0001053C ;---------------------------------------------------------------------------
PAGE:0001053C 相等跳到这里
PAGE:0001053Cloc_1053C:                             ; CODE XREF: ConExeToSys+35 j
PAGE:0001053C                mov    ecx, [ebp+arg_4] ;IRP地址
PAGE:0001053F                mov    edx, [ecx+0Ch];
+0x00cAssociatedIrp   : __unnamed
PAGE:00010542                mov    [ebp+SourceString], edx
  +0x00cAssociatedIrp   : __unnamed
     +0x000MasterIrp       : Ptr32 _IRP
     +0x000IrpCount        : Int4B
     +0x000SystemBuffer    : Ptr32 Void
传给sourcestring 
pIrp->AssociatedIrp.SystemBuffer;

PAGE:00010545                mov    eax, [ebp+SourceString]
PAGE:00010548                push   eax            ; SourceString
PAGE:00010549                lea    ecx, [ebp+DestinationString]
PAGE:0001054C                push   ecx            ; DestinationString
PAGE:0001054D                call   ds:__imp__RtlInitAnsiString@8 ;RtlInitAnsiString(x,x)
PAGE:00010553                push                ; AllocateDestinationString
PAGE:00010555                lea    edx, [ebp+DestinationString]
PAGE:00010558                push   edx            ; SourceString
PAGE:00010559                lea    eax, [ebp+UnicodeString]
PAGE:0001055C                push   eax            ; DestinationString
PAGE:0001055D                call   ds:__imp__RtlAnsiStringToUnicodeString@12 ;RtlAnsiStringToUnicodeString(x,x,x)
RtlAnsiStringToUnicodeString转换状态在eax中
PAGE:00010563                mov    [ebp+var_24], eax
PAGE:00010566                cmp    [ebp+var_24], 0
PAGE:0001056A                jge     shortloc_1057B ;若大于等于则跳 =>成功
PAGE:0001056C                push    offsetaConverUnsucces ; "conver unsuccess!\n"
PAGE:00010571                call   _DbgPrint
PAGE:00010576                add    esp, 4
PAGE:00010579                 jmp    short loc_1059B ;这里退出 break
PAGE:0001057B ;---------------------------------------------------------------------------
PAGE:0001057B
PAGE:0001057Bloc_1057B:                             ; CODE XREF: ConExeToSys+67 j
PAGE:0001057B                mov    ecx, [ebp+UnicodeString.Buffer]
PAGE:0001057E                push   ecx
PAGE:0001057F                mov    edx, dword ptr [ebp+UnicodeString.Length]
PAGE:00010582                push   edx
PAGE:00010583                call   SetReg
PAGE:00010588                lea    eax, [ebp+UnicodeString]
PAGE:0001058B                push   eax            ; UnicodeString
PAGE:0001058C                call   ds:__imp__RtlFreeUnicodeString@4 ;RtlFreeUnicodeString(x)
PAGE:00010592                jmp    short loc_1059B ==>break
PAGE:00010594 ;---------------------------------------------------------------------------
PAGE:00010594 不相等跳到这里
PAGE:00010594loc_10594:                             ; CODE XREF: ConExeToSys+37 j
PAGE:00010594                mov    [ebp+var_24], 0C0000232h
#defineSTATUS_INVALID_VARIANT          ((NTSTATUS)0xC0000232L)
PAGE:0001059B 这里是流程语句结束。[这个各种流程若是没优化编译的话都是有一定的特征的]
PAGE:0001059Bloc_1059B:                             ; CODE XREF: ConExeToSys+76 j
PAGE:0001059B                                        ; ConExeToSys+8F j
PAGE:0001059B                mov    ecx, [ebp+arg_4]
PAGE:0001059E                mov    edx, [ebp+var_24]
PAGE:000105A1                mov    [ecx+18h], edx
PAGE:000105A4                mov    eax, [ebp+arg_4]
PAGE:000105A7                mov    dword ptr [eax+1Ch], 0
PAGE:000105AE                xor    dl, dl
PAGE:000105B0                mov    ecx, [ebp+arg_4]
PAGE:000105B3                call   ds:__imp_@IofCompleteRequest@8 ;IofCompleteRequest(x,x)
PAGE:000105B9                mov    eax, [ebp+var_24]
PAGE:000105BC                mov    esp, ebp
PAGE:000105BE                pop    ebp
PAGE:000105BF                retn   8
PAGE:000105BFConExeToSys    endp
PAGE:000105BF
总结:反汇编的主要是一些变量分配及堆栈平衡及一些结构成员的赋值。多看应会慢慢熟悉。还有各种流程控制语句要多练。

PAGE:0001057B                mov    ecx, [ebp+UnicodeString.Buffer]
PAGE:0001057E                push   ecx
PAGE:0001057F                mov    edx, dword ptr [ebp+UnicodeString.Length]
PAGE:00010582                push   edx
PAGE:00010583                call    SetReg;这里设SetReg有一个UnicodeString参数
这里可以看到,当压入一个UnicodeString字符时,会把缓冲区及长度分别压入,所以这种字符串不用以0为标志作为结尾。

 

SetReg         procnear              ; CODE XREF: ConExeToSys+80 p
INIT:00010938
INIT:00010938var_54         = dword ptr -54h
INIT:00010938var_50         = dword ptr -50h
INIT:00010938var_4C         = dword ptr -4Ch
INIT:00010938var_48         = dword ptr -48h
INIT:00010938var_44         = dword ptr -44h
INIT:00010938var_40         = dword ptr -40h
INIT:00010938var_3C         = dword ptr -3Ch
INIT:00010938 DestinationString= UNICODE_STRING ptr -38h
INIT:00010938KeyHandle      = dword ptr -30h
INIT:00010938 ObjectAttributes= OBJECT_ATTRIBUTES ptr-2Ch
INIT:00010938ValueName      = UNICODE_STRING ptr -14h
INIT:00010938Handle         = dword ptr -0Ch
INIT:00010938Disposition    = dword ptr -8
INIT:00010938Data           = dword ptr -4
INIT:00010938arg_0          = byte ptr 8
INIT:00010938
INIT:00010938                push   ebp
INIT:00010939                mov    ebp, esp
INIT:0001093B                sub    esp, 54h
INIT:0001093E                push    offsetaRegistryMachin ; "\\Registry\\Machine\\SOFTWARE\\Microsoft\\Wi"...
INIT:00010943                lea    eax, [ebp+DestinationString]
INIT:00010946                push   eax            ; DestinationString
INIT:00010947                call   ds:__imp__RtlInitUnicodeString@8 ;RtlInitUnicodeString(x,x)
INIT:0001094D                mov    [ebp+ObjectAttributes.Length], 18h
INIT:00010954                mov    [ebp+ObjectAttributes.RootDirectory], 0
INIT:0001095B                mov    [ebp+ObjectAttributes.Attributes], 40h
INIT:00010962                lea    ecx, [ebp+DestinationString]
INIT:00010965                mov    [ebp+ObjectAttributes.ObjectName], ecx
INIT:00010968                mov    [ebp+ObjectAttributes.SecurityDescriptor], 0
INIT:0001096F                mov    [ebp+ObjectAttributes.SecurityQualityOfService], 0
INIT:00010976                lea    edx, [ebp+ObjectAttributes]
INIT:00010979                push   edx            ; ObjectAttributes
INIT:0001097A                push   0F003Fh        ; DesiredAccess
INIT:0001097F                lea    eax, [ebp+KeyHandle]
INIT:00010982                push   eax            ; KeyHandle
INIT:00010983                call   ds:__imp__ZwOpenKey@12 ;ZwOpenKey(x,x,x)
INIT:00010989                mov    [ebp+var_3C], eax
INIT:0001098C                cmp    [ebp+var_3C], 0
INIT:00010990                jge    short loc_109A4
INIT:00010992                push    offsetaOpenNotSuccess ; "Open Not Success\n"
INIT:00010997                call   _DbgPrint
INIT:0001099C                add    esp, 4
INIT:0001099F                jmp    loc_10A6C
INIT:000109A4 ;---------------------------------------------------------------------------
INIT:000109A4
INIT:000109A4loc_109A4:                             ; CODE XREF: SetReg+58 j
INIT:000109A4                mov    [ebp+var_54], 18h
INIT:000109AB                mov    ecx, [ebp+KeyHandle]
INIT:000109AE                mov    [ebp+var_50], ecx
INIT:000109B1                mov    [ebp+var_48], 40h
INIT:000109B8                lea    edx, [ebp+arg_0]
INIT:000109BB                mov    [ebp+var_4C], edx
INIT:000109BE                mov    [ebp+var_44], 0
INIT:000109C5                mov    [ebp+var_40], 0
INIT:000109CC                lea    eax, [ebp+Disposition]
INIT:000109CF                push   eax            ; Disposition
INIT:000109D0                push                ; CreateOptions
INIT:000109D2                push                ; Class
INIT:000109D4                push                ; TitleIndex
INIT:000109D6                lea    ecx, [ebp+var_54]
INIT:000109D9                push   ecx            ; ObjectAttributes
INIT:000109DA                push   0F003Fh        ; DesiredAccess
INIT:000109DF                lea    edx, [ebp+Handle]
INIT:000109E2                push   edx            ; KeyHandle
INIT:000109E3                call   ds:__imp__ZwCreateKey@28 ; ZwCreateKey(x,x,x,x,x,x,x)
INIT:000109E9                mov    [ebp+var_3C], eax
INIT:000109EC                cmp    [ebp+var_3C], 0
INIT:000109F0                jl     short loc_10A1A
INIT:000109F2                cmp    [ebp+Disposition], 1
INIT:000109F6                jnz    short loc_10A07
INIT:000109F8                push    offsetaCreate ; "create\n"
INIT:000109FD                call   _DbgPrint
INIT:00010A02                add    esp, 4
INIT:00010A05                jmp    short loc_10A1A
INIT:00010A07 ;---------------------------------------------------------------------------
INIT:00010A07
INIT:00010A07loc_10A07:                             ; CODE XREF: SetReg+BE j
INIT:00010A07                cmp    [ebp+Disposition], 2
INIT:00010A0B                jnz    short loc_10A1A
INIT:00010A0D                push    offsetaOpen    ;"Open\n"
INIT:00010A12                call   _DbgPrint
INIT:00010A17                add    esp, 4
INIT:00010A1A
INIT:00010A1Aloc_10A1A:                             ; CODE XREF: SetReg+B8 j
INIT:00010A1A                                        ; SetReg+CD j ...
INIT:00010A1A                push    offsetaDebugger ; "Debugger"
INIT:00010A1F                lea    eax, [ebp+ValueName]
INIT:00010A22                push   eax            ; DestinationString
INIT:00010A23                call   ds:__imp__RtlInitUnicodeString@8 ;RtlInitUnicodeString(x,x)
INIT:00010A29                mov    [ebp+Data], offset aCWindowsNtll_e ;"C:\\WINDOWS\\ntll.exe"
INIT:00010A30                mov    ecx, [ebp+Data]
INIT:00010A33                push   ecx            ; wchar_t *
INIT:00010A34                call   ds:__imp__wcslen
INIT:00010A3A                add    esp, 4
INIT:00010A3D                lea    edx, [eax+eax+2]
INIT:00010A41                push   edx            ; DataSize
INIT:00010A42                mov    eax, [ebp+Data]
INIT:00010A45                push   eax            ; Data
INIT:00010A46                push                ; Type
INIT:00010A48                push                ; TitleIndex
INIT:00010A4A                lea    ecx, [ebp+ValueName]
INIT:00010A4D                push   ecx            ; ValueName
INIT:00010A4E                mov    edx, [ebp+Handle]
INIT:00010A51                push   edx            ; KeyHandle
INIT:00010A52                call   ds:__imp__ZwSetValueKey@24 ; ZwSetValueKey(x,x,x,x,x,x)
INIT:00010A58                mov    eax, [ebp+Handle]
INIT:00010A5B                push   eax            ; Handle
INIT:00010A5C                call   ds:__imp__ZwClose@4 ; ZwClose(x)
INIT:00010A62                mov    ecx, [ebp+KeyHandle]
INIT:00010A65                push   ecx            ; Handle
INIT:00010A66                call   ds:__imp__ZwClose@4 ; ZwClose(x)
INIT:00010A6C
INIT:00010A6Cloc_10A6C:                             ; CODE XREF: SetReg+67 j
INIT:00010A6C                mov    esp, ebp
INIT:00010A6E                pop    ebp
INIT:00010A6F                retn   8

 

INIT:00010A6FSetReg         ends

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

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 FF350E304000 push 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语言来解释,可以把这些寄存器当作变量看待。

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

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

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

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

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

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

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

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

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值