Windows中将线程环境称为“Thread Context”(注意:没有进程Context,因为进程是不活动的),对一个线程来说,只要所有的寄存器没有改变,环境就没有改变,所以线程环境实际上就是寄存器的状态,它可以用一个CONTEXT结构来表示:
CONTEXT STRUCT
ContextFlags DWORD ?
iDr0 DWORD ?
iDr1 DWORD ?
iDr2 DWORD ?
iDr3 DWORD ?
iDr6 DWORD ?
iDr7 DWORD ?
FloatSave FLOATING_SAVE_AREA <>
regGs DWORD ?
regFs DWORD ?
regEs DWORD ?
regDs DWORD ?
regEdi DWORD ?
regEsi DWORD ?
regEbx DWORD ?
regEdx DWORD ?
regEcx DWORD ?
regEax DWORD ?
regEbp DWORD ?
regEip DWORD ?
regCs DWORD ?
regFlag DWORD ?
regEsp DWORD ?
regSs DWORD ?
ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
CONTEXT ENDS
结构中的字段包括80x86系列处理器中的全部寄存器,其中FloatSave字段用来保存浮点寄存器的内容,ExtendedRegisters字段用来保存扩展寄存器的内容(如MMX寄存器等),ContextFlags字段是供结构自己用的标志。
获取和设置线程环境函数
用于获取和重新设置线程环境的函数是GetThreadContext和SetThreadContext,它们的用法是:
invoke GetThreadContext,hThread,lpContext
invoke SetThreadContext,hThread,lpContext
hThread指定目标线程句柄,lpContext指向一个CONTEXT结构,GetThreadContext函数会将目标线程的环境返回到这个结构中,SetThreadContext函数将结构中的寄存器设置 到 目 标线 程 中。为 了 执 行这 两 个 函数,程序必 须 对 目标 线 程 拥有THREAD_GET_CONTEXT和THREAD_SET_CONTEXT权限。
在执行函数前,必须设置CONTEXT结构中的ContextFlags字段,这个字段表示需要操作的寄存器的范围。访问通用寄存器可以指定CONTEXT_INTEGER;访问段寄存器可以指定CONTEXT_SEGMENTS;要访问全部寄存器则指定为CONTEXT_FULL。
另外,在定义CONTEXT结构的时候,应该将它定义为双字对齐,否则,在NT下将得到奇怪的结果,双字对齐的方法是在结构的定义前加上“align dword”关键字。
在执行GetThreadContext函数前,最好使用SuspendThread函数将目标线程挂起,防止函数执行到一半的时候被Windows切换走了,在执行SetThreadContext以后可以再使用ResumeThread函数将目标线程恢复运行。但是在调试事件中就没有这个必要了,因为在ContinueDebugEvent函数返回之前,目标线程不会恢复运行。