日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OllyDBG完美教程(超强入门级)

發(fā)布時(shí)間:2024/7/23 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OllyDBG完美教程(超强入门级) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

OllyDBG?視頻教程:https://www.bilibili.com/video/av6889190

動(dòng)態(tài)調(diào)試工具之OllyDbg(OD)教程:https://www.bilibili.com/video/av70600053

?

使用 OllyDbg 從零開(kāi)始 Cracking.chm ( 58章?):https://pan.baidu.com/s/18iXvF5I_No4-a1DK3jKrbg????提取碼:45xy?
OllyDBG 完美教程(超強(qiáng)入門(mén)級(jí))?:鏈接:https://pan.baidu.com/s/1fLTdBn9400rkx_iAgJ7bZg????提取碼:dvi5
OllyDbg 幫助文檔翻譯:https://www.0xaa55.com/thread-1122-1-1.html
看雪論壇工具介紹及下載:https://tools.pediy.com/win/debuggers.htm

?

?

?

一、OllyDBG?的安裝與配置

?

OllyDBG?1.10?版的發(fā)布版本是個(gè)?ZIP?壓縮包,只要解壓到一個(gè)目錄下,運(yùn)行?OllyDBG.exe?就可以了。漢化版的發(fā)布版本是個(gè)?RAR?壓縮包,同樣只需解壓到一個(gè)目錄下運(yùn)行?OllyDBG.exe?即可:

OllyDBG?中各個(gè)窗口的功能如上圖。簡(jiǎn)單解釋一下各個(gè)窗口的功能,更詳細(xì)的內(nèi)容可以參考?TT?小組翻譯的中文幫助:

  • 反匯編窗口?:顯示被調(diào)試程序的反匯編代碼,標(biāo)題欄上的地址、HEX?數(shù)據(jù)、反匯編、注釋 可以通過(guò)在窗口中右擊出現(xiàn)的菜單?界面選項(xiàng) -> 隱藏標(biāo)題?或?顯示標(biāo)題?來(lái)進(jìn)行切換是否顯示。用鼠標(biāo)左鍵點(diǎn)擊注釋標(biāo)簽可以切換注釋顯示的方式。
  • 寄存器窗口?:顯示當(dāng)前所選線(xiàn)程的?CPU?寄存器內(nèi)容。同樣點(diǎn)擊標(biāo)簽?寄存器?(FPU)?可以切換顯示寄存器的方式。
  • 信息窗口?:顯示反匯編窗口中選中的第一個(gè)命令的參數(shù)及一些跳轉(zhuǎn)目標(biāo)地址、字串等。
  • 數(shù)據(jù)窗口?:顯示內(nèi)存或文件的內(nèi)容。右鍵菜單可用于切換顯示方式。
  • 堆棧窗口?:顯示當(dāng)前線(xiàn)程的堆棧。

要調(diào)整上面各個(gè)窗口的大小的話(huà),只需左鍵按住邊框拖動(dòng),等調(diào)整好了,重新啟動(dòng)一下?OllyDBG?就可以生效了。

啟動(dòng)后,我們要把 插件 及?UDD的目錄?配置為 絕對(duì)路徑,點(diǎn)擊菜單上的?選項(xiàng) -> 界面,將會(huì)出來(lái)一個(gè)界面選項(xiàng)的對(duì)話(huà)框,我們點(diǎn)擊其中的 目錄 標(biāo)簽 :

因?yàn)槲疫@里是把?OllyDBG?解壓在?F:\OllyDBG?目錄下,所以相應(yīng)的?UDD?目錄及插件目錄按圖上配置。還有一個(gè)常用到的標(biāo)簽就是上圖后面那個(gè)字體,在這里你可以更改?OllyDBG?中顯示的字體。上圖中其它的選項(xiàng)可以保留為默認(rèn),若有需要也可以自己修改。修改完以后點(diǎn)擊確定,彈出一個(gè)對(duì)話(huà)框,說(shuō)我們更改了插件路徑,要重新啟動(dòng)?OllyDBG。在這個(gè)對(duì)話(huà)框上點(diǎn)確定,重新啟動(dòng)一下?OllyDBG,我們?cè)俚浇缑孢x項(xiàng)中看一下,會(huì)發(fā)現(xiàn)我們?cè)仍O(shè)置好的路徑都已保存了。

有人可能知道插件的作用,但對(duì)那個(gè)?UDD?目錄不清楚。我這簡(jiǎn)單解釋一下:這個(gè)?UDD?目錄的作用是保存你調(diào)試的工作。比如你調(diào)試一個(gè)軟件,設(shè)置了斷點(diǎn),添加了注釋,一次沒(méi)做完,這時(shí)?OllyDBG?就會(huì)把你所做的工作保存到這個(gè)?UDD?目錄,以便你下次調(diào)試時(shí)可以繼續(xù)以前的工作。如果不設(shè)置這個(gè)?UDD?目錄,OllyDBG?默認(rèn)是在其安裝目錄下保存這些后綴名為?udd?的文件,時(shí)間長(zhǎng)了就會(huì)顯的很亂,所以還是建議專(zhuān)門(mén)設(shè)置一個(gè)目錄來(lái)保存這些文件。

另外一個(gè)重要的選項(xiàng)就是調(diào)試選項(xiàng),可通過(guò) 菜單?-> 選項(xiàng) -> 調(diào)試設(shè)置?來(lái)配置:

新手一般不需更改這里的選項(xiàng),默認(rèn)已配置好,可以直接使用。建議在對(duì)?OllyDBG?已比較熟的情況下再來(lái)進(jìn)行配置。上面那個(gè)異常標(biāo)簽中的選項(xiàng)經(jīng)常會(huì)在脫殼中用到,建議在有一定調(diào)試基礎(chǔ)后學(xué)脫殼時(shí)再配置這里。

除了直接啟動(dòng)?OllyDBG?來(lái)調(diào)試外,我們還可以把?OllyDBG?添加到資源管理器右鍵菜單,這樣我們就可以直接在?.exe?及?.dll?文件上點(diǎn)右鍵選擇 "?用Ollydbg打開(kāi) "?菜單來(lái)進(jìn)行調(diào)試。要把?OllyDBG?添加到資源管理器右鍵菜單,只需點(diǎn) 菜單 -> 選項(xiàng) -> 添加到瀏覽器,將會(huì)出現(xiàn)一個(gè)對(duì)話(huà)框,先點(diǎn)擊 "?添加?Ollydbg?到系統(tǒng)資源管理器菜單 ",再點(diǎn)擊 ”完成” 按鈕即可。要從右鍵菜單中刪除也很簡(jiǎn)單,還是這個(gè)對(duì)話(huà)框,點(diǎn)擊 "?從系統(tǒng)資源管理器菜單刪除?Ollydbg ",再點(diǎn)擊”完成”就行了。

OllyDBG?支持插件功能,插件的安裝也很簡(jiǎn)單,只要把下載的插件(一般是個(gè)?DLL?文件)復(fù)制到?OllyDBG?安裝目錄下的?PLUGIN?目錄中就可以了,OllyDBG?啟動(dòng)時(shí)會(huì)自動(dòng)識(shí)別。要注意的是?OllyDBG?1.10?對(duì)插件的個(gè)數(shù)有限制,最多不能超過(guò)?32?個(gè),否則會(huì)出錯(cuò)。建議插件不要添加的太多。
到這里基本配置就完成了,OllyDBG?把所有配置都放在安裝目錄下的?ollydbg.ini?文件中。

?

?

二、基本調(diào)試方法

?

OllyDBG?有三種方式來(lái)載入程序進(jìn)行調(diào)試:

  • 一種是點(diǎn)擊 菜單 ->?文件 -> 打開(kāi)?( 快捷鍵是?F3 )來(lái)打開(kāi)一個(gè)可執(zhí)行文件進(jìn)行調(diào)試,
  • 另一種是點(diǎn)擊 菜單 -> 文件 -> 附加,來(lái)附加到一個(gè)已運(yùn)行的進(jìn)程上進(jìn)行調(diào)試。注意這里要附加的程序必須已運(yùn)行。
  • 第三種就是用右鍵菜單來(lái)載入程序(不知這種算不算)。
  • 一般情況下我們選第一種方式。比如我們選擇一個(gè)?test.exe?來(lái)調(diào)試,通過(guò)菜單?文件->打開(kāi)?來(lái)載入這個(gè)程序,OllyDBG?中顯示的內(nèi)容將會(huì)是這樣:

    調(diào)試中我們經(jīng)常要用到的快捷鍵有這些:

    • F2:設(shè)置斷點(diǎn)。只要在光標(biāo)定位的位置(上圖中灰色條)按F2鍵即可,再按一次F2鍵則會(huì)刪除斷點(diǎn)。(相當(dāng)于?SoftICE?中的?F9)
    • F8:單步跳過(guò)。每按一次這個(gè)鍵執(zhí)行一條反匯編窗口中的一條指令,遇到?CALL?等子程序不進(jìn)入其代碼。(相當(dāng)于?SoftICE?中的?F10)
    • F7:單步步入。功能同單步步過(guò)(F8)類(lèi)似,區(qū)別是遇到?CALL?等子程序時(shí)會(huì)進(jìn)入其中,進(jìn)入后首先會(huì)停留在子程序的第一條指令上。(相當(dāng)于?SoftICE?中的?F8)
    • F4:運(yùn)行到選定位置。作用就是直接運(yùn)行到光標(biāo)所在位置處暫停。(相當(dāng)于?SoftICE?中的?F7)
    • F9:運(yùn)行。按下這個(gè)鍵如果沒(méi)有設(shè)置相應(yīng)斷點(diǎn)的話(huà),被調(diào)試的程序?qū)⒅苯娱_(kāi)始運(yùn)行。(相當(dāng)于?SoftICE?中的?F5)
    • CTR + F9:執(zhí)行到返回。此命令在執(zhí)行到一個(gè)?ret?(返回指令)指令時(shí)暫停,常用于從系統(tǒng)領(lǐng)空返回到我們調(diào)試的程序領(lǐng)空。(相當(dāng)于?SoftICE?中的?F12)
    • ALT + F9:執(zhí)行到用戶(hù)代碼。可用于從系統(tǒng)領(lǐng)空快速返回到我們調(diào)試的程序領(lǐng)空。(相當(dāng)于?SoftICE?中的?F11)

    上面提到的幾個(gè)快捷鍵對(duì)于一般的調(diào)試基本上已夠用了。要開(kāi)始調(diào)試只需設(shè)置好斷點(diǎn),找到你感興趣的代碼段再按?F8?或?F7?鍵來(lái)一條條分析指令功能就可以了

    ?

    ?

    字串參考

    ?

    Crackme?#3?鏈接:https://pan.baidu.com/s/1AVJliU_L9BrqIrTVJBL8dw?? ?提取碼:un9n?

    上一篇是使用入門(mén),現(xiàn)在我們開(kāi)始正式進(jìn)入破解。今天的目標(biāo)程序是看雪兄《加密與解密》第一版附帶光盤(pán)中的?crackmes.cjb.NET?鏡像打包中的?CFF?Crackme?#3,采用用戶(hù)名/序列號(hào)保護(hù)方式。原版加了個(gè)?UPX?的殼。剛開(kāi)始學(xué)破解先不涉及殼的問(wèn)題,我們主要是熟悉用?OllyDBG?來(lái)破解的一般方法。我這里把殼脫掉來(lái)分析,附件是脫殼后的文件,直接就可以拿來(lái)用。先說(shuō)一下一般軟件破解的流程:拿到一個(gè)軟件先別接著馬上用?OllyDBG?調(diào)試,先運(yùn)行一下,有幫助文檔的最好先看一下幫助,熟悉一下軟件的使用方法,再看看注冊(cè)的方式。如果是序列號(hào)方式可以先輸個(gè)假的來(lái)試一下,看看有什么反應(yīng),也給我們破解留下一些有用的線(xiàn)索。如果沒(méi)有輸入注冊(cè)碼的地方,要考慮一下是不是讀取注冊(cè)表或?Key?文件(一般稱(chēng)?keyfile,就是程序讀取一個(gè)文件中的內(nèi)容來(lái)判斷是否注冊(cè)),這些可以用其它工具來(lái)輔助分析。如果這些都不是,原程序只是一個(gè)功能不全的試用版,那要注冊(cè)為正式版本就要自己來(lái)寫(xiě)代碼完善了。有點(diǎn)跑題了,呵呵。獲得程序的一些基本信息后,還要用查殼的工具來(lái)查一下程序是否加了殼,若沒(méi)殼的話(huà)看看程序是什么編譯器編的,如?VC、Delphi、VB?等。這樣的查殼工具有?PEiD?和?FI。有殼的話(huà)我們要盡量脫了殼后再來(lái)用?OllyDBG?調(diào)試,特殊情況下也可帶殼調(diào)試。下面進(jìn)入正題:
    我們先來(lái)運(yùn)行一下這個(gè)?crackme(用?PEiD?檢測(cè)顯示是?Delphi?編的),界面如圖:

    這個(gè)?crackme?已經(jīng)把用戶(hù)名和注冊(cè)碼都輸好了,省得我們動(dòng)手^_^。我們?cè)谀莻€(gè)“Register?now?!”按鈕上點(diǎn)擊一下,將會(huì)跳出一個(gè)對(duì)話(huà)框:

    好了,今天我們就從這個(gè)錯(cuò)誤對(duì)話(huà)框中顯示的“Wrong?Serial,?try?again!”來(lái)入手。啟動(dòng)?OllyDBG,選擇菜單?文件->打開(kāi)?載入?CrackMe3.exe?文件,我們會(huì)停在這里:

    我們?cè)诜磪R編窗口中右擊,出來(lái)一個(gè)菜單,我們?cè)?查找->所有參考文本字串?上左鍵點(diǎn)擊:

    當(dāng)然如果用上面那個(gè)?超級(jí)字串參考+?插件會(huì)更方便。但我們的目標(biāo)是熟悉?OllyDBG?的一些操作,我就盡量使用?OllyDBG?自帶的功能,少用插件。好了,現(xiàn)在出來(lái)另一個(gè)對(duì)話(huà)框,我們?cè)谶@個(gè)對(duì)話(huà)框里右擊,選擇”查找文本”菜單項(xiàng),輸入“Wrong?Serial,?try?again!”的開(kāi)頭單詞“Wrong”(注意這里查找內(nèi)容要區(qū)分大小寫(xiě))來(lái)查找,找到一處:

    在我們找到的字串上右擊,再在出來(lái)的菜單上點(diǎn)擊”反匯編窗口中跟隨”,我們來(lái)到這里:

    見(jiàn)上圖,為了看看是否還有其他的參考,可以通過(guò)選擇右鍵菜單查找參考->立即數(shù),會(huì)出來(lái)一個(gè)對(duì)話(huà)框:

    分別雙擊上面標(biāo)出的兩個(gè)地址,我們會(huì)來(lái)到對(duì)應(yīng)的位置:

    00440F79?|.?BA?8C104400? ? ? ?MOV?EDX,CrackMe3.0044108C?????????????;?ASCII?“Wrong?Serial,try?again!”
    00440F7E?|.?A1?442C4400? ? ? ?MOV?EAX,DWORD?PTR?DS:[442C44]
    00440F83?|.?8B00? ? ? ? ? ? ? ? ? ? ?MOV?EAX,DWORD?PTR?DS:[EAX]
    00440F85?|.?E8?DEC0FFFF? ? ?CALL?CrackMe3.0043D068
    00440F8A?|.?EB?18? ? ? ? ? ? ? ? ? ?JMP?SHORT?CrackMe3.00440FA4
    00440F8C?|>?6A?00? ? ? ? ? ? ? ? ? PUSH?0
    00440F8E?|.?B9?80104400? ? ? ?MOV?ECX,CrackMe3.00441080?????????????;?ASCII?“Beggar?off!”
    00440F93?|.?BA?8C104400? ? ? ?MOV?EDX,CrackMe3.0044108C?????????????;?ASCII?“Wrong?Serial,try?again!”
    00440F98?|.?A1?442C4400? ? ? ?MOV?EAX,DWORD?PTR?DS:[442C44]
    00440F9D?|.?8B00? ? ? ? ? ? ? ? ? ? MOV?EAX,DWORD?PTR?DS:[EAX]
    00440F9F?|.?E8?C4C0FFFF?????CALL?CrackMe3.0043D068

    我們?cè)诜磪R編窗口中向上滾動(dòng)一下再看看:

    00440F2C |. 8B45 FC ? ? ? ? MOV EAX,DWORD PTR SS:[EBP-4]
    00440F2F |. BA 14104400 ? ? MOV EDX,CrackMe3.00441014 ? ? ? ? ? ? ; ASCII “Registered User”
    00440F34 |. E8 F32BFCFF ? ? CALL CrackMe3.00403B2C ? ? ? ? ? ? ? ?; 關(guān)鍵,要用F7跟進(jìn)去
    00440F39 |. 75 51 ? ? ? ? ? JNZ SHORT CrackMe3.00440F8C ? ? ? ? ? ; 這里跳走就完蛋
    00440F3B |. 8D55 FC ? ? ? ? LEA EDX,DWORD PTR SS:[EBP-4]
    00440F3E |. 8B83 C8020000 ? MOV EAX,DWORD PTR DS:[EBX+2C8]
    00440F44 |. E8 D7FEFDFF ? ? CALL CrackMe3.00420E20
    00440F49 |. 8B45 FC ? ? ? ? MOV EAX,DWORD PTR SS:[EBP-4]
    00440F4C |. BA 2C104400 ? ? MOV EDX,CrackMe3.0044102C ? ? ? ? ? ? ; ASCII “GFX-754-IER-954”
    00440F51 |. E8 D62BFCFF ? ? CALL CrackMe3.00403B2C ? ? ? ? ? ? ? ?; 關(guān)鍵,要用F7跟進(jìn)去
    00440F56 |. 75 1A ? ? ? ? ? JNZ SHORT CrackMe3.00440F72 ? ? ? ? ? ; 這里跳走就完蛋
    00440F58 |. 6A 00 PUSH 0
    00440F5A |. B9 3C104400 ? ? MOV ECX,CrackMe3.0044103C ? ? ? ? ? ? ; ASCII “CrackMe cracked successfully”
    00440F5F |. BA 5C104400 ? ? MOV EDX,CrackMe3.0044105C ? ? ? ? ? ? ; ASCII “Congrats! You cracked this CrackMe!”
    00440F64 |. A1 442C4400 ? ? MOV EAX,DWORD PTR DS:[442C44]
    00440F69 |. 8B00 ? ? ? ? ? ?MOV EAX,DWORD PTR DS:[EAX]
    00440F6B |. E8 F8C0FFFF ? ? CALL CrackMe3.0043D068
    00440F70 |. EB 32 ? ? ? ? ? JMP SHORT CrackMe3.00440FA4
    00440F72 |> 6A 00 ? ? ? ? ? PUSH 0
    00440F74 |. B9 80104400 ? ? MOV ECX,CrackMe3.00441080 ? ? ? ? ? ? ; ASCII “Beggar off!”
    00440F79 |. BA 8C104400 ? ? MOV EDX,CrackMe3.0044108C ? ? ? ? ? ? ; ASCII “Wrong Serial,try again!”
    00440F7E |. A1 442C4400 ? ? MOV EAX,DWORD PTR DS:[442C44]
    00440F83 |. 8B00 ? ? ? ? ? ?MOV EAX,DWORD PTR DS:[EAX]
    00440F85 |. E8 DEC0FFFF ? ? CALL CrackMe3.0043D068
    00440F8A |. EB 18 ? ? ? ? ? JMP SHORT CrackMe3.00440FA4
    00440F8C |> 6A 00 ? ? ? ? ? PUSH 0
    00440F8E |. B9 80104400 ? ? MOV ECX,CrackMe3.00441080 ? ? ? ? ? ? ; ASCII “Beggar off!”
    00440F93 |. BA 8C104400 ? ? MOV EDX,CrackMe3.0044108C ? ? ? ? ? ? ; ASCII “Wrong Serial,try again!”
    00440F98 |. A1 442C4400 ? ? MOV EAX,DWORD PTR DS:[442C44]
    00440F9D |. 8B00 ? ? ? ? ? ?MOV EAX,DWORD PTR DS:[EAX]
    00440F9F |. E8 C4C0FFFF ? ? CALL CrackMe3.0043D068

    大家注意看一下上面的注釋,我在上面標(biāo)了兩個(gè)關(guān)鍵點(diǎn)。有人可能要問(wèn),你怎么知道那兩個(gè)地方是關(guān)鍵點(diǎn)?其實(shí)很簡(jiǎn)單,我是根據(jù)查看是哪條指令跳到 “wrong?serial,try?again” 這條字串對(duì)應(yīng)的指令來(lái)決定的。如果你在?調(diào)試選項(xiàng)->CPU?標(biāo)簽中把”顯示跳轉(zhuǎn)路徑”及其下面的兩個(gè)”如跳轉(zhuǎn)未實(shí)現(xiàn)則顯示灰色路徑”、”顯示跳轉(zhuǎn)到選定命令的路徑”都選上的話(huà),就會(huì)看到是從什么地方跳到出錯(cuò)字串處的:

    我們?cè)谏蠄D中地址?00440F2C?處按?F2?鍵設(shè)個(gè)斷點(diǎn),現(xiàn)在我們按?F9?鍵,程序已運(yùn)行起來(lái)了。我在上面那個(gè)編輯框中隨便輸入一下,如?CCDebuger,下面那個(gè)編輯框我還保留為原來(lái)的“754-GFX-IER-954”,我們點(diǎn)一下那個(gè)“Register?now?!”按鈕,呵,OllyDBG?跳了出來(lái),暫停在我們下的斷點(diǎn)處。我們看一下信息窗口,你應(yīng)該發(fā)現(xiàn)了你剛才輸入的內(nèi)容了吧?我這里顯示是這樣:

    堆棧?SS:[0012F9AC]=00D44DB4,?(ASCII?“CCDebuger”)
    EAX=00000009

    上面的內(nèi)存地址?00D44DB4?中就是我們剛才輸入的內(nèi)容,我這里是?CCDebuger。你可以在?堆棧?SS:[0012F9AC]=00D44DB4,?(ASCII?“CCDebuger”)?這條內(nèi)容上左擊選擇一下,再點(diǎn)右鍵,在彈出菜單中選擇”數(shù)據(jù)窗口中跟隨數(shù)值”,你就會(huì)在下面的數(shù)據(jù)窗口中看到你剛才輸入的內(nèi)容。而?EAX=00000009?指的是你輸入內(nèi)容的長(zhǎng)度。如我輸入的?CCDebuger?是9個(gè)字符。如下圖所示:

    現(xiàn)在我們來(lái)按?F8?鍵一步步分析一下:

    00440F2C?|.?8B45?FC?????????MOV?EAX,DWORD?PTR?SS:[EBP-4]??????????;?把我們輸入的內(nèi)容送到EAX,我這里是“CCDebuger”
    00440F2F?|.?BA?14104400?????MOV?EDX,CrackMe3.00441014?????????????;?ASCII?“Registered?User”
    00440F34?|.?E8?F32BFCFF?????CALL?CrackMe3.00403B2C????????????????;?關(guān)鍵,要用F7跟進(jìn)去
    00440F39?|.?75?51???????????JNZ?SHORT?CrackMe3.00440F8C???????????;?這里跳走就完蛋

    當(dāng)我們按?F8?鍵走到?00440F34?|.?E8?F32BFCFF?????CALL?CrackMe3.00403B2C?這一句時(shí),我們按一下?F7?鍵,進(jìn)入這個(gè)?CALL,進(jìn)去后光標(biāo)停在這一句:

    我們所看到的那些?PUSH?EBX、?PUSH?ESI?等都是調(diào)用子程序保存堆棧時(shí)用的指令,不用管它,按?F8?鍵一步步過(guò)來(lái),我們只關(guān)心關(guān)鍵部分:

    00403B2C?/$?53??????????????PUSH?EBX
    00403B2D?|.?56??????????????PUSH?ESI
    00403B2E?|.?57??????????????PUSH?EDI
    00403B2F?|.?89C6????????????MOV?ESI,EAX?????????????????????????;?把EAX內(nèi)我們輸入的用戶(hù)名送到?ESI
    00403B31?|.?89D7????????????MOV?EDI,EDX?????????????????????????;?把EDX內(nèi)的數(shù)據(jù)“Registered?User”送到EDI
    00403B33?|.?39D0????????????CMP?EAX,EDX?????????????????????????;?用“Registered?User”和我們輸入的用戶(hù)名作比較
    00403B35?|.?0F84?8F000000???JE?CrackMe3.00403BCA????????????????;?相同則跳
    00403B3B?|.?85F6????????????TEST?ESI,ESI????????????????????????;?看看ESI中是否有數(shù)據(jù),主要是看看我們有沒(méi)有輸入用戶(hù)名
    00403B3D?|.?74?68???????????JE?SHORT?CrackMe3.00403BA7??????????;?用戶(hù)名為空則跳
    00403B3F?|.?85FF????????????TEST?EDI,EDI
    00403B41?|.?74?6B???????????JE?SHORT?CrackMe3.00403BAE
    00403B43?|.?8B46?FC?????????MOV?EAX,DWORD?PTR?DS:[ESI-4]????????;?用戶(hù)名長(zhǎng)度送EAX
    00403B46?|.?8B57?FC?????????MOV?EDX,DWORD?PTR?DS:[EDI-4]????????;?“Registered?User”字串的長(zhǎng)度送EDX
    00403B49?|.?29D0????????????SUB?EAX,EDX?????????????????????????;?把用戶(hù)名長(zhǎng)度和“Registered?User”字串長(zhǎng)度相減
    00403B4B?|.?77?02???????????JA?SHORT?CrackMe3.00403B4F??????????;?用戶(hù)名長(zhǎng)度大于“Registered?User”長(zhǎng)度則跳
    00403B4D?|.?01C2????????????ADD?EDX,EAX?????????????????????????;?把減后值與“Registered?User”長(zhǎng)度相加,即用戶(hù)名長(zhǎng)度
    00403B4F?|>?52??????????????PUSH?EDX
    00403B50?|.?C1EA?02?????????SHR?EDX,2???????????????????????????;?用戶(hù)名長(zhǎng)度值右移2位,這里相當(dāng)于長(zhǎng)度除以4
    00403B53?|.?74?26???????????JE?SHORT?CrackMe3.00403B7B??????????;?上面的指令及這條指令就是判斷用戶(hù)名長(zhǎng)度最少不能低于4
    00403B55?|>?8B0E????????????MOV?ECX,DWORD?PTR?DS:[ESI]??????????;?把我們輸入的用戶(hù)名送到ECX
    00403B57?|.?8B1F????????????MOV?EBX,DWORD?PTR?DS:[EDI]??????????;?把“Registered?User”送到EBX
    00403B59?|.?39D9????????????CMP?ECX,EBX?????????????????????????;?比較
    00403B5B?|.?75?58???????????JNZ?SHORT?CrackMe3.00403BB5?????????;?不等則完蛋

    根據(jù)上面的分析,我們知道用戶(hù)名必須是“Registered?User”。我們按?F9?鍵讓程序運(yùn)行,出現(xiàn)錯(cuò)誤對(duì)話(huà)框,點(diǎn)確定,重新在第一個(gè)編輯框中輸入“Registered?User”,再次點(diǎn)擊那個(gè)“Register?now?!”按鈕,被?OllyDBG?攔下。因?yàn)榈刂?00440F34?處的那個(gè)?CALL?我們已經(jīng)分析清楚了,這次就不用再按?F7?鍵跟進(jìn)去了,直接按?F8?鍵通過(guò)。我們一路按?F8?鍵,來(lái)到第二個(gè)關(guān)鍵代碼處:

    00440F49?|.?8B45?FC?????????MOV?EAX,DWORD?PTR?SS:[EBP-4]?????????;?取輸入的注冊(cè)碼
    00440F4C?|.?BA?2C104400?????MOV?EDX,CrackMe3.0044102C????????????;?ASCII?“GFX-754-IER-954”
    00440F51?|.?E8?D62BFCFF?????CALL?CrackMe3.00403B2C???????????????;?關(guān)鍵,要用F7跟進(jìn)去
    00440F56?|.?75?1A???????????JNZ?SHORT?CrackMe3.00440F72??????????;?這里跳走就完蛋

    大家注意看一下,地址?00440F51?處的?CALL?CrackMe3.00403B2C?和上面我們分析的地址?00440F34?處的?CALL?CrackMe3.00403B2C?是不是匯編指令都一樣啊?這說(shuō)明檢測(cè)用戶(hù)名和注冊(cè)碼是用的同一個(gè)子程序。而這個(gè)子程序?CALL?我們?cè)谏厦嬉呀?jīng)分析過(guò)了。我們執(zhí)行到現(xiàn)在可以很容易得出結(jié)論,這個(gè)?CALL?也就是把我們輸入的注冊(cè)碼與?00440F4C?地址處指令后的“GFX-754-IER-954”作比較,相等則?OK。好了,我們已經(jīng)得到足夠的信息了。現(xiàn)在我們?cè)诓藛?查看->斷點(diǎn)?上點(diǎn)擊一下,打開(kāi)斷點(diǎn)窗口(也可以通過(guò)組合鍵?ALT+B?或點(diǎn)擊工具欄上那個(gè)“B”圖標(biāo)打開(kāi)斷點(diǎn)窗口):

    為什么要做這一步,而不是把這個(gè)斷點(diǎn)刪除呢?這里主要是為了保險(xiǎn)一點(diǎn),萬(wàn)一分析錯(cuò)誤,我們還要接著分析,要是把斷點(diǎn)刪除了就要做一些重復(fù)工作了。還是先禁用一下,如果經(jīng)過(guò)實(shí)際驗(yàn)證證明我們的分析是正確的,再刪不遲。現(xiàn)在我們把斷點(diǎn)禁用,在?OllyDBG?中按?F9?鍵讓程序運(yùn)行。輸入我們經(jīng)分析得出的內(nèi)容:
    用戶(hù)名:Registered?User
    注冊(cè)碼:GFX-754-IER-954
    點(diǎn)擊“Register?now?!”按鈕,呵呵,終于成功了:

    ?

    ?

    函數(shù)參考

    ?

    現(xiàn)在進(jìn)入第三篇,這一篇我們重點(diǎn)講解怎樣使用?OllyDBG?中的函數(shù)參考(即名稱(chēng)參考)功能。仍然選擇?crackmes.cjb.Net?鏡像打包中的一個(gè)名稱(chēng)為?CrackHead?的crackme。老規(guī)矩,先運(yùn)行一下這個(gè)程序看看:

    呵,竟然沒(méi)找到輸入注冊(cè)碼的地方!別急,我們點(diǎn)一下程序上的那個(gè)菜單“Shit”(真是?Shit?啊,呵呵),在下拉菜單中選“Try?It”,會(huì)來(lái)到如下界面:

    我們點(diǎn)一下那個(gè)“Check?It”按鈕試一下,哦,竟然沒(méi)反應(yīng)!我再輸個(gè)“78787878”試試,還是沒(méi)反應(yīng)。再試試輸入字母或其它字符,輸不進(jìn)去。由此判斷注冊(cè)碼應(yīng)該都是數(shù)字,只有輸入正確的注冊(cè)碼才有動(dòng)靜。用?PEiD?檢測(cè)一下,結(jié)果為?MASM32?/?TASM32,怪不得程序比較小。信息收集的差不多了,現(xiàn)在關(guān)掉這個(gè)程序,我們用?OllyDBG?載入,按?F9?鍵直接讓它運(yùn)行起來(lái),依次點(diǎn)擊上面圖中所說(shuō)的菜單,使被調(diào)試程序顯示如上面的第二個(gè)圖。先不要點(diǎn)那個(gè)“Check?It”按鈕,保留上圖的狀態(tài)。現(xiàn)在我們沒(méi)有什么字串好參考了,我們就在?API?函數(shù)上下斷點(diǎn),來(lái)讓被調(diào)試程序中斷在我們希望的地方。我們?cè)?OllyDBG?的反匯編窗口中右擊鼠標(biāo),在彈出菜單中選擇?查找->當(dāng)前模塊中的名稱(chēng)?(標(biāo)簽),或者我們通過(guò)按?CTR+N?組合鍵也可以達(dá)到同樣的效果(注意在進(jìn)行此操作時(shí)要在?OllyDBG?中保證是在當(dāng)前被調(diào)試程序的領(lǐng)空,我在第一篇中已經(jīng)介紹了領(lǐng)空的概念,如我這里調(diào)試這個(gè)程序時(shí)?OllyDBG?的標(biāo)題欄顯示的就是“[CPU?-?主線(xiàn)程,?模塊?-?CrackHea]”,這表明我們當(dāng)前在被調(diào)試程序的領(lǐng)空)。通過(guò)上面的操作后會(huì)彈出一個(gè)對(duì)話(huà)框,如圖:

    對(duì)于這樣的編輯框中輸注冊(cè)碼的程序我們要設(shè)斷點(diǎn)首選的?API?函數(shù)就是?GetDlgItemText?及?GetWindowText。每個(gè)函數(shù)都有兩個(gè)版本,一個(gè)是?ASCII?版,在函數(shù)后添加一個(gè)?A?表示,如?GetDlgItemTextA,另一個(gè)是?UNICODE?版,在函數(shù)后添加一個(gè)?W?表示。如?GetDlgItemTextW。對(duì)于編譯為?UNCODE?版的程序可能在?Win98?下不能運(yùn)行,因?yàn)?Win98?并非是完全支持?UNICODE?的系統(tǒng)。而?NT?系統(tǒng)則從底層支持?UNICODE,它可以在操作系統(tǒng)內(nèi)對(duì)字串進(jìn)行轉(zhuǎn)換,同時(shí)支持?ASCII?和?UNICODE?版本函數(shù)的調(diào)用。一般我們打開(kāi)的程序看到的調(diào)用都是?ASCII?類(lèi)型的函數(shù),以“A”結(jié)尾。又跑題了,呵呵。現(xiàn)在回到我們調(diào)試的程序上來(lái),我們現(xiàn)在就是要找一下我們調(diào)試的程序有沒(méi)有調(diào)用?GetDlgItemTextA?或?GetWindowTextA?函數(shù)。還好,找到一個(gè)?GetWindowTextA。在這個(gè)函數(shù)上右擊,在彈出菜單上選擇”在每個(gè)參考上設(shè)置斷點(diǎn)”,我們會(huì)在?OllyDBG?窗口最下面的那個(gè)狀態(tài)欄里看到”已設(shè)置?2?個(gè)斷點(diǎn)”。另一種方法就是那個(gè)?GetWindowTextA?函數(shù)上右擊,在彈出菜單上選擇”查找輸入函數(shù)參考”(或者按回車(chē)鍵),將會(huì)出現(xiàn)下面的對(duì)話(huà)框:

    看上圖,我們可以把兩條都設(shè)上斷點(diǎn)。這個(gè)程序只需在第一條指令設(shè)斷點(diǎn)就可以了。好,我們現(xiàn)在按前面提到的第一條方法,就是”在每個(gè)參考上設(shè)置斷點(diǎn)”,這樣上圖中的兩條指令都會(huì)設(shè)上斷點(diǎn)。斷點(diǎn)設(shè)好后我們轉(zhuǎn)到我們調(diào)試的程序上來(lái),現(xiàn)在我們?cè)诒晃覀冋{(diào)試的程序上點(diǎn)擊那個(gè)“Check?It”按鈕,被?OllyDBG?斷下:

    00401323?|.?E8?4C010000?????????CALL?<JMP.&USER32.GetWindowTextA>???????????;?GetWindowTextA
    00401328?|.?E8?A5000000?????????CALL?CrackHea.004013D2??????????????????????;?關(guān)鍵,要按F7鍵跟進(jìn)去
    0040132D?|.?3BC6????????????????CMP?EAX,ESI?????????????????????????????????;?比較
    0040132F?|.?75?42???????????????JNZ?SHORT?CrackHea.00401373?????????????????;?不等則完蛋
    00401331?|.?EB?2C???????????????JMP?SHORT?CrackHea.0040135F
    00401333?|.?4E?6F?77?20?7>??????ASCII?“Now?write?a?keyg”
    00401343?|.?65?6E?20?61?6>??????ASCII?“en?and?tut?and?y”
    00401353?|.?6F?75?27?72?6>??????ASCII?“ou&apos;re?done.”,0
    0040135F?|>?6A?00???????????????PUSH?0??????????????????????????????????????;?Style?=?MB_OK|MB_APPLMODAL
    00401361?|.?68?0F304000?????????PUSH?CrackHea.0040300F??????????????????????;?Title?=?“Crudd&apos;s?Crack?Head”
    00401366?|.?68?33134000?????????PUSH?CrackHea.00401333??????????????????????;?Text?=?“Now?write?a?keygen?and?tut?and?you&apos;re?done.”
    0040136B?|.?FF75?08?????????????PUSH?DWORD?PTR?SS:[EBP+8]???????????????????;?hOwner
    0040136E?|.?E8?19010000?????????CALL?<JMP.&USER32.MessageBoxA>??????????????;?MessageBoxA

    從上面的代碼,我們很容易看出?00401328?地址處的?CALL?CrackHea.004013D2?是關(guān)鍵,必須仔細(xì)跟蹤。而注冊(cè)成功則會(huì)顯示一個(gè)對(duì)話(huà)框,標(biāo)題是“Crudd&apos;s?Crack?Head”,對(duì)話(huà)框顯示的內(nèi)容是“Now?write?a?keygen?and?tut?and?you&apos;re?done.”現(xiàn)在我按一下?F8,準(zhǔn)備步進(jìn)到?00401328?地址處的那條?CALL?CrackHea.004013D2?指令后再按?F7?鍵跟進(jìn)去。等等,怎么回事?怎么按一下?F8?鍵跑到這來(lái)了:

    00401474?-?FF25?30204000??????JMP?DWORD?PTR?DS:[<&USER32.LoadCursorA>]?????;?USER32.LoadCursorA
    00401480?-?FF25?20204000??????JMP?DWORD?PTR?DS:[<&USER32.LoadMenuA>]???????;?USER32.LoadMenuA
    0040148C?$-?FF25?24204000??????JMP?DWORD?PTR?DS:[<&USER32.MessageBoxA>]?????;?USER32.MessageBoxA

    原來(lái)是跳到另一個(gè)斷點(diǎn)了。這個(gè)斷點(diǎn)我們不需要,按一下?F2?鍵刪掉它吧。刪掉?00401474?地址處的斷點(diǎn)后,我再按?F8?鍵,呵,完了,跑到?User32.dll?的領(lǐng)空了。看一下?OllyDBG?的標(biāo)題欄:“[CPU?-?主線(xiàn)程,?模塊?-?USER32],跑到系統(tǒng)領(lǐng)空了,OllyDBG?反匯編窗口中顯示代碼是這樣:

    77D3213C?6A?0C?????????????????PUSH?0C
    77D3213E?68?A021D377???????????PUSH?USER32.77D321A0
    77D32143?E8?7864FEFF???????????CALL?USER32.77D185C0

    怎么辦?別急,我們按一下?ALT+F9?組合鍵,呵,回來(lái)了:

    00401328?|.?E8?A5000000????????CALL?CrackHea.004013D2?????????????????????;?關(guān)鍵,要按F7鍵跟進(jìn)去
    0040132D?|.?3BC6???????????????CMP?EAX,ESI????????????????????????????????;?比較
    0040132F?|.?75?42??????????????JNZ?SHORT?CrackHea.00401373????????????????;?不等則完蛋

    光標(biāo)停在?00401328?地址處的那條指令上。現(xiàn)在我們按?F7?鍵跟進(jìn):

    004013D2?/$?56????????????????PUSH?ESI????????????????????????????????????;?ESI入棧
    004013D3?|.?33C0??????????????XOR?EAX,EAX?????????????????????????????????;?EAX清零
    004013D5?|.?8D35?C4334000?????LEA?ESI,DWORD?PTR?DS:[4033C4]???????????????;?把注冊(cè)碼框中的數(shù)值送到ESI
    004013DB?|.?33C9??????????????XOR?ECX,ECX?????????????????????????????????;?ECX清零
    004013DD?|.?33D2??????????????XOR?EDX,EDX?????????????????????????????????;?EDX清零
    004013DF?|.?8A06??????????????MOV?AL,BYTE?PTR?DS:[ESI]????????????????????;?把注冊(cè)碼中的每個(gè)字符送到AL
    004013E1?|.?46????????????????INC?ESI?????????????????????????????????????;?指針加1,指向下一個(gè)字符
    004013E2?|.?3C?2D?????????????CMP?AL,2D???????????????????????????????????;?把取得的字符與16進(jìn)制值為2D的字符(即“-“)比較,這里主要用于判斷輸入的是不是負(fù)數(shù)
    004013E4?|.?75?08?????????????JNZ?SHORT?CrackHea.004013EE?????????????????;?不等則跳
    004013E6?|.?BA?FFFFFFFF???????MOV?EDX,-1??????????????????????????????????;?如果輸入的是負(fù)數(shù),則把-1送到EDX,即16進(jìn)制FFFFFFFF
    004013EB?|.?8A06??????????????MOV?AL,BYTE?PTR?DS:[ESI]????????????????????;?取“-“號(hào)后的第一個(gè)字符
    004013ED?|.?46????????????????INC?ESI?????????????????????????????????????;?指針加1,指向再下一個(gè)字符
    004013EE?|>?EB?0B?????????????JMP?SHORT?CrackHea.004013FB
    004013F0?|>?2C?30?????????????SUB?AL,30???????????????????????????????????;?每位字符減16進(jìn)制的30,因?yàn)檫@里都是數(shù)字,如1的ASCII碼是“31H”,減30H后為1,即我們平時(shí)看到的數(shù)值
    004013F2?|.?8D0C89????????????LEA?ECX,DWORD?PTR?DS:[ECX+ECX*4]????????????;?把前面運(yùn)算后保存在ECX中的結(jié)果乘5再送到ECX
    004013F5?|.?8D0C48????????????LEA?ECX,DWORD?PTR?DS:[EAX+ECX*2]????????????;?每位字符運(yùn)算后的值與2倍上一位字符運(yùn)算后值相加后送ECX
    004013F8?|.?8A06??????????????MOV?AL,BYTE?PTR?DS:[ESI]????????????????????;?取下一個(gè)字符
    004013FA?|.?46????????????????INC?ESI?????????????????????????????????????;?指針加1,指向再下一個(gè)字符
    004013FB?|>?0AC0??????????????OR?AL,AL
    004013FD?|.^?75?F1????????????JNZ?SHORT?CrackHea.004013F0?????????????????;?上面一條和這一條指令主要是用來(lái)判斷是否已把用戶(hù)輸入的注冊(cè)碼計(jì)算完
    004013FF?|.?8D040A????????????LEA?EAX,DWORD?PTR?DS:[EDX+ECX]??????????????;?把EDX中的值與經(jīng)過(guò)上面運(yùn)算后的ECX中值相加送到EAX
    00401402?|.?33C2??????????????XOR?EAX,EDX?????????????????????????????????;?把EAX與EDX異或。如果我們輸入的是負(fù)數(shù),則此處功能就是把EAX中的值取反
    00401404?|.?5E????????????????POP?ESI?????????????????????????????????????;?ESI出棧。看到這條和下一條指令,我們要考慮一下這個(gè)ESI的值是哪里運(yùn)算得出的呢?
    00401405?|.?81F6?53757A79?????XOR?ESI,797A7553????????????????????????????;?把ESI中的值與797A7553H異或
    0040140B?\.?C3????????????????RETN


    這里留下了一個(gè)問(wèn)題:那個(gè)?ESI?寄存器中的值是從哪運(yùn)算出來(lái)的?先不管這里,我們接著按?F8?鍵往下走,來(lái)到?0040140B?地址處的那條?RETN?指令(這里可以通過(guò)在調(diào)試選項(xiàng)的”命令”標(biāo)簽中勾選”使用?RET?代替?RETN”來(lái)更改返回指令的顯示方式),再按一下?F8,我們就走出?00401328?地址處的那個(gè)?CALL?了。現(xiàn)在我們回到了這里:

    0040132D?|.?3BC6?????????????CMP?EAX,ESI??????????????????????????????????;?比較
    0040132F?|.?75?42????????????JNZ?SHORT?CrackHea.00401373??????????????????;?不等則完蛋

    光標(biāo)停在了?0040132D?地址處的那條指令上。根據(jù)前面的分析,我們知道?EAX?中存放的是我們輸入的注冊(cè)碼經(jīng)過(guò)計(jì)算后的值。我們來(lái)看一下信息窗口:

    ESI=E6B5F2F9
    EAX=FF439EBE

    左鍵選擇信息窗口中的?ESI=E6B5F2F9,再按右鍵,在彈出菜單上選”修改寄存器”,我們會(huì)看到這樣一個(gè)窗口:

    可能你的顯示跟我不一樣,因?yàn)檫@個(gè)?crackme?中已經(jīng)說(shuō)了每個(gè)機(jī)器的序列號(hào)不一樣。關(guān)掉上面的窗口,再對(duì)信息窗口中的?EAX=FF439EBE?做同樣操作:

    由上圖我們知道了原來(lái)前面分析的對(duì)我們輸入的注冊(cè)碼進(jìn)行處理后的結(jié)果就是把字符格式轉(zhuǎn)為數(shù)字格式。我們?cè)瓉?lái)輸入的是字串“12345666”,現(xiàn)在轉(zhuǎn)換為了數(shù)字?12345666。這下就很清楚了,隨便在上面那個(gè)修改?ESI?圖中顯示的有符號(hào)或無(wú)符號(hào)編輯框中復(fù)制一個(gè),粘貼到我們調(diào)試的程序中的編輯框中試一下:

    呵呵,成功了。且慢高興,這個(gè)?crackme?是要求寫(xiě)出注冊(cè)機(jī)的。我們先不要求寫(xiě)注冊(cè)機(jī),但注冊(cè)的算法我們要搞清楚。還記得我在前面說(shuō)到的那個(gè)?ESI?寄存器值的問(wèn)題嗎?現(xiàn)在看看我們上面的分析,其實(shí)對(duì)做注冊(cè)機(jī)來(lái)說(shuō)是沒(méi)有多少幫助的。要搞清注冊(cè)算法,必須知道上面那個(gè)?ESI?寄存器值是如何產(chǎn)生的,這弄清楚后才能真正清楚這個(gè)?crackme?算法。今天就先說(shuō)到這里,關(guān)于如何追出?ESI?寄存器的值我就留到下一篇-內(nèi)存斷點(diǎn)?中再講吧。

    ?

    ?

    內(nèi)存斷點(diǎn)

    ?

    還記得上一篇的內(nèi)容嗎?在那篇文章中我們分析后發(fā)現(xiàn)一個(gè)?ESI?寄存器值不知是從什么地方產(chǎn)生的,要弄清這個(gè)問(wèn)題必須要找到生成這個(gè)?ESI?值的計(jì)算部分。今天我們的任務(wù)就是使用?OllyDBG?的內(nèi)存斷點(diǎn)功能找到這個(gè)地方,搞清楚這個(gè)值是如何算出來(lái)的。這次分析的目標(biāo)程序還是上一篇的那個(gè)?crackme,附件我就不再上傳了,用上篇中的附件就可以了。下面我們開(kāi)始:
    還記得我們上篇中所說(shuō)的關(guān)鍵代碼的地方嗎?溫習(xí)一下:

    00401323?|.?E8?4C010000?????????CALL?<JMP.&USER32.GetWindowTextA>???????????;?GetWindowTextA
    00401328?|.?E8?A5000000?????????CALL?CrackHea.004013D2??????????????????????;?關(guān)鍵,要按F7鍵跟進(jìn)去
    0040132D?|.?3BC6????????????????CMP?EAX,ESI?????????????????????????????????;?比較
    0040132F?|.?75?42???????????????JNZ?SHORT?CrackHea.00401373?????????????????;?不等則完蛋

    我們重新用?OllyDBG?載入目標(biāo)程序,F9運(yùn)行來(lái)到上面代碼所在的地方(你上次設(shè)的斷點(diǎn)應(yīng)該沒(méi)刪吧?),我們向上看看能不能找到那個(gè)?ESI?寄存器中最近是在哪里賦的值。哈哈,原來(lái)就在附近啊:

    我們現(xiàn)在知道?ESI?寄存器的值是從內(nèi)存地址?40339C?中送過(guò)來(lái)的,那內(nèi)存地址?40339C?中的數(shù)據(jù)是什么時(shí)候產(chǎn)生的呢?大家注意,我這里信息窗口中顯示的是?DS:[0040339C]=9FCF87AA,你那可能是?DS:[0040339C]=XXXXXXXX,這里的?XXXXXXXX?表示的是其它的值,就是說(shuō)與我這里顯示的?9FCF87AA?不一樣。我們按上圖的操作在數(shù)據(jù)窗口中看一下:

    從上圖我們可以看出內(nèi)存地址?40339C?處的值已經(jīng)有了,說(shuō)明早就算過(guò)了。現(xiàn)在怎么辦呢?我們考慮一下,看情況程序是把這個(gè)值算出來(lái)以后寫(xiě)在這個(gè)內(nèi)存地址,那我們要是能讓?OllyDBG?在程序開(kāi)始往這個(gè)內(nèi)存地址寫(xiě)東西的時(shí)候中斷下來(lái),不就有可能知道目標(biāo)程序是怎么算出這個(gè)值的嗎?說(shuō)干就干,我們?cè)?OllyDBG?的菜單上點(diǎn)?調(diào)試->重新開(kāi)始,或者按?CTR+F2?組合鍵(還可以點(diǎn)擊工具欄上的那個(gè)有兩個(gè)實(shí)心左箭頭的圖標(biāo))來(lái)重新載入程序。這時(shí)會(huì)跳出一個(gè)”進(jìn)程仍處于激活狀態(tài)”的對(duì)話(huà)框(我們可以在在調(diào)試選項(xiàng)的安全標(biāo)簽下把”終止活動(dòng)進(jìn)程時(shí)警告”這條前面的勾去掉,這樣下次就不會(huì)出現(xiàn)這個(gè)對(duì)話(huà)框了),問(wèn)我們是否要終止進(jìn)程。這里我們選”是”,程序被重新載入,我們停在下面這一句上:

    00401000?>/$?6A?00??????????????PUSH?0??????????????????????????????????????;?pModule?=?NULL

    現(xiàn)在我們就要來(lái)設(shè)內(nèi)存斷點(diǎn)了。在?OllyDBG?中一般我們用到的內(nèi)存斷點(diǎn)有內(nèi)存訪(fǎng)問(wèn)和內(nèi)存寫(xiě)入斷點(diǎn)。內(nèi)存訪(fǎng)問(wèn)斷點(diǎn)就是指程序訪(fǎng)問(wèn)內(nèi)存中我們指定的內(nèi)存地址時(shí)中斷,內(nèi)存寫(xiě)入斷點(diǎn)就是指程序往我們指定的內(nèi)存地址中寫(xiě)東西時(shí)中斷。更多關(guān)于斷點(diǎn)的知識(shí)大家可以參考?論壇精華7->基礎(chǔ)知識(shí)->斷點(diǎn)技巧->斷點(diǎn)原理?這篇?Lenus?兄弟寫(xiě)的《如何對(duì)抗硬件斷點(diǎn)之一?—?調(diào)試寄存器》文章,也可以看這個(gè)帖:http://bbs.pediy.com/showthread.PHP?threadid=10829。根據(jù)當(dāng)前我們調(diào)試的具體程序的情況,我們選用內(nèi)存寫(xiě)入斷點(diǎn)。還記得前面我叫大家記住的那個(gè)?40339C?內(nèi)存地址嗎?現(xiàn)在我們要用上了。我們先在?OllyDBG?的數(shù)據(jù)窗口中左鍵點(diǎn)擊一下,再右擊,會(huì)彈出一個(gè)如下圖所示的菜單。我們選擇其中的轉(zhuǎn)到->表達(dá)式(也可以左鍵點(diǎn)擊數(shù)據(jù)窗口后按?CTR+G?組合鍵)。如下圖:

    現(xiàn)在將會(huì)出現(xiàn)這樣一個(gè)對(duì)話(huà)框:
    ?
    我們?cè)谏厦婺莻€(gè)編輯框中輸入我們想查看內(nèi)容的內(nèi)存地址?40339C,然后點(diǎn)確定按鈕,數(shù)據(jù)窗口中顯示如下:

    我們可以看到,40339C?地址開(kāi)始處的這段內(nèi)存里面還沒(méi)有內(nèi)容。我們現(xiàn)在在?40339C?地址處后面的?HEX?數(shù)據(jù)或?ASCII?欄中按住左鍵往后拖放,選擇一段。內(nèi)存斷點(diǎn)的特性就是不管你選幾個(gè)字節(jié),OllyDBG?都會(huì)分配?4096?字節(jié)的內(nèi)存區(qū)。這里我就選從?40339C?地址處開(kāi)始的四個(gè)字節(jié),主要是為了讓大家提前了解一下硬件斷點(diǎn)的設(shè)法,因?yàn)橛布帱c(diǎn)最多只能選?4?個(gè)字節(jié)。選中部分會(huì)顯示為灰色。選好以后松開(kāi)鼠標(biāo)左鍵,在我們選中的灰色部分上右擊:

    經(jīng)過(guò)上面的操作,我們的內(nèi)存斷點(diǎn)就設(shè)好了(這里還有個(gè)要注意的地方:內(nèi)存斷點(diǎn)只在當(dāng)前調(diào)試的進(jìn)程中有效,就是說(shuō)你如果重新載入程序的話(huà)內(nèi)存斷點(diǎn)就自動(dòng)刪除了。且內(nèi)存斷點(diǎn)每一時(shí)刻只能有一個(gè)。就是說(shuō)你不能像按?F2?鍵那樣同時(shí)設(shè)置多個(gè)斷點(diǎn))。現(xiàn)在按?F9?鍵讓程序運(yùn)行,呵,OllyDBG?中斷了!

    7C932F39?8808???????????????????MOV?BYTE?PTR?DS:[EAX],CL????????????????????;?這就是我們第一次斷下來(lái)的地方
    7C932F3B?40?????????????????????INC?EAX
    7C932F3C?4F?????????????????????DEC?EDI
    7C932F3D?4E?????????????????????DEC?ESI
    7C932F3E?^?75?CB????????????????JNZ?SHORT?ntdll.7C932F0B
    7C932F40?8B4D?10????????????????MOV?ECX,DWORD?PTR?SS:[EBP+10]

    上面就是我們中斷后反匯編窗口中的代碼。如果你是其它系統(tǒng),如?Win98?的話(huà),可能會(huì)有所不同。沒(méi)關(guān)系,這里不是關(guān)鍵。我們看一下領(lǐng)空,原來(lái)是在?ntdll.dll?內(nèi)。系統(tǒng)領(lǐng)空,我們現(xiàn)在要考慮返回到程序領(lǐng)空。返回前我們看一下數(shù)據(jù)窗口:

    現(xiàn)在我們轉(zhuǎn)到反匯編窗口,右擊鼠標(biāo),在彈出菜單上選擇斷點(diǎn)->刪除內(nèi)存斷點(diǎn),這樣內(nèi)存斷點(diǎn)就被刪除了。

    現(xiàn)在我們來(lái)按一下?ALT+F9?組合鍵,我們來(lái)到下面的代碼:

    00401431?|.?8D35?9C334000??????LEA?ESI,DWORD?PTR?DS:[40339C]???????????????;?ALT+F9返回后來(lái)到的位置
    00401437?|.?0FB60D?EC334000????MOVZX?ECX,BYTE?PTR?DS:[4033EC]
    0040143E?|.?33FF???????????????XOR?EDI,EDI

    我們把反匯編窗口往上翻翻,呵,原來(lái)就在我們上一篇分析的代碼下面啊?

    現(xiàn)在我們?cè)?0040140C?地址處那條指令上按?F2?設(shè)置一個(gè)斷點(diǎn),現(xiàn)在我們按??CTR+F2?組合鍵重新載入程序,載入后按?F9?鍵運(yùn)行,我們將會(huì)中斷在我們剛才在?0040140C?地址下的那個(gè)斷點(diǎn)處:

    0040140C?/$?60?????????????????PUSHAD
    0040140D?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?/RootPathName?=?NULL
    0040140F?|.?E8?B4000000????????CALL?<JMP.&KERNEL32.GetDriveTypeA>??????????;?\GetDriveTypeA
    00401414?|.?A2?EC334000????????MOV?BYTE?PTR?DS:[4033EC],AL?????????????????;?磁盤(pán)類(lèi)型參數(shù)送內(nèi)存地址4033EC
    00401419?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?/pFileSystemNameSize?=?NULL
    0040141B?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|pFileSystemNameBuffer?=?NULL
    0040141D?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|pFileSystemFlags?=?NULL
    0040141F?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|pMaxFilenameLength?=?NULL
    00401421?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|pVolumeSerialNumber?=?NULL
    00401423?|.?6A?0B??????????????PUSH?0B?????????????????????????????????????;?|MaxVolumeNameSize?=?B?(11.)
    00401425?|.?68?9C334000????????PUSH?CrackHea.0040339C??????????????????????;?|VolumeNameBuffer?=?CrackHea.0040339C
    0040142A?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|RootPathName?=?NULL
    0040142C?|.?E8?A3000000????????CALL?<JMP.&KERNEL32.GetVolumeInformationA>??;?\GetVolumeInformationA
    00401431?|.?8D35?9C334000??????LEA?ESI,DWORD?PTR?DS:[40339C]???????????????;?把crackme程序所在分區(qū)的卷標(biāo)名稱(chēng)送到ESI
    00401437?|.?0FB60D?EC334000????MOVZX?ECX,BYTE?PTR?DS:[4033EC]??????????????;?磁盤(pán)類(lèi)型參數(shù)送ECX
    0040143E?|.?33FF???????????????XOR?EDI,EDI?????????????????????????????????;?把EDI清零
    00401440?|>?8BC1???????????????MOV?EAX,ECX?????????????????????????????????;?磁盤(pán)類(lèi)型參數(shù)送EAX
    00401442?|.?8B1E???????????????MOV?EBX,DWORD?PTR?DS:[ESI]??????????????????;?把卷標(biāo)名作為數(shù)值送到?EBX
    00401444?|.?F7E3???????????????MUL?EBX?????????????????????????????????????;?循環(huán)遞減取磁盤(pán)類(lèi)型參數(shù)值與卷標(biāo)名值相乘
    00401446?|.?03F8???????????????ADD?EDI,EAX?????????????????????????????????;?每次計(jì)算結(jié)果再加上上次計(jì)算結(jié)果保存在EDI中
    00401448?|.?49?????????????????DEC?ECX?????????????????????????????????????;?把磁盤(pán)類(lèi)型參數(shù)作為循環(huán)次數(shù),依次遞減
    00401449?|.?83F9?00????????????CMP?ECX,0???????????????????????????????????;?判斷是否計(jì)算完
    0040144C?|.^?75?F2?????????????JNZ?SHORT?CrackHea.00401440?????????????????;?沒(méi)完繼續(xù)
    0040144E?|.?893D?9C334000??????MOV?DWORD?PTR?DS:[40339C],EDI???????????????;?把計(jì)算后值送到內(nèi)存地址40339C,這就是我們后來(lái)在ESI中看到的值
    00401454?|.?61?????????????????POPAD
    00401455?\.?C3?????????????????RETN

    通過(guò)上面的分析,我們知道基本算法是這樣的:先用?GetDriveTypeA?函數(shù)獲取磁盤(pán)類(lèi)型參數(shù),再用?GetVolumeInformationA?函數(shù)獲取這個(gè)?crackme?程序所在分區(qū)的卷標(biāo)。如我把這個(gè)?Crackme?程序放在?F:\OD教程\crackhead\?目錄下,而我?F?盤(pán)設(shè)置的卷標(biāo)是?GAME,則這里獲取的就是?GAME,ASCII?碼為“47414D45”。但我們發(fā)現(xiàn)一個(gè)問(wèn)題:假如原來(lái)我們?cè)跀?shù)據(jù)窗口中看到的地址?40339C?處的?16?進(jìn)制代碼是“47414D45”,即“GAME”,但經(jīng)過(guò)地址?00401442?處的那條?MOV?EBX,DWORD?PTR?DS:[ESI]?指令后,我們卻發(fā)現(xiàn)?EBX?中的值是“454D4147”,正好把我們上面那個(gè)“47414D45”反過(guò)來(lái)了。為什么會(huì)這樣呢?如果大家對(duì)?x86系列?CPU?的存儲(chǔ)方式了解的話(huà),這里就容易理解了。我們知道“GAME”有四個(gè)字節(jié),即?ASCII?碼為“47414D45”。我們看一下數(shù)據(jù)窗口中的情況:

    0040339C?????47?41?4D?45?00?00?00?00?00?00?00?00?00?00?00?00?????GAME…………

    大家可以看出來(lái)內(nèi)存地址?40339CH?到?40339FH?分別按順序存放的是?47?41?4D?45。
    如下圖:

    系統(tǒng)存儲(chǔ)的原則為”高高低低”,即低字節(jié)存放在地址較低的字節(jié)單元中,高字節(jié)存放在地址較高的字節(jié)單元中。比如一個(gè)字由兩個(gè)字節(jié)組成,像這樣:12?34?,這里的高字節(jié)就是?12?,低字節(jié)就是?34。上面的那條指令?MOV?EBX,DWORD?PTR?DS:[ESI]?等同于?MOV?EBX,DWORD?PTR?DS:[40339C]。注意這里是?DWORD,即”雙字”,由?4?個(gè)連續(xù)的字節(jié)構(gòu)成。而取地址為?40339C?的雙字單元中的內(nèi)容時(shí),我們應(yīng)該得到的是“454D4147”,即由高字節(jié)到低字節(jié)順序的值。因此經(jīng)過(guò)?MOV?EBX,DWORD?PTR?DS:[ESI]?這條指令,就是把從地址?40339C?開(kāi)始處的值送到?EBX,所以我們得到了“454D4147”。好了,這里弄清楚了,我們?cè)俳又勥@個(gè)程序的算法。前面我們已經(jīng)說(shuō)了取磁盤(pán)類(lèi)型參數(shù)做循環(huán)次數(shù),再取卷標(biāo)值?ASCII?碼的逆序作為數(shù)值,有了這兩個(gè)值就開(kāi)始計(jì)算了。現(xiàn)在我們把磁盤(pán)類(lèi)型值作為?n,卷標(biāo)值?ASCII?碼的逆序數(shù)值作為?a,最后得出的結(jié)果作為?b,有這樣的計(jì)算過(guò)程:
    第一次:b?=?a?*?n
    第二次:b?=?a?*?(n?-?1)?+?b
    第三次:b?=?a?*?(n?-?2)?+?b

    第?n?次:b?=?a?*?1?+?b
    可得出公式為?b?=?a?*?[n?+?(n?-?1)?+?(n?-?2)?+?…?+?1]?=?a?*?[n?*?(n?+?1)?/?2]
    還記得上一篇我們的分析嗎?看這一句:

    00401405?|.?81F6?53757A79?????XOR?ESI,797A7553????????????????????????????;?把ESI中的值與797A7553H異或

    這里算出來(lái)的?b?最后還要和?797A7553H?異或一下才是真正的注冊(cè)碼。只要你對(duì)編程有所了解,這個(gè)注冊(cè)機(jī)就很好寫(xiě)了。如果用匯編來(lái)寫(xiě)這個(gè)注冊(cè)機(jī)的話(huà)就更簡(jiǎn)單了,很多內(nèi)容可以直接照抄。
    到此已經(jīng)差不多了,最后還有幾個(gè)東西也說(shuō)一下吧:
    1、上面用到了兩個(gè)?API?函數(shù),一個(gè)是?GetDriveTypeA,還有一個(gè)是?GetVolumeInformationA,關(guān)于這兩個(gè)函數(shù)的具體用法我就不多說(shuō)了,大家可以查一下?MSDN。這里只要大家注意函數(shù)參數(shù)傳遞的次序,即調(diào)用約定。先看一下這里:

    00401419?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?/pFileSystemNameSize?=?NULL
    0040141B?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|pFileSystemNameBuffer?=?NULL
    0040141D?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|pFileSystemFlags?=?NULL
    0040141F?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|pMaxFilenameLength?=?NULL
    00401421?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|pVolumeSerialNumber?=?NULL
    00401423?|.?6A?0B??????????????PUSH?0B?????????????????????????????????????;?|MaxVolumeNameSize?=?B?(11.)
    00401425?|.?68?9C334000????????PUSH?CrackHea.0040339C??????????????????????;?|VolumeNameBuffer?=?CrackHea.0040339C
    0040142A?|.?6A?00??????????????PUSH?0??????????????????????????????????????;?|RootPathName?=?NULL
    0040142C?|.?E8?A3000000????????CALL?<JMP.&KERNEL32.GetVolumeInformationA>??;?\GetVolumeInformationA

    把上面代碼后的?OllyDBG?自動(dòng)添加的注釋與?MSDN?中的函數(shù)原型比較一下:
    BOOL?GetVolumeInformation(
    LPCTSTR?lpRootPathName,?????????????//?address?of?root?directory?of?the?file?system
    LPTSTR?lpVolumeNameBuffer,??????????//?address?of?name?of?the?volume
    DWORD?nVolumeNameSize,??????????????//?length?of?lpVolumeNameBuffer
    LPDWORD?lpVolumeSerialNumber,???????//?address?of?volume?serial?number
    LPDWORD?lpMaximumComponentLength,???//?address?of?system&apos;s?maximum?filename?length
    LPDWORD?lpFileSystemFlags,??????????//?address?of?file?system?flags
    LPTSTR?lpFileSystemNameBuffer,??????//?address?of?name?of?file?system
    DWORD?nFileSystemNameSize???????????//?length?of?lpFileSystemNameBuffer
    );

    大家應(yīng)該看出來(lái)點(diǎn)什么了吧?函數(shù)調(diào)用是先把最后一個(gè)參數(shù)壓棧,參數(shù)壓棧順序是從后往前。這就是一般比較常見(jiàn)的?stdcall?調(diào)用約定。
    2、我在前面的?00401414?地址處的那條?MOV?BYTE?PTR?DS:[4033EC],AL?指令后加的注釋是”磁盤(pán)類(lèi)型參數(shù)送內(nèi)存地址4033EC”。為什么這樣寫(xiě)?大家把前一句和這一句合起來(lái)看一下:

    0040140F?|.?E8?B4000000????????CALL?<JMP.&KERNEL32.GetDriveTypeA>??????????;?\GetDriveTypeA
    00401414?|.?A2?EC334000????????MOV?BYTE?PTR?DS:[4033EC],AL?????????????????;?磁盤(pán)類(lèi)型參數(shù)送內(nèi)存地址4033EC

    地址?0040140F?處的那條指令是調(diào)用?GetDriveTypeA?函數(shù),一般函數(shù)調(diào)用后的返回值都保存在?EAX?中,所以地址?00401414?處的那一句?MOV?BYTE?PTR?DS:[4033EC],AL?就是傳遞返回值。查一下?MSDN?可以知道?GetDriveTypeA?函數(shù)的返回值有這幾個(gè):

    Value?????????????????????Meaning????????????????????????????????????????返回在EAX中的值
    DRIVE_UNKNOWN?????????????The?drive?type?cannot?be?determined.???????????????0
    DRIVE_NO_ROOT_DIR?????????The?root?directory?does?not?exist.?????????????????1
    DRIVE_REMOVABLE???????????The?disk?can?be?removed?from?the?drive.????????????2
    DRIVE_FIXED???????????????The?disk?cannot?be?removed?from?the?drive.?????????3
    DRIVE_REMOTE??????????????The?drive?is?a?remote?(network)?drive.?????????????4
    DRIVE_CDROM???????????????The?drive?is?a?CD-ROM?drive.???????????????????????5
    DRIVE_RAMDISK?????????????The?drive?is?a?RAM?disk.???????????????????????????6

    上面那個(gè)”返回在EAX中的值”是我加的,我這里返回的是?3,即磁盤(pán)不可從驅(qū)動(dòng)器上刪除。
    3、通過(guò)分析這個(gè)程序的算法,我們發(fā)現(xiàn)這個(gè)注冊(cè)算法是有漏洞的。如果我的分區(qū)沒(méi)有卷標(biāo)的話(huà),則卷標(biāo)值為?0,最后的注冊(cè)碼就是?797A7553H,即十進(jìn)制?2038068563。而如果你的卷標(biāo)和我一樣,且磁盤(pán)類(lèi)型一樣的話(huà),注冊(cè)碼也會(huì)一樣,并不能真正做到一機(jī)一碼。

    ?

    ?

    消息斷點(diǎn)及?RUN?跟蹤

    ?

    找了幾十個(gè)不同語(yǔ)言編寫(xiě)的?crackme,發(fā)現(xiàn)只用消息斷點(diǎn)的話(huà)有很多并不能真正到達(dá)我們要找的關(guān)鍵位置,想想還是把消息斷點(diǎn)和?RUN?跟蹤結(jié)合在一起講,更有效一點(diǎn)。關(guān)于消息斷點(diǎn)的更多內(nèi)容大家可以參考?jingulong?兄的那篇《幾種典型程序Button處理代碼的定位》的文章,堪稱(chēng)經(jīng)典之作。今天仍然選擇?crackmes.cjb.net?鏡像打包中的一個(gè)名稱(chēng)為?cycle?的?crackme。按照慣例,我們先運(yùn)行一下這個(gè)程序看看:

    我們輸入用戶(hù)名?CCDebuger,序列號(hào)?78787878,點(diǎn)上面那個(gè)“Check”按鈕,呵,?沒(méi)反應(yīng)!看來(lái)是要注冊(cè)碼正確才有動(dòng)靜。現(xiàn)在關(guān)掉這個(gè)?crackme,用?PEiD?查一下殼,原來(lái)是?MASM32?/?TASM32?[Overlay]。啟動(dòng)?OllyDBG?載入這個(gè)程序,F9讓它運(yùn)行。這個(gè)程序按我們前面講的采用字串參考或函數(shù)參考的方法都很容易斷下來(lái)。但我們今天主要學(xué)習(xí)的是消息斷點(diǎn)及?RUN?跟蹤,就先用消息斷點(diǎn)來(lái)斷這個(gè)程序吧。在設(shè)消息斷點(diǎn)前,有兩個(gè)內(nèi)容我們要簡(jiǎn)單了解一下:首先我們要了解的是消息。Windows?的中文翻譯就是”窗口”,而?Windows?上面的應(yīng)用程序也都是通過(guò)窗口來(lái)與用戶(hù)交互的。現(xiàn)在就有一個(gè)問(wèn)題,應(yīng)用程序是如何知道用戶(hù)作了什么樣的操作的?這里就要用到消息了。Windows?是個(gè)基于消息的系統(tǒng),它在應(yīng)用程序開(kāi)始執(zhí)行后,為該程序創(chuàng)建一個(gè)”消息隊(duì)列”,用來(lái)存放該程序可能創(chuàng)建的各種不同窗口的信息。比如你創(chuàng)建窗口、點(diǎn)擊按鈕、移動(dòng)鼠標(biāo)等等,都是通過(guò)消息來(lái)完成的。通俗的說(shuō),Windows?就像一個(gè)中間人,你要干什么事是先通知它,然后它才通過(guò)傳遞消息的方式通知應(yīng)用程序作出相應(yīng)的操作。說(shuō)到這,又有個(gè)問(wèn)題了,在?Windows?下有多個(gè)程序都在運(yùn)行,那我點(diǎn)了某個(gè)按鈕,或把某個(gè)窗口最大化,Windows?知道我是點(diǎn)的哪個(gè)嗎?這里就要說(shuō)到另一個(gè)內(nèi)容:句柄(handle)了。句柄一般是個(gè)?32?位的數(shù),表示一個(gè)對(duì)象。Windows?通過(guò)使用句柄來(lái)標(biāo)識(shí)它代表的對(duì)象。比如你點(diǎn)擊某個(gè)按鈕,Windows?就是通過(guò)句柄來(lái)判斷你是點(diǎn)擊了那一個(gè)按鈕,然后發(fā)送相應(yīng)的消息通知程序。說(shuō)完這些我們?cè)倩氐轿覀冋{(diào)試的程序上來(lái),你應(yīng)該已經(jīng)用?OllyDBG?把這個(gè)?crackme?載入并按?F9?鍵運(yùn)行了吧?現(xiàn)在我們輸入用戶(hù)名“CCDebuger”,序列號(hào)“78787878”,先不要點(diǎn)那個(gè)“Check”按鈕,我們來(lái)到?OllyDBG?中,點(diǎn)擊菜單?查看->窗口(或者點(diǎn)擊工具欄上那個(gè)“W”的圖標(biāo)),我們會(huì)看到以下內(nèi)容:

    我們?cè)谶x中的條目上點(diǎn)右鍵,再選擇上圖所示的菜單項(xiàng),會(huì)來(lái)到下面這個(gè)窗口:

    現(xiàn)在我們點(diǎn)擊圖上的那個(gè)下拉菜單,呵,原來(lái)里面的消息真不少。這么多消息我們選哪個(gè)呢?注冊(cè)是個(gè)按鈕,我們就在按下按鈕再松開(kāi)時(shí)讓程序中斷。查一下?MSDN,我們知道這個(gè)消息應(yīng)該是?WM_LBUTTON_UP,看字面意思也可以知道是左鍵松開(kāi)時(shí)的消息:

    從下拉菜單中選中那個(gè)?202?WM_LBUTTON_UP,再按確定按鈕,我們的消息斷點(diǎn)就設(shè)好了。現(xiàn)在我們還要做一件事,就是把?RUN?跟蹤打開(kāi)。有人可能要問(wèn),這個(gè)?RUN?跟蹤是干什么的?簡(jiǎn)單的說(shuō),RUN?跟蹤就是把被調(diào)試程序執(zhí)行過(guò)的指令保存下來(lái),讓你可以查看被調(diào)試程序運(yùn)行期間干了哪些事。RUN?跟蹤會(huì)把地址、寄存器的內(nèi)容、消息以及已知的操作數(shù)記錄到?RUN?跟蹤緩沖區(qū)中,你可以通過(guò)查看?RUN?跟蹤的記錄來(lái)了解程序執(zhí)行了那些指令。在這還要注意一個(gè)緩沖區(qū)大小的問(wèn)題,如果執(zhí)行的指令太多,緩沖區(qū)滿(mǎn)了的話(huà),就會(huì)自動(dòng)丟棄前面老的記錄。我們可以在調(diào)試選項(xiàng)->跟蹤中設(shè)置:

    現(xiàn)在我們回到?OllyDBG?中,點(diǎn)擊菜單調(diào)試->打開(kāi)或清除?RUN?跟蹤(第一次點(diǎn)這個(gè)菜單是打開(kāi)?RUN?跟蹤,在打開(kāi)的情況下點(diǎn)擊就是清除?RUN?跟蹤的記錄,對(duì)?RUN?跟蹤熟悉時(shí)還可以設(shè)置條件),保證當(dāng)前在我們調(diào)試的程序領(lǐng)空,在反匯編窗口中點(diǎn)擊右鍵,在彈出菜單中選擇?RUN?跟蹤->添加所有函數(shù)過(guò)程的入口:

    我們可以看到?OllyDBG?把識(shí)別出的函數(shù)過(guò)程都在前面加了灰色條:

    現(xiàn)在我們回到那個(gè)?crackme?中按那個(gè)“Check”按鈕,被?OllyDBG?斷下了:

    這時(shí)我們點(diǎn)擊菜單查看->內(nèi)存,或者點(diǎn)擊工具欄上那個(gè)“M”按鈕(也可以按組合鍵?ALT+M),來(lái)到內(nèi)存映射窗口:

    為什么在這里設(shè)訪(fǎng)問(wèn)斷點(diǎn),我也說(shuō)一下。我們可以看一下常見(jiàn)的?PE?文件,沒(méi)加過(guò)殼的用?PEiD?檢測(cè)是這樣:

    點(diǎn)一下?EP?段后面那個(gè)“>”符號(hào),我們可以看到以下內(nèi)容:

    看完上面的圖我們應(yīng)該了解為什么在?401000?處的代碼段下訪(fǎng)問(wèn)斷點(diǎn)了,我們這里的意思就是在消息斷點(diǎn)斷下后,只要按?F9?鍵運(yùn)行時(shí)執(zhí)行到程序代碼段的指令我們就中斷,這樣就可以回到程序領(lǐng)空了(當(dāng)然在?401000?處所在的段不是絕對(duì)的,我們主要是要看程序的代碼段在什么位置,其實(shí)在上面圖中?OllyDBG?內(nèi)存窗口的”包含”欄中我們就可以看得很清楚了)。設(shè)好訪(fǎng)問(wèn)斷點(diǎn)后我們按?F9?鍵,被?OllyDBG?斷下:

    現(xiàn)在我們先不管,按?F9?鍵(或者按?CTR+F12?組合鍵跟蹤步過(guò))讓程序運(yùn)行,再點(diǎn)擊菜單查看->RUN?跟蹤,或者點(diǎn)擊工具欄上的那個(gè)“…”符號(hào),打開(kāi)?RUN?跟蹤的記錄窗口看看:

    我們現(xiàn)在再來(lái)看看統(tǒng)計(jì)的情況:

    在地址?401082?處的那條指令上雙擊一下,來(lái)到以下位置:

    現(xiàn)在我們?cè)诘刂?4010A6?處的那條指令上按?F2,刪除所有其它的斷點(diǎn),點(diǎn)菜單調(diào)試->關(guān)閉?RUN?跟蹤,現(xiàn)在我們就可以開(kāi)始分析了:

    004010E2?|.?8BFE?????????????MOV?EDI,ESI?????????????????????????????????????????;?用戶(hù)名送?EDI
    004010E4?|.?03F8?????????????ADD?EDI,EAX
    004010E6?|.?FC???????????????CLD
    004010E7?|.?F3:A4????????????REP?MOVS?BYTE?PTR?ES:[EDI],BYTE?PTR?DS:[ESI]
    004010E9?|.?33C9?????????????XOR?ECX,ECX?????????????????????????????????????????;?清零,設(shè)循環(huán)計(jì)數(shù)器
    004010EB?|.?BE?71214000??????MOV?ESI,cycle.00402171??????????????????????????????;?注冊(cè)碼送ESI
    004010F0?|>?41???????????????INC?ECX
    004010F1?|.?AC???????????????LODS?BYTE?PTR?DS:[ESI]??????????????????????????????;?取注冊(cè)碼的每個(gè)字符
    004010F2?|.?0AC0?????????????OR?AL,AL????????????????????????????????????????????;?判斷是否為空
    004010F4?|.?74?0A????????????JE?SHORT?cycle.00401100?????????????????????????????;?沒(méi)有則跳走
    004010F6?|.?3C?7E????????????CMP?AL,7E???????????????????????????????????????????;?判斷字符是否為非ASCII字符
    004010F8?|.?7F?06????????????JG?SHORT?cycle.00401100?????????????????????????????;?非ASCII字符跳走
    004010FA?|.?3C?30????????????CMP?AL,30???????????????????????????????????????????;?看是否小于30H,主要是判斷是不是數(shù)字或字母等
    004010FC?|.?72?02????????????JB?SHORT?cycle.00401100?????????????????????????????;?小于跳走
    004010FE?|.^?EB?F0???????????JMP?SHORT?cycle.004010F0
    00401100?|>?83F9?11??????????CMP?ECX,11??????????????????????????????????????????;?比較注冊(cè)碼位數(shù),必須為十進(jìn)制17位
    00401103?|.?75?1A????????????JNZ?SHORT?cycle.0040111F
    00401105?|.?E8?E7000000??????CALL?cycle.004011F1?????????????????????????????????;?關(guān)鍵,F7跟進(jìn)去
    0040110A?|.?B9?01FF0000??????MOV?ECX,0FF01
    0040110F?|.?51???????????????PUSH?ECX
    00401110?|.?E8?7B000000??????CALL?cycle.00401190?????????????????????????????????;?關(guān)鍵,跟進(jìn)去
    00401115?|.?83F9?01??????????CMP?ECX,1
    00401118?|.?74?06????????????JE?SHORT?cycle.00401120
    0040111A?|>?E8?47000000??????CALL?cycle.00401166?????????????????????????????????;?注冊(cè)失敗對(duì)話(huà)框
    0040111F?|>?C3???????????????RETN
    00401120?|>?A1?68214000??????MOV?EAX,DWORD?PTR?DS:[402168]
    00401125?|.?8B1D?6C214000????MOV?EBX,DWORD?PTR?DS:[40216C]
    0040112B?|.?33C3?????????????XOR?EAX,EBX
    0040112D?|.?3305?82214000????XOR?EAX,DWORD?PTR?DS:[402182]
    00401133?|.?0D?40404040??????OR?EAX,40404040
    00401138?|.?25?77777777??????AND?EAX,77777777
    0040113D?|.?3305?79214000????XOR?EAX,DWORD?PTR?DS:[402179]
    00401143?|.?3305?7D214000????XOR?EAX,DWORD?PTR?DS:[40217D]
    00401149?|.^?75?CF???????????JNZ?SHORT?cycle.0040111A?????????????????????????????;?這里跳走就完蛋
    0040114B?|.?E8?2B000000??????CALL?cycle.0040117B??????????????????????????????????;?注冊(cè)成功對(duì)話(huà)框

    寫(xiě)到這準(zhǔn)備跟蹤算法時(shí),才發(fā)現(xiàn)這個(gè)?crackme?還是挺復(fù)雜的,具體算法我就不寫(xiě)了,實(shí)在沒(méi)那么多時(shí)間詳細(xì)跟蹤。有興趣的可以跟一下,注冊(cè)碼是17位,用戶(hù)名采用復(fù)制的方式擴(kuò)展到?16?位,如我輸入“CCDebuger”,擴(kuò)展后就是“CCDebugerCCDebug”。大致是先取擴(kuò)展后用戶(hù)名的前?8?位和注冊(cè)碼的前?8?位,把用戶(hù)名的前四位和后四位分別與注冊(cè)碼的前四位和后四位進(jìn)行運(yùn)算,算完后再把擴(kuò)展后用戶(hù)名的后?8?位和注冊(cè)碼的后?8?位分兩部分,再與前面用戶(hù)名和注冊(cè)碼的前?8?位計(jì)算后的值進(jìn)行異或計(jì)算,最后結(jié)果等于?0?就成功。注冊(cè)碼的第?17?位我尚未發(fā)現(xiàn)有何用處。對(duì)于新手來(lái)說(shuō),可能這個(gè)?crackme?的難度大了一點(diǎn)。沒(méi)關(guān)系,我們主要是學(xué)習(xí)?OllyDBG?的使用,方法掌握就可以了。

    最后說(shuō)明一下:
    1、這個(gè)程序在設(shè)置了消息斷點(diǎn)后可以省略在代碼段上設(shè)訪(fǎng)問(wèn)斷點(diǎn)那一步,直接打開(kāi)?RUN?跟蹤,消息斷點(diǎn)斷下后按?CTR+F12?組合鍵讓程序執(zhí)行,RUN?跟蹤記錄中就可以找到關(guān)鍵地方。
    2、對(duì)于這個(gè)程序,你可以不設(shè)消息斷點(diǎn),在輸入用戶(hù)名和注冊(cè)碼后先不按那個(gè)“Check”按鈕,直接打開(kāi)?RUN?跟蹤,添加”所有函數(shù)過(guò)程的入口”后再回到程序中點(diǎn)“Check”按鈕,這時(shí)在?OllyDBG?中打開(kāi)?RUN?跟蹤記錄同樣可以找到關(guān)鍵位置。

    ?

    ?

    匯編功能

    ?

    今天我們的目標(biāo)程序是?MyUninstaller?1.34?版。這是一個(gè)非常小的程序卸載工具,VC6編寫(xiě),大小只有61K。我拿到的這個(gè)是上次閃電狼兄弟給我的,附帶在里面的簡(jiǎn)體中文語(yǔ)言文件是由六芒星制作的。這個(gè)程序有個(gè)毛病:就是在列出的可卸載程序上雙擊查看屬性時(shí),彈出的屬性窗口的字體非常難看,應(yīng)該就是系統(tǒng)字體(SYSTEM_FONT):

    我們今天的目標(biāo)就是利用?OllyDBG?的匯編功能把上面顯示的字體改成我們常見(jiàn)的9號(hào)(小五)宋體。首先我們用?OllyDBG?載入程序,按?CTR+N?組合鍵查找一下有哪些?API?函數(shù),只發(fā)現(xiàn)一個(gè)和設(shè)置字體相關(guān)的?CreateFontIndirectA。現(xiàn)在我們按鼠標(biāo)右鍵,選擇”在每個(gè)參考上設(shè)置斷點(diǎn)”,關(guān)掉名稱(chēng)對(duì)話(huà)框,F9運(yùn)行,程序已經(jīng)運(yùn)行起來(lái)了。我們?cè)诔绦虻牧斜砜蛑须S便找一項(xiàng)雙擊一下,很不幸,那個(gè)字體難看的界面又出現(xiàn)了,OllyDBG?沒(méi)有任何動(dòng)作。可見(jiàn)創(chuàng)建這個(gè)窗口的時(shí)候根本沒(méi)調(diào)用?CreateFontIndirectA,問(wèn)題現(xiàn)在就變得有點(diǎn)復(fù)雜了。先點(diǎn)確定把這個(gè)字體難看的對(duì)話(huà)框關(guān)閉,現(xiàn)在我們從另一個(gè)方面考慮:既然沒(méi)有調(diào)用設(shè)置字體的函數(shù),那我們來(lái)看看這個(gè)窗口是如何創(chuàng)建的,跟蹤窗口創(chuàng)建過(guò)程可能會(huì)找到一些對(duì)我們有用的信息。現(xiàn)在我們?cè)倩氐轿覀冋{(diào)試程序的領(lǐng)空,按?CTR+N?看一下,發(fā)現(xiàn)?CreateWindowExA?這個(gè)?API?函數(shù)比較可疑。我們?cè)?CreateWindowExA?函數(shù)的每個(gè)參考上設(shè)上斷點(diǎn),在?MyUninstaller?的列表框中再隨便找一項(xiàng)雙擊一下,被?OllyDBG?斷下:

    ??00408F5E??|.??FF15?98B24000???|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]????;?\斷在這里

    上下翻看一下代碼:

    ??00408F3B??|.??50??????????????|PUSH?EAX?????????????????????????????????????????;?|hInst
    ??00408F3C??|.??8B45?C0?????????|MOV?EAX,DWORD?PTR?SS:[EBP-40]????????????????????;?|
    ??00408F3F??|.??6A?00???????????|PUSH?0???????????????????????????????????????????;?|hMenu?=?NULL
    ??00408F41??|.??03C6????????????|ADD?EAX,ESI??????????????????????????????????????;?|
    ??00408F43??|.??FF75?08?????????|PUSH?DWORD?PTR?SS:[EBP+8]????????????????????????;?|hParent
    ??00408F46??|.??FF75?D0?????????|PUSH?DWORD?PTR?SS:[EBP-30]???????????????????????;?|Height
    ??00408F49??|.??57??????????????|PUSH?EDI?????????????????????????????????????????;?|Width
    ??00408F4A??|.??50??????????????|PUSH?EAX?????????????????????????????????????????;?|Y
    ??00408F4B??|.??FF75?BC?????????|PUSH?DWORD?PTR?SS:[EBP-44]???????????????????????;?|X
    ??00408F4E??|.??FF75?EC?????????|PUSH?DWORD?PTR?SS:[EBP-14]???????????????????????;?|Style
    ??00408F51??|.??68?80DE4000?????|PUSH?myuninst.0040DE80???????????????????????????;?|WindowName?=?”“
    ??00408F56??|.??68?DCD94000?????|PUSH?myuninst.0040D9DC???????????????????????????;?|Class?=?“STATIC”
    ??00408F5B??|.??FF75?D4?????????|PUSH?DWORD?PTR?SS:[EBP-2C]???????????????????????;?|ExtStyle
    ??00408F5E??|.??FF15?98B24000???|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]????;?\斷在這里
    ??00408F64??|???6A?00???????????|PUSH?0???????????????????????????????????????????;??第一處要修改的地方
    ??00408F66??|???8945?F4?????????|MOV?DWORD?PTR?SS:[EBP-C],EAX
    ??00408F69??|.??E8?A098FFFF?????|CALL?<myuninst.sub_40280E>
    ??00408F6E??|.??50??????????????|PUSH?EAX?????????????????????????????????????????;?|hInst
    ??00408F6F??|.??8B45?DC?????????|MOV?EAX,DWORD?PTR?SS:[EBP-24]????????????????????;?|
    ??00408F72??|.??6A?00???????????|PUSH?0???????????????????????????????????????????;?|hMenu?=?NULL
    ??00408F74??|.??03F0????????????|ADD?ESI,EAX??????????????????????????????????????;?|
    ??00408F76??|.??FF75?08?????????|PUSH?DWORD?PTR?SS:[EBP+8]????????????????????????;?|hParent
    ??00408F79??|.??FF75?CC?????????|PUSH?DWORD?PTR?SS:[EBP-34]???????????????????????;?|Height
    ??00408F7C??|.??53??????????????|PUSH?EBX?????????????????????????????????????????;?|Width
    ??00408F7D??|.??56??????????????|PUSH?ESI?????????????????????????????????????????;?|Y
    ??00408F7E??|.??FF75?D8?????????|PUSH?DWORD?PTR?SS:[EBP-28]???????????????????????;?|X
    ??00408F81??|.??FF75?E8?????????|PUSH?DWORD?PTR?SS:[EBP-18]???????????????????????;?|Style
    ??00408F84??|.??68?80DE4000?????|PUSH?myuninst.0040DE80???????????????????????????;?|WindowName?=?”“
    ??00408F89??|.??68?D4D94000?????|PUSH?myuninst.0040D9D4???????????????????????????;?|Class?=?“EDIT”
    ??00408F8E??|.??FF75?B8?????????|PUSH?DWORD?PTR?SS:[EBP-48]???????????????????????;?|ExtStyle
    ??00408F91??|.??FF15?98B24000???|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]????;?\CreateWindowExA
    ??00408F97??|???8945?F0?????????|MOV?DWORD?PTR?SS:[EBP-10],EAX????????????????????;??第二處要修改的地方
    ??00408F9A??|???8B45?F8?????????|MOV?EAX,DWORD?PTR?SS:[EBP-8]
    ??00408F9D??|.??FF30????????????|PUSH?DWORD?PTR?DS:[EAX]??????????????????????????;?/<%s>
    ??00408F9F??|.??8D85?B0FEFFFF???|LEA?EAX,DWORD?PTR?SS:[EBP-150]???????????????????;?|
    ??00408FA5??|.??68?D0D94000?????|PUSH?myuninst.0040D9D0???????????????????????????;?|format?=?”%s:”
    ??00408FAA??|.??50??????????????|PUSH?EAX?????????????????????????????????????????;?|s
    ??00408FAB??|.??FF15?90B14000???|CALL?DWORD?PTR?DS:[<&MSVCRT.sprintf>]????????????;?\sprintf
    ??00408FB1??|.??8B35?84B24000???|MOV?ESI,DWORD?PTR?DS:[<&USER32.SetWindowTextA>]??;??USER32.SetWindowTextA
    ??00408FB7??|.??83C4?0C?????????|ADD?ESP,0C
    ??00408FBA??|.??8D85?B0FEFFFF???|LEA?EAX,DWORD?PTR?SS:[EBP-150]
    ??00408FC0??|.??50??????????????|PUSH?EAX?????????????????????????????????????????;?/Text
    ??00408FC1??|.??FF75?F4?????????|PUSH?DWORD?PTR?SS:[EBP-C]????????????????????????;?|hWnd
    ??00408FC4??|.??FFD6????????????|CALL?ESI?????????????????????????????????????????;?\SetWindowTextA
    ??00408FC6??|.??8D85?ACFAFFFF???|LEA?EAX,DWORD?PTR?SS:[EBP-554]
    ??00408FCC??|.??50??????????????|PUSH?EAX?????????????????????????????????????????;?/Arg3
    ??00408FCD??|.??FF75?FC?????????|PUSH?DWORD?PTR?SS:[EBP-4]????????????????????????;?|Arg2
    ??00408FD0??|.??FF35?00EF4000???|PUSH?DWORD?PTR?DS:[40EF00]???????????????????????;?|Arg1?=?00BEADCC
    ??00408FD6??|.??E8?1884FFFF?????|CALL??<myuninst.sub_4013F3>??????????????????????;?\sub_4013F3
    ??00408FDB??|.??83C4?0C?????????|ADD?ESP,0C
    ??00408FDE??|.??50??????????????|PUSH?EAX
    ??00408FDF??|.??FF75?F0?????????|PUSH?DWORD?PTR?SS:[EBP-10]
    ??00408FE2??|.??FFD6????????????|CALL?ESI
    ??00408FE4??|.??FF45?FC?????????|INC?DWORD?PTR?SS:[EBP-4]
    ??00408FE7??|.??8345?F8?14??????|ADD?DWORD?PTR?SS:[EBP-8],14
    ??00408FEB??|.??837D?FC?0F??????|CMP?DWORD?PTR?SS:[EBP-4],0F
    ??00408FEF??|.^?0F8C?32FFFFFF???\JL?<myuninst.loc_408F27>
    ??00408FF5??|.??5F??????????????POP?EDI
    ??00408FF6??|.??5E??????????????POP?ESI
    ??00408FF7??|.??5B??????????????POP?EBX
    ??00408FF8??|.??C9??????????????LEAVE
    ??00408FF9??\.??C3??????????????RETN
     

    我想上面的代碼我不需多做解釋,OllyDBG?自動(dòng)給出的注釋已經(jīng)夠清楚的了。我們雙擊?MyUninstaller?列表框中的的某項(xiàng)查看屬性時(shí),彈出的屬性窗口上的?STATIC?控件和?EDIT?控件都是由?CreateWindowExA?函數(shù)創(chuàng)建的,然后再調(diào)用?SetWindowTextA?來(lái)設(shè)置文本,根本沒(méi)考慮控件上字體顯示的問(wèn)題,所以我們看到的都是系統(tǒng)默認(rèn)的字體。我們要設(shè)置控件上的字體,可以考慮在?CreateWindowExA?創(chuàng)建完控件后,在使用?SetWindowTextA?函數(shù)設(shè)置文本之前調(diào)用相關(guān)字體創(chuàng)建函數(shù)來(lái)選擇字體,再調(diào)用?SendMessageA?函數(shù)發(fā)送?WM_SETFONT?消息來(lái)設(shè)置控件字體。思路定下來(lái)后,我們就開(kāi)始來(lái)實(shí)施。首先我們看一下這個(gè)程序中的導(dǎo)入函數(shù),CreateFontIndirectA?這個(gè)字體創(chuàng)建函數(shù)已經(jīng)有了,再看看?SendMessageA,呵呵,不錯(cuò),原程序也有這個(gè)函數(shù)。這樣我們就省事了。有人可能要問(wèn),如果原來(lái)并沒(méi)有這兩個(gè)導(dǎo)入函數(shù),那怎么辦呢?其實(shí)這也很簡(jiǎn)單,我們可以直接用?LordPE?來(lái)在程序中添加我們需要的導(dǎo)入函數(shù)。我這里用個(gè)很小的?PE?工具?zeroadd?來(lái)示范一下,這個(gè)程序里面沒(méi)有?CreateFontIndirectA?和?SendMessageA?函數(shù)(這里還有個(gè)問(wèn)題說(shuō)一下,其實(shí)我們編程時(shí)調(diào)用這兩個(gè)函數(shù)時(shí)都是直接寫(xiě)?CreateFontIndirect?及?SendMessage,一般不需指定。但在程序中寫(xiě)補(bǔ)丁代碼時(shí)我們要指定這是什么類(lèi)型的函數(shù)。這里在函數(shù)后面加個(gè)“A”表示這是?ASCII?版本,同樣?UNICODE?版本在后面加個(gè)“W”,如?SendMessageW。在?Win9X?下我們一般都用?ASCII?版本的函數(shù),UNICODE?版本的函數(shù)很多在?Win9X?下是不能運(yùn)行的。而NT?系統(tǒng)如?WinXP?一般都是?UNICODE?版本的,但如果我們用了?ASCII?版本的函數(shù),系統(tǒng)會(huì)自動(dòng)轉(zhuǎn)換調(diào)用?UNICODE?版本。這樣我們寫(xiě)補(bǔ)丁代碼的時(shí)候就可以直接指定為?ASCII?版本的函數(shù),可以兼容各個(gè)系統(tǒng)):我們用?LordPE?的?PE?編輯器載入?zeroadd?程序,選擇”目錄”,再在彈出的目錄表對(duì)話(huà)框中選擇輸入表后面的那個(gè)“…”按鈕,會(huì)彈出一個(gè)對(duì)話(huà)框:

    因?yàn)?SendMessageA?在?USER32.dll?中,我們?cè)谟益I菜單中點(diǎn)擊按鈕”添加導(dǎo)入表”,來(lái)到下面:

    按上面的提示完成后點(diǎn)”確定”,我們回到原先的那個(gè)”輸入表”對(duì)話(huà)框:

    從上圖中我們可以看出多出了一個(gè)?USER32.dll,這就是我們添加?SendMessageA?的結(jié)果。這也是用工具添加的一個(gè)缺點(diǎn)。我們一般希望把添加的函數(shù)直接放到已存在的?DLL?中,而不是多出來(lái)一個(gè),這樣顯得不好看。但用工具就沒(méi)辦法,LordPE?默認(rèn)是建一個(gè)?1K?的新區(qū)段來(lái)保存添加后的結(jié)果,由此出現(xiàn)了上圖中的情況。如果你對(duì)?PE?結(jié)構(gòu)比較熟悉的話(huà),也可以直接用?16進(jìn)制編輯工具來(lái)添加你需要的函數(shù),這樣改出來(lái)的東西好看。如果想偷懶,就像我一樣用工具吧,呵呵。在上圖中我還標(biāo)出了要注意?FirstThunk?及那個(gè)?ThunkRVA?的值,并且要把”總是查看?FirstThunk”那個(gè)選項(xiàng)選上。有人可能不理解其作用,我這里也解釋一下:一般講述?PE?格式的文章中對(duì)?FirstThunk?的解釋是這樣的:FirstThunk?包含指向一個(gè)?IMAGE_THUNK_DATA?結(jié)構(gòu)數(shù)組的?RVA?偏移地址,當(dāng)把?PE?文件裝載到內(nèi)存中時(shí),PE裝載器將查找?IMAGE_THUNK_DATA?和?IMAGE_IMPORT_BY_NAME?這些結(jié)構(gòu)數(shù)組來(lái)決定導(dǎo)入函數(shù)的地址,隨后用導(dǎo)入函數(shù)真實(shí)地址來(lái)替代由?FirstThunk?指向的?IMAGE_THUNK_DATA?數(shù)組里的元素值。這樣說(shuō)起來(lái)還是讓人不明白,我舉個(gè)例子:比如你有個(gè)很要好的朋友,他是個(gè)大忙人,雖然你知道他的家庭住址,可他很少回家。如果你哪天想找他,直接去他家,很可能吃個(gè)閉門(mén)羹,找不到他人。怎么辦?幸好你有他的手機(jī)號(hào)碼,你就給他撥了一個(gè)電話(huà):”小子,你在哪呢?”,他告訴你:”我正在XXX飯店喝酒呢!”這時(shí)你怎么辦?(當(dāng)然是殺到他說(shuō)的那家飯店去蹭飯了!^_^)這里的?ThunkRVA?就相當(dāng)于你朋友的手機(jī)號(hào)碼,?SendMessageA?就相當(dāng)于你那個(gè)朋友。而?FirstThunk?就是你手機(jī)里的號(hào)碼分組。你把你的多個(gè)朋友都放在?FirstThunk?這樣的號(hào)碼分組里,每個(gè)?ThunkRVA?就是你一個(gè)朋友的手機(jī)號(hào)碼。你要找他們,就是通過(guò)?ThunkRVA?這樣的手機(jī)號(hào)碼來(lái)和他們聯(lián)系,直接去他家找他你很可能要碰壁。而移動(dòng)或聯(lián)通就相當(dāng)于操作系統(tǒng),他們負(fù)責(zé)把你的手機(jī)號(hào)碼和你的朋友對(duì)應(yīng)上。而?FirstThunk?這樣的號(hào)碼分組還有一個(gè)好處就是你可以不記你某個(gè)朋友的具體號(hào)碼,只要記得?FirstThunk?號(hào)碼分組的值,你的朋友會(huì)按順序在里面排列。比如上圖中?USER32.dll?中的第一個(gè)函數(shù)是?SendMessageA,它的?ThunkRVA?值就是?FirstThunk?值。如果還有第二個(gè)函數(shù),比如是?MessageBoxA,它的值就是?FirstThunk?值加上?4,其余類(lèi)推。你只要記住各個(gè)函數(shù)的位置,也可以通過(guò)?FirstThunk?加上位置對(duì)應(yīng)值來(lái)找到它。當(dāng)然這比不上直接看?ThunkRVA?來(lái)得方便。說(shuō)了上面這些,我們就要考慮怎么在程序中調(diào)用了。你可能會(huì)說(shuō),我在?OllyDBG?中直接在我們要修改的程序中這樣調(diào)用:CALL?SendMessageA。哦,別這樣。這等于我上面說(shuō)的都是廢話(huà),會(huì)讓我感到傷心的。你這里的?CALL?SendMessageA?就相當(dāng)于也不跟你朋友打個(gè)招呼就直接去他家找他,很有可能你會(huì)乘興而去,敗興而歸。別忘了他的手機(jī)號(hào)碼,我們只有通過(guò)號(hào)碼才知道他到底在什么地方。我們應(yīng)該這樣:CALL?DWORD?PTR?[40B01A],這里的?40B01A?就是上面的?SendMessageA?在程序載入后的所在的地方,由基址?00400000?加上?ThunkRVA?0000B01A?得到的。這就是你要找的人所在的地方,不管他跑到哪,你有他的手機(jī)號(hào)碼就能找到他。同樣道理,你只要記住了?ThunkRVA?值,就按這個(gè)來(lái)調(diào)用你需要的函數(shù),在別的?Windows?系統(tǒng)下也是沒(méi)有問(wèn)題的。系統(tǒng)會(huì)自動(dòng)把你要找到函數(shù)和?ThunkRVA?值對(duì)應(yīng)上。而你在?OllyDBG?中寫(xiě)?CALL?SendMessageA,可能你在你的系統(tǒng)上成功了,可放到別的系統(tǒng)下就要出錯(cuò)了。為什么?因?yàn)槟阏业娜艘呀?jīng)不在原來(lái)的位置了,他跑到別的地方去了。你還到老地方找他,當(dāng)然看不見(jiàn)人了。說(shuō)了這么多廢話(huà),也不知大家聽(tīng)明白了沒(méi)有,別越聽(tīng)越糊涂就行了。總之一句話(huà),別像?CALL?SendMessageA?這樣直接調(diào)用某個(gè)函數(shù),而應(yīng)該通過(guò)?ThunkRVA?值來(lái)調(diào)用它。下面我們回到我們要修改的?MyUninstaller?上來(lái),先用?LordPE?打開(kāi)看一下,呵呵,原來(lái)?CreateFontIndirectA?和?SendMessageA?原程序里面都有了,省了我們不少事情。看一下這兩個(gè)函數(shù)的?ThunkRVA?值,CreateFontIndirectA?在?GDI32.dll?里面,ThunkRVA?值是?0000B044,這樣我們就知道在程序中調(diào)用它的時(shí)候就是?CALL?DWORD?PTR?[0040B044]。同樣,SendMessageA?的ThunkRVA?值是?0000B23C,調(diào)用時(shí)應(yīng)該是這樣:CALL?DWORD?PTR?[0040B23C]。了解了這些東西我們就來(lái)考慮怎么寫(xiě)代碼了。首先我們來(lái)看一下?CreateFontIndirectA?和?SendMessageA?這兩個(gè)函數(shù)的定義:

    CreateFontIndirectA:

    HFONT?CreateFontIndirect(
    CONST?LOGFONT?*lplf?//?pointer?to?logical?font?structure
    );
    CreateFontIndirect的返回值就是字體的句柄。

    對(duì)于這個(gè)函數(shù)我們需要的參數(shù)就是給它一個(gè)?LOGFONT?的字體結(jié)構(gòu)指針,我們只要在要修改程序的空白處建一個(gè)標(biāo)準(zhǔn)的9號(hào)(小五)宋體的?LOGFONT?字體結(jié)構(gòu),再把指針給?CreateFontIndirectA?就可以了。

    SendMessageA:

    LRESULT?SendMessage(
    HWND?hWnd,?//?handle?of?destination?window
    UINT?Msg,?//?message?to?send
    WPARAM?wParam,?//?first?message?parameter
    LPARAM?lParam?//?second?message?parameter
    );
    上面的第一個(gè)參數(shù)是窗口句柄,我們知道?CreateWindowExA?返回的就是窗口句柄,我們可以直接拿來(lái)用。第二個(gè)消息參數(shù)我們這里是設(shè)置字體,選WM_SETFONT,這個(gè)值是?30H。第三個(gè)參數(shù)是字體句柄,可以由上面的?CreateFontIndirectA?獲得。第四個(gè)參數(shù)我們不需要,留空。現(xiàn)在我們準(zhǔn)備開(kāi)始寫(xiě)代碼,首先我們要在程序中建一個(gè)標(biāo)準(zhǔn)9號(hào)宋體的?LOGFONT,以便于我們調(diào)用。對(duì)于?LOGFONT,我們?cè)賮?lái)看一下定義:

    typedef?struct?tagLOGFONT?{?//?lf?
    LONG?lfHeight;?
    LONG?lfWidth;?
    LONG?lfEscapement;?
    LONG?lfOrientation;?
    LONG?lfWeight;?
    BYTE?lfItalic;?
    BYTE?lfUnderline;?
    BYTE?lfStrikeOut;?
    BYTE?lfCharSet;?
    BYTE?lfOutPrecision;?
    BYTE?lfClipPrecision;?
    BYTE?lfQuality;?
    BYTE?lfPitchAndFamily;?
    TCHAR?lfFaceName[LF_FACESIZE];?
    }?LOGFONT;

    這樣我們的標(biāo)準(zhǔn)9號(hào)宋體的?LOGFONT?值應(yīng)該是32字節(jié),16進(jìn)制就像這樣:F4FFFFFF000000000000000000000000900100000000008600000000CBCECCE5。現(xiàn)在在程序中找個(gè)空地。我們用?PEiD?來(lái)幫助我們尋找,用?PEiD?打開(kāi)程序,點(diǎn)?EP?段后面的那個(gè)?>?號(hào),隨便選擇一個(gè)區(qū)段右擊,選”搜索全0處”(原版好像是cave什么的):

    我們看到?PEiD?把搜索到的空間都給我們列出來(lái)了:

    現(xiàn)在我們用?WinHEX?打開(kāi)我們要修改的程序,轉(zhuǎn)到偏移?9815?處,從?9815?處選擇?32?字節(jié)(16進(jìn)制是0X20)的一個(gè)選塊,把光標(biāo)定位到?9815?處,右鍵選擇菜單?剪貼板數(shù)據(jù)->寫(xiě)入(從當(dāng)前位置覆寫(xiě)),隨后的格式選擇?ASCII?Hex,把我們?LOGFONT?的?16?進(jìn)制值

    ?F4FFFFFF000000000000000000000000900100000000008600000000CBCECCE5?

    寫(xiě)入保存。現(xiàn)在我們用?OllyDBG?載入已添加了?LOGFONT?數(shù)據(jù)的程序,先轉(zhuǎn)到?VA?40A415?處(從上圖中看到的)往下看一下:
    ?

    因?yàn)?SendMessageA?還要用到一個(gè)窗口句柄,我們可以通過(guò)前面的?CreateWindowExA?來(lái)獲得。現(xiàn)在我們就把前一張圖中的?.rdata?區(qū)段中的地址?0040C56E?作為我們保存窗口句柄?HWND?值的臨時(shí)空間。一切就緒,開(kāi)始寫(xiě)代碼。先回顧一下我們最先說(shuō)的那兩個(gè)要修改的地方:

    第一個(gè)要改的地方:

    ??00408F5E??|.??FF15?98B24000?|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]??;?\CreateWindowExA
    ??00408F64??????6A?00?????????PUSH?0??????????????????????????????????????????;??修改前
    ??00408F66??????8945?F4???????MOV?DWORD?PTR?SS:[EBP-C],EAX
    ??00408F69??|.??E8?A098FFFF???|CALL?<myuninst.sub_40280E>

    修改后:

    ??00408F5E??|.??FF15?98B24000?|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]??;?\CreateWindowExA
    ??00408F64??????E9?D5140000???JMP?myuninst.0040A43E???????????????????????????;??跳轉(zhuǎn)到我們的補(bǔ)丁代碼處
    ??00408F69??|.??E8?A098FFFF???|CALL?<myuninst.sub_40280E>

    第二個(gè)要改的地方:

    ??00408F91??|.??FF15?98B24000????|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]????;?\CreateWindowExA
    ??00408F97??????8945?F0???????????MOV?DWORD?PTR?SS:[EBP-10],EAX?????????????????????;??改這里
    ??00408F9A??????8B45?F8???????????MOV?EAX,DWORD?PTR?SS:[EBP-8]
    ??00408F9D??|.??FF30?????????????|PUSH?DWORD?PTR?DS:[EAX]??????????????????????????;?/<%s>
    ??00408F9F??|.??8D85?B0FEFFFF????|LEA?EAX,DWORD?PTR?SS:[EBP-150]???????????????????;?|
    ??00408FA5??|.??68?D0D94000??????|PUSH?myuninst.0040D9D0???????????????????????????;?|format?=?”%s:”
    ??00408FAA??|.??50???????????????|PUSH?EAX?????????????????????????????????????????;?|s
    ??00408FAB??|.??FF15?90B14000????|CALL?DWORD?PTR?DS:[<&MSVCRT.sprintf>]????????????;?\sprintf
    ??00408FB1??|.??8B35?84B24000????|MOV?ESI,DWORD?PTR?DS:[<&USER32.SetWindowTextA>]??;??USER32.SetWindowTextA

    修改后:

    ??00408F91??|.??FF15?98B24000????|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]????;?\CreateWindowExA
    ??00408F97??????E9?D4140000??????JMP?myuninst.0040A470?????????????????????????????;??跳到我們的第二部分補(bǔ)丁代碼處
    ??00408F9C??????90???????????????NOP
    ??00408F9D??|.??FF30?????????????|PUSH?DWORD?PTR?DS:[EAX]??????????????????????????;?/<%s>
    ??00408F9F??|.??8D85?B0FEFFFF????|LEA?EAX,DWORD?PTR?SS:[EBP-150]???????????????????;?|
    ??00408FA5??|.??68?D0D94000??????|PUSH?myuninst.0040D9D0???????????????????????????;?|format?=?”%s:”
    ??00408FAA??|.??50???????????????|PUSH?EAX?????????????????????????????????????????;?|s
    ??00408FAB??|.??FF15?90B14000????|CALL?DWORD?PTR?DS:[<&MSVCRT.sprintf>]????????????;?\sprintf
    ??00408FB1??|.??8B35?84B24000????|MOV?ESI,DWORD?PTR?DS:[<&USER32.SetWindowTextA>]??;??USER32.SetWindowTextA

    這兩個(gè)地方的修改都是把原代碼改成跳轉(zhuǎn),跳到我們的補(bǔ)丁代碼那繼續(xù)執(zhí)行。在修改之前先把原代碼復(fù)制下來(lái),以便恢復(fù)。我們?cè)?OllyDBG?中按?CTR+G?組合鍵,來(lái)到?0040A43E?地址處,開(kāi)始輸補(bǔ)丁代碼:

    同樣,我們也在?0040A470?地址處輸入我們另一部分的補(bǔ)丁代碼。兩部分的補(bǔ)丁代碼分別如下:

    補(bǔ)丁代碼1:

    ??0040A43E??????60???????????????PUSHAD????????????????????????????????????????????;??保護(hù)現(xiàn)場(chǎng)
    ??0040A43F??????A3?6EC54000??????MOV?DWORD?PTR?DS:[40C56E],EAX?????????????????????;??保存窗口句柄
    ??0040A444??????68?15A44000??????PUSH?myuninst.0040A415????????????????????????????;??傳遞字體句柄LOGFONT
    ??0040A449??????FF15?44B04000????CALL?DWORD?PTR?DS:[<&GDI32.CreateFontIndirectA>]??;??GDI32.CreateFontIndirectA
    ??0040A44F??????6A?00????????????PUSH?0????????????????????????????????????????????;??lParam?參數(shù)留空
    ??0040A451??????50???????????????PUSH?EAX??????????????????????????????????????????;??字體句柄LOGFONT
    ??0040A452??????6A?30????????????PUSH?30???????????????????????????????????????????;??WM_SETFONT
    ??0040A454??????8B0D?6EC54000????MOV?ECX,DWORD?PTR?DS:[40C56E]?????????????????????;??窗口句柄送ECX
    ??0040A45A??????51???????????????PUSH?ECX??????????????????????????????????????????;??壓入窗口句柄參數(shù)
    ??0040A45B??????FF15?3CB24000????CALL?DWORD?PTR?DS:[<&USER32.SendMessageA>]????????;??USER32.SendMessageA
    ??0040A461??????61???????????????POPAD?????????????????????????????????????????????;??恢復(fù)現(xiàn)場(chǎng)
    ??0040A462??????6A?00????????????PUSH?0????????????????????????????????????????????;??恢復(fù)原代碼
    ??0040A464??????8945?F4??????????MOV?DWORD?PTR?SS:[EBP-C],EAX
    ??0040A467????^?E9?FDEAFFFF??????JMP?myuninst.00408F69?????????????????????????????;??返回

    補(bǔ)丁代碼2:

    ??0040A470???>?\60????????????PUSHAD
    ??0040A471???.??A3?6EC54000???MOV?DWORD?PTR?DS:[40C56E],EAX
    ??0040A476???.??68?15A44000???PUSH?myuninst.0040A415?????????????????????????????;?/pLogfont?=?myuninst.0040A415
    ??0040A47B???.??FF15?44B04000?CALL?DWORD?PTR?DS:[<&GDI32.CreateFontIndirectA>]???;?\CreateFontIndirectA
    ??0040A481???.??6A?00?????????PUSH?0?????????????????????????????????????????????;?/lParam?=?0
    ??0040A483???.??50????????????PUSH?EAX???????????????????????????????????????????;?|wParam
    ??0040A484???.??6A?30?????????PUSH?30????????????????????????????????????????????;?|Message?=?WM_SETFONT
    ??0040A486???.??8B0D?6EC54000?MOV?ECX,DWORD?PTR?DS:[40C56E]??????????????????????;?|
    ??0040A48C???.??51????????????PUSH?ECX???????????????????????????????????????????;?|hWnd?=>?NULL
    ??0040A48D???.??FF15?3CB24000?CALL?DWORD?PTR?DS:[<&USER32.SendMessageA>]?????????;?\SendMessageA
    ??0040A493???.??61????????????POPAD
    ??0040A494???.??8945?F0???????MOV?DWORD?PTR?SS:[EBP-10],EAX
    ??0040A497???.??8B45?F8???????MOV?EAX,DWORD?PTR?SS:[EBP-8]
    ??0040A49A???.^?E9?FEEAFFFF???JMP?myuninst.00408F9D

    補(bǔ)丁代碼2因?yàn)榕c補(bǔ)丁代碼1類(lèi)似,我就不做詳細(xì)解釋了。現(xiàn)在我們的代碼都寫(xiě)完了,現(xiàn)在我們開(kāi)始保存我們的工作,選中我們修改的代碼,點(diǎn)擊鼠標(biāo)右鍵,會(huì)出來(lái)一個(gè)菜單:

    我們左鍵選所有修改(當(dāng)然選它了,要不然只會(huì)保存我們選定的這一部分。關(guān)于這個(gè)地方還要說(shuō)一下,有的時(shí)候我們修改完程序選”復(fù)制到可執(zhí)行文件”時(shí)只有”選擇”菜單,沒(méi)有”所有修改”菜單項(xiàng)。按?OllyDBG?幫助里關(guān)于備份功能的說(shuō)法,好像是受內(nèi)存塊限制的,補(bǔ)丁功能也同樣是這樣。對(duì)于備份及補(bǔ)丁功能我用的比較少,并不是很了解,這方面的內(nèi)容還是大家自己去研究吧,有什么好的心得也希望能共享一下。我遇到不能保存所有修改的情況就是先把補(bǔ)丁代碼全部復(fù)制下來(lái),同時(shí)利用二進(jìn)制功能復(fù)制代碼,先選一段補(bǔ)丁代碼保存為文件,再用?OllyDBG?打開(kāi)保存后的文件,轉(zhuǎn)到相應(yīng)位置分別把我們復(fù)制下來(lái)的補(bǔ)丁二進(jìn)制代碼粘貼上去后保存。純屬笨辦法,當(dāng)然你也可以用?HexView?這樣的工具來(lái)修改代碼),隨后會(huì)出來(lái)一個(gè)”把選中的內(nèi)容復(fù)制到可執(zhí)行文件”的對(duì)話(huà)框,我們選”全部復(fù)制”,又出來(lái)一個(gè)對(duì)話(huà)框,我們?cè)谏厦纥c(diǎn)右鍵,在彈出的菜單上選”保存文件”:

    這時(shí)會(huì)出來(lái)一個(gè)另存文件的對(duì)話(huà)框,我們另選一個(gè)名字如?myuninst1.exe?來(lái)保存,不要直接覆蓋原文件?myuninst.exe,以便于出錯(cuò)后好修改。現(xiàn)在關(guān)閉?OllyDBG,先不要急著運(yùn)行剛剛修改過(guò)的文件,因?yàn)槲覀冞€有個(gè)地方要改一下。大家還記得我們?cè)?.rdata?中用了個(gè)地方作為我們保存臨時(shí)變量的地方吧?原先的?.rdata?段屬性設(shè)置是不可寫(xiě)的,現(xiàn)在我們寫(xiě)入了數(shù)據(jù),運(yùn)行時(shí)是會(huì)出錯(cuò)的。現(xiàn)在我們要修改一下?.rdata?段的屬性。用?LordPE?的?PE?編輯器打開(kāi)我們修改后的程序,點(diǎn)”區(qū)段”按鈕,在彈出的對(duì)話(huà)框中點(diǎn)擊?.rdata?段,右鍵選擇彈出菜單中的”編輯區(qū)段”:

    在彈出的對(duì)話(huà)框中選標(biāo)志后面那個(gè)“…”按鈕:

    現(xiàn)在我們把區(qū)段標(biāo)志添加一個(gè)可寫(xiě)入的屬性:

    完成后按確定保存我們所做的工作,運(yùn)行一下修改后的程序,呵呵,終于把字體改過(guò)來(lái)了:

    如果你運(yùn)行出錯(cuò)也沒(méi)關(guān)系,用?OllyDBG?調(diào)試一下你修改后的程序,看看錯(cuò)在什么地方。這一般都是輸入補(bǔ)丁代碼時(shí)造成的,你只要看一下你補(bǔ)丁代碼運(yùn)行的情況就可以了。到這里我們的任務(wù)似乎也完成了,但細(xì)心的朋友可能會(huì)發(fā)現(xiàn)補(bǔ)丁代碼1和補(bǔ)丁代碼2前面的代碼基本上是相同的。一個(gè)兩個(gè)這樣的補(bǔ)丁還好,如果要是多的話(huà),這樣重復(fù)就要浪費(fèi)不少空間了,況且工作量也相應(yīng)加大了。既然前面有很多代碼都是重復(fù)的,為什么我們不把這些重復(fù)的代碼做成一個(gè)子程序呢?這樣調(diào)用起來(lái)要方便的多。下面我們把前面的補(bǔ)丁代碼修改一下,我們先把補(bǔ)丁代碼1的代碼改成這樣:

    ??0040A43E??????60??????????????PUSHAD????????????????????????????????????????????;??保護(hù)現(xiàn)場(chǎng)
    ??0040A43F??????A3?6EC54000?????MOV?DWORD?PTR?DS:[40C56E],EAX?????????????????????;??保存窗口句柄
    ??0040A444??????68?15A44000?????PUSH?myuninst.0040A415????????????????????????????;??我們建的LOGFONT對(duì)應(yīng)指針
    ??0040A449??????FF15?44B04000???CALL?DWORD?PTR?DS:[<&GDI32.CreateFontIndirectA>]??;??GDI32.CreateFontIndirectA
    ??0040A44F??????6A?00???????????PUSH?0????????????????????????????????????????????;??lParam?參數(shù)留空
    ??0040A451??????50??????????????PUSH?EAX??????????????????????????????????????????;??字體句柄
    ??0040A452??????6A?30???????????PUSH?30???????????????????????????????????????????;??WM_SETFONT
    ??0040A454??????8B0D?6EC54000???MOV?ECX,DWORD?PTR?DS:[40C56E]?????????????????????;??窗口句柄
    ??0040A45A??????51??????????????PUSH?ECX??????????????????????????????????????????;??窗口句柄壓棧
    ??0040A45B??????FF15?3CB24000???CALL?DWORD?PTR?DS:[<&USER32.SendMessageA>]????????;??USER32.SendMessageA
    ??0040A461??????61??????????????POPAD?????????????????????????????????????????????;??恢復(fù)現(xiàn)場(chǎng)
    ??0040A462??????C3??????????????RETN??????????????????????????????????????????????;??返回

    這樣我們的子程序代碼就寫(xiě)好了。現(xiàn)在我們?cè)僭谧映绦虼a后面寫(xiě)上兩個(gè)補(bǔ)丁代碼,當(dāng)然不要忘了改前面原程序中的跳轉(zhuǎn):

    修改后的補(bǔ)丁代碼1:

    ??0040A467??????E8?D2FFFFFF?????CALL?myuninst.0040A43E????????????????????????????;??調(diào)用子程序
    ??0040A46C??????6A?00???????????PUSH?0????????????????????????????????????????????;??恢復(fù)前面修改過(guò)的代碼
    ??0040A46E??????8945?F4?????????MOV?DWORD?PTR?SS:[EBP-C],EAX
    ??0040A471????^?E9?F3EAFFFF?????JMP?myuninst.00408F69?????????????????????????????;??返回繼續(xù)執(zhí)行

    修改后的補(bǔ)丁代碼2:
    ??0040A47A??????E8?BFFFFFFF?????CALL?myuninst.0040A43E
    ??0040A47F??????8945?F0?????????MOV?DWORD?PTR?SS:[EBP-10],EAX
    ??0040A482??????8B45?F8?????????MOV?EAX,DWORD?PTR?SS:[EBP-8]
    ??0040A485????^?E9?13EBFFFF?????JMP?myuninst.00408F9D

    我在每個(gè)補(bǔ)丁代碼片斷間留了4個(gè)字節(jié)來(lái)分隔。同樣,我們還要修改一下我們前面的跳轉(zhuǎn):
    第一個(gè)要修改跳轉(zhuǎn)的地方:
    ??00408F5E??|.??FF15?98B24000???|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]????;?\斷在這里
    ??00408F64??????E9?FE140000?????JMP?myuninst.0040A467?????????????????????????????;??跳到我們的第一部分補(bǔ)丁代碼處
    ??00408F69??|.??E8?A098FFFF?????|CALL?<myuninst.sub_40280E>

    第二個(gè)要修改跳轉(zhuǎn)的地方:
    ??00408F91??|.??FF15?98B24000???|CALL?DWORD?PTR?DS:[<&USER32.CreateWindowExA>]????;?\CreateWindowExA
    ??00408F97??????E9?DE140000?????JMP?myuninst.0040A47A?????????????????????????????;??跳到我們的第二部分補(bǔ)丁代碼處
    ??00408F9C??????90??????????????NOP
    ??00408F9D??|.??FF30????????????|PUSH?DWORD?PTR?DS:[EAX]??????????????????????????;?/<%s>
    修改好后保存,同樣不要忘了再修改一下?.rdata?區(qū)段的屬性。運(yùn)行一下,一切OK!

    ?

    原文作者:CCDebuger(再次感謝CCDebuger)

    上傳者后記:再次感謝作者 CCDebuger?

    !!!希望對(duì)您能起到幫助,如果你需要文中所涉及的軟件(包括OllyDBG以及相關(guān)的crackme等,可與我聯(lián)系,我將盡快發(fā)給你,聯(lián)系QQ:20003138,謝謝!)

    ?

    ?

    ?

    總結(jié)

    以上是生活随笔為你收集整理的OllyDBG完美教程(超强入门级)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。