STEP 3——记录/恢复用户栈
有了前面的基础,要完成用户栈的记录也不是难事了。基本思路就是想办法找到用户栈的栈底地址,再找到栈顶地址,计算出栈的大小,然后调用函数PspRecordOrCopyData即可。
栈顶的地址是由栈顶指针esp寄存器保存的。前面已经说过,在系统调用时,使用的是内核栈,所以当前的esp寄存器并不是我们所期望的。那么这个栈顶地址应该去哪儿找呢。答案还是在那个“陷阱帧”TrapFrame里。TrapFrame记录了用户线程的寄存器状态,里面自然就包括esp寄存器的状态了。
剩下的就是获得栈底地址了。在Windows里,一个线程的用户空间的信息都记录在了TEB中,而TEB中又有一个域叫做NtTib,这里面就存放着有关用户站的信息。由于TEB结构过于复杂,这里只列举涉及到的,完整的定义在这一部分的末尾给出。
typedef struct PEBTEB_STRUCT(_TEB) {
PEBTEB_STRUCT(NT_TIB) NtTib;
….
…
…
}
typedef struct _NT_TIB {
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
PVOID StackBase;
PVOID StackLimit;
PVOID SubSystemTib;
union {
PVOID FiberData;
ULONG Version;
};
PVOID ArbitraryUserPointer;
struct _NT_TIB *Self;