理論:
在前面一章中,我們學會了如何裝載被調試的進程以及如何處理進程中發(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
在前面一章中,我們學會了如何裝載被調試的進程以及如何處理進程中發(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

