調試器第二講,單步步入/步過功能實現,以及基本的斷點功能實現


           調試器第二講,單步步入/步過功能實現,以及基本的斷點功能實現

昨天,我們實現了調試器的基本框架,那么今天我們實現單步功能,還有斷點功能,以及使用反匯編引擎

作者:IBinary
出處:http://www.cnblogs.com/iBinary/
版權所有,歡迎保留原文鏈接進行轉載:)

一丶反匯編引擎的編譯,生成LIB

首先,我們有一個反匯編引擎的代碼,現在我們編譯連接一下(注意,可以使用GitHub下載,或者百度Google下載)

關於反匯編引擎的介紹: 請參考轉載博客 http://blog.csdn.net/earbao/article/details/72857805

先編譯成OBJ文件,(不連接),上面兩個函數就是我們需要的使用的,准確的來說,是下面的這個,因為上面那個不會給你二進制數據.

比如我們反匯編的結果是

00401000    CC         int 3  那么這樣就是用下面這個,有二進制代碼顯示

如果使用上面那個則是

00401000  int3      具體愛好看你使用那個,這里具體講解第二個

先編譯成OBJ

需要的就這有3個,  除了stdafx.obj 還有MyDisasm.obj 其余的都是我們用的

現在我們使用lib工具,講編譯好的obj打包成一個lib(當然你也可以寫)

關於lib工具的使用,請參考我寫的博客,32位匯編第七講,混合編程 連接: http://www.cnblogs.com/iBinary/p/7555503.html

現在回車,生成我們的lib

 

 

然后我們還需要這兩個函數的頭文件.

現在准備齊全了,准備開始我們的代碼編寫.

注意: 這里我們是生成的靜態lib,你也可以生成動態鏈接庫 (也就是俗稱的 DLL)

二丶使用反匯編引擎API

直接看代碼吧

新建一個工程,控制台的(隨你便,啥都行,能寫代碼,調用API的就可以)

把我們的lib,和.h文件,拷貝到我們的程序目錄下(靜態使用)

#include "stdafx.h"
#include <WINDOWS.H>
#include <STDLIB.H>
#include "Decode2Asm.h"

#pragma comment(lib,"MyDisAsm.lib")
int main(int argc, char* argv[])
{
    BYTE OpCode[] = {0xcc,0x90};      //解析的地址,地址里面有機器碼,我們不知道是什么(這里舉例子我們知道)
    char szAsm[256] = {NULL};        //通過地址,得出反匯編字符串,放到這個緩沖區中
    char szBin[256] = {NULL};        //通過地址,得出二進制機器碼,放到這個緩沖區中
    UINT binSize = NULL;           //每次只解析一個指令長度,所以我們要遍歷數組,加上這個長度,接着輸出出來.
    BYTE *pCurCode = OpCode;         //遍歷的時候需要給個指針
    do 
    {
        Decode2AsmOpcode(pCurCode,szAsm,szBin,&binSize,(UINT)pCurCode);//調用API,解析,
        printf("%-16p%-20s%-20s\r\n",pCurCode,szBin,szAsm);        //輸出
        pCurCode = pCurCode + binSize;                    //地址 + 指令長度 = 下一次需要解析的指令的地址
    } while (pCurCode < (OpCode + sizeof(OpCode)));            //判斷是否數組越界
    system("pause");
    return 0;
}
Decode2AsmOpcode的各個參數意思:
第一個參數: 地址,你要給我一個地址,我去解析
第二個參數: 反匯編代碼的緩沖區,通過地址,解析的反匯編會放到這個緩沖區當中
第三個參數: 二進制代碼緩沖區,通過地址,解析二進制,放到這個緩沖區當中
第四個參數: 是否計算偏移
關於這個參數,其實是給EIP的值,(也就是地址),例如我們上面的給的.
這個參數的作用是
比如你有一個 JMP 指令
00401000 JMP 000010 這個是正常的匯編代碼,我們知道JMP是JMP的偏移
而后面給了這個參數,它則會給我們計算出來
00401000 JMP 00401010

看下輸出結果

配合我們昨天寫的,則可以反匯編出來調試進程的代碼了.

三丶匯編調用反匯編引擎API,顯示調試進程的匯編代碼.

在上面,我們對API有了一個認識.

下面我們就結合我們昨天寫的匯編代碼,接着寫,顯示出來斷點位置的反匯編代碼.

首先在處理異常的事件中,我們要調用

先加載我們的LIB,以及INC文件(INC文件中,是那個兩個API的函數聲明,你可以自己通過LIB生成,

具體請參考上面的混合編程的博客鏈接)

1.加載LIB,以及INC文件

2.使用ReadProcessMemory,和我們的API配合使用

首先使用Read..讀取.然后放到我們的數組中,

然后使用API,獲取反匯編的各種信息

invoke ReadProcessMemory,g_hProcess,
                             [ebx].u.Exception.pExceptionRecord.ExceptionAddress,
                             @OpCode,sizeof @OpCode,
                              NULL
invoke ShowAsm,addr @OpCode,[ebx].u.Exception.pExceptionRecord.ExceptionAddress

當然,Read的時候,需要注意要保存g_hProcess句柄.這樣才可以.

下面的ShowAsm是封裝的函數,內部還是調用的Decode2AsmOpco

ShowAsm proc pCode :ptr byte, pAddr:ptr Byte
    LOCAL  @szAsmCode[256]:BYTE
    LOCAL  @szOpCode[256]:BYTE
    LOCAL  @CodeSize1:DWORD
    
    invoke Decode2AsmOpcode, pCode, addr @szAsmCode, addr @szOpCode,
                             addr @CodeSize1, pAddr
    invoke crt_printf, offset g_szDcode, pAddr, addr @szOpCode, addr @szAsmCode

    ret

ShowAsm endp

這里提一下簡單思路,因為真正的都寫出來,匯編代碼很多,影響觀看,所以都是簡單思路,沒有完整代碼,完整代碼,在每天的課件資料中,可以去看,這里這說一下核心代碼的思路

四丶匯編設置F2斷點,以及單步(步入,步過)

簡單思路

1.斷點的設置:

  1.首先,系統斷點第一次來,然后在創建進程的時候會有一個地址,我們使用Read...讀取地址內容,然后反匯編出來顯示

  2.讀取出來之前,使用VirtualProtectEx將保護屬性去除,(注意保存舊的)

  3.使用WriteProcessMemory往地址寫入CC(注意保存以前的值)

  4.重新修改保護屬性,改回去(使用舊的)

然后一個斷點即完成了,具體代碼,請看課件.

2.單步的設置(步入,進函數)

如果是單步,我們要判斷斷點是我們設置的還是系統設置的.

1.判斷是否使我們設置的斷點

2.修改內存保護屬性(注意保存舊的)

3.寫入CC,(int 3斷點)

4.讀取內存數據

5.顯示反匯編

設置單步(步入)異常

1.打開線程獲得線程句柄

2.使用GetThreadContext獲取寄存器的值

3.設置單步標志,單步表示是要我們設置的,他是第9個標志

or [esi].regflag,0100h 這樣設置即可.設置第九位為1

4.設置寄存器環境 SetThreadContext

設置單步步過異常

但步步過和單步步入一樣

只不過遇到Call的時候我們要把他的下一條指令設置一個int3斷點才可以.

課堂資料: 鏈接:http://pan.baidu.com/s/1geBOgQR 密碼:5dw9


作者:IBinary
出處:http://www.cnblogs.com/iBinary/
版權所有,歡迎保留原文鏈接進行轉載:)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM