Win32調試API第二部分

字號:

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