OllyDbg完全教程
OllyDbg完全教程
目錄
第一章概述..................................................................1
第二章組件..................................................................5
一、一般原理[General prnciples]........................................5
二、反匯編器[Disassembler].............................................8
三、分析器[Analysis]...................................................9
四、Object掃描器[Object scanner]......................................12
五、Implib掃描器[Implib scanner].....................................12
第三章 OllyDbg的使用........................................................13
一、如何開始調(diào)試[How to start debugging session]......................13
二、CPU 窗口[CPU window]..............................................14
三、斷點[Breakpoints].................................................14
四、數(shù)據(jù)窗口[Dump]....................................................15
五、可執(zhí)行模塊窗口[Executable modules window].........................16
六、內(nèi)存映射窗口[Memory map window]...................................17
七、監(jiān)視與監(jiān)察器[Watches and inspectors]..............................19
八、線程[Threads].....................................................19
九、調(diào)用棧[Call stack]................................................20
十、調(diào)用樹[Call tree].................................................21
十一、選項[Options]...................................................21
十二、搜索[Search]....................................................22
十三、自解壓文件[Self—extracting (SFX)files]........................22
十四、單步執(zhí)行與自動執(zhí)行[Step—by—step execution and animation]......23
十五、Hit跟蹤[Hit trace]..............................................23
十六、Run 跟蹤[Run trace].............................................24
十七、快捷鍵...........................................................26
十八、插件[Plugins]...................................................29
十九、技巧提示[Tips and tricks].......................................29
第四章其他功能.............................................................30
一、調(diào)試獨立的DLL[Debugging of stand—alone DLLs].....................30
二、解碼提示[Decoding hints]..........................................32
三、表達式賦值[Evaluation of expressions].............................32
四、自定義函數(shù)描述[Custom function descriptions]......................34
?
第一章 概述
?
OllyDbg 是一種具有可視化界面的 32 位匯編—分析調(diào)試器。它的特別之處在于可以在沒有源代碼時解決問題,并且可以處理其它編譯器無法解決的難題。
Version 1.10 是最終的發(fā)布版本。 這個工程已經(jīng)停止,我不再繼續(xù)支持這個軟件了。但不用擔(dān)心:全新打造的OllyDbg2.00 不久就會面世!
運行環(huán)境:OllyDbg可以以在任何采用奔騰處理器的 Windows 95、98、ME、NT 或是 XP(未經(jīng)完全測試)操作系統(tǒng)中工作,但我們強烈建議你采用300—MHz以上的奔騰處理器以達到最佳效果。還有,OllyDbg 是極占內(nèi)存的,因此如果你需要使用諸如追蹤調(diào)試[Trace]之類的擴展功能話,建議你最好使用128MB以上的內(nèi)存。
支持的處理器:OllyDbg支持所有 80x86、奔騰、MMX、3DNOW!、Athlon 擴展指令集、SSE指令集以及相關(guān)的數(shù)據(jù)格式,但是不支持SSE2指令集。
配置: 有多達百余個選項用來設(shè)置OllyDbg的外觀和運行。
數(shù)據(jù)格式:OllyDbg的數(shù)據(jù)窗口能夠顯示的所有數(shù)據(jù)格式:HEX、ASCII、UNICODE、 16/32位有/無符號/HEX整數(shù)、32/64/80位浮點數(shù)、地址、反匯編(MASM、IDEAL或是HLA)、PE文件頭或線程數(shù)據(jù)塊。
幫助: 此文件中包含了關(guān)于理解和使用OllyDbg的必要的信息。如果你還有 Windows API 幫助文件的話(由于版權(quán)的問題win32.hlp沒有包括在內(nèi)),你可以將它掛在OllyDbg 中,這樣就可以快速獲得系統(tǒng)函數(shù)的相關(guān)幫助。
啟動: 你可以采用命令行的形式指定可執(zhí)行文件、也可以從菜單中選擇,或直接拖放到OllyDbg中,或者重新啟動上一個被調(diào)試程序,或是掛接[Attach]一個正在運行的程序。OllyDbg支持即時調(diào)試。OllyDbg根本不需要安裝,可直接在軟盤中運行!
調(diào)試DLLs: 你可以利用OllyDbg調(diào)試標(biāo)準(zhǔn)動態(tài)鏈接庫 (DLLs)。OllyDbg 會自動運行一個可執(zhí)行程序。這個程序會加載鏈接庫,并允許你調(diào)用鏈接庫的輸出函數(shù)。
源碼級調(diào)試:OllyDbg可以識別所有 Borland 和 Microsoft 格式的調(diào)試信息。這些信息包括源代碼、函數(shù)名、標(biāo)簽、全局變量、靜態(tài)變量。有限度的支持動態(tài)(棧)變量和結(jié)構(gòu)。
代碼高亮:OllyDbg的反匯編器可以高亮不同類型的指令(如:跳轉(zhuǎn)、條件跳轉(zhuǎn)、入棧、出棧、調(diào)用、返回、特殊的或是無效的指令)和不同的操作數(shù)(常規(guī)[general]、FPU/SSE、段/系統(tǒng)寄存器、在棧或內(nèi)存中的操作數(shù),常量)。你可以定制個性化高亮方案。
線程:OllyDbg可以調(diào)試多線程程序。因此你可以在多個線程之間轉(zhuǎn)換,掛起、恢復(fù)、終止線程或是改變線程優(yōu)先級。并且線程窗口將會顯示每個線程的錯誤(就像調(diào)用 GETLASTERROR 返回一樣)。
分析:OllyDbg 的最大特點之一就是分析。它會分析函數(shù)過程、循環(huán)語句、選擇語句、表[tables]、常量、代碼中的字符串、欺騙性指令[tricky constructs]、API調(diào)用、函數(shù)中參數(shù)的數(shù)目,import表等等。這些分析增加了二進制代碼的可讀性,減少了出錯的可能性,使得我們的調(diào)試工作更加容易。
Object掃描:OllyDbg 可以掃描Object文件/庫(包括 OMF 和 COFF 格式),解壓代碼段[code segments]并且對其位置進行定向。
Implib掃描: 由于一些DLL文件的輸出函數(shù)使用的索引號,對于人來說,這些索引號沒有實際含義。如果你有與DLL相應(yīng)的輸入庫[importlibrary],OllyDbg 就可以將序號轉(zhuǎn)換成符號名稱。
完全支持Unicode: 幾乎所有支持 ASCII 的操作同時也支持 UNICODE,反之亦然。
名稱:OllyDbg可以根據(jù) Borland 和 Microsoft 格式的調(diào)試信息,顯示輸入/輸出符號及名稱。Object掃描器可以識別庫函數(shù)。其中的名稱和注釋你可任意添加。如果DLL中的某些函數(shù)是通過索引號輸出的,則你可通過掛接輸入庫[import library]來恢復(fù)原來的函數(shù)名稱。不僅如此,OllyDbg還能識別大量的常量符號名(如:窗口消息、錯誤代碼、位域[bit fields]…)并能夠解碼為已知的函數(shù)調(diào)用。
已知函數(shù):OllyDbg 可以識別 2300 多個 C 和 Windows API 中的常用函數(shù)及其使用的參數(shù)。你可以添加描述信息、預(yù)定義解碼。你還可以在已知函數(shù)設(shè)定 Log 斷點并可以對參數(shù)進行記錄。
函數(shù)調(diào)用:OllyDbg可以在沒有調(diào)試信息或函數(shù)過程使用非標(biāo)準(zhǔn)的開始部分[prolog]和結(jié)尾部分[epilog]的情況下,對遞歸調(diào)用進行回溯。
譯者注:
004010D0?? push?ebp????????????? \
004010D1?? mov??ebp,esp?????????????????? ? |
004010D3?? sub??esp,10h??????????????????? ? |>prolog
004010D6?? push?ebx????????????????????????? ? |
004010D7?? push?esi??????????????????????????? ? |
004010D8?? push?edi?????????????????????????? /
……
004010C5?? pop ??edi?????????????????????????? \?
004010C6?? pop?? esi??????????????????????????? |
004010C7?? pop?? ebx????????????????????????? |>epilog
004010C8?? mov?? esp,ebp??????????????????????????? |
004010CA?? pop??ebp????????????????????????? |
004010CB?? ret?????????????????????????????????????? /
棧:在棧窗口中,OllyDbg 能智能識別返回地址和棧框架[Stack Frames]。并會留下一些先前的調(diào)用。如果程序停在已知函數(shù)上,堆棧窗口將會對其參數(shù)進行分析解碼。
譯者注:棧框架[Stack Frames]是指一個內(nèi)存區(qū)域,用于存放函數(shù)參數(shù)和局部變量。
SEH 鏈: 跟蹤棧并顯示結(jié)構(gòu)化異常句柄鏈。全部鏈會顯示在一個單獨的窗口中。
搜索:方法真是太多了!可精確、模糊搜索命令或命令序列,搜索常數(shù),搜索二進制、文本字符串,搜索全部命令地址,搜索全部常量或地址域[address range],搜索所有能跳到選定地址的跳轉(zhuǎn),搜索所有調(diào)用和被調(diào)用的函數(shù),搜索所有參考字符串,在不同模塊中搜索所有調(diào)用、搜索函數(shù)名稱,在全部已分配的內(nèi)存中搜索二進制序列。如果搜索到多個結(jié)果,你可以對其進行快速操作。
窗口:OllyDbg 能夠列出關(guān)于調(diào)試程序中的各種窗口,并且可以在窗口、類甚至選定的消息上設(shè)置斷點。
資源:如果 Windows API 函數(shù)使用了參考資源串,OllyDbg 可以顯示它。其支持顯示的類型僅限于附帶資源[attached resources]的列表、數(shù)據(jù)顯示及二進制編輯。
斷點:OllyDbg支持各種斷點:一般斷點、條件斷點、記錄斷點(比如記錄函數(shù)參數(shù)到記錄窗口)、內(nèi)存讀寫斷點、硬件斷點(只適用于ME/NT/2000)等。在Hit跟蹤情況下,可以在模塊的每條命令上都設(shè)置INT3斷點。在使用500—MHZ處理器的 Windows NT 中,OllyDbg 每秒可以處理高達 5000 個中斷。
監(jiān)視與監(jiān)察器:每個監(jiān)視都是一個表達式并能實時顯示表達式的值。你可以使用寄存器、常數(shù)、地址表達式、布爾值以及任何復(fù)雜代數(shù)運算,你還可以比較ASCII和UNICODE字符串。監(jiān)察器[inspectors]是一種包含了兩個的索引序列的監(jiān)視[Watches],它以二維表的形式呈現(xiàn),可以對數(shù)組和結(jié)構(gòu)進行解碼分析。?
Heap walk.:在基于Win95的系統(tǒng)中,OllyDbg 可以列出所有的已分配的堆。
句柄:在基于NT的系統(tǒng)中,OllyDbg 可列出被調(diào)試程序的所有系統(tǒng)句柄。
執(zhí)行:.你可以單步執(zhí)行、步入子程序或者步過子程序。你也可以執(zhí)行程序直到函數(shù)返回時、執(zhí)行到指定地址處,還可以自動執(zhí)行。當(dāng)程序運行時,你仍然可以操縱程序并能夠查看內(nèi)存、設(shè)置斷點甚至修改代碼。你也可以任意的暫停或重啟被調(diào)試的程序。
Hit跟蹤:.Hit跟蹤可以顯示出目前已執(zhí)行的指令或函數(shù)過程,幫助你檢驗代碼的各個分支。Hit跟蹤會在指定指令到達之前設(shè)置斷點,而在這個指令執(zhí)行后,會把這個斷點清除掉。譯者注:Hit在英文中是“擊中”的意思,指令如果運行了就表示這個指令被“擊中”了,沒有執(zhí)行的指令就是“未擊中”,這樣我們就很容易看出被調(diào)試程序哪些部分運行了,而哪些沒有運行。
Run跟蹤: Run跟蹤可以單步執(zhí)行程序,它會在一個很大的循環(huán)緩沖區(qū)中模擬運行程序。這個模擬器包含了除了SSE指令集以外的所以寄存器、標(biāo)志、線程錯誤、消息、已經(jīng)函數(shù)的參數(shù)。你可以保存命令,這樣可以非常方便地調(diào)試自修改代碼(譯者注:比如加殼程序)。你可以設(shè)置條件中斷,條件包括地址范圍、表達式、命令。你可以將Run跟蹤信息保存到一個文件中,這樣就可以對比兩次運行的差別。Run跟蹤可以回溯分析已執(zhí)行過的上百萬條命令的各種細(xì)節(jié)。
統(tǒng)計: 統(tǒng)計[Profiler]可以在跟蹤時計算某些指令出現(xiàn)的次數(shù)。因此你就能了解代碼的哪一部分被頻繁執(zhí)行。
補丁:內(nèi)置匯編器能夠自動找到修改過的代碼段。二進制編輯器則會以ASCII、UNICODE或者十六進制的形式同步顯示修改后的數(shù)據(jù)。修改后的數(shù)據(jù)同其它數(shù)據(jù)一樣,能夠進行復(fù)制—粘貼操作。原來的數(shù)據(jù)會自動備份,以便數(shù)據(jù)恢復(fù)時使用。你可以把修改的部分直接復(fù)制到執(zhí)行文件中,OllyDbg會自動修正。 OllyDbg還會記錄以前調(diào)試過程中使用的所有補丁。你可以通過空格鍵實現(xiàn)補丁的激活或者禁止。
自解壓文件: 當(dāng)調(diào)試自解壓文件時,你往往希望跳過解壓部分,直接停在程序的原始入口點。OllyDbg的自解壓跟蹤將會使你實現(xiàn)這一目的。如果是加保護的自解壓段,自解壓跟蹤往往會失敗。而一旦OllyDbg找到了入口點,它將會跳過解壓部分,并準(zhǔn)確的到達入口點。
插件:你可以把自己的插件添加到OllyDbg中,以增加新的功能。OllyDbg 的插件能夠訪問幾乎所有重要的數(shù)據(jù)的結(jié)構(gòu)、能夠在OllyDbg的窗口中添加菜單和快捷鍵,能夠使用100個以上的插件API函數(shù)。插件API函數(shù)有詳細(xì)的說明文檔。默認(rèn)安裝已經(jīng)包含了兩個插件:命令行插件和書簽插件。
UDD:OllyDbg 把所有程序或模塊相關(guān)的信息保存至單獨的文件中,并在模塊重新加載時繼續(xù)使用。這些信息包括了標(biāo)簽、注釋、斷點、監(jiān)視、分析數(shù)據(jù)、條件等等
更多:這里介紹的功能,僅僅是OllyDbg的部分功能。因為其具有如此豐富的功能,以至于OllyDbg能成為非常方便的調(diào)試器!
第二章 組件
一、一般原理[General prnciples]
我希望你能對80x86系列處理器的內(nèi)部結(jié)構(gòu)有所了解,同時具有一定的編寫匯編程序的能力。對于Microsoft Windows方面的知識,你也要熟悉。
OllyDbg是運行在Windows 95、Windows 98、Windows ME、Windows NT 和 Windows 2000系統(tǒng)下的一個單進程、多線程的分析代碼級調(diào)試工具。它可以調(diào)試PE格式的執(zhí)行文件及動態(tài)鏈接庫,并可以對其打補丁。“代碼級”意味著你可以直接與比特、字節(jié)或處理器指令打交道。OllyDbg 僅使用已公開的 Win32 API 函數(shù),因此它可以在所有 Windows 操作系統(tǒng)及后繼版本中使用。但是由于我沒有對 XP 系統(tǒng)進行徹底測試,因此不能保證OllyDbg功能的充分發(fā)揮。注意:OllyDbg 不支持對 .NET 程序的調(diào)試。
OllyDbg不是面向編譯器的。它沒有特別的規(guī)則規(guī)定必須是哪一個編譯器產(chǎn)生的代碼。因此,OllyDbg可以非常好的處理通過編譯器生成的代碼,或是直接用匯編寫入的代碼。
OllyDbg可以并行調(diào)試程序。你無須暫停執(zhí)行程序,就可以瀏覽代碼和數(shù)據(jù),設(shè)置斷點、停止或恢復(fù)線程,甚至直接修改內(nèi)存。(這可以視為一種軟件調(diào)試的模式,與之相對的硬件模式則是當(dāng)進程在運行時調(diào)試器被阻滯,反之亦然)。假使所需的操作比較復(fù)雜,OllyDbg會讓進程終止一小段時間,但是這種暫停對于用戶來說是透明的。有時進程會發(fā)生非法操作。你可以把OllyDbg設(shè)置成即時[just—in—time]調(diào)試器,它會掛接出錯程序,并停在程序產(chǎn)生異常的地方。
通過OllyDbg,你可以調(diào)試單獨的DLL[standaloneDLLs]文件。操作系統(tǒng)不能直接運行DLL 文件,因此OllyDbg將一個可以加載 DLL 的小程序壓縮到資源里,這個程序允許你調(diào)用最多10個參數(shù)的輸出函數(shù)。
OllyDbg是完全面向模塊[module—oriented]的。模塊[Module]包括可執(zhí)行文件(擴展名通常為.EXE)和在啟動時加載或需要時動態(tài)加載的動態(tài)鏈接庫(擴展名通常為.DLL)。在調(diào)試期間,你可以設(shè)置斷點[breakpoints]、定義新的標(biāo)簽[labels]、注釋[comment]匯編指令,當(dāng)某個模塊從內(nèi)存中卸載[unload]時,調(diào)試器會把這些信息保存在文件中,文件名就是模塊的名稱,擴展名為.UDD(表示 用戶自定義文件[User—Defined Data])當(dāng)OllyDbg下一次加載該模塊時,它會自動恢復(fù)所有的調(diào)試信息,而不管是哪一個程序使用這個模塊。假設(shè)你正在調(diào)試程序Myprog1,這個程序使用了Mydll。你在 Mydll 中設(shè)置了一些斷點,然后你開始調(diào)試Myprog2,這個程序同樣使用了Mydll。這時你會發(fā)現(xiàn),所有 Mydll 中的斷點依然存在,即使 Mydll 加載到不同的位置!
一些調(diào)試器把被調(diào)試進程的內(nèi)存當(dāng)作一個單一的(并且大部分是空的)大小為2 ^32字節(jié)的區(qū)域。OllyDbg采用了與之不同的技術(shù):在這里,內(nèi)存由許多獨立的塊組成,任何對內(nèi)存內(nèi)容的操作都被限制在各自的塊內(nèi)。在大多數(shù)情況下,這種方式工作得很好并且方便了調(diào)試。但是,如果模塊包含好幾個可執(zhí)行段[executable ?sections],你將不能一次看到全部代碼,然而這種情況是非常少見的。
OllyDbg 是一個很占用內(nèi)存的程序[memory—hungry application]。它在啟動時就需要 3 MB,并且當(dāng)你第一次裝載被調(diào)試的程序時還需要一到兩兆的內(nèi)存。每一次的分析、備份、跟蹤或者文件數(shù)據(jù)顯示都需要占用一定的內(nèi)存。因此當(dāng)你調(diào)試一個很大的項目,發(fā)現(xiàn)程序管理器顯示有 40 或 60 兆內(nèi)存被占用時,請不要驚慌。
為了有效地調(diào)試一些不帶源碼的程序,你必須首先理解它是如何工作的。OllyDbg 包含的大量特性可以使這種理解變得非常容易。
首先,OllyDbg包含一個內(nèi)置的代碼分析器。分析器遍歷整個代碼,分出指令和數(shù)據(jù),識別出不同的數(shù)據(jù)類型和過程,分析出標(biāo)準(zhǔn)API函數(shù)(最常用的大約有1900個)的參數(shù)并且試著猜出未知函數(shù)的參數(shù)數(shù)目。你也可以加入自己的函數(shù)說明[yourown function descriptions]。它標(biāo)記出程序入口點和跳轉(zhuǎn)目的地,識別出跳轉(zhuǎn)表[table—drivenswitches]和指向字符串的指針,加入一些注釋,甚至標(biāo)示出跳轉(zhuǎn)的方向等等。在分析結(jié)果的基礎(chǔ)上,調(diào)用樹[call tree]顯示哪些函數(shù)被指定過程調(diào)用(直接或間接)并且識別出遞歸調(diào)用、系統(tǒng)調(diào)用和葉子過程[leaf procedures]。如果需要的話,你可以設(shè)置解碼提示[decoding hints]來幫助分析器解析那些不明確的代碼或數(shù)據(jù)。
OllyDbg還包含Object掃描器[Object Scanner]。如果你有庫文件[libraries]或目標(biāo)文件[object files],掃描器會在被調(diào)試的程序中定位這些庫函數(shù)。在全部函數(shù)調(diào)用中,對標(biāo)準(zhǔn)函數(shù)的調(diào)用占很重要的一部分(據(jù)我估計可達70%)。如果你知道正要被調(diào)用的函數(shù)的功能,你就不必把注意力集中在這個函數(shù)上,可以簡單地單步步過[step over]這個call。分析器知道400多個標(biāo)準(zhǔn)C函數(shù),比如fopen和memcpy。然而我必須承認(rèn)當(dāng)前版本的OllyDbg不能定位很短的函數(shù)(比一個return命令多不了多少的)或相似的函數(shù)(只在重定位上有不同)。Object掃描器[Object scanner]也能夠識別輸入庫[import libraries]。如果某個DLL是按序號輸出的,你不會看到函數(shù)名,只會發(fā)現(xiàn)一堆無意義的神秘數(shù)字。這種DLL的開發(fā)者通常會提供一個輸入庫來實現(xiàn)函數(shù)符號名與序號間的對應(yīng)。讓OllyDbg使用這個輸入庫,它就會恢復(fù)原始的函數(shù)符號名。
面向?qū)ο蟮恼Z言(如C++),使用了一種叫做名稱修飾[namemangling]的技術(shù),把函數(shù)類型和參數(shù)都加入函數(shù)名中。OllyDbg 可以解碼[demangle]這種函數(shù)名,使程序更易讀。譯者注:C++的名稱修飾是編譯器將函數(shù)的名稱轉(zhuǎn)變成為一個唯一的字符串的過程,這個字符串會對函數(shù)的類、其命名空間、其參數(shù)表,以及其他等等進行編碼。 C++的名稱修飾適用于靜態(tài)成員函數(shù),也適用于非靜態(tài)成員函數(shù)。靜態(tài)函數(shù)的名稱修飾的一個好處之一,是能夠在不同的類里使用同一個名稱來聲明兩個或者更多的靜態(tài)成員函數(shù)————而不會發(fā)生名稱上的沖突。
OllyDbg完全支持 UNICODE,幾乎所有對 ASCII 字符串的操作都可以同樣應(yīng)用于 UNICODE。
匯編指令都是很相似的。你經(jīng)常會搞不清自己是不是已經(jīng)跟蹤過某一段代碼。在OllyDbg中你可以加入自己的標(biāo)簽[labels]和注釋[comments]。這些極大地方便了調(diào)試。注意一旦你注釋了某個DLL,以后每次加載這個DLL時,注釋和標(biāo)簽都有效————盡管你在調(diào)試不同的程序。
OllyDbg可以跟蹤標(biāo)準(zhǔn)的棧幀[stack frames](由PUSH EBP; MOV EBP,ESP所創(chuàng)建的)。現(xiàn)代編譯器有禁止產(chǎn)生標(biāo)準(zhǔn)棧框架的選項,在這種情況下分配棧[stackwalk]是不可能的。當(dāng)程序運行到已知的函數(shù)時,棧窗口[stack window]解析它的參數(shù),調(diào)用棧[Call stack]窗口顯示到達當(dāng)前位置所調(diào)用函數(shù)的序列。
?
現(xiàn)代的面向?qū)ο髴?yīng)用程序廣泛地使用了一種叫做結(jié)構(gòu)化異常處理[Structured Exception Handling,SHE]的技術(shù)。SHE窗口[SEH window] 可以顯示異常處理鏈。
多種不同的搜索[search]選項可以讓你找到二進制代碼或數(shù)據(jù)、命令或命令序列、常量或字符串、符號名或在 Run跟蹤中的一條記錄。
對于任何地址或常量,OllyDbg 可以找出參考[referencing]到該地址或常量的全部命令的列表。然后你可以在這個列表里找出對你來說是重要的參考。舉例來說,某個函數(shù)可能被直接調(diào)用,或者經(jīng)過編譯器優(yōu)化后把地址放入寄存器間接調(diào)用,或者把地址壓入堆棧作為一個參數(shù)————沒問題,OllyDbg 會找出所有這樣的地方。它甚至能找到并列出所有和某個指定的位置有關(guān)的跳轉(zhuǎn)。
OllyDbg 支持所有標(biāo)準(zhǔn)類型的斷點[breakpoints]————非條件和條件斷點、內(nèi)存斷點(寫入或訪問)、硬件斷點或在整個內(nèi)存塊上下斷點(后兩項功能只在 Window ME,NT,2000,XP中有效)。條件表達式可以非常復(fù)雜(“當(dāng) [ESP+8] 的第 2 位被設(shè)置,并且 123456 位置處的字[word]小于10,或者 EAX 指向一個以“ABC”開頭的 UNICODE 字串,但跳過前10次斷點而在第11次中斷”)。你可以設(shè)定一條或多條指令,當(dāng)程序暫停時由OllyDbg傳遞給插件插件[plugins]。除了暫停,你還可以記錄某個表達式的值(可以帶有簡短的說明),或者記錄OllyDbg已知的函數(shù)的參數(shù)。在Athlon 2600+、Windows2000 環(huán)境下,OllyDbg 可以每秒處理多達 25000 個條件斷點。
另一個有用的特性是跟蹤。OllyDbg 支持兩種方式的跟蹤:hit和run。
在第一種情況下,它對指定范圍內(nèi)的每條指令上設(shè)置斷點(比如在全部可執(zhí)行代碼中)。當(dāng)?shù)竭_設(shè)斷的指令后,OllyDbg清除斷點并且把該指令標(biāo)記為hit。這種方法可以用來檢測某段代碼是否被執(zhí)行。Hit跟蹤速度驚人的快,在一個很短時間的啟動后程序幾乎達到了全速(譯者注:這應(yīng)該是與不進行調(diào)試時速度相比而言)。因為INT3斷點可能對數(shù)據(jù)有災(zāi)難性的影響,所以我建議不要使用模糊識別過程。當(dāng)代碼沒有被分析時Hit跟蹤是不可以使用的。
Run跟蹤[Run trace]是一步一步地執(zhí)行程序,同時記錄精確的運行歷史和所有寄存器的內(nèi)容、已知的參數(shù)和可選的指令(當(dāng)代碼是自修改時會有幫助)。當(dāng)然,這需要大量的內(nèi)存(每個指令需要15至50個字節(jié),取決于調(diào)試的模式)但是可以精確地回溯和分析。你可以只在選定的一段代碼甚至是一條指令中進行Run跟蹤,或者你可以跳過無關(guān)緊要的代碼。對于每個地址,OllyDbg能夠計算這個地址在Run跟蹤日志中出現(xiàn)的次數(shù),雖然會導(dǎo)致執(zhí)行緩慢但是可以得到代碼執(zhí)行的統(tǒng)計。比如說,某命令讓你在每個已識別的過程入口處進行Run跟蹤,那么統(tǒng)計[profile]就會給你每個過程被調(diào)用的次數(shù)。在到達某條指令、某個地址范圍或指令計數(shù)器達到某一數(shù)值時Run跟蹤可以自動地暫停[pause]。
在多線程程序里OllyDbg可以自動管理線程[threads],如果你單步調(diào)試或跟蹤程序,它會自動恢復(fù)當(dāng)前線程而掛起其它線程。如果你運行程序,OllyDbg 會恢復(fù)先前的線程狀態(tài)。
你可以為內(nèi)存塊建立快照(叫做備份)。OllyDbg會高亮顯示所有的改動。你可以把備份保存到文件或從文件中讀取出來,從而發(fā)現(xiàn)兩次運行的不同之處。你可以查看備份,搜索下一處改動,恢復(fù)全部或選定的改動。補丁管理器[Patch manager]記錄了上次應(yīng)用到程序中的所有補丁,在下次調(diào)試時可以再次應(yīng)用它們。你可以很容易地把你的補丁加在可執(zhí)行文件上。OllyDbg 會自動進行修正。
你不能在帶有 Win32 的16位 Windows 下使用 OllyDbg。這種32位擴展操作系統(tǒng)無法實現(xiàn)某些必需的調(diào)試功能。你既不能調(diào)試 DOS 程序也不能調(diào)試16位 NE(New Executable)格式文件,我也沒有打算在未來的版本中支持這些。
?
二、反匯編器[Disassembler]
反匯編器識別所有的標(biāo)準(zhǔn)80x86、保護、FPU、MMX和3DNow!指令集(包括Athlon擴展的MMX指令集)。但它不識別ISSI命令,盡管計劃要在下個版本中支持這種命令。某些過時或者未公開的命令,像LOADALL,也不支持。
反匯編器可以正確解碼16位地址。但它假設(shè)所有的段都是32位的(段屬性使用32位)。這對于PE[Portable Executable]格式文件總是正確的。OllyDbg不支持16位的NE[NewExecutables]格式。
如果你熟悉MASM或者TASM,那么反匯編的代碼對于你沒有任何問題。但是,一些特例也是存在的。以下命令的解碼與Intel的標(biāo)準(zhǔn)不同:
AAD (ASCII Adjust AX BeforeDivision)—該命令的解碼后的一般形式為:AAD imm8
AAM (ASCII Adjust AX AfterMultiply)—該命令(非十進制數(shù))的一般解碼形式為:AAM imm8
SLDT (Store Local DescriptorTable register)—操作數(shù)總被解碼為16位。這個命令的32位形式會在目的操作數(shù)的低16位中存儲段選擇器,并保留高16位不變。
SALC (Sign—extend Carry bit to AL,undocumented)—OllyDbg 支持這個未公開指令。
PINSRW (Insert Word FromInteger Register, Athlon extension to MMX)—在AMD的官方文檔中,這個命令的內(nèi)存形式使用了16位內(nèi)存操作數(shù);然而寄存器形式需要32位寄存器,但只使用了低16位。為了方便處理,反匯編器解碼寄存器為16位形式。而匯編器兩種形式都支持。
CVTPS2PI and CVTTPS2PI(Convert Packed Single—Precision Floating to Packed Doubleword, Convert with TruncationPacked Single—PrecisionFloating to Packed Doubleword)—在這些命令中,第一個操作數(shù)是MMX寄存器,第二個或者是128位XMM寄存器或者是64位內(nèi)存區(qū)域。為了方便處理,內(nèi)存操作數(shù)也被解碼為128位。
有些指令的助記符要依賴操作數(shù)的大小:
不分大小的形式 明確的16位形式?????? 明確的32位形式
PUSHA??????????????? PUSHAW??????????????????? PUSHAD
POPA??????????????????????????? POPAW??????????????????????? POPAD
LOOP??????????????????????????? LOOPW?????????????????????? LOOPD
LOOPE??????????????? LOOPWE???????????????????? LOOPDE
LOOPNE???????????? LOOPWNE????????????????? LOOPDNE
PUSHF ????????????? PUSHFW???????????????????? PUSHFD
POPF?????????????????? POPFW??????????????????????? POPFD
IRET???????????????????? IRETW???????????????????????? IRETD
你可以改變解碼大小敏感助記符[decoding of size—sensitive mnemonics]。根據(jù)選項,反匯編器從三種可能中選擇之一進行解碼。這個選項也會影響匯編器的默認(rèn)處理方式。解碼MMX和3DNow!指令總是開啟的,盡管你的處理器并不支持這些指令。
?
三、分析器[Analysis]
OllyDbg 整合了一個快速而強大的代碼分析器。你可以從快捷菜單,或者在CPU窗口的反匯編面板中按 Ctrl+A ,或者在可執(zhí)行模塊中選擇“分析全部模塊[Analyze all modules]”,來使用它。??
分析器有很高的啟發(fā)性。它能區(qū)分代碼和數(shù)據(jù),標(biāo)記入口和跳轉(zhuǎn)目的地址,識別轉(zhuǎn)換表[switch tables],ASCII 和 UNICODE 串,定位函數(shù)過程,循環(huán),高階轉(zhuǎn)換[high—level switches]并且能解碼標(biāo)準(zhǔn)API函數(shù)的參數(shù)(示例[example])。OllyDbg 的其他部分也廣泛的使用了分析后的數(shù)據(jù)。
這是如何實現(xiàn)的?我將為你揭開這一神秘面紗。第一遍,OllyDbg反匯編代碼段中所有可能的地址,并計算調(diào)用的每個目的地址的個數(shù)。當(dāng)然,很多調(diào)用是假的,但不可能兩個錯誤的調(diào)用都指向了相同的命令,當(dāng)然如果有三個的話,就更不可能了。因此如果有三個或者更多的調(diào)用指向了相同的地址,我可以肯定的說這個地址是某個頻繁使用的子程序的入口。從定位的入口出發(fā),我繼續(xù)跟蹤所有的跳轉(zhuǎn)和函數(shù)調(diào)用,等等。按這種方法,我可能準(zhǔn)確定位99.9% 的命令。但是,某些字節(jié)并不在這個鏈條上。我再用20多種高效的啟發(fā)方法(最簡單的方法,比如“直接訪問前64K內(nèi)存是不允許的,像在MOV [0],EAX中”)來探測他們。有時,分析器在你感興趣的地方分析錯誤。有兩種解決方法:或者從選中的部分移除分析(快捷鍵退格鍵),這樣OllyDbg將使用默認(rèn)的解碼(反匯編)方式;或者設(shè)置解碼提示[decoding hints]并重新分析。注意:在某些情況下,當(dāng)分析器認(rèn)為你的提示是不合適的,或者有沖突,則可能忽略你的設(shè)置。
探測程序的函數(shù)過程也很簡單。在分析器眼中看來,程序只是一個連綿不斷的代碼,從一個入口開始,可能達到(至少從理論上)所有的命令(除了NOP以及類似的用于填充間隙的命令)。你可能指定三個識別級別。嚴(yán)格的函數(shù)過程要求有準(zhǔn)確的一個入口,并且至少有一個返回。在啟發(fā)級別下,分析器只要求過程有一個入口。而如果你選擇模糊模式,差不多連貫的代碼都會被識別為單獨的過程。現(xiàn)代編譯器進行全局代碼優(yōu)化,有可能把一個過程分成幾個部份。在這種情況下,模糊模式非常有用。但是也會誤識別的機率也就更高。
同樣地,循環(huán)是一個封閉的連續(xù)的命令序列,并有一個到開始處的跳轉(zhuǎn)作為一個入口,還有若干個出口。循環(huán)與高級操作命令 do, while 和 for 相對應(yīng)。OllyDbg能夠識別任何復(fù)雜的嵌套循環(huán)。他們會在反匯編欄[Disassembly]中用長而粗括號標(biāo)記。如果入口不是循環(huán)的第一個命令,OllyDbg會用一個小三角進行標(biāo)記。
為了實現(xiàn)一個轉(zhuǎn)換[switch], 許多編譯器,讀取轉(zhuǎn)換變量[switch variable]到寄存器中,然后減它,像如下的代碼序列:
???? MOV EDX,<switchvariable>
???? SUB EDX,100
???? JB DEFAULTCASE
???? JE CASE100??????? ; Case 100
???? DEC EDX
???? JNE DEFAULTCASE
???? ...?????????????? ; Case 101
?
這個序列可能還包含一到兩階的轉(zhuǎn)換表、直接比較、優(yōu)化和其他元素。如果在比較或跳轉(zhuǎn)的很深處,這就很難知道哪是一個分支[Case]。OllyDbg 會幫助你,它會標(biāo)記所有的分支,包括默認(rèn)的,甚至嘗試分析每個分支的含義,如'A'、WM_PAINT 或者 EXCEPTION_ACCESS_VIOLATION。如果命令序列沒有修改寄存器(也就是僅僅由比較組成),那么這可能不是轉(zhuǎn)換,而很有可能是選擇嵌套:
???? if (i==0) {...}
???? else if (i==5) {...}
???? else if (i==10) {...}
如果需要OllyDbg將選擇嵌套解碼成選擇語句,請在分析1[Analysis1]中設(shè)置相關(guān)選項。
OllyDbg包含多達1900條常用API函數(shù),這些都作為內(nèi)部預(yù)處理資源。這個列表包含了KERNEL32, GDI32, USER32, ADVAPI32, COMDLG32, SHELL32, VERSION,SHLWAPI, COMCTL32, WINSOCK, WS2_32 和 MSVCRT。你可以添加自己的函數(shù)描述[add your own descriptions]。如果分析器遇到的調(diào)用,使用了已知的函數(shù)名(或者跳轉(zhuǎn)到這樣的函數(shù)),它將在調(diào)用之前立即解碼PUSH命令。因此,你只需略微一看就能明白函數(shù)調(diào)用的含義。OllyDbg還包含了大約400多種的標(biāo)準(zhǔn)C函數(shù)。如果你有原始的庫文件,我推薦你在分析前掃描目標(biāo)文件。這樣OllyDbg將能解碼這些C函數(shù)的參數(shù)。
如果選項“猜測未知函數(shù)的參數(shù)個數(shù)”開啟,分析器將會決定這個調(diào)用函數(shù)過程使用的長度為雙字的參數(shù)個數(shù)。并且標(biāo)記他們?yōu)閰?shù)1[Arg1],參數(shù)2[ Arg2],等等。注意:無論如何,寄存器參數(shù)是無法識別的,所以不會增加參數(shù)的數(shù)目。分析器使用了一種比較安全的方法。例如,它不能識別的沒有參數(shù)的函數(shù)過程,或者該過程POP命令直接做返回前的寄存器恢復(fù),而不銷毀參數(shù)。然而,識別出來的函數(shù)參數(shù)數(shù)目通常非常高,這大大加大了代碼的可讀性。
分析器能夠跟蹤整型寄存器的內(nèi)容。現(xiàn)代優(yōu)化編譯器,特別是奔騰系列,頻繁地使用寄存器讀取常量和地址,或使用盡量少的使用內(nèi)存。如果某個常量讀取到寄存器中,分析器會注意它,并嘗試解碼函數(shù)和其參數(shù)。分析器還能完成簡單的算術(shù)計算,甚至可以跟蹤壓棧和出棧。
分析器不能區(qū)分不同類的名稱[different kinds of names]。如果你將某些函數(shù)指定為已知的名稱,OllyDbg將會解碼所有到該地址的調(diào)用。這是幾個預(yù)定義的特殊名稱WinMain, DllEntryPoint and WinProc。你可能使用這些標(biāo)簽標(biāo)記主程序、DLL的的入口以及窗口過程(注意:OllyDbg不檢查用戶自定義的標(biāo)簽是否唯一)。另外,假定預(yù)定義參數(shù)assumepredefined arguments是一種更好的方法,不幸的是,沒有一般規(guī)則能夠做到100%的準(zhǔn)確分析。在某些情況下,例如當(dāng)模塊包含了P—Code或代碼段中包換了大量的數(shù)據(jù),分析器可能將一些數(shù)據(jù)解釋成代碼。如果統(tǒng)計分析顯示代碼部分很可能是壓縮包或者經(jīng)過加密了,分析器會發(fā)出警告。如果你想使用Hit跟蹤[Hit trace],我建議你不要使用模糊分析[fuzzy analysis],因為設(shè)置斷點的地方可能正是數(shù)據(jù)部分。
自解壓文件[Self—extractablefiles] 通常有一個自提取器,在“正式”代碼段之外。如果你選擇自解壓選項[SFX option]中的“擴展代碼段,包含提取器[Extend code section to include self—extractor]”,OllyDbg將會擴展代碼段,形式上允許分析它,并可以使用Hit跟蹤[Hit] trace和Run跟蹤[Run trace]。
?
四、Object掃描器[Objectscanner]
?
掃描器將特定的目標(biāo)文件或者目標(biāo)庫(包括OMF和COFF兩種格式),提取出代碼段,然后將這些段定位在當(dāng)前模塊的代碼節(jié)[Codesection]中.如果段定位好了,掃描器將從目標(biāo)文件中的調(diào)試信息提取名稱(也就是所謂的庫標(biāo)簽[librarylabels])。這極大的增加了代碼與數(shù)據(jù)的可讀性。掃描器并不會對已識別的目標(biāo)文件進行標(biāo)簽匹配,所以它不能識別非常小或相似的函數(shù)(比如:兩個函數(shù)只是在重定位有區(qū)別)。因此要經(jīng)常檢查掃描器發(fā)送到登陸窗口的警告列表!
?
五、Implib掃描器 [Implibscanner]
?
某些DLL的輸出符號僅僅是一個序號。許多符號都是井號加數(shù)字(比如:MFC42.#1003),這非常不便于理解。幸運的是,軟件零售商提供了輸入連接庫(implibs),它與序號符號名相關(guān)。
使用implib掃描器的方法:從主菜單中選擇調(diào)試[Debug]—>選擇輸入鏈接庫[Select importlibraries]。當(dāng)你加載應(yīng)用程序時,OllyDbg會讀取鏈接庫并從內(nèi)置表格[internal tables]中提取符號名。每次遇到序號符號,而對應(yīng)的鏈接庫已經(jīng)注冊到OllyDbg中時,這個序號符號會被替換。
?
第三章 OllyDbg的使用
一、如何開始調(diào)試[How to start debugging session]
最簡單的方法是:運行 OllyDbg,點擊菜單上的文件[File]—>打開[Open],選擇你想調(diào)試的程序。如果程序需要命令行參數(shù),你可以在對話框底部的輸入欄中,輸入?yún)?shù)或者選擇以前調(diào)試時輸入過的一條參數(shù)。
OllyDbg 能夠調(diào)試獨立的DLL[stand—alone DLLs]。在這種情況下,OllyDbg 會創(chuàng)建并運行一個小的應(yīng)用程序來加載鏈接庫并根據(jù)你的需要調(diào)用輸出函數(shù)。
如果你想重新啟動上一次調(diào)試的程序,只要按一下 Ctrl+F2(這是重啟程序的快捷鍵)(???),這樣OllyDbg會以同樣的參數(shù)運行這個程序。另一種做法是在菜單中選擇文件[File],從歷史列表中選擇程序。你也可以在 Windows 資源管理器中將可執(zhí)行文件或 DLL 文件拖拽到OllyDbg中。
當(dāng)然,你可以在OllyDbg啟動時,運行指定帶有運行參數(shù)的被調(diào)試程序。例如:你可以在桌面創(chuàng)建一個OllyDbg的快捷方式,右擊并選擇“屬性”,在“快捷方式”中的“目標(biāo)”中添加調(diào)試的程序的全路徑。這樣,你每次雙擊快捷方式時,OllyDbg 將自動運行被調(diào)試程序。注意:DLL文件不支持這種方式。
你可以把正在運行的進程掛接到OllyDbg中。在菜單中打開文件[File]—>掛接[Attach],從進程列表中選擇要掛接的進程。注意:在你關(guān)閉OllyDbg的同時,這個進程也會被關(guān)閉。不要掛接系統(tǒng)進程,否則可能會導(dǎo)致整個操作系統(tǒng)的崩潰。(事實上在大多數(shù)情況下,操作系統(tǒng)禁止你掛接敏感進程)。
OllyDbg 可以作為即時[just—in—time]調(diào)試器。這需要在系統(tǒng)注冊表中注冊。在菜單中選擇選項[Options]—>即時調(diào)試[Just—in—time debugging] 并在彈出的對話框中單擊按鈕“設(shè)置OllyDbg為即時調(diào)試器”[MakeOllyDbgjust—in—time debugger]。今后,如果某個應(yīng)用程序發(fā)生了非法操作,系統(tǒng)將提示你是否用OllyDbg 調(diào)試這個程序。操作系統(tǒng)會啟動OllyDbg并直接停在發(fā)生異常的地方。如果你選擇了“掛接時不詢問”[attaching without confirmation],則在即時調(diào)試時OllyDbg不會彈出詢問對話框。如果想恢復(fù)成以前的即時調(diào)試器[Restore oldjust—in—time debuger],按相應(yīng)的按鈕即可。
另一種方法是把OllyDbg添加到與可執(zhí)行文件關(guān)聯(lián)的快捷菜單中(這個想法是 Jochen Gerster 提出的)。在主菜單中,選擇選項[Options]—>添加到資源管理器中[Addto Explorer]。以后你可以在所有的文件列表中,右擊可執(zhí)行文件或DLL,在快捷菜單中選擇OllyDbg。這個功能會創(chuàng)建四個注冊表鍵值:
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\exefile\shell\Open with OllyDbg\command
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg
HKEY_CLASSES_ROOT\dllfile\shell\Open with OllyDbg\command
OllyDbg能夠調(diào)試控制臺程序(基于文字的)。
OllyDbg不能調(diào)試.NET應(yīng)用程序。.NET程序是由微軟的中間語言這種偽指令組成的,或是on—the—fly to native ?6 commands編譯的。
注意:如果你運行的是Windows NT、2000 或XP操作系統(tǒng),你應(yīng)該擁有管理員權(quán)限以便能夠調(diào)試程序。。
?
二、CPU 窗口[CPUwindow]
對于用戶來說,CPU窗口在OllyDbg中是最重要的窗口。你調(diào)試自己程序的絕大部分操作都要在這個窗口中進行。它包括以下五個面板(這五個面板的大小都是可以調(diào)節(jié)的):
l? 反匯編[Disassembler]
l? 信息[Information]
l? 數(shù)據(jù)[Dump]
l? 寄存器[Registers]
l? 棧[Stack]
按TAB鍵,可以切換到下一個CPU面板中(順時針方向)。
按Shift+TAB,可以切換到前一個CPU面板(逆時針方向)。
?
三、斷點[Breakpoints]
OllyDbg支持?jǐn)?shù)種不同類型的斷點:
一般斷點[Ordinary breakpoint], 將你想中斷的命令的第一個字節(jié),用一個特殊命令I(lǐng)NT3(調(diào)試器陷阱)來替代。你可以在反匯編窗口中選中要設(shè)斷點的指令行并按下 F2鍵就可以設(shè)定一個此類型的斷點。也可以在快捷菜單中設(shè)置。再次按下F2 鍵時,斷點將被刪除。注意,程序?qū)⒃谠O(shè)斷指令被執(zhí)行之前中斷下來。INT3斷點的設(shè)置數(shù)量是沒有限制的。當(dāng)你關(guān)閉被調(diào)試程序或者調(diào)試器的時候,OllyDbg將自動把這些斷點保存到硬盤中,永遠不要試圖在數(shù)據(jù)段或者指令的中間設(shè)置這種斷點,如果你試圖在代碼段以外設(shè)置斷點,OllyDbg將會警告。你可以在安全選項[Security options]中永遠關(guān)閉這個提示,在某些情況下調(diào)試器會插入自帶的臨時INT3斷點。
條件斷點[Conditional breakpoint](快捷鍵 Shift+F2)是一個帶有條件表達式的普通INT3斷點。當(dāng)調(diào)試器遇到這類斷點時,它將計算表達式的值,如果結(jié)果非零或者表達式無效,將暫停被調(diào)試程序,當(dāng)然,由條件為假的斷點引起的開銷是非常高的(主要歸因于操作系統(tǒng)的反應(yīng)時間)。在Windows NT、奔騰Ⅱ/450處理器環(huán)境下OllyDbg每秒最多處理2500個條件為假的斷點。條件斷點的一個典型使用情況就是在Windows消息上設(shè)置斷點(比如 WM_PAINT)。為此,你可以將偽變量 MSG 同適當(dāng)?shù)膮?shù)說明聯(lián)合使用。如果窗口被激活,參考一下后面的消息斷點描述。
條件記錄斷點Conditional logging breakpoint](Shift+F4)是一種條件斷點,每當(dāng)遇到此類斷點或者滿足條件時,它將記錄已知函數(shù)表達式或參數(shù)的值。例如,你可以在一些窗口過程函數(shù)上設(shè)置記錄斷點并列出對該函數(shù)的所有調(diào)用。或者只對接收到的WM_COMMAND消息標(biāo)識符設(shè)斷,或者對創(chuàng)建文件的函數(shù)(CreateFile)設(shè)斷,并且記錄以只讀方式打開的文件名等,記錄斷點和條件斷點速度相當(dāng),并且從記錄窗口中瀏覽上百條消息要比按上百次F9輕松的多,你可以為表達式選擇一個預(yù)先定義好的解釋說明。你可以設(shè)置通過的次數(shù)—每次符合暫停條件時,計數(shù)器就會減一。如果通過計數(shù)在減一前,不等于零,OllyDbg就會繼續(xù)執(zhí)行。如果一個循環(huán)執(zhí)行100次(十進制),在循環(huán)體內(nèi)設(shè)置一個斷點,并設(shè)置通過次數(shù)為99(十進制)。OllyDbg將會在最后一次執(zhí)行循環(huán)體時暫停。
另外,條件記錄斷點允許你傳遞一個或多個命令給插件[plugins]。例如,你需要使用命令行插件改變一個寄存器的內(nèi)容,然后繼續(xù)執(zhí)行程序。
消息斷點[Message breakpoint]和條件記錄斷點基本相同,除了OllyDbg會自動產(chǎn)生一個條件,這個條件允許在窗口過程的入口處設(shè)置某些消息(比如WM_PSINT)斷點,你可以在窗口[Windows]中設(shè)置它。
跟蹤斷點[Trace breakpoint] 是在每個選中命令上設(shè)置的一種特殊的INT3斷點。如果你設(shè)置了Hit跟蹤[hit trace],斷點會在命令執(zhí)行后移除,并在該地址處做一個標(biāo)記。如果你使用的是Run跟蹤[run trace],OllyDbg會添加跟蹤數(shù)據(jù)記錄并且斷點仍然是保持激活狀態(tài)。
內(nèi)存斷點[Memory breakpoint]OllyDbg每一時刻只允許有一個內(nèi)存斷點。你可以在反匯編窗口、CPU窗口、數(shù)據(jù)窗口中選擇一部分內(nèi)存,然后使用快捷菜單設(shè)置內(nèi)存斷點。如果有以前的內(nèi)存斷點,將被自動刪除。你有兩個選擇:在內(nèi)存訪問(讀,寫,執(zhí)行)時中斷,或內(nèi)存寫入時中斷。設(shè)置此類斷點時,OllyDbg將會改變所選部分的內(nèi)存塊的屬性。在與80x86兼容的處理器上將會有4096字節(jié)的內(nèi)存被分配并保護起來。即使你僅僅選擇了一個字節(jié),OllyDbg 也會將整個內(nèi)存塊都保護起來。這將會引起大量的錯誤警告,請小心使用此類斷點。某些系統(tǒng)函數(shù)(特別是在Windows95/98下)在訪問受保護的內(nèi)存時不但不會產(chǎn)生調(diào)試事件反而會造成被調(diào)試程序的崩潰。
硬斷點[Hardware breakpoint](僅在Windows ME,NT或2000下可用)在80x86兼容的處理器上,允許你設(shè)置4個硬件斷點。和內(nèi)存斷點不同,硬件斷點并不會降低執(zhí)行速度,但是最多只能覆蓋四個字節(jié)。在單步執(zhí)行或者跟蹤代碼時,OllyDbg能夠使用硬斷點代替INT3斷點。
內(nèi)存訪問一次性斷點[Single—shot break on memory access](僅在Windows NT或2000下可用)。你可以通過內(nèi)存窗口的快捷菜單(或按F2),對整個內(nèi)存塊設(shè)置該類斷點。當(dāng)你想捕捉調(diào)用或返回到某個模塊時,該類斷點就顯得特別有用。中斷發(fā)生以后,斷點將被刪除。
暫停Run跟蹤[Run trace pause] (快捷鍵:Ctrl+T)是在每一步Run跟蹤[run trace]時都要檢查的一個條件集。你可以在EIP進入某個范圍或超出某個范圍時暫停,某個條件為真時暫停,或者命令與指定的模式匹配時暫停,或者當(dāng)命令可疑的時候暫停。注意,這一選擇會極大的(高達20%)降低Run跟蹤的速度。OllyDbg也可以在一些調(diào)試事件[debugging events]上暫停程序執(zhí)行。比如加載或卸載DLL,啟動或終止線程,或者程序發(fā)出調(diào)試字符串的時候。
?
四、數(shù)據(jù)窗口[Dump]
數(shù)據(jù)窗口用于顯示內(nèi)存或文件的內(nèi)容。你可以從以下預(yù)處理格式[predefined formats]中選擇一種顯示方式:字節(jié)[byte]、文本[text]、整數(shù)[integer]、浮點數(shù)[float]、地址[address],反匯編[disassembly]、 PE頭[PE Header]。
所有的dump窗口支持備份[backup]、搜索和編輯操作。CPU 窗口[CPU window]的Dump面板允許你對可執(zhí)行代碼的數(shù)據(jù)和可執(zhí)行文件(.exe,或.dll)的內(nèi)存映射做如下操作:定義標(biāo)簽[labels]、設(shè)置內(nèi)存斷點[memory breakpoints], 查找參考[references]。數(shù)據(jù)菜單[Dump menu]只顯示與選中部分相關(guān)的命令。
如果 備份[backup]可用,則單擊第一個列標(biāo)題欄,會在地址[Address]/備份[Backup] 兩種顯示模式之間切換。點擊其他列標(biāo)題欄,會改變Dump模式。
像反匯編窗口一樣,數(shù)據(jù)窗口也保存了大量查看內(nèi)存地址的歷史記錄。你可以通過“+”和“—”鍵來訪問過去查看過的數(shù)據(jù)地址空間。要翻動一字節(jié)的數(shù)據(jù),可以按住Ctrl+↓或Ctrl+↑。
?
五、可執(zhí)行模塊窗口[Executable modules window]
可執(zhí)行模塊窗口(快捷鍵:Alt+E)列出了當(dāng)前被調(diào)試進程加載的所有可執(zhí)行模塊。它也顯示了很多有用的信息,比如模塊大小、入口地址、模塊版本、以及可執(zhí)行文件路徑等。一些信息,如以十進制顯示的模塊大小、入口地址的符號名、是否為系統(tǒng)模塊等,通常是被隱藏的。如果想看,可以增加相應(yīng)欄的寬度。快捷菜單支持以下操作:
刷新[Actualize]—重新掃描模塊并去除對新加載模塊的高亮顯示。在大多數(shù)情況下,OllyDbg會自動完成該操作。
查看內(nèi)存[View memory]—打開內(nèi)存窗口,并定位到屬于該模塊鏡像的第一個內(nèi)存塊處。
在CPU窗口中查看代碼[Viewcode in CPU](快捷鍵:回車鍵)—在反匯編窗口中顯示模塊的可執(zhí)行代碼。
跟進到入口[Follow entry]—在反匯編窗口中跟進到模塊的入口處。
在CPU窗口中查看數(shù)據(jù)[Dumpdata in CPU]—在CPU窗口的數(shù)據(jù)面板中顯示模塊的數(shù)據(jù)段。塊代碼段。
顯示名稱[View names](快捷鍵:Ctrl+N)—顯示當(dāng)前模塊定義或使用的全部名稱[names](包括輸出表、引入表、鏈接庫、用戶自定義)。
標(biāo)記為系統(tǒng)DLL[Mark assystem DLL],標(biāo)記為非系統(tǒng)DLL[Mark as non—system DLL]—將選中模塊標(biāo)記為系統(tǒng)或非系統(tǒng)屬性。如果設(shè)置為系統(tǒng)屬性,則在Run跟蹤[Run trace]時會直接執(zhí)行(不進行跟蹤)這個模塊,從而大大加快跟蹤速度。默認(rèn)情況下,所有駐留在系統(tǒng)目錄(通常在Windows 95/98下為c:\windows\system,在WinNT/2000/XP下為c:\winnt\system32)的模塊都認(rèn)為是系統(tǒng)模塊。
立即更新.udd文件[Update .uddfile now]—向文件“<模塊名>.udd”寫入模塊相關(guān)的全部數(shù)據(jù),udd文件保存了在調(diào)試期間設(shè)置的斷點、標(biāo)簽、注釋、監(jiān)視、分析等信息。當(dāng)模塊卸載時OllyDbg會自動創(chuàng)建.udd文件。
查看可執(zhí)行文件[View executable file]—顯示可執(zhí)行文件的全部內(nèi)容。
查看全部資源[View all resources]—以列表形式顯示模塊定義的全部資源,并帶有一個簡短信息。OllyDbg并不把資源當(dāng)作單獨實體來支持。你可以提取[Dump]并以二進制的形式進行編輯。
查看資源字符串[View resource strings]—以列表形式顯示資源字符串及其標(biāo)識符。
查看Run跟蹤的統(tǒng)計[View runtrace profile]—在此模塊中計算統(tǒng)計[profile]。
分析全部模塊[Analyze all modules]—允許同時分析全部模塊。分析將從代碼中提取大量的有用信息;代碼經(jīng)過分析后再進行調(diào)試,通常會非常快并且可靠。
鼠標(biāo)雙擊某一行,將會在反匯編窗口中顯示模塊的執(zhí)行代碼。
?
六、內(nèi)存映射窗口[Memory map window]
內(nèi)存映射窗口顯示了被調(diào)試程序分配的所有內(nèi)存塊。因為沒有標(biāo)準(zhǔn)的方法來完成這項任務(wù),所以 OllyDbg可能會把一個大的內(nèi)存塊分成幾個部分。然而,在大多數(shù)情況下,并非一定要精確處理。如果想查看由應(yīng)用程序通過調(diào)用GlobalAlloc ()和LocalAlloc()等申請的內(nèi)存塊列表,請使用堆列表[Heap list]。
如果內(nèi)存塊是可執(zhí)行模塊的一個節(jié),OllyDbg則會報告這個內(nèi)存塊所包含的數(shù)據(jù)類型:代碼、數(shù)據(jù)、資源等。
Windows95/98是和WindowsNT/2000是有一些區(qū)別的。在Windows95/98下,OllyDbg是不能顯示被映射文件的名稱的。另外,Windows95/98不允許的訪存類型為讀和寫,然而,在WindowsNT/2000下,OllyDbg卻有擁有更多功能,包括執(zhí)行訪問,寫復(fù)制[copy—on—write]以及監(jiān)視標(biāo)志位。OllyDbg忽略寫復(fù)制[copy—on—write]屬性。
如果OllyDbg發(fā)現(xiàn)程序分配了新內(nèi)存或者重新分配了已經(jīng)存在的內(nèi)存塊,它將在內(nèi)存映射窗口中高亮顯示相應(yīng)的記錄,去掉高亮度顯示,可以選擇快捷菜單中的刷新[Actualize]項。你可以按Alt+M來調(diào)用內(nèi)存窗口。
以下是快捷菜單中可以選擇的菜單項:
刷新[Actualize]—更新已分配內(nèi)存的列表并去除對新內(nèi)存塊的高亮顯示。
在反匯編窗口中查看[View in Disassembler]—在反匯編窗口中查看:在反匯編窗口中打開內(nèi)存塊,這一選項僅在某些模塊的內(nèi)存塊中包含可執(zhí)行代碼或者自解壓器時可用。
在CPU數(shù)據(jù)窗口中查看[Dumpin CPU]—在CPU的數(shù)據(jù)窗口中顯示內(nèi)存塊的內(nèi)容。
?
數(shù)據(jù)窗口[Dump]—在單獨窗口中顯示內(nèi)存塊內(nèi)容。如果內(nèi)存塊的類型已知,則OllyDbg會自動選擇顯示格式。
查看全部資源[View all resources]—如果內(nèi)存塊包含資源數(shù)據(jù),則列出所有資源及相關(guān)數(shù)據(jù)。OllyDbg并不把資源當(dāng)作單獨實體來支持。你可以顯示其數(shù)據(jù)并以二進制的形式進行編輯。
查看資源字符串[View resource strings]—如果內(nèi)存塊包含資源數(shù)據(jù),則列出全部資源字符串及其標(biāo)識符。
搜索[Search]—允許搜索所有的內(nèi)存塊,從選擇處開始,搜索匹配的二進制串。如果找到,則OllyDbg將顯示該內(nèi)存塊。內(nèi)存映像窗口和數(shù)據(jù)窗口共享同一種搜索模式,所以你可以在彈出的數(shù)據(jù)窗口中立即繼續(xù)搜索該二進制串出現(xiàn)的下一位置。按Esc鍵可以關(guān)閉數(shù)據(jù)窗口。
搜索下一個[Search next](快捷鍵:Ctrl+L)—繼續(xù)上次搜索。
設(shè)置訪問中斷[Set break—on—access](快捷鍵:F2,僅在WindowsNT/2000下可用)—保護整個內(nèi)存塊。當(dāng)中斷發(fā)生后OllyDbg暫停被調(diào)試程序并清除斷點。這類斷點在你想捕捉調(diào)用或返回到某個模塊的時候特別有用。
清除訪問中斷[Remove break—on—access](快捷鍵:F2)—從內(nèi)存塊中清除訪問中斷保護。
設(shè)置內(nèi)存訪問斷點[Set memory breakpoint on access]—在整個內(nèi)存塊上設(shè)置斷點,每當(dāng)該內(nèi)存塊被訪問時程序都將中斷。OllyDbg只支持一個內(nèi)存訪問斷點。在Windows95/98下,當(dāng)系統(tǒng)程序訪問含有內(nèi)存斷點的內(nèi)存塊時,可能會導(dǎo)致所被調(diào)試程序崩潰,因此,不到萬不得已,請不要設(shè)置這種斷點。
設(shè)置內(nèi)存寫入斷點[Set memory breakpoint on write]—在整個內(nèi)存塊上設(shè)置斷點,每當(dāng)該內(nèi)存塊被寫入數(shù)據(jù)時程序都將中斷。在Windows95/98下,當(dāng)系統(tǒng)程序訪問含有內(nèi)存斷點的內(nèi)存塊時,可能會導(dǎo)致所被調(diào)試程序崩潰,因此,不到萬不得已,請不要設(shè)置這種斷點。
清除內(nèi)存斷點[Remove memory breakpoint]—清除內(nèi)存斷點。
清除自解壓內(nèi)存斷點[Remove SFX memory breakpoint]—停止搜索自解壓程序[self—extractable(SFX) program]的真實入口。這個搜索使用了特殊類型的內(nèi)存斷點。
訪問設(shè)置[Set access]—設(shè)置整個內(nèi)存塊的保護屬性,可選擇的有:
禁止訪問[No access]
只讀[Read only]
讀/寫[Read/write]
執(zhí)行[Execute]
執(zhí)行/讀[Execute/read]
完全訪問[Full access]
復(fù)制到剪切板[Copy to clipboard]
?
?
整行[Whole line]—以多行文本(包括解釋)的方式把所選記錄復(fù)制到剪切板,如果復(fù)制時想排除某些列,可將該列的寬度置為最小(該欄剩余的邊框?qū)⒆兓?#xff09;。
整個表格[Whole table]—以多行文本的方式將整個內(nèi)存映像信息復(fù)制到剪切板,該文本的第一行為窗口標(biāo)題("內(nèi)存映射[Memorymap]"),第二行為列標(biāo)題欄,后面幾行的內(nèi)容為內(nèi)存數(shù)據(jù)記錄。復(fù)制將保持列的寬度。如果復(fù)制時想排除某些列,可將該列的寬度置為最小(該欄剩余的邊框?qū)⒆兓?#xff09;。
?
七、監(jiān)視與監(jiān)察器[Watches and inspectors]
監(jiān)視[Watch]窗口包含若干個表達式[expressions]。它在第二列里顯示這些表達式的值。OllyDbg 會把這些表達式保存到主模塊的.UDD文件中,因此它們在下一次調(diào)試時同樣有效。
監(jiān)察器[inspector]是顯示若干變量、1/2維數(shù)組或是選定項目結(jié)構(gòu)數(shù)組[selecteditems of array of structures]的獨立窗口。它的表達式與監(jiān)視窗口中的基本相同,只是多包含了兩個參數(shù):%A和%B。你可以指定這兩個參數(shù)的界限,OllyDbg 將會用所有可能的組合代替表達式中的%A和%B。從0開始一直到界限(不包含界限),并在表格中顯示結(jié)果。參數(shù)%B(列數(shù))的界限不能超過16。
例如,如果你指定了表達式%A+%B,并且限定%A和%B的上限為3,你將獲得如下的表格:
?
八、線程[Threads]
OllyDbg 以簡單而有效的線程管理為特色。如果你單步調(diào)試、跟蹤、執(zhí)行到返回或者執(zhí)行到所選,則線程管理器將停止除當(dāng)前線程以外的所有線程。即使當(dāng)前線程被掛起,它也會將其恢復(fù)。在這種情況下,如果你手動掛起或者恢復(fù)線程,動作將被延期。如果你運行被調(diào)試的應(yīng)用程序,OllyDbg將恢復(fù)最初的線程狀態(tài)。(從調(diào)試器的角度來看,Hit跟蹤[hit trace]和自由運行是等效的)。
依據(jù)這種方案,線程窗口可能會有如下五種線程狀態(tài):
激活[Active]??????????? 線程運行中,或被調(diào)試信息暫停t
掛起[Suspended]????? 線程被掛起
跟蹤[Traced] ????????? 線程被掛起,但OllyDbg正在單步跟蹤此線程
暫停[Paused]???????? 線程是活動的,但OllyDbg臨時將其掛起,并在跟蹤其它的線程
結(jié)束[Finished]???????? 線程結(jié)束
線程窗口同時也顯示了最后的線程錯誤(GetlastError函數(shù)的返回值)并計算該線程以用戶模式和系統(tǒng)模式(僅NT/2000/XP)運行的時間。線程窗口還會高亮主線程的標(biāo)識符。
以下在快捷菜單中可用:
刷新[Actualize]—標(biāo)記所有線程為舊的。
掛起[Suspend]—掛起線程。
恢復(fù)[Resume]—恢復(fù)先前掛起的線程。
設(shè)置優(yōu)先級[Set priority]—調(diào)整進程中線程的優(yōu)先級。以下選項可用:
空閑[Idle]????????????????????????? —進程中線程的最低優(yōu)先級
最低[Lowest]??????
低[Low]??????
標(biāo)準(zhǔn)[Normal]??????
高[High]??????
最高[Highest]??????
時間臨界[Time critical]???? —最高優(yōu)先級
在CPU窗口打開[Open inCPU](雙擊)—在CPU窗口中顯示所選線程的當(dāng)前狀態(tài)。
復(fù)制到剪切板[Copy to clipboard]:
整行[Whole line]—全部行——以多行文本的形式并帶注釋將所選記錄復(fù)制到剪切板。如果在復(fù)制時想排除某個欄目,可以將該欄的寬度置為最小(欄目的殘留部分將變灰)。
整個表格[Whole table]—整個表格——以多行文本的形式將整個內(nèi)存映象復(fù)制到剪切板,該文本的第一行包含窗口標(biāo)題(“內(nèi)存映射[Memorymap]”),第二行是欄目標(biāo)題,所有后繼行是內(nèi)存數(shù)據(jù)記錄。復(fù)制將保持欄目的寬度。如果在復(fù)制時想排除某些欄目,可以將該欄的寬度置為最小(欄目的殘留部分將變灰)。
?
九、調(diào)用棧[Call stack]
調(diào)用棧窗口(快捷鍵:Alt+K)根據(jù)選定線程的棧,嘗試反向跟蹤函數(shù)調(diào)用順序并將其顯示出來,同時包含被調(diào)用函數(shù)的已知的或隱含的參數(shù)。如果調(diào)用函數(shù)創(chuàng)建了標(biāo)準(zhǔn)的堆棧框架(PUSH EBP; MOV EBP,ESP),則這個任務(wù)非常容易完成。現(xiàn)代的優(yōu)化編譯器并不會為棧框架而操心,所以O(shè)llyDbg另辟蹊徑,采用了一個變通的辦法。例如,跟蹤代碼到下一個返回處,并計算其中全部的入棧、出棧,及 ESP 的修改。如果不成功,則嘗試另外一種辦法,這個辦法風(fēng)險更大,速度也更慢:移動棧,搜索所有可能的返回地址,并檢查這個地址是否被先前的已分析的命令調(diào)用。如果還不行,則會采用啟發(fā)式搜索。棧移動[Stack Walk]可能會非常慢。OllyDbg 僅在調(diào)用棧窗口打開時才會使用。
調(diào)用棧窗口包含5個欄目:地址[Address]、棧[Stack]、過程[Procedure],調(diào)用來自[Called from],框架[Frame]。
地址[Adress]欄包含棧地址,棧[Stack]欄顯示了相應(yīng)的返回地址或參數(shù)值。
函數(shù)[Procedure](或 函數(shù)/參數(shù)[Procedure / arguments])顯示了被調(diào)用函數(shù)的地址,在某些情況下,OllyDbg并不能保證該地址是正確的并會添加如下標(biāo)記之一:
??????? ??????????????????????????? 找到的入口點不可靠
可能[Maybe]??????? OllyDbg無法找到精確的入口點,報告的地址是用啟發(fā)式算法猜測的。
包含[Includes]?????? OllyDbg無法找到入口點,僅知道該函數(shù)包含顯示的地址
通過按例標(biāo)題欄上的按鈕或從菜單中選擇“隱藏/顯示參數(shù)[Hide/Show arguments]”,可以在顯示或隱藏函數(shù)的參數(shù)之間切換。
調(diào)用來自[Called from]用于顯示調(diào)用該函數(shù)的命令地址。
最后一欄是框架[Frame]這一欄默認(rèn)是隱藏的,如果框架指針的值(寄存器EBP)已知的話,則該欄用于顯示這個值。
當(dāng)調(diào)用函數(shù)經(jīng)過分析[analyzed].后,棧移動會更可靠并且迅速。
?
十、調(diào)用樹[Call tree]
調(diào)用樹(快捷鍵:在反匯編窗口中Ctrl+K)利用分析[Analysis]的結(jié)果來找出指定函數(shù)過程直接或間接調(diào)用的函數(shù)列表,同時列出指定函數(shù)過程被調(diào)用的地址。為了避免由此可能造成的副作用。調(diào)用樹會判斷選定函數(shù)是否明確地是遞歸的。 “明確地”意味著它不會跟蹤目標(biāo)未知的調(diào)用,比如CALL EAX。如果函數(shù)過程中有未知調(diào)用,調(diào)用樹將會添加標(biāo)記“未知目標(biāo)”。
某些函數(shù)調(diào)用將會添加如下注釋之一:
葉子[Leaf]???? ????? 不調(diào)用其他函數(shù)
純函數(shù)[Pure]??? ??? 不調(diào)用函數(shù),不會產(chǎn)生副作用
單返回[RETN]? ???? 只有一個RETN 命令
系統(tǒng)[Sys]???? ????????????? 系統(tǒng)動態(tài)鏈接庫中的函數(shù)。系統(tǒng)動態(tài)鏈接庫定義為保存在系統(tǒng)目錄下的動態(tài)鏈接庫。
如果想在調(diào)用樹上移動,可以雙擊“被調(diào)用[Calledfrom]”或“調(diào)用/直接調(diào)用[Calls/Callsdirectly]”兩欄中的地址。調(diào)用樹窗口保存了移動記錄(快捷鍵“—”和“+”)。
如果被調(diào)試的程序包含幾個模塊,推薦你分析所有模塊。Call tree 不會試圖處理系統(tǒng)函數(shù)。
?
十一、選項[Options]
外觀選項[Appearance options]
常規(guī)[General]
默認(rèn)[Defaults]
對話框[Dialogs]
目錄[Directories]
字體[Fonts]
顏色[Colours]
代碼高亮[Code highlighting]
調(diào)試選項[Debugging options] (Alt+O)
安全[Security]
調(diào)試[Debug]
事件[Events]
異常[Exceptions]
跟蹤[Trace]
自解壓[SFX]
字符串[Strings]
地址[Addresses]
命令[Commands]
反匯編[Disasm]
CPU
寄存器[Registers]
棧[Stack]
分析1[Analysis 1]
分析2[Analysis 2]
分析3[Analysis 3]
即時調(diào)試[Just—in—time debugging]
添加到資源管理器[Add to Explorer]
?
十二、搜索[Search]
OllyDbg 允許你使用以下的搜索方式:
符號名(標(biāo)簽)[Symbolic name (label)]
二進制串[binary string]
常量[constant]
命令[command]
命令序列[sequence of commands]
模塊間調(diào)用[intermodular calls]
修改過的命令或數(shù)據(jù)[modified command or data]
自定義標(biāo)簽[user—defined label]
自定義注釋[user—defined comment
文本字符串[text string]
Run跟蹤的記錄[recordin run trace]
參考命令[referencing commands]
?
十三、自解壓文件[Self—extracting(SFX) files]
自解壓文件由提取程序和壓縮的原程序兩部分組成。當(dāng)遇到自解壓文件(SFX)文件時,我們通常希望跳過解壓部分,而直接跳到原始程序的入口(真正的入口)。
OllyDbg 包含了幾個便于完成這一任務(wù)的功能。
通常提取程序的加載地址都在執(zhí)行代碼之外。在這種情況下,OllyDbg 將這類文件均視作為自解壓文件(SFX)。
當(dāng)自解壓選項[SFX options]要求跟蹤真正入口時,OllyDbg 在整個代碼節(jié)[Code section]設(shè)置內(nèi)存斷點,最初這里是空的,或者只包含壓縮數(shù)據(jù)。當(dāng)程序試圖執(zhí)行某個在這個保護區(qū)域的命令,而這些命令不是RET和JMP時,OllyDbg 會報告真正的入口。這就是提取工作的原理。
上面的方法非常慢。有另外一種比較快的方法。每次讀取數(shù)據(jù)發(fā)生異常時,OllyDbg 使這個4K內(nèi)存區(qū)域變?yōu)榭勺x,而使原先可讀的區(qū)域變?yōu)闊o效。而每次發(fā)生寫數(shù)據(jù)異常時,OllyDbg 使這個區(qū)域變?yōu)榭蓪?#xff0c;而使原先可寫的區(qū)域變?yōu)闊o效。當(dāng)程序執(zhí)行在保留的保護區(qū)域中的指令時,OllyDbg 報告真正的入口。但是,當(dāng)真正的入口點在可讀或可寫區(qū)域內(nèi)部時,報告的地址就可能有誤。
你可以糾正入口位置,選擇新的入口,從反匯編窗口的快捷菜單中選擇“斷點[Breakpoint]—>設(shè)置真正的自解壓入口[Set real SFX entry here]”。如果相應(yīng)的SFX選項是開啟的,OllyDbg下次可以迅速而可靠的跳過自提取程序。
注意:OllyDbg 在跟蹤采取了保護或者反調(diào)試技術(shù)的解壓程序時通常會失敗。
?
十四、單步執(zhí)行與自動執(zhí)行[Step—by—step execution and animation]
你可以通過按 F7(單步步入)或 F8(單步步過),對程序進行單步調(diào)試。這兩個單步執(zhí)行操作的主要區(qū)別在于:如果當(dāng)前的命令是一個子函數(shù),按F7,將會進入子函數(shù),并停在子函數(shù)的第一條命令上;而按 F8,將會一次運行完這個子函數(shù)。如果你單步步過的子函數(shù)中含有斷點或其他調(diào)試事件,執(zhí)行將會被暫停,并且OllyDbg會在子函數(shù)的后一條命令上,自動下一個斷點,而這個斷點你遲早會碰到。
如果被調(diào)試程序停在異常上,你可以跳過它,并轉(zhuǎn)到被調(diào)試程序建立的句柄處。只需簡單的 Shift 鍵和任何一個單步命令。
如果需要連續(xù)按F7、F8鍵上百次,你可以使用自動執(zhí)行(Ctrl+F7或者Ctrl+F8)功能。在這種情況下,OllyDbg 將自動重復(fù)F7或者F8操作,并且實時更新所有的窗口。這個過程會在下面情況停止:
—按 Esc 鍵或發(fā)出任何單步命令
—OllyDbg 遇到斷點
—被調(diào)試程序發(fā)生異常
使用“+”和“—”按鍵,可以回朔以前的執(zhí)行歷史[execution history]。
注意:當(dāng)執(zhí)行停止時OllyDbg將會刷新大部分窗口。如果動態(tài)執(zhí)行過程非常慢,可以嘗試關(guān)掉或最小化沒有用的窗口。
另外,更快捷的找到以前執(zhí)行指令的辦法是Run跟蹤[run trace]。它將創(chuàng)建一個執(zhí)行協(xié)議并告知你指定指令的執(zhí)行時間和次數(shù)
?
十五、Hit跟蹤[Hittrace]
Hit跟蹤能夠讓你辨別哪一部分代碼執(zhí)行了,哪一部分沒有。OllyDbg的實現(xiàn)方法相當(dāng)簡單。它將選中區(qū)域的每一條命令處均設(shè)置一個INT3斷點。當(dāng)中斷發(fā)生的時候,OllyDbg便把它去除掉,并把該命令標(biāo)志為命中[hit]。因為每個跟蹤斷點只執(zhí)行一次,所以這種方法速度非常快。
在使用Hit跟蹤的時候,一定要注意不能在數(shù)據(jù)中設(shè)置斷點,否則應(yīng)用程序極有可能崩潰。因此,你必須打開相關(guān)的菜單選項,以進行代碼分析[analyze]。我推薦你選擇嚴(yán)格或啟發(fā)式函數(shù)識別[strict or heuristical procedure recognition]。如果選擇模糊[Fuzzy]的話,可能會產(chǎn)生很多難以容忍的錯誤,而且經(jīng)常把本不是函數(shù)的代碼段識別成函數(shù)。
只要你在模塊中設(shè)置了跟蹤斷點,哪怕只設(shè)了一個,OllyDbg都會分配兩倍于代碼段大小的緩沖區(qū)。
注意:當(dāng)你退出Hit跟蹤的時候,Run跟蹤也會同時退出。
?
十六、Run 跟蹤[Run trace]
Run跟蹤是一種反方向跟蹤程序執(zhí)行的方式,可以了解以前發(fā)生的事件。你還可以使用Run跟蹤來了解運行的簡單統(tǒng)計[profile]。基本上,OllyDbg是一步一步地執(zhí)行被調(diào)試程序的,就像動畫[animation]演示一樣,但不會實時刷新窗口,最重要的是它能將地址、寄存器的內(nèi)容、消息以及已知的操作數(shù)記錄到Run跟蹤緩沖區(qū)中。如果被調(diào)試的代碼是自修改的,你就能夠保存原始的命令。可以通過按Ctrl+F11(Run跟蹤步入,進入子函數(shù))或者 Ctrl+F12(Run跟蹤步過,一次執(zhí)行完子函數(shù))開始Run跟蹤,并用F12或者Esc鍵停止跟蹤。
你可以指定在Run跟蹤時執(zhí)行每一步的條件集(快捷鍵:Ctrl+T)。如果條件符合,Run跟蹤將暫停。條件包括:
(1)當(dāng)EIP在某個地址范圍內(nèi)時暫停[Pause when EIP is in the address range];
(2)當(dāng)EIP在某個地址范圍之外時暫停[Pause when EIP is outside the address range];
(3)當(dāng)某個條件為真時暫停[Pause when some conditionis true];
(4)當(dāng)下一條指令可疑時暫停[Pause when next commandis suspicious],比如:可能為非法指令(根據(jù)在分析3[Analysis 3]中設(shè)定的規(guī)則而定),訪問不存在的內(nèi)存,設(shè)置了單步陷阱標(biāo)志[single—step trap flag]或者越ESP界訪問棧。注意:這個選項會明顯地(大約20%)減慢Run跟蹤的速度;
(5)當(dāng)命令執(zhí)行達到指定的次數(shù)(更確切的說,是添加到Run跟蹤的緩沖區(qū)里面的命令數(shù)量)時暫停[Pause afterspecified number of commands is traced]。注意計數(shù)器不能自動歸零。也就是說,如果你設(shè)置指令次數(shù)為10,則在第10次執(zhí)行到該命令時暫停,并不是該命令每執(zhí)行10次就暫停一次。
(6)當(dāng)下一條命令符合指定的樣式之一時暫停[Pause when nextcommand matches one of the specified patterns]。你可以使用模糊命令和操作數(shù)[imprecise commands and operands]及匹配32位寄存器RA和RB,像R32一樣,這兩個寄存器可以替代任何通用32位寄存器,但是在同一條命令中其值是不能變的。而RA和RB在同一條命令中,則一定是不同的。例如,在程序中含有 XOR EAX,EAX;XOR ESI,EDX 兩條命令,兩條命令均符合樣式XOR R32,R32;第一條命令符合樣式XORRA,RA;而等二條命令 XORESI,EDX 符合樣式XOR RA,RB。
毫無疑問,Run跟蹤需要足夠的內(nèi)存,每條命令平均需要占用16到35字節(jié),同時速度也非常慢。在500—MHZ處理器、Windows NT環(huán)境下,它每秒能跟蹤5000條指令。Windows95更慢:每秒鐘僅2200條指令。但是在許多情況下,例如當(dāng)一個程序跳轉(zhuǎn)到不存在的地址的時候,這是找到原因的唯一方法。你可以在Run 跟蹤時將準(zhǔn)線性命令序列(即序列尾部只有唯一出口)跳過。當(dāng)OllyDbg遇到這些需跳過的命令序列時,會設(shè)置一個臨時斷點,然后跟進到序列中,并一次運行完。當(dāng)然了,如果排除命令中返回或跳轉(zhuǎn)的地址在跟蹤范圍之外,將可能導(dǎo)致跟蹤發(fā)生錯誤;因此OllyDbg會檢查你想跳過的代碼塊,如果存在上述情況,會向你詢問。
在大多數(shù)情況下,你對跟蹤系統(tǒng)API代碼不感興趣。跟蹤選項總是跟過系統(tǒng)DLL[Always traceover system DLLs]允許你在 跟蹤/自動模式下跟過API函數(shù)。如果模塊在系統(tǒng)目錄下,OllyDbg就假設(shè)該模塊是系統(tǒng)的。你可以在模塊[Modules]窗口中標(biāo)記任意DLL是系統(tǒng)的或者非系統(tǒng)的。
為了使執(zhí)行速度更快,你可以通過設(shè)置Run跟蹤斷點,先將Run跟蹤限制在選定的命令或代碼塊上,然后再運行程序。我把這種做法稱作“強迫Run跟蹤”。一般來說,刪除Run跟蹤斷點不會移除Hit跟蹤斷點。但如果你刪除了hit跟蹤斷點,同時你也移除了Run跟蹤斷點。
跟蹤命令會保存到跟蹤緩沖區(qū)中,這個緩沖區(qū)在跟蹤開始時自動創(chuàng)建。你可以在選項中指定它的大小(最高64MB)。這個緩沖區(qū)是循環(huán)隊列,當(dāng)滿了的時候,會丟棄老的記錄。你可以通過從OllyDbg主菜單中選擇“調(diào)試[Debug]—>打開或者清除Run跟蹤[Open or clear run trace]”,來打開或者清除Run跟蹤緩沖區(qū)。在Run跟蹤緩沖區(qū)打開后,OllyDbg 會記錄在執(zhí)行過程中的所有暫停,甚至那些不是由Run跟蹤引起的暫停。例如,你可以通過按 F7 或者 F8 單步執(zhí)行程序,然后通過使用+鍵和—鍵來反方向跟蹤程序的執(zhí)行。注意:如果Run跟蹤緩沖區(qū)已經(jīng)關(guān)閉,則用這些鍵瀏覽的是歷史[history]記錄。在你查看Run跟蹤記錄時,寄存器和信息面板會變灰,來強調(diào)它們所顯示的寄存器并不是實際的寄存器。跟蹤緩沖區(qū)并不保存棧頂或由寄存器所指向的內(nèi)容。寄存器、信息和棧在Run跟蹤的時候使用實際的內(nèi)存狀態(tài)來解釋寄存器的變化。
OllyDbg能夠記下每個指令在Run跟蹤緩沖區(qū)里面出現(xiàn)的次數(shù)。在反匯編窗口快捷菜單中,選擇是“查看[View]—>統(tǒng)計作為注釋[Profile as comments]”。這個命令使用統(tǒng)計取代了注釋欄。或者,如果列標(biāo)題欄可見,則可以單擊它幾次直到它顯示統(tǒng)計信息。注意顯示出來的數(shù)字是動態(tài)的,而且不計算已經(jīng)從跟蹤緩沖區(qū)中丟棄的指令。你還可以在單獨的統(tǒng)計窗口[Profile window]中,按觸發(fā)次數(shù)排序,來查看整個模塊的統(tǒng)計數(shù)據(jù)。
在反匯編窗口的快捷菜單中選擇“Run跟蹤[Run trace]—>添加到所有函數(shù)入口處[Add entries of all procedures]”,這樣能夠檢查每個可識別的函數(shù)被調(diào)用的次數(shù)。另一個命令“Run跟蹤[Run trace]—>添加到函數(shù)中所有的分支[Add branches in procedure]”會強行跟蹤此函數(shù)中所有識別的跳轉(zhuǎn)目的地址的內(nèi)容。在這種情況下,統(tǒng)計功能能夠找到最頻繁執(zhí)行的分支,你可以優(yōu)化這部分的代碼,以提高速度。
在反匯編窗口中的某條命令上使用快捷菜單中選擇“搜索[Search for]—>Run跟蹤的最新記錄[Last record in run trace]”用于查找該命令是否被執(zhí)行過,如果執(zhí)行過,最后一次執(zhí)行在哪里。
Run跟蹤窗口顯示跟蹤緩沖區(qū)的內(nèi)容。對每個指令來說包括被指令改變的整數(shù)寄存器的內(nèi)容(更準(zhǔn)確的說是給定的記錄變成下一條記錄的變化)。如果你雙擊某條指令,窗口會選擇在跟蹤緩沖區(qū)里全部含有該命令的記錄,而且你可以通過按+和—鍵來快速的瀏覽;如果你在調(diào)試選項[Debugging options]中設(shè)置了 “跟蹤[Trace]—>同步CPU和Run跟蹤[Synchronize CPU and Run trace]”,雙擊記錄則會跟進到對應(yīng)的反匯編窗口中位置。
注意:當(dāng)你退出Hit跟蹤時,你同時也強行退出了Run跟蹤。
?
十七、快捷鍵
1、通用快捷鍵[Global shortcuts]
無論當(dāng)前的OllyDbg窗口是什么,這些快捷鍵均有效:
Ctrl+F2—重啟程序,即重新啟動被調(diào)試程序。如果當(dāng)前沒有調(diào)試的程序,OllyDbg會運行歷史列表[history list]中的第一個程序。程序重啟后,將會刪除所有內(nèi)存斷點和硬件斷點。譯者注:從實際使用效果看,硬件斷點在程序重啟后并沒有移除。
Alt+F5—讓OllyDbg總在最前面。如果被調(diào)試程序在某個斷點處發(fā)生中斷,而這時調(diào)試程序彈出一個總在最前面的窗口(一般為模式消息或模式對話框[modal message or dialog]),它可能會遮住OllyDbg的一部分,但是我們又不能移動最小化這個窗口。激活OllyDbg(比如按任務(wù)欄上的標(biāo)簽)并按Alt+ F5,OllyDbg將設(shè)置成總在最前面,會反過來遮住剛才那個窗口。如果你再按一下Alt+F5,OllyDbg會恢復(fù)到正常狀態(tài)。OllyDbg是否處于總在最前面狀態(tài),將會保存,在下一次調(diào)試時依然有效。當(dāng)前是否處于總在最前面狀態(tài),會顯示在狀態(tài)欄中。
F4—運行到選定位置。作用就是直接運行到光標(biāo)所在位置處暫停。
F7—單步步入到下一條命令,如果當(dāng)前命令是一個函數(shù)[Call],則會停在這個函數(shù)體的第一條命令上。如果當(dāng)前命令是是含有REP前綴,則只執(zhí)行一次重復(fù)操作。
Shift+F7—與F7相同,但是如果被調(diào)試程序發(fā)生異常而中止,調(diào)試器會首先嘗試步入被調(diào)試程序指定的異常處理(請參考忽略Kernel32中的內(nèi)存非法訪問)。
Ctrl+F7—自動步入,在所有的函數(shù)調(diào)用中一條一條地執(zhí)行命令(就像你按住F7鍵不放一樣,只是更快一些)。當(dāng)你執(zhí)行其他一些單步命令,或者程序到達斷點,或者發(fā)生異常時,自動步入過程都會停止。每次單步步入,OllyDbg都會更新所有的窗口。所以為了提高自動步入的速度,請你關(guān)閉不必要成窗口,對于保留的窗口最好盡量的小。按Esc鍵,可以停止自動步入。
F8—單步步過到下一條命令。如果當(dāng)前命令是一個函數(shù),則一次執(zhí)行完這個函數(shù)(除非這個函數(shù)內(nèi)部包含斷點,或發(fā)生了異常)。如果當(dāng)前命令是含有REP前綴,則會執(zhí)行完重復(fù)操作,并停在下一條命令上。
Shift+F8—與F8相同,但是如果被調(diào)試程序發(fā)生異常而中止,調(diào)試器會首先嘗試步過被調(diào)試程序指定的異常處理(請參考忽略Kernel32中的內(nèi)存非法訪問)。
Ctrl+F8—自動步過,一條一條的執(zhí)行命令,但并不進入函數(shù)調(diào)用內(nèi)部(就像你按住F8鍵不放一樣,只是更快一些)。當(dāng)你執(zhí)行其他一些單步命令,或者程序到達斷點,或者發(fā)生異常時,自動步過過程都會停止。每次單步步過,OllyDbg都會更新所有的窗口。所以為了提高自動步過的速度,請你關(guān)閉不必要成窗口,對于保留的窗口最好盡量的小。按Esc鍵,可以停止自動步過。
F9—讓程序繼續(xù)執(zhí)行。
Shift+F9—與F9相同,但是如果被調(diào)試程序發(fā)生異常而中止,調(diào)試器會首先嘗試執(zhí)行被調(diào)試程序指定的異常處理(請參考忽略Kernel32中的內(nèi)存非法訪問)。
Ctrl+F9—執(zhí)行直到返回,執(zhí)行程序直到遇到返回,在此期間不進入子函數(shù)也不更新CPU數(shù)據(jù)。因為程序是一條一條命令執(zhí)行的,所以速度可能會慢一些。按Esc鍵,可以停止跟蹤。
Alt+F9—執(zhí)行直到返回到用戶代碼段,執(zhí)行程序直到指令所屬于的模塊不在系統(tǒng)目錄中,在此期間不進入子函數(shù)也不更新CPU數(shù)據(jù)。因為程序是一條一條執(zhí)行的,所以速度可能會慢一些。按Esc鍵,可以停止跟蹤。
Ctrl+F11—Run跟蹤步入,一條一條執(zhí)行命令,進入每個子函數(shù)調(diào)用,并把寄存器的信息加入到Run跟蹤的存儲數(shù)據(jù)中。Run跟蹤不會同步更新CPU窗口。
F12—停止程序執(zhí)行,同時暫停被調(diào)試程序的所有線程。請不要手動恢復(fù)線程運行,最好使用繼續(xù)執(zhí)行快捷鍵或菜單選項(像 F9)。
Ctrl+F12—Run跟蹤步過,一條一條執(zhí)行命令,但是不進入子函數(shù)調(diào)用,并把寄存器的信息加入到Run跟蹤的存儲數(shù)據(jù)中。Run跟蹤不會同步更新CPU窗口。
Esc—如果當(dāng)前處于自動運行或跟蹤狀態(tài),則停止自動運行或跟蹤;如果CPU顯示的是跟蹤數(shù)據(jù),則顯示真實數(shù)據(jù)。
Alt+B—顯示斷點窗口。在這個窗口中,你可以編輯、刪除、或跟進到斷點處。
Alt+C—顯示CPU窗口。
Alt+E—顯示模塊列表[listof modules]。
Alt+K—顯示調(diào)用棧[Callstack]窗口。
Alt+L—顯示日志窗口。
Alt+M—顯示內(nèi)存窗口。
Alt+O—顯示選項對話框[Optionsdialog]
Ctrl+P—顯示補丁窗口。
Ctrl+T—打開“暫停Run跟蹤”對話框
Alt+X—關(guān)閉 OllyDbg。
2、大多數(shù)窗口都支持以下的鍵盤命令
Alt+F3—關(guān)閉當(dāng)前窗口。
Ctrl+F4—關(guān)閉當(dāng)前窗口。
F5—最大化當(dāng)前窗口或?qū)?dāng)前窗口大小改為正常化。
F6—切換到下一個窗口。
Shift+F6—切換到前一個窗口。
F10—打開與當(dāng)前窗口或面板相關(guān)的快捷菜單。
左方向鍵—顯示窗口左方一個字節(jié)寬度的內(nèi)容。
Ctrl+左方向鍵—顯示窗口左方一欄的內(nèi)容。
右方向鍵—顯示窗口右方一個字節(jié)寬度的內(nèi)容
Ctrl+右方向鍵—顯示窗口右方一欄的內(nèi)容
3、反匯編窗口中的快捷鍵[Disassembler shortcuts]
當(dāng)CPU窗口中的反匯編面板[Disassemblerpane]處于激活狀態(tài)時,你可以使用以下快捷鍵:
回車鍵—將選中的命令添加到命令歷史[command history]中,如果當(dāng)前命令是一個跳轉(zhuǎn)、函數(shù)或者是轉(zhuǎn)換表的一個部分,則進入到目的地址。
退格鍵—移除選中部分的自動分析信息。如果分析器將代碼誤識別為數(shù)據(jù),這個快捷鍵就非常有用。請參考解碼提示[decoding hints].
Alt+退格鍵—撤消所選部分的修改,以備份數(shù)據(jù)的相應(yīng)內(nèi)容替換所選部分。僅當(dāng)備份數(shù)據(jù)存在且與所選部分不同時可用。
Ctrl+F1—如果API幫助文件已經(jīng)選擇,將打開與首個選擇行內(nèi)的符號名相關(guān)聯(lián)的幫助主題。
F2—在首個選擇的命令上開關(guān)INT3 斷點[Breakpoint],也可以雙擊該行第二列。
Shift+F2—在首個選擇命令設(shè)置條件斷點,參見忽略Kernel32中內(nèi)存訪問異常[Ignore memory accessviolations in Kernel32]。
F4—執(zhí)行到所選行,在首個選擇的命令上設(shè)置一次性斷點,然后繼續(xù)執(zhí)行調(diào)試程序,直到OllyDbg捕獲到異常或者停止在該斷點上。在程序執(zhí)行到該命令之前,該一次性斷點一直有效。如有必要,可在斷點窗口[Breakpoints window]中刪除它。
Shift+F4—設(shè)置記錄斷點(一種條件斷點,當(dāng)條件滿足時一些表達式的值會記錄下來), 詳情參見斷點[Breakpoint]。
Ctrl+F5—打開與首個選擇的命令相對應(yīng)的源文件。
Alt+F7—轉(zhuǎn)到上一個找到的參考。
Alt+F8—轉(zhuǎn)到下一個找到參考。
Ctrl+A—分析當(dāng)前模塊的代碼段。
Ctrl+B—開始二進制搜索。
Ctrl+C—復(fù)制所選內(nèi)容到剪貼板。復(fù)制時會簡單地按列寬截斷不可見內(nèi)容,如果希望排除不需要的列,可把這些列的寬度調(diào)整到最小。
Ctrl+E—以二進制(十六進制)格式編輯所選內(nèi)容。
Ctrl+F—開始命令搜索。
Ctrl+G—轉(zhuǎn)到某地址。該命令將彈出輸入地址或表達式的窗口。該命令不會修改 EIP。
Ctrl+J—列出所有的涉及到該位置的調(diào)用和跳轉(zhuǎn),在你用這個功能之前,你必須使用分析代碼功能。
Ctrl+K—查看與當(dāng)前函數(shù)相關(guān)的調(diào)用樹[Call tree]。在你用這個功能之前,你必須使用分析代碼功能。
Ctrl+L—搜索下一個,重復(fù)上一次的搜索內(nèi)容。
Ctrl+N—打開當(dāng)前模塊的名稱(標(biāo)簽)列表。
Ctrl+O—掃描object文件。掃描Object文件。該命令會顯示掃描Object文件對話框,你可以在該對話框中選擇Object文件或者lib文件,并掃描這個文件,試圖找到在實際代碼段中用到的目標(biāo)模塊。
Ctrl+R—搜索所選命令的參考。該命令掃描激活模塊的全部可執(zhí)行代碼,以找到涉及到首個選中的命令的全部相關(guān)參考(包括:常量、跳轉(zhuǎn)及調(diào)用),你可以在參考中使用快捷鍵 Alt+F7 和 Alt+F8來瀏覽這些參考。為便于你使用,被參考的命令也包含在該列表中。
Ctrl+S—命令搜索。該命令顯示命令查找[Find command]對話框供你輸入?yún)R編命令,并從當(dāng)前命令開始搜索。
星號[Asterisk](*)—轉(zhuǎn)到原始位置(激活線程的EIP處)。
Ctrl+星號(*)—指定新的起始位置,設(shè)置當(dāng)前所選線程的EIP為首個選擇字節(jié)的地址。你可以在選擇EIP并撤消該操作。
加號[Plus](+)—如果run跟蹤[run trace] 沒有激活,則根據(jù)命令歷史[command history]跳到下一條運行過命令的地方;否則跳到Run跟蹤的下一個記錄。
Ctrl+加號—跳到前一個函數(shù)的開始處。(注意只是跳到,并不執(zhí)行)
減號[Minus](—)—如果run跟蹤[run trace] 沒有激活,則根據(jù)命令歷史[command history]跳到前一條運行過命令的地方;否則跳到Run跟蹤的前一個記錄。
Ctrl+減號—跳到下一個函數(shù)的開始處。(注意只是跳到,并不執(zhí)行)
空格[Space]—修改命令。你可在顯示對話框中以匯編語言修改實際指令或輸入新指令,這些指令將替換實際代碼,你也可以在想要修改的指令處雙擊鼠標(biāo)。
冒號[Colon](:)—添加標(biāo)簽。顯示添加標(biāo)簽窗口[Add label]或修改標(biāo)簽窗口[Change label],你可在此輸入與首個選擇的命令中的第一個字節(jié)相關(guān)聯(lián)的標(biāo)簽(符號名)。注意,在多種編程語言中,冒號可以是標(biāo)簽的一部分。
分號[Semicolon](;)—添加注釋[comment]。顯示添加注釋窗口[Add label]或修改注釋窗口[Change label],你可在此輸入與首條所選命令的第一個字節(jié)相關(guān)聯(lián)的注釋(注釋串會顯示在最后一列中)。注意,多種匯編語言使用分號作為注釋開始。你也可以在注釋列雙擊需要注釋的命令行。
十八、插件[Plugins]
插件是一個DLL,存放在OllyDbg的目錄中,用于增加OllyDbg的功能。你可以從OllyDbg的主頁上(http://home.t—online.de/home/Ollydbg)免費下載插件開發(fā)工具包plug110.zip。
插件可以設(shè)置斷點,增加標(biāo)簽和注釋,修改寄存器和內(nèi)存。插件可以添加到主菜單和很多的窗口(比如反匯編窗口、內(nèi)存窗口)的快捷菜單中,也可以攔截快捷鍵。插件還可以創(chuàng)建MDI(多文檔界面)窗口。插件還可以根據(jù)模塊信息和OllyDbg.ini文件,將自己數(shù)據(jù)寫到.udd文件中;并能讀取描述被調(diào)試程序的各種數(shù)據(jù)結(jié)構(gòu)。插件API包含了多達170個函數(shù)。
許多第三方插件都可以從Internet網(wǎng)上獲得,比如由網(wǎng)友TBD創(chuàng)建并維護的OllyDbg的論壇(http://ollydbg.win32asmcommunity.net)。
安裝插件的方法:將DLL復(fù)制到插件目錄[plugin directory]中,然后重新啟動Ollydbg。默認(rèn)情況下,這個插件目錄為ollydbg.exe文件所在的目錄。
現(xiàn)在的版本中已經(jīng)包含了兩個“原始”插件: 書簽[Bookmark]和命令行[Command line]. 他們的源代碼都保存在plug110.zip.文件中。這些插件都是免費的,你可以任意修改或使用它們。
十九、技巧提示[Tips and tricks]
(1)OllyDbg 可以作為二進制編輯器使用。選擇視圖[View]→文件[File]并選定需要查看的文件。文件不能大于剩余內(nèi)存數(shù)量。
(2)假使你修改了內(nèi)存中的執(zhí)行文件,這時你想恢復(fù)修改的部分,但是你忘記哪里被修改了,你可以把原始文件當(dāng)作備份進行加載,這樣你就可以找到修改的部分了。
(3)分析前,先掃描 OBJ 文件。這時OllyDbg會對已知 C 函數(shù)的參數(shù)進行解碼。
(4)一些表格中包含了隱藏數(shù)據(jù)。可以通過增加列寬來顯示出來。
(5)所有數(shù)據(jù)窗口(包括反匯編窗口),可以通過雙擊顯示相對的地址。
(6)你可以通過 Ctrl +↑ 或 Ctrl+↓ 對數(shù)據(jù)窗口翻動一個字節(jié)。
第四章 其他功能
一、調(diào)試獨立的DLL[Debugging of stand—alone DLLs]
打開DLL,也可以直接將其從資源管理器拖放到OllyDbg上。OllyDbg 會詢問你并將該文件的全路徑作為參數(shù)傳遞給loaddll.exe。然后鏈接庫被加載并停在代碼的入口(<DllEntryPoint>)。你可以設(shè)置斷點,運行或跟蹤啟動代碼,等等。在初始化完成后,應(yīng)該程序會再次暫停。這次停在標(biāo)簽名為 Firstbp 的位置,其在立即進入主消息循環(huán)之前。
現(xiàn)在,你可以調(diào)用DLL函數(shù)。從主菜單選擇“調(diào)試[Debug]—>調(diào)用DLL輸出[Call DLL export]”。這時會彈出一個對話框。由于這個對話框是無模式對話框,因此你仍然能夠使用OllyDbg的全部功能,比如查看代碼、數(shù)據(jù),查看斷點,修改內(nèi)存等等。
選擇你想調(diào)用的函數(shù)。例如我們將開始使用 USER32.DLL 里的MessageBox 函數(shù)。注意loaddll.exe 已經(jīng)使用了這個鏈接庫,因此會假定這個 DLL 已經(jīng)初始化而不再調(diào)用入口。MessageBox這個函數(shù)名是通用函數(shù)名,事實上,這個函數(shù)有處理 ASCII 的 MessageBoxA 和處理 Unicode 的MessageBoxW 兩種。我們繼續(xù)往下看:
?
在我們選擇這個函數(shù)后,右邊的消息框中會出現(xiàn) Number of arguments: 4(有四個參數(shù))的字樣。OllyDbg 會根據(jù)函數(shù)尾部的RET 10語句來正確識別參數(shù)的數(shù)量。RETnnn 是使用PASCAL調(diào)用約定的函數(shù)的典型特征。(參數(shù)被放入棧中,第一個參數(shù)會被最后一個壓入棧中,函數(shù)調(diào)用完畢后,參數(shù)會被遺棄)。大多數(shù)的 WindowsAPI 函數(shù)都是PASCAL形式的。
下一步,我們要設(shè)定棧中參數(shù)的個數(shù)。在這個例子中,不必做進行這個操作,因為OllyDbg已經(jīng)知道了MessageBoxW函數(shù)的參數(shù)數(shù)量。但是,如果你愿意的話,也可以單擊左邊的復(fù)選框,改變成你認(rèn)為合適的參數(shù)數(shù)量。
現(xiàn)在填寫參數(shù)列表。這個對話框中支持至多10個參數(shù). 參數(shù)可以是任何有效的表達式,而不必使用寄存器。如果操作數(shù)指向了內(nèi)存,則參數(shù)右邊的緩沖區(qū)窗口會顯示內(nèi)存中的數(shù)據(jù)。Loaddll.exe 有10個大小為1K的緩沖區(qū),這些緩沖區(qū)被標(biāo)記為Arg1 .. Arg10,,你可以方便自由的使用它們。另外,對話框還支持兩個偽變量:由loaddll.exe創(chuàng)建的父窗口句柄<Hwnd>,以及l(fā)oaddll的實例句柄<Hinst>。為了方便你的使用,在你第一次使用調(diào)用輸出函數(shù)時,OllyDbg就已經(jīng)將這兩個偽變量加到了歷史列表中去了。
MessageBoxW e函數(shù)需要4個參數(shù):
l? 父窗口句柄。 這里我們選擇<Hwnd> ;handle of owner window. Here, we simply select <Hwnd>;
l? 在消息框中UNICODE文本的地址。選擇Arg2并按回車。緩沖區(qū)窗口會以16進制的格式顯現(xiàn)內(nèi)存中的緩沖區(qū)。這個緩沖區(qū)初始化全是0。點擊第一個字節(jié),并按快捷鍵Ctrl+E(另外, 也可以從菜單中選擇“二進制[Binary]—>編輯[Edit]”)。這時會出現(xiàn)一個對話框,在對話框中鍵入“Text in box”或者其他希望顯示的字符串;
l? 消息框標(biāo)題的UNICODE文本的地址。選擇Arg3并在Unicode格式的內(nèi)存中寫上“Box title”;
l? 消息框的風(fēng)格。使用常量MB_xxx進行組合.OllyDbg 可以識別這些常量。在這里我們鍵入:MB_OK—>MB_ICONEXCLAMATION。
這里不需要寄存器參數(shù)。
現(xiàn)在我們準(zhǔn)備調(diào)用輸出函數(shù)。選項“在調(diào)用時隱藏[Hide oncall]”意思是說,當(dāng)函數(shù)運行時對話框?qū)钠聊幌А.?dāng)我們執(zhí)行一個會運行很長時間的函數(shù),或者設(shè)置了斷點的時候,這個選項非常的有用。你也可以手動關(guān)閉對話框。當(dāng)函數(shù)執(zhí)行完畢后,OllyDbg會重新自動打開。“調(diào)用輸出函數(shù)”對話框。選項“在調(diào)用后暫停[Pause after call]”意思是說,在執(zhí)行完函數(shù)后,loaddll將會被暫停。
按“調(diào)用[Call]按鈕”后,OllyDbg 會自動備份所有的內(nèi)存、校驗、參數(shù)、寄存器等信息。并隱藏對話框,然后調(diào)用 MessageBoxW 函數(shù)。和期望的一樣,消息框在屏幕中出現(xiàn)了:
函數(shù) MessageBoxW 不會修改參數(shù)。如果你調(diào)用的函數(shù)更新了內(nèi)存,比如函數(shù) GetWindowName,修改的字節(jié)將會在數(shù)據(jù)區(qū)里高亮。注意:EAX 返回值為1,表示成功。
其他的例子請訪問我的網(wǎng)站:http://home.t—online.de/home/Ollydbg/Loaddll.htm
不幸的是,你不能通過這種方式調(diào)試OllyDbg的插件,插件關(guān)聯(lián)到ollydbg.exe文件,Windows系統(tǒng)不能在同一個應(yīng)用程序里加載并運行兩個可執(zhí)行文件。
二、解碼提示[Decoding hints]
在某些情況下,分析器不能區(qū)分代碼和數(shù)據(jù)。讓我們看看下面的例子:
const char s[11] = "0123456789";
...for (i=0x30; i<0x3a;i++) t[i—0x30]=s[i—0x30];
好的編譯器將會將上面的代碼優(yōu)化成如下樣子: e
for (i=0x30; i<0x3a; i++) (t—0x30)=(s—0x30);
這里t—0x30 和 s—0x30 都是常量,并編譯成如下形式:
MOV AL,[BYTE s_minus_30+EBX]
MOV [BYTE t_minus_30+EBX],AL
編譯器也可能將常量字符串"0123456789"插入到執(zhí)行代碼中。在1.10版本中,我打算用寄存器的值來決定是否的數(shù)據(jù)或代碼。當(dāng)遇到上面的命令,分析器將假定地址s_minus_30處包含字符數(shù)據(jù)。但事實上,可能那里是代碼。
萬一出現(xiàn)上述問題,我們應(yīng)該怎么辦呢?有兩種辦法:最快最笨的辦法是:將分析錯誤的部分刪除(快捷鍵:退格鍵),這樣OllyDbg將使用默認(rèn)的反匯編器進行解碼。
更好的辦法是使用解碼提示[decoding hints]。你可以告訴OllyDbg如何解釋選中的內(nèi)存內(nèi)容。這種方法在重新分析(Ctrl+A)時,解釋依然有效。
設(shè)置提示的方法:在反匯編窗口中,選中需要修正提示的代碼或數(shù)據(jù),然后在快捷菜單中選擇分析[Analysis]—>在下次分析時,將選擇部分視為[During next analysis, treat selection as]。選擇以下選項之一:
命令[Command]—第一個被選中的字節(jié)開始的有效命令。這條命令,還有所有后面的部分,直到有Jump或Return命令出現(xiàn),以及含有Jump或Call命令所到達位置的部分,都會被視為命令;
字節(jié)[Byte],字[Word],雙字[Doubleword]—選中的前1、2、4字節(jié)視為對應(yīng)大小的數(shù)據(jù);
所有選中命令[Commands]—全部選中部分(直到第一個無效命令)和可以到達由有效命令集組成的目的地址;
字節(jié)[Bytes],字[Words],雙字[Doublewords],—全部選中部分以1、2、或 4字節(jié)分組;
ASCII字符串[ASCII text], UNICODE字符串[UNICODE text]—全部選中部分為ASCII 或 UNICODE 字符串;
默認(rèn)(移除提示)[Default (removehints)]—從選中部分中移除全面提示;
移除全部提示[Remove all hints]—從全部模塊中移除解碼提示。
OllyDbg 保存提示到.udd文件中。
?
三、表達式賦值[Evaluation of expressions]
OllyDbg能夠支持非常復(fù)雜的表達式。表達式的語法格式將在這個主題的后面進行介紹,但我想你對此不一定真的感興趣。那么我先舉幾個實例來說明:
10—常量 0x10 (無符號)。所有整數(shù)常量都認(rèn)為是十六進制的,除非后面跟了點;
10.—十進制常量10(帶符號);
'A'—字符常量 0x41;
EAX—寄存器EAX的內(nèi)容,解釋為無符號數(shù);
EAX.—寄存器EAX的內(nèi)容,解釋為帶符號數(shù);
[123456]—在地址123456處的無符號雙字內(nèi)容。默認(rèn)情況,OllyDbg假定是雙字長操作數(shù);
DWORD PTR [123456]—同上。關(guān)鍵字 PTR 可選;
[SIGNED BYTE123456]—在地址123456處帶符號單字節(jié)。OllyDbg支持類MASM和類IDEAL兩種內(nèi)存表達式;
STRING [123456]—以地址123456作為開始,以零作為結(jié)尾的ASCII字符串。中括號是必須的,因為你要顯示內(nèi)存的內(nèi)容;
<123456>—在地址123456處存儲的雙字所指向的地址內(nèi)的雙字內(nèi)容;
2+3*4—值為14。OllyDbg 按標(biāo)準(zhǔn)C語言的優(yōu)先級進行算術(shù)運行;
(2+3)*4—值為20。使用括號改變運算順序。
EAX.<0.—如果EAX在0到0x7FFFFFFF之間,則值為0,否則值為1。注意0也是有符號的。當(dāng)帶符號數(shù)與無符號數(shù)比較時,OllyDbg會將帶符號數(shù)轉(zhuǎn)成無符號數(shù)。
EAX<0—總為0(假),因為無符號數(shù)永遠是正的。
MSG==111—如果消息為WM_COMMAND,則為真。0x0111是命令 WM_COMMAND 的數(shù)值。MSG只能用于設(shè)置在進程消息函數(shù)的條件斷點內(nèi)。
[STRING123456]=="Brown fox"—如果從地址0x00123456開始的內(nèi)存為ASCII字符串"Brownfox"、"BROWN FOX JUMPS"、 "brown fox???",或類似的串,那么其值為1。比較不區(qū)分大小寫和文本長度。
EAX=="Brownfox"—同上,EAX按指針對待。
UNICODE[EAX]=="Brown fox"—OllyDbg認(rèn)為EAX是一個指向UNICODE串的指針,并將其轉(zhuǎn)換為ASCII,然后與文本常量進行比較。
[ESP+8]==WM_PAINT—i在表達式中你可以使用上百種Windows API符號常量。
([BYTE ESI+DWORDDS:[450000+15*(EAX—1)> & 0F0)!=0—這絕對是個有效的表達式。
現(xiàn)在我們介紹語法格式。在大括號({})內(nèi)的每個元素都只能出現(xiàn)一次,括號內(nèi)的元素順序可以交換:
表達式 = 內(nèi)存中間碼|內(nèi)存中間碼<二元操作符>內(nèi)存中間碼
內(nèi)存中間碼 = 中間碼 | ?{ 符號標(biāo)志 大小標(biāo)志 前綴} [表達式 ]
中間碼 =(表達式) | 一元操作符 內(nèi)存中間碼 | 帶符號寄存器 | 寄存器 | FPU寄存器 | 段寄存器 | 整型常量 | 浮點常量 | 串常量 | 參數(shù) | 偽變量
一元操作符 = ! | ?~ | ?+ | ?
帶符號寄存器 = 寄存器.
寄存器 = AL | BL |CL ... | AX | ?BX | CX... | ?EAX | EBX | ECX...
FPU寄存器 = ST | ST0 | ST1 ...
段寄存器 = CS | DS | ES | SS| FS | GS
整型常量 = <十進制常量>. | <十六進制常量> | <字符常量> | <API符號常量>
浮點常量 = <符點常量>
串常量 = "<串常量>"
符號標(biāo)志 = SIGNED | UNSIGNED
大小標(biāo)志 = BYTE | CHAR | WORD| SHORT | DWORD | LONG | QWORD | FLOAT | DOUBLE | FLOAT10 | STRING | UNICODE
前綴 = 中間碼:
參數(shù) = %A | %B?????? // 僅允許在監(jiān)察器[inspector] 中使用
偽變量 = MSG?????? // 窗口消息中的代碼
這個語法并不嚴(yán)格。在解釋[WORD [EAX]]或類似的表達式時會產(chǎn)生歧義。可以理解為以寄存器EAX所指向地址的兩字節(jié)內(nèi)容為地址,所指向的雙字內(nèi)容;也可以理解為以寄存器EAX所指向地址的四字節(jié)內(nèi)容為地址,所指向的兩字節(jié)內(nèi)容。而OllyDbg會將修飾符盡可能的放在地址最外面,所以在這種情況下,[WORD [EAX]]等價于 WORD 。
默認(rèn)情況下,BYTE、WORD 和 DWORD 都是無符號的,而CHAR、SHORT 和 LONG都是帶符號的。也可以使用明確的修飾符SIGNED 或 UNSIGNED。例如在二元操作時,如果一個操作數(shù)是浮點的,那么另外一個就要轉(zhuǎn)成浮點數(shù);或者如果一個是無符號膽,那么另外一個要轉(zhuǎn)成無符號的。浮點類型不支持UNSIGNED。大小修飾符后面跟MASM兼容關(guān)鍵字PTR(如:BYTE PTR)也允許的,也可以不要PTR。寄存器名和大小修飾符不區(qū)分大小寫。
你可以使用下面類C的運算符(0級最高):
優(yōu)先級?????? 類型?????? 運算符
0?????? 一元運算符???? ? ! ~+—
1?????? 乘除運算?????? ? */ %
2?????? 加減運算?????? ? +—
3?????? 位移動?????? ????? <<>>
4?????? 比較?????? ????????? <<= > >=
5?????? 比較?????? ????????? ==!=
6?????? 按位與?????? ????? &
7?????? 按位異或?????? ? ^
8?????? 按位或????? ??????? |
9?????? 邏輯與?????? ????? &&
10?????? 邏輯或????? ????? ||
在計算時,中間結(jié)果以 DWORD 或 FLOAT10 形式保存。某些類型組合和操作是不允許的。例如:QWODRD 類型只能顯示;STRING 和 UNICODE只能進行加減操作(像C語言里的指針)以及與STRING、UNICODE 類型或串常量進行比較操作;你不能按位移動浮點[FLOAT] 類型,等等。
?
四、自定義函數(shù)描述[Custom function descriptions]
1、概論[Introduction]
OllyDbg包含(做為內(nèi)部資源)1900多種標(biāo)準(zhǔn)函數(shù)以及400多種標(biāo)準(zhǔn)C函數(shù)的名稱和參數(shù)。分析器[Analyzer]用這些描述使被調(diào)試程序更加易懂。比較下面一個例子,分析器的函數(shù)CreateFont:
????? PUSH OT.00469F2A??????????????; ASCII "Times New Roman"
??????? PUSH 12??????????????????????????
??????? PUSH 2??????????????????????????
??????? PUSH 0?????????????????????????
??????? PUSH 0??????????????????????????
??????? PUSH 0??????????????????????????
??????? PUSH 0???????????????????????
??????? PUSH 0??????????????????????????
??????? MOV EAX,DWORD PTR [49FA70]
??????? PUSH EAX
??????? PUSH 190????????????????????????
??????? PUSH 0
??????? PUSH 0?????????????????????????
??????? PUSH 0????????????????????????
??????? PUSH 10???????????????????????
??????? CALL <JMP.&GDI32.CreateFontA>
這是分析后的:
????? MOV EAX,DWORD PTR[49FA70]????
??????? PUSH OT.00469F2A??????? ?????????????????? ; ?/ FaceName = "Times New Roman"
??????? PUSH 12???????????????????? ? ; ?| PitchAndFamily =VARIABLE_PITCH—>FF_ROMAN
??????? PUSH 2????????????????????? ? ; ?| Quality = PROOF_QUALITY
??????? PUSH 0???????????????????? ??? ; ?| ClipPrecision =CLIP_DEFAULT_PRECIS
????? ??PUSH 0???????????????????? ??? ; ?| OutputPrecision =OUT_DEFAULT_PRECIS
??????? PUSH 0?????????????????????? ????????? ; ?| CharSet =ANSI_CHARSET
??????? PUSH 0???????????????????? ??? ; ?| StrikeOut = FALSE
??????? PUSH 0????????????????????? ? ; ?| Underline = FALSE
??????? PUSH EAX??????????????????? ???????? ; ?| Italic => TRUE
??????? PUSH 190???????????????????? ????????? ; ?| Weight =FW_NORMAL
??????? PUSH 0?????????????????????? ????????? ; ?| Orientation = 0
??????? PUSH 0????????????????????? ? ; ?| Escapement = 0
??????? PUSH 0????? ????????????????? ; ?| Width = 0
??????? PUSH 10???????????????????? ? ; ?| Height = 10 (16.)
??????? CALL <JMP.&GDI32.CreateFontA>; ?\ CreateFontA
顯然,后面的代碼更容易理解。API函數(shù)CreateFont 有14個參數(shù)。分析器標(biāo)記所有這些參數(shù)的名稱并解碼他們的值。如果寄存器跟蹤開啟,那么分析器同時會解碼參數(shù)Italic的值為地址49FA70處雙字長的內(nèi)容。解碼使用參數(shù)的真實值,所以如果[49FA70]里的內(nèi)容改變了,那么參數(shù)Italic的值也會隨之改變。當(dāng)EIP指向跳轉(zhuǎn)或調(diào)用該函數(shù)的命令,或指向入口時,OllyDbg也會在棧中對已知函數(shù)的參數(shù)進行解碼。
OllyDbg可以對像printf()這樣參數(shù)個數(shù)可變的函數(shù)進行參數(shù)解碼:
??????? PUSH EAX???????????????????? ?????? ; / <%.*s>
??????? PUSH E8??????????????????????? ???? ; | <*> = E8 (232.)
??????? PUSH EBX?????????????????????? ??? ; | <%08X>
??????? PUSH Mymodule.004801D2???????? ??? ;| format = "Size %08X (%.*s) bytes"
??????? PUSH ESI?????????????????????? ????? ; | s
??????? CALL Mymodule.sprintf????????? ???????? ;\sprintf
你可以定義自己的函數(shù)。每次你打開某個應(yīng)用程序時,OllyDbg都會重新設(shè)置函數(shù)參數(shù)表并用內(nèi)嵌描述添充這個表。然后嘗試打開文件“< OllyDbg目錄>\common.arg”和“<OllyDbg目錄>\<應(yīng)用程序名>.arg”,這里<應(yīng)用程序名>使用8.3格式(DOS)被調(diào)試程序文件名(不帶路徑和擴展名)。
下面看一個簡單的.arg文件實例:
??????? INFO Simple .ARG file that decodesCreateHatchBrush
??????? TYPE HS_X
????????? IF 0 "HS_HORIZONTAL"
????????? IF 1 "HS_VERTICAL"
????????? IF 2 "HS_FDIAGONAL"
????????? IF 3 "HS_BDIAGONAL"
????????? IF 4 "HS_CROSS"
????????? IF 5 "HS_DIAGCROSS"
????????? ELSEINT
??????? END
??????? TYPE COLORREF
????????? IF 0 "<BLACK>"
????????? IF 00FFFFFF "<WHITE>"
????????? OTHERWISE
????????? TEXT "RGB("
????????? FIELD 000000FF
????????? UINT
????????? TEXT ","
????????? FIELD 0000FF00
????????? UINT
????????? TEXT ","
????????? FIELD 00FF0000
????????? UINT
????????? TEXT ")"
??????? END
??????? STDFUNC CreateHatchBrush
???????? ?"style" HS_X
????????? "colorref" COLORREF
??????? END
標(biāo)準(zhǔn)Windos API函數(shù)CreateHatchBrush(int style,int colorref) 有兩個參數(shù)。第一個必須是陰影風(fēng)格[hatch style],第二個是常量由紅色、綠色、藍色組成,并用一個32位整數(shù)的低三字節(jié)表示。為了解碼這些參數(shù),文件定義了兩個新的參數(shù)類型:HS_X和 COLORREF。
陰影風(fēng)格是一個簡單的枚舉類型,如0表示HS_HORIZONTAL(水平風(fēng)格)、1表示HS_VERTICAL(垂直風(fēng)格)。IF關(guān)鍵字比較參數(shù)與第一個操作數(shù)(注意:其總是十六進制的),如果相同則顯示第二個操作數(shù)里的文本。但萬一匹配失敗會如何?關(guān)鍵字ELSEINT 會然OllyDbg會將參數(shù)解釋為一個整數(shù)。
COLORREF 更復(fù)雜一些。首先嘗試解碼兩個廣泛使用的顏色值:黑(全0組成)與白(全0xFF組成)。如果匹配失敗,COLORREF嘗試解碼顏色為一個結(jié)構(gòu)包含紅、綠、藍的亮度。FIELD會用第一個操作數(shù)與參數(shù)進行邏輯與操作。然后轉(zhuǎn)換結(jié)果為整數(shù),并同時按位右移第一個操作及該整數(shù),直到第一個操作數(shù)的二進制個位數(shù)字為1,這時整數(shù)按位右移的結(jié)果以無符號10進制顯示出來。這個例子做了三次這樣的操作,以分離出每個顏色成份。TEXT關(guān)鍵字用于無條件顯示文本。如果參數(shù)為00030201,那么COLORREF將其解碼為RGB(1.,2.,3.)。
大多斷API函數(shù)都會從棧中移除參數(shù)并保護寄存器EBX, EBP, ESI 和 EDI。聲明這樣的函數(shù)為STDFUNC,以告訴分析器該函數(shù)做了這樣的事情。否則請其描述為FUNCTION。
萬一某個參數(shù)由多個域及比特值組成,比如上面提到的fdwPitchAndFamily ,我們該怎么辦?請看下面這個例子:
?????? ?TYPE FF_PITCH
????????? MASK 03
????????? IF 00 "DEFAULT_PITCH"
????????? IF 01 "FIXED_PITCH"
????????? IF 02 "VARIABLE_PITCH"
????????? ELSEHEX
????????? TEXT "—>"
????????? MASK 0C
????????? BIT 04 "4—>"
????????? BIT 08 "8—>"
????????? MASK FFFFFFF0
????????? IF 00 "FF_DONTCARE"
????????? IF 10 "FF_ROMAN"
????????? IF 20 "FF_SWISS"
????????? IF 30 "FF_MODERN"
????????? IF 40 "FF_SCRIPT"
????????? IF 50 "FF_DECORATIVE"
????????? ELSEHEX
??????? END
前兩個比特位(第0和等1位)表示傾斜度,必須一起解碼。我們使用 MASK 03 來提取這兩個比特并通過IF序列來解碼。增加了連接符“—>”,分別提取第2和第3個比特位,并分別單獨解碼。最后提取剩余部分并進行解碼。
OllyDbg 會移除生成串尾部的連接符“—>”、空格、冒號、逗號、分號和等號。
目前版本的分析僅能夠解碼32位參數(shù)。如你不能解碼雙精度浮點或長雙精度浮點的函數(shù)參數(shù)。
2、格式描述
自定義解碼信息由函數(shù)描述和類型描述兩部分組成。函數(shù)描述部分非常的簡單:
FUNCTION|STDFUNC [模塊名]函數(shù)名
? <第一個參數(shù)的名稱> <第一個參數(shù)的類型>
? ……
? <最后一個參數(shù)的名稱> <最后一個參數(shù)的類型>
END
如果函數(shù)從棧中移除參數(shù)并保護寄存器EBX, EBP, ESI 和 EDI,請使用關(guān)鍵字STDFUNC。大多少函數(shù)都遵循這樣的規(guī)則。其他情況則聲明為FUNCTION。模塊(EXE 或 DLL)名是可選的。如果模塊名被忽略,OllyDbg會對嘗試匹配任何模塊。模塊名不區(qū)分大小寫。
函數(shù)名稱總是區(qū)分大小寫的。有針對UNICODE的函數(shù)必須使用后綴 A 或 W 加以區(qū)分,比如SetWindowTextA.。
參數(shù)的順序又C風(fēng)格的參數(shù)使用慣例一致。而16位Windows和32位API函數(shù)也是按慣例使用。如果參數(shù)名由多個字組成,或者包含特殊字符,那么請將其用兩個單引號引起來。與在C語言中一樣,省略號()是一個特殊的記錄用于表示參數(shù)數(shù)目可變。它必須在函數(shù)描述的最后。OllyDbg不會嘗試解碼這樣的參數(shù)。如果函數(shù)的參數(shù)為空,則按functionname(void)對待。
OllyDbg 僅支持32位的參數(shù)。某些參數(shù)已經(jīng)預(yù)定義好了:
INT?????????????????????? 以十六進制和帶符號整數(shù)兩種格式顯示值
UINT??????????????????? 以十六進制和無符號整數(shù)兩種格式顯示值
HEX???????????????????? 以十六進制格式顯示值
BOOL ??????????????? TRUE 或 FALSE
CHAR?????? ??? ASCII字符
WCHAR?????? ????????? UNICODE字符
FLOAT?????? ?? 32位浮點數(shù)
ERRCODE??? ?? 系統(tǒng)錯誤代碼(像由函數(shù)GetLastError()報告的)
ADDR, PTR?? ? 地址(特殊情況:NULL)
ASCII??????? ?? ASCII串指針
UNICODE???? UNICODE串指針
FORMAT???? ?? 在類似函數(shù)printf()(不包括wscanfW()!)使用的 ASCII 格式串
WFORMAT??? 類似函數(shù)wsprintfW()(不包括scanf()!)使用的 UNICODE 格式串
RECT?????? ???? RECT(矩形)結(jié)構(gòu)指針
MESSAGE??? ? MSG(ASCII 窗口消息)結(jié)構(gòu)指針
WMESSAGE? ?? MSG(UNICODE 窗口消息)結(jié)構(gòu)指針
HANDLE???? ?? 句柄(特殊情況:NULL,ERROR_INVALID_HANDLE)
HWND?????? ?? 窗口句柄
HMODULE?? ?? 模塊句柄
RSRC_STRING ????????? 帶索引的資源串
NULL, DUMMY????????? 有參數(shù),但解碼時跳過了
你不能重定義預(yù)定義類型。自定義類型允許你將參數(shù)分離成幾個域并分別解碼。類型描述有以下幾種格式:
TYPE 類型名
? [TEXT "任何文本"]
? [<域選擇器>]
? <域解碼>
? <域解碼>
? [TEXT "任何文本"]
? [PURGE]
? ...
? <域選擇器>
? <域解碼>
? <域解碼>
? [TEXT "任何文本"]
END
類型名的程度限制在16個字符以內(nèi)。 OllyDbg會無條件將"任何文本"作為生成的解碼。域選擇器提取一部分參數(shù)用于解碼。以下域選擇器,可以用于提取域:
MASK 十六進制掩碼—域等于參數(shù)同十六進制掩碼按位與(AND)的結(jié)果。
FIELD 十六進制掩碼—參數(shù)同十六進制掩碼按位與(AND)的數(shù)值,然后OllyDbg同時按位右移掩碼和計算的數(shù)值直到掩碼的二進制個位為1,這時數(shù)值按位右移的結(jié)果就是域的值。例如參數(shù)0xC250, FIELD F0,得到的結(jié)果是5。
SIGFIELD十六進制掩碼—參數(shù)同十六進制掩碼按位與(AND)的數(shù)值,然后OllyDbg同時按位右移掩碼和計算的數(shù)值直到掩碼的二進制個位為1,這時數(shù)值按位右移的結(jié)果轉(zhuǎn)成帶符號32位數(shù)就是域的值。例如參數(shù)0xC250 ,SIGFIELD FF00,得到的結(jié)果是0xFFFFFFC2。
簡單域的解碼會一次顯示整個域的內(nèi)容:
HEX—以十六進制形式顯示域內(nèi)容;
INT—以帶符號十進制形式顯示域內(nèi)容(帶小數(shù)點);
UINT—以無符號十進制形式顯示域內(nèi)容(帶小數(shù)點);
CHAR—以 ASCII 字符形式顯示域內(nèi)容。
域若是一個枚舉類型,則可以使用IF序列,如果必要的話還可以在IF序列后跟關(guān)鍵字 TRYxxx 與 ELSExxx:
IF 十六進制值 "文本"—如果域等于十六進制值,則將文本作為輸出字符串;
TRYASCII—如果域是一個指向ASCII串的指針,則顯示這個串;
TRYUNICODE—如果域是一個指向UNICODE串的指針,則顯示這個串;
TRYORDINAL—如果域是一序號(有16位均為0),則會顯示為序號(“#”后跟整數(shù));
OTHERWISE—如果前面IF語句為真,則停止解碼,否則繼續(xù)解碼;
ELSEINT—如果前面所有的 IF 和 TRYxxx 語句均失敗,則以帶符號十進制數(shù)形式(帶小數(shù)點)顯示這個域;
ELSEHEX—如果前面所有的 IF 和 TRYxxx 語句均為失敗,則以十六進制形式顯示這個域;
ELSECHAR—如果前面所有的 IF 和 TRYxxx 語句均為失敗,則以 ASCII 字符形式顯示這個域;
ELSEWCHAR—如果前面所有的 IF 和 TRYxxx 語句均為失敗,則以 UNICODE 字符形式顯示這個域。
如果域是一個二進制位集,則可以使用BIT序列,如果必要的話可以后面跟關(guān)鍵字 BITZ 與 BITHEX :
BIT 十六進制掩碼 "文本"—如果值與十六進制掩碼按位與(AND)的結(jié)果不是0,則將文本做為輸出串;
BITZ十六進制掩碼 "文本"—如果值與十六進制掩碼按位與(AND)的結(jié)果是0,則將文本做為輸出串;
BITHEX十六進制掩碼—如果值與十六進制掩碼按位與(AND)的結(jié)果不是0,則將結(jié)果以十六進制形式顯示。
特殊關(guān)鍵字 PURGE 會從輸出串尾部移除以下幾種符號:
空格?????? ' '
逗號?????? ','
或?????? '—>'
冒號?????? ':'
等于?????? '='
這會讓某些解碼情況變的簡單。關(guān)鍵字END是類型定義結(jié)尾標(biāo)記并會自動運行PURGE命令。
3、預(yù)編譯類型
OllyDbg在預(yù)編譯資源時,已經(jīng)包含150多種類型描述。以下列出了一部分。你可以在自定義文件中直接使用這些類型:
LANG_X—操作系統(tǒng)語言ID(0—未知、 9—語言、 C—法語,等等)
GENERIC_X—訪問類型(GENERIC_READ,GENERIC_WRITE...)
FILE_SHARE_X—共享類型(FILE_SHARE_READ,FILE_SHARE_WRITE)
CREATEFILE_X—文件創(chuàng)建模式(CREATE_NEW,OPEN_EXISTING...)
FILE_ATTRIBUTE_X—文件屬性(READONLY, SYSTEM,DELETE_ON_CLOSE...)
RT_AXX—資源類型(RT_CURSOR,RT_GROUP_ICON, ASCII string...)
RT_WXX—資源類型(RT_CURSOR,RT_GROUP_ICON, UNICODE string...)
COORD—坐標(biāo)結(jié)構(gòu)"(X=xxx,Y=yyy)"
STD_IO_X—標(biāo)準(zhǔn)句柄(STD_INPUT_HANDLE,STD_ERROR_HANDLE...)
GMEM_X—全局內(nèi)存類型(GMEM_FIXED,GPTR...)
LMEM_X—局部內(nèi)存類型(LMEM_FIXED,LPTR...)
FSEEK_X—文件查找類型(FILE_BEGIN,FILE_CURRENT...)
OF_X—文件模式(fOF_READ,OF_SHARE_COMPAT, OF_VERIFY...)
O_X—文件創(chuàng)建模式(O_RDONLY,O_BINARY, SH_COMPAT...)
SEMAPHORE_X—信號量類型(SEMAPHORE_ALL_ACCESS,SYNCHRONIZE...)
SLEEP_TIMEOUT—超時(INFINITE 或時間)
ROP—一些標(biāo)準(zhǔn)柵格運算標(biāo)志代碼(ROP)(SRCCOPY,MERGEPAINT...)
COLORREF—RGB 顏色值("<WHITE>","RGB(rr.,gg.,bb.)"...)
WS_X—窗口風(fēng)格(WS_OVERLAPPED,WS_POPUP...)
WS_EX_X—擴展窗口風(fēng)格(WS_EX_DLGMODALFRAME,WS_EX_TOPMOST...)
MF_X—菜單標(biāo)志(MF_BYPOSITION,MF_ENABLED...)
WM_X—ASCII窗口消息類型(WM_CREATE,WM_KILLFOCUS, CB_SETCURSEL...)
WM_W—UNICODE窗口消息類型(WM_CREATE,WM_KILLFOCUS, CB_SETCURSEL...)
VK_X—虛擬鍵盤代碼(VK_LBUTTON,VK_TAB, VK_F10...)
MB_X—message box style(MB_OK, MB_ICONHAND...)
HKEY_X—預(yù)定義注冊表句柄(HKEY_CLASSES_ROOT,HKEY_LOCAL_MACHINE...)
還有更多的預(yù)編譯類型。如果常量在它文件被定義為ABC_ xxxxxxxx,那么一般就有ABC_X預(yù)編譯類型。
注意:
1.如果OllyDbg是即時調(diào)試器,并且在Windows 95下掛接執(zhí)行了DebugBreak() 的應(yīng)用程序,則這個應(yīng)用程序在掛接后,還會運行。在基于NT的系統(tǒng)下,應(yīng)用程序應(yīng)該會在DebugBreak()暫停。
2. 命令 SMSW (保存機器狀態(tài)字[Store Machine Status Word])。 這個命令僅接受寄存器 AX 作為參數(shù),而程序編譯成EAX接受參數(shù)。
總結(jié)
以上是生活随笔為你收集整理的OllyDbg完全教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VS2008编译汇编程序的问题
- 下一篇: Linux网络编程——浅谈 TCP 三次