1. 程式人生 > >IDA反匯編學習

IDA反匯編學習

hex print 可執行文件 一個個 chang 列表 sca 地址轉換 ast

1 轉自:http://www.cnblogs.com/vento/archive/2013/02/09/2909579.html

IDA Pro是一款強大的反匯編軟件,特有的IDA視圖和交叉引用,可以方便理解程序邏輯和快速定位代碼片斷,以方便修改。

技術分享

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]窗口中,可以看到程序邏輯的樹形圖,如下:

技術分享技術分享

樹形圖把條件分支清晰地顯示出來了,綠色線連著的表示條件為true時執行的邏輯,而紅色線表示條件為false時執行的邏輯。右下角有IDA視圖的縮略圖,在上面點擊可以快速定位到視圖的指定位置。 IDA的工具欄有幾個按鈕對定位代碼很重要,如下圖所示:

技術分享

從左到右分別是: 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]按鈕,可以看到如下的程序字符串:

技術分享

程序的字符串較少,可以很快地看到我們需要的字符串“a > 0”在數據段00403003位置。假如字符串多到已不能肉眼定位查找,因為字符串窗口是沒有查找功能的,這時需要借助其他的文本編輯器,如notepad,editplus等。在字符串窗口內右鍵,選擇菜單[copy]命令,會把字符串窗口的所有內容復制到剪貼板,再粘貼到記事本中查找就可以了。 雙擊字符串窗口的該行字符串,會跳轉到IDA視圖的00403003位置,如下圖所示:

技術分享

該位置的字符串後面會註釋有DATA XREF的字樣,這是程序中引用到該字符串的代碼片斷的地址!在該行上右鍵,選擇[Jump to cross reference...]項,會立即跳轉到引用該字符串的代碼片斷位置!

技術分享

技術分享

最後定位的代碼片斷 上圖顯示的匯編指令即是我們要找的代碼片斷,這時點擊[Hex View-A]窗口,會切換到二進制瀏覽模式,並高亮了匯編代碼的二進制格式指令,如下圖所示:

技術分享

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

修改程序文件

在IDA中,可以在[Hex View-A]窗口右鍵選擇[Edit]來修改二進制指令。修改後通過右鍵選擇[Commit Change]可以看到修改後的IDA視圖。但需要註意的是,這種方式的修改並不會更新原始程序文件,實際只是修改了IDA的項目文件!IDA中只適合做一些驗證性的修改,確保正確後再使用其他工具修改原始程序文件。 在IDA中驗證修改正確後,可以使用UltraEdit或Hex Workshop來修改原始程序文件。下面會以UltraEdit為例來說明如何修改。

技術分享

用UltraEdit直接打開程序文件,UltraEdit會以16進制模式顯示程序文件。UltraEdit顯示的地址和IDA顯示的地址是不同的,為了找到對應代碼片斷在UltraEdit中的實際地址,需要使用到UltraEdit的查找功能。在IDA中復制需修改的16進制模式顯示的指令,在UltraEdit中打開查找,粘貼並查找該16進制字符串,UltrEdit會很快定位到該指令處,如下圖所示:

技術分享

在IDA中使得右鍵來復制

技術分享

在UltraEdit打開查找功能

技術分享

找到了UltraEdit的對應位置 現在我們要把“a > 0”改成“n > 0”,a對應的ASCII碼是61,而n對應的ASCII碼是6E,只需把61改成6E就可以了,修改後保存。

技術分享

再次運行,可以看到結果已改變!

技術分享

示例只是修改了字符串,只需更改數據段內容就可以了,不用更改指令。假如需要更改指令,需要參考< 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 MyUnload proc 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: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
+0x000 Type : Int2B
+0x002 Size : Int2B
+0x004 DeviceObject : Ptr32 _DEVICE_OBJECT ;eax+4這裏剛好是驅動對象裏存放設備地址的地方
PAGE:0001049A mov [ebp+var_4], ecx ;傳給變量1 ebp-4
;這句 pDeviceObject=pDriverObject->DeviceObject; 變量1是設備對象指針。下面[變量1=pDeviceObject]表示
PAGE:0001049D
PAGE:0001049D loc_1049D: ; CODE XREF: MyUnload+40 j
PAGE:0001049D cmp [ebp+var_4], 0 ;變量與0比較
PAGE:000104A1 jz short loc_104D0 ;即是退出
等於0時跳
push offset Format ; "Driver Exit!\n"
PAGE:000104D5 call _DbgPrint
PAGE:000104DA add esp, 4
PAGE:000104DD mov esp, ebp
PAGE:000104DF pop ebp
PAGE:000104E0 retn 4
PAGE:000104E0 MyUnload endp

PAGE:000104A3 mov edx, [ebp+var_4];pDeviceObject的地址傳給edx,PAGE:000104A6 mov eax, [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: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_STRING uDeviceNameSave;8位
UNICODE_STRING uSysmbolicLinkNameSave;
}Device_Save,*PDevice_Save;
add ecx, 0Ch結構地址加上0ch這裏正好是指向uSysmbolicLinkNameSave地址
PAGE:000104B2 push ecx ; SymbolicLinkName
PAGE:000104B3 call ds:[email protected] ; IoDeleteSymbolicLink(x)
PAGE:000104B9 mov edx, [ebp+var_4];pDeviceObject地址
PAGE:000104BC mov eax, [edx+0Ch]; +0x00c NextDevice : 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:[email protected] ; IoDeleteDevice(x)
PAGE:000104CE jmp short loc_1049D ;
無條件回跳GE:0001049D cmp [ebp+var_4], 0到這裏。所以可以看出這是一個死循環,若是沒有jz 這個語句的話,所以可以看出這是一個while(x){......} x為真是循環。
PAGE:000104D0 ; ---------------------------------------------------------------------------
PAGE:000104D0
PAGE:000104D0 loc_104D0: ; CODE XREF: MyUnload+13 j
PAGE:000104D0 push offset Format ; "Driver Exit!\n"
PAGE:000104D5 call _DbgPrint
PAGE:000104DA add esp, 4
PAGE:000104DD mov esp, ebp
PAGE:000104DF pop ebp
PAGE:000104E0 retn 4
PAGE:000104E0 MyUnload endp

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\偶的分割線\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

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: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
+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:000105E4 mov edx, [ebp+arg_4]
PAGE:000105E7 mov dword 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:000105EE xor dl, dl
PAGE:000105F0 mov ecx, [ebp+arg_4]
PAGE:000105F3 call ds:[email protected]@8 ; IofCompleteRequest(x,x)
PAGE:000105F9 mov eax, [ebp+var_4] ;return 0;
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:00010503 ConExeToSys proc 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: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] ;
+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: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:0001053C loc_1053C: ; CODE XREF: ConExeToSys+35 j
PAGE:0001053C mov ecx, [ebp+arg_4] ;IRP地址
PAGE:0001053F mov edx, [ecx+0Ch];
+0x00c AssociatedIrp : __unnamed
PAGE:00010542 mov [ebp+SourceString], edx
+0x00c AssociatedIrp : __unnamed
+0x000 MasterIrp : Ptr32 _IRP
+0x000 IrpCount : Int4B
+0x000 SystemBuffer : 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 1 ; 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 short loc_1057B ;若大於等於則跳 =>成功
PAGE:0001056C push offset aConverUnsucces ; "conver unsuccess!\n"
PAGE:00010571 call _DbgPrint
PAGE:00010576 add esp, 4
PAGE:00010579 jmp short loc_1059B ;這裏退出 break
PAGE:0001057B ; ---------------------------------------------------------------------------
PAGE:0001057B
PAGE:0001057B loc_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:[email protected] ; RtlFreeUnicodeString(x)
PAGE:00010592 jmp short loc_1059B ==>break
PAGE:00010594 ; ---------------------------------------------------------------------------
PAGE:00010594 不相等跳到這裏
PAGE:00010594 loc_10594: ; CODE XREF: ConExeToSys+37 j
PAGE:00010594 mov [ebp+var_24], 0C0000232h
#define STATUS_INVALID_VARIANT ((NTSTATUS)0xC0000232L)
PAGE:0001059B 這裏是流程語句結束。[這個各種流程若是沒優化編譯的話都是有一定的特征的]
PAGE:0001059B loc_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:[email protected]@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:000105BF ConExeToSys 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 proc 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:00010938 push ebp
INIT:00010939 mov ebp, esp
INIT:0001093B sub esp, 54h
INIT:0001093E push offset aRegistryMachin ; "\\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 offset aOpenNotSuccess ; "Open Not Success\n"
INIT:00010997 call _DbgPrint
INIT:0001099C add esp, 4
INIT:0001099F jmp loc_10A6C
INIT:000109A4 ; ---------------------------------------------------------------------------
INIT:000109A4
INIT:000109A4 loc_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 0 ; CreateOptions
INIT:000109D2 push 0 ; Class
INIT:000109D4 push 0 ; 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:[email protected] ; 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 offset aCreate ; "create\n"
INIT:000109FD call _DbgPrint
INIT:00010A02 add esp, 4
INIT:00010A05 jmp short loc_10A1A
INIT:00010A07 ; ---------------------------------------------------------------------------
INIT:00010A07
INIT:00010A07 loc_10A07: ; CODE XREF: SetReg+BE j
INIT:00010A07 cmp [ebp+Disposition], 2
INIT:00010A0B jnz short loc_10A1A
INIT:00010A0D push offset aOpen ; "Open\n"
INIT:00010A12 call _DbgPrint
INIT:00010A17 add esp, 4
INIT:00010A1A
INIT:00010A1A loc_10A1A: ; CODE XREF: SetReg+B8 j
INIT:00010A1A ; SetReg+CD j ...
INIT:00010A1A push offset aDebugger ; "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 1 ; Type
INIT:00010A48 push 0 ; 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:[email protected] ; ZwSetValueKey(x,x,x,x,x,x)
INIT:00010A58 mov eax, [ebp+Handle]
INIT:00010A5B push eax ; Handle
INIT:00010A5C call ds:[email protected] ; ZwClose(x)
INIT:00010A62 mov ecx, [ebp+KeyHandle]
INIT:00010A65 push ecx ; Handle
INIT:00010A66 call ds:[email protected] ; ZwClose(x)
INIT:00010A6C
INIT:00010A6C loc_10A6C: ; CODE XREF: SetReg+67 j
INIT:00010A6C mov esp, ebp
INIT:00010A6E pop ebp
INIT:00010A6F retn 8

INIT:00010A6F SetReg ends

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

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 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語言來解釋,可以把這些寄存器當作變量看待。

比方說: 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 構成了該函數的一個框架, 在

IDA反匯編學習