elphi/C++ Builder采用控件拖放的方式來完成界面的設計,並和事件聯系起來。而這些信息以資源(RCDATA)的方式存放於可執行文件中。DeDe便利用這個原理進行反編譯,獲取相關信息,將界面與事件聯系關系還原,但事件的匯編代碼不能還原。DeDe公開了源代碼,感興趣的讀者可以研究一下。
1.主要功能
用DeDe可以查看Delphi程序窗體的屬性,可以查看按鈕對應的事件,並將事件代碼反匯編出來,其能識別出Delphi庫函數,具有良好的可讀性。另外,還可以把事件輸出到map文件中供其他工具使用。
2.配置
(1)DSF文件
①DSF文件的含義
DSF文件內容來自不同版本BPL庫文件的輸出符號表。DeDe反匯編引擎使用這些符號表對生成的ASM代碼文件添加類成員方法調用的注釋,這非常類似於IDA Pro的FLIRT技術。如果沒有加載任何BPL符號表文件,對BPL類的調用就無法以注釋的格式說明。
②加載DSF文件
經由“File/Load Symbol File”菜單,就可加載所需要的DSF文件。程序若能正確識別出相應版本的Delphi程序,會自動加載DSF文件。若希望每次啟動DeDe的同時自動加載若干DSF文件,選中“Options/Configuration”菜單,在Symbols選項卡中就可完成本項工作。如果想查看包含在某個特定DSF文件中的輸出符號表,選擇“Options/Symbols”。
③為何需要創建DSF文件
處理使用自定義構件(即不是Delphi安裝的構件)的程序時,如果有這些自定義構件的BPL,並且為它們創建了DSF文件,那么DeDe將會注釋所有對這些自定義構件的調用。創建DSF的速度也是很快的。
(2)DOI文件
DOI意思是Delphi Class Offset Information(Delphi類偏移信息),該技術使用偏移信息識別類成員:方法和域(實例變量,屬性)。DOI文件包含用於識別的必要數據。DeDe仿真指令的執行來查找使用這些偏移的引用所在。例如,在繼承自TForm類的任何子類的偏移0xCC處,代表指向ShowModal方法的指針。當遇到類似call [reg + $00CC]的調用時,仿真器就知道寄存器包含的對象是引用TForm.ShowModal方法的TForm子類。DOI文件應該存放在DSF文件夾內。
下面是一個生成的帶有DOI幫助信息的簡單示例。
* Reference to control LogMemo : TMemo
004E4E7C 8B80F4020000 mov eax, [eax+$02F4]
* Reference to field TMemo.Lines : TStrings
004E4E82 8B8004020000 mov eax, [eax+$0204]
* Possible String Reference to: 'Loading Export Names ...'
004E4E88 BA0C584E00 mov dx, $004E580C
004E4E8D 8B08 mov ecx, [eax]
* Reference to method TStrings.Add(string)
004E4E8F FF5134 call dword ptr [ecx+$34]
使用DOI文件,只需復制*.DOI文件到DSF文件夾即可。DOI數據會自動插入到生成的代碼文件中。
(3)字符串參考的含義
在DeDe中,如果處理含有非英文字符串的程序,則選擇“Option/Configuration”菜單,在References選項卡中可以設置DeDe反編譯引擎查找字符串參考時使用的字符集。
注意:如果使用全部的字符集合#32~#255,則可能得到殘缺的字符串參考。Delphi程序一般不用Unicode字符串,這也是該選項沒有包括在字符串參考配置中的原因。
3.基本操作
DeDe安裝很簡單。安裝好后直接執行主程序,出現如圖7.1所示的主界面。單擊 按鈕打開光盤映像文件中的DE_Delphi文件,然后單擊“Process”按鈕進行反編譯。DeDe先將被分析的文件裝載到內存中,再進行反編譯,因此對一些壓縮加殼的程序也能反編譯。
CLasses Info:顯示程序中使用的類信息;
Units Info:顯示程序中使用的單元信息;
Forms:顯示程序中的窗體信息,這部分可以用資源編輯工具修改;
Procedures:顯示程序的過程信息;
Project:可將當前項目保存;
Exports:導出符號文件。
圖7.1 DeDe界面
在此顯示了Events(事件)和Controls(控件)兩方面的內容(見圖7.2)。Button1Click事件對應的是“確定”按鈕,雙擊可打開代碼窗口。該窗口顯示當前事件對應的匯編代碼,右邊控制條顯示全局變量和局變量。雙擊某個表達式,可以加注釋。在跳轉指令、CALL指令上雙擊可跳到相應代碼上。
圖7.2 查看事件按鈕
設目標實例DE_Delphi的用戶名為Name[],具體代碼如下:
* Reference to control TMainForm.Edit1 : TEdit ;用戶名框控件
004502C6 mov eax, [esi+$02F8]
* Reference to: controls.TControl.GetText(TControl):System.String;
004502CC call 0042F4F8
004502D1 cmp dword ptr [ebp-$0C],+$00 ;判斷是否輸入字符
004502D5 jnz 004502F5
……
* Reference to: controls.TControl.GetText(TControl):System.String;
004502FE call 0042F4F8
00450303 mov eax, [ebp-$10] ;指向用戶名
* Reference to: system.@LStrLen:Integer;
00450306 call 004044C4
0045030B cmp eax, +$04 ;判斷是否輸入了4個字符
0045030E jnl 0045032E
……
* Reference to: controls.TControl.GetText(TControl):System.String;
00450345 call 0042F4F8
0045034A mov eax, [ebp-$14] 指向Name[]
* Reference to: system.@LStrLen:Integer;
0045034D call 004044C4 ;得到用戶名長度
00450352 mov ebx, eax ;將長度放到ebx中作為計數器
00450354 test ebx, ebx
00450356 jle 00450381
00450358 mov edi, $00000001 ;edi=1
0045035D /mov eax, [ebp-$08] ;指向Name[]
00450360 |movzx eax, byte ptr[eax+edi-$01]
00450365 |lea ecx, [ebp-$18]
00450368 |mov edx, $00000002
*Referenceto: sysutils.IntToHex(System.Integer;System.Integer)
0045036D |call 00408310 ;inttohex(ord(Name[i]),2)
00450372 |mov edx, [ebp-$18] ;[ebp-$18]指向Name[i]16進制
00450375 |lea eax, [ebp-$04] ;[ebp-$04]變量是指向Sn指針的指針
* Reference to: system.@LStrCat;
00450378 |call 004044CC ;將兩個串連起來,設為Sn
0045037D |inc edi ;i+1
0045037E |dec ebx ;計數器減1
0045037F \jnz 0045035D ;循環
……
* Reference to: controls.TControl.GetText(TControl):System.String;
0045038A call 0042F4F8 ;取輸入的序列號
0045038F mov eax, [ebp-$1C] ;[ebp-$1C]是輸入的序列號指針
00450392 mov edx, [ebp-$04] ;[ebp-$04]中存放的是正確的序列號
* Reference to: system.@LStrCmp;
00450395 call 00404608 ;比較兩個臨時變量
0045039A jnz 004503B7
由於DeDe的符號識別技術,使得上述代碼可讀性非常容易理解。
在圖7.2中有兩個按鈕值得注意:
DPR按鈕:是反匯編項目文件.dpr,該文件控制或記錄程序中的所有文件。
OFFS按鈕:反匯編指定地址的代碼。