Win32調(diào)試API第二部分

字號:

理論:
    在前面一章中,我們學(xué)會了如何裝載被調(diào)試的進(jìn)程以及如何處理進(jìn)程中發(fā)生的事件。為了有實際用途,我們的程序應(yīng)具有修改被調(diào)試程序的能力。有好幾個API函數(shù)用于這一目的。
    ReadProcessMemory該函數(shù)允許你去讀指定的進(jìn)程的內(nèi)存。函數(shù)原型如下:
    ReadProcessMemory proto hProcess:DWORD, lpBaseAddress:DWORD, lpBuffer:DWORD, nSize:DWORD, lpNumberOfBytesRead:DWORD
    hProcess 待讀進(jìn)程的句柄.
    lpBaseAddress 目標(biāo)進(jìn)程中待讀內(nèi)存起始地址。例如,如果你想要讀目標(biāo) 進(jìn)程中從地址401000h開始的4個字節(jié),該參數(shù)值應(yīng)置為401000h。
    lpBuffer 接收緩沖區(qū)地址
    nSize 想要讀的字節(jié)數(shù)。
    lpNumberOfBytesRead 記錄實際讀取的字節(jié)數(shù)的變量地址。如果對這個值 不關(guān)心,填入NULL即可。
    WriteProcessMemory 是對應(yīng)于ReadProcessMemory的函數(shù),通過它 可以寫目標(biāo)進(jìn)程的內(nèi)存。其參數(shù)和ReadProcessMemory 相同。
    理解接下去的兩個函數(shù)需要一些進(jìn)程上下文的有關(guān)背景知識。在象Windows這樣的 多任務(wù)操作系統(tǒng)中,同一時間里可能運行著幾個程序。Windows分配給每個線程一個 時間片,當(dāng)時間片結(jié)束后,Windows將凍結(jié)當(dāng)前線程并切換到下一具有優(yōu)先級的 線程。在切換之前,Windows將保存當(dāng)前進(jìn)程的寄存器的 內(nèi)容,這樣當(dāng)在該線程再 次恢復(fù)運行時,Windows可以恢復(fù)最近一次線程運行的*環(huán)境*。保存的寄存器內(nèi)容總 稱為進(jìn)程上下文。
    現(xiàn)在回到我們的主題。當(dāng)一個調(diào)試事件發(fā)生時,Windows暫停被調(diào)試進(jìn)程,并保存其 進(jìn)程上下文。由于進(jìn)程被暫停運行,我們可以確信其進(jìn)程上下文內(nèi)容將保持不變。 可以用GetThreadContext來獲取進(jìn)程上下文內(nèi)容,并且也可以用GetThreadContext 來修改進(jìn)程上下文內(nèi)容。
    這兩個函數(shù)威力非凡。有了他們,對被調(diào)試進(jìn)程你就具有象VxD的能力: 如改變其寄 存器內(nèi)容,而在被調(diào)試程序恢復(fù)運行前,這些值將會寫回寄存器中。在進(jìn)程上下文中 所做的任何改動,將都會反映到被調(diào)試程序中。想象一下: 甚至可以改變eip寄存器 的內(nèi)容,這樣你可以讓程序運行到你想要的任何地方! 在正常情況下是不可能做到這 一點的。
    GetThreadContext proto hThread:DWORD, lpContext:DWORD
    hThread 你想要獲得上下文的線程句柄
    lpContext 函數(shù)成功返回時用來保存上下文內(nèi)容的結(jié)構(gòu)指針。
    SetThreadContext 參數(shù)相同。讓我們來看看上下文的結(jié)構(gòu):
    CONTEXT STRUCT
    ContextFlags dd ?
    ;----------------------------------------------------------------------------------------------------------
    ;當(dāng)ContextFlags包含CONTEXT_DEBUG_REGISTERS,返回本部分
    ;-----------------------------------------------------------------------------------------------------------
    iDr0 dd ?
    iDr1 dd ?
    iDr2 dd ?
    iDr3 dd ?
    iDr6 dd ?
    iDr7 dd ?
    ;----------------------------------------------------------------------------------------------------------
    ;當(dāng)ContextFlags包含CONTEXT_FLOATING_POINT,返回本部分
    ;-----------------------------------------------------------------------------------------------------------
    FloatSave FLOATING_SAVE_AREA <>
    ;----------------------------------------------------------------------------------------------------------
    ;當(dāng)ContextFlags包含CONTEXT_SEGMENTS,返回本部分
    ;-----------------------------------------------------------------------------------------------------------
    regGs dd ?
    regFs dd ?
    regEs dd ?
    regDs dd ?
    ;----------------------------------------------------------------------------------------------------------
    ;當(dāng)ContextFlags包含CONTEXT_INTEGER,返回本部分
    ;-----------------------------------------------------------------------------------------------------------
    regEdi dd ?
    regEsi dd ?
    regEbx dd ?
    regEdx dd ?
    regEcx dd ?
    regEax dd ?
    ;----------------------------------------------------------------------------------------------------------
    ;當(dāng)ContextFlags包含CONTEXT_CONTROL,返回本部分
    ;-----------------------------------------------------------------------------------------------------------
    regEbp dd ?
    regEip dd ?
    regCs dd ?
    regFlag dd ?
    regEsp dd ?
    regSs dd ?
    ;----------------------------------------------------------------------------------------------------------
    ;當(dāng)ContextFlags包含CONTEXT_EXTENDED_REGISTERS,返回本部分
    ;-----------------------------------------------------------------------------------------------------------
    ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?) CONTEXT ENDS
    可以看出,該結(jié)構(gòu)中的成員是對實際處理器的寄存器的模仿。在使用該結(jié)構(gòu)之前 要在ContextFlags 中指定哪些寄存器組用來讀寫。如要訪問所有的寄存器, 你可以置ContextFlags 為CONTEXT_FULL 。或者只訪問regEbp, regEip, regCs, regFlag, regEsp 或 regSs, 應(yīng)置ContextFlags 為 CONTEXT_CONTROL