每个线程内核对象都维护着一个CONTEXT结构,里面保存了线程运行的状态,使得CPU可以记得上次运行该线程运行到哪里了,该从哪里开始运行,该线程内部数据如何如何。
在Platform SDK文档中记录着CONTEXT结构的信息。该结构是与CPU有关的,特定的CPU对应着特定的CONTEXT结构。
x86类型CPU对应的CONTEXT结构文档如下:
typedef struct _CONTEXT {
//
// The flag values within this flag control the contents of
// a CONTEXT record.
//
// If the context record is used as an input parameter, then
// for each portion of the context record controlled by a flag
// whose value is set, it is assumed that that portion of the
// context record contains valid context. If the context record
// is being used to modify a thread’s context, only that
// portion of the thread’s context will be modified.
//
// If the context record is used as an IN OUT parameter to capture
// the context of a thread, only those portions of the thread’s
// context corresponding to set flags will be returned.
//
// The context record is never used as an OUT only parameter.
//
DWORD ContextFlags;
//
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
//
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
//
FLOATING_SAVE_AREA FloatSave;
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_SEGMENTS.
//
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_INTEGER.
//
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
//
// This section is specified/returned if the
// ContextFlags word contains the flag CONTEXT_CONTROL.
//
DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs;
//
// This section is specified/returned if the ContextFlags word
// contains the flag CONTEXT_EXTENDED_REGISTERS.
// The format and contexts are processor specific
//
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;
可见,该CONTEXT结构中,保存着直接和CPU有关的信息:
1、ContextFlags,在查询的时候需要设置该字段,表示查询哪些其他的CONTEXT结构字段。
2、调试寄存器组
3、FLOATING_SAVE_AREA FloatSave —— 浮点寄存器
4、段寄存器
5、通用数据寄存器(整型寄存器)组
6、控制寄存器组——比如CS、BP、SP之类的保存基址指针和堆栈指针、程序计数器。
7、BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION] —— 展寄存器组
当然,你可以查询CONTEXT结构中的内容。如上所述,通过设置CONTEXT中的ContextFlags字段,选择要查询的内容:
1、CONTEXT_DEBUG_REGISTERS,查询调式寄存器
2、CONTEXT_FLOATING_POINT,查询浮点寄存器
3、CONTEXT_SEGMENTS,查询段寄存器
4、CONTEXT_INTEGER,查询通用数据寄存器
5、CONTEXT_CONTROL,查询控制寄存器组
6、CONTEXT_EXTENDED_REGISTERS,扩展寄存器组
设置好ContextFlag字段之后,可以通过呼叫GetThreadContext函数查询CONTEXT中的相关内容:
BOOL GetThreadContext(
HANDLE hThread,
//
线程句柄
PCONTEXT pContext);
//
上下文结构指针
在查询之前,先呼叫SuspendThread函数暂停一个线程的执行,然后呼叫GetThreadContext函数取得CONTEXT结构中相关内容。
下面代码查询一个线程的控制寄存器组信息:
SuspendThread(hTherad);
//
必须首先暂停线程运行
CONTEXT Context;
Context.ContextFlags
=
CONTEXT_CONTROL;
GetThreadContext(hThread,
&
Context);
你可以呼叫SetThreadContext函数来设置一个线程的CONTEXT结构。
BOOL SetThreadContext(HANDLE hThread, CONST CONTEXT
*
pContext);
该函数呼叫之前,也需要先呼叫SuspendThread函数,然后设置CONTEXT中的ContextFlags字段,但是SetThreadContext可能会导致内存访问违规。
下面代码展示了使用SetThreadContext的基本步骤:
CONTEXT Context;
SuspendThread(hThread);
//
必须首先暂停线程
Context.ContextFlags
=
CONTEXT_CONTROL;
GetThreadContext(hThread,
&
Context);
//
首先取得CONTEXT结构内容
Context.Eip
=
0x00010000
;
//
将指令指针指向的地址设置为0x00010000
Context.ContextFlags
=
CONTEXT_CONTROL;
//
重新设置ContextFlags
SetThreadContext(hThread,
&
Context);
//
设置CONTEXT结构
ResumeThread(hThread);
//
恢复线程运行,会从0x00010000的地址运行