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;
} NT_TIB;
其中NtTib中的StackBase就是用户栈的基地址了。用户栈的大小只要用通过栈底地址和栈顶地址简单相减就可以得到了。
对于用户栈的记录/恢复就这样得到了完成。
下面是关于TEB的完整定义:
typedef struct
PEBTEB_STRUCT(_TEB) {
PEBTEB_STRUCT(NT_TIB) NtTib;
PEBTEB_POINTER(PVOID) EnvironmentPointer;
PEBTEB_STRUCT(CLIENT_ID) ClientId;
PEBTEB_POINTER(PVOID) ActiveRpcHandle;
PEBTEB_POINTER(PVOID)
ThreadLocalStoragePointer;
PEBTEB_POINTER(PPEB)
ProcessEnvironmentBlock;
ULONG LastErrorValue;
ULONG CountOfOwnedCriticalSections;
PEBTEB_POINTER(PVOID) CsrClientThread;
PEBTEB_POINTER(PVOID) Win32ThreadInfo; // PtiCurrent
ULONG User32Reserved[26]; // user32.dll items
ULONG UserReserved[5]; // Winsrv SwitchStack
PEBTEB_POINTER(PVOID) WOW32Reserved; // used by WOW
LCID CurrentLocale;
ULONG FpSoftwareStatusRegister; // offset
known by outsiders!
PEBTEB_POINTER(PVOID)
SystemReserved1[54]; // Used by FP
emulator
NTSTATUS ExceptionCode; // for RaiseUserException
// 4 bytes of padding here on native 64bit
TEB and TEB64
PEBTEB_POINTER(PACTIVATION_CONTEXT_STACK)
ActivationContextStackPointer; // Fusion activation stack
#if
(defined(PEBTEB_BITS) && (PEBTEB_BITS == 64)) || (!defined(PEBTEB_BITS)
&& defined(_WIN64))
UCHAR SpareBytes1[28]; // native 64bit TEB
and TEB64
#else
UCHAR SpareBytes1[40]; // native 32bit TEB
and TEB32
#endif
PEBTEB_STRUCT(GDI_TEB_BATCH)
GdiTebBatch; // Gdi batching
PEBTEB_STRUCT(CLIENT_ID) RealClientId;
PEBTEB_POINTER(HANDLE)
GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PEBTEB_POINTER(PVOID) GdiThreadLocalInfo;
PEBTEB_POINTER(ULONG_PTR)
Win32ClientInfo[WIN32_CLIENT_INFO_LENGTH]; // User32 Client Info
PEBTEB_POINTER(PVOID) glDispatchTable[233]; // OpenGL
PEBTEB_POINTER(ULONG_PTR)
glReserved1[29]; // OpenGL
PEBTEB_POINTER(PVOID) glReserved2; // OpenGL
PEBTEB_POINTER(PVOID) glSectionInfo; // OpenGL
PEBTEB_POINTER(PVOID) glSection; // OpenGL
PEBTEB_POINTER(PVOID) glTable; // OpenGL
PEBTEB_POINTER(PVOID) glCurrentRC; // OpenGL
PEBTEB_POINTER(PVOID) glContext; // OpenGL
ULONG LastStatusValue;
PEBTEB_STRUCT(UNICODE_STRING)
StaticUnicodeString;
WCHAR
StaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
PEBTEB_POINTER(PVOID) DeallocationStack;
PEBTEB_POINTER(PVOID)
TlsSlots[TLS_MINIMUM_AVAILABLE];
PEBTEB_STRUCT(LIST_ENTRY) TlsLinks;
PEBTEB_POINTER(PVOID) Vdm;
PEBTEB_POINTER(PVOID) ReservedForNtRpc;
PEBTEB_POINTER(PVOID) DbgSsReserved[2];
ULONG HardErrorMode;
PEBTEB_POINTER(PVOID) Instrumentation[14];
PEBTEB_POINTER(PVOID) SubProcessTag;
PEBTEB_POINTER(PVOID) EtwTraceData;
PEBTEB_POINTER(PVOID) WinSockData; // WinSock
ULONG GdiBatchCount;
BOOLEAN InDbgPrint;
BOOLEAN FreeStackOnTermination;
BOOLEAN HasFiberData;
BOOLEAN IdealProcessor;
ULONG GuaranteedStackBytes;
PEBTEB_POINTER(PVOID) ReservedForPerf;
PEBTEB_POINTER(PVOID) ReservedForOle;
ULONG WaitingOnLoaderLock;
PEBTEB_POINTER(ULONG_PTR) SparePointer1;
PEBTEB_POINTER(ULONG_PTR) SoftPatchPtr1;
PEBTEB_POINTER(ULONG_PTR) SoftPatchPtr2;
PEBTEB_POINTER(PPVOID) TlsExpansionSlots;
#if (defined(_WIN64)
&& !defined(PEBTEB_BITS)) /
|| ((defined(_WIN64) || defined(_X86_))
&& defined(PEBTEB_BITS) && PEBTEB_BITS == 64)
//
// These are in native Win64 TEB, Win64 TEB64,
and x86 TEB64.
//
PEBTEB_POINTER(PVOID) DeallocationBStore;
PEBTEB_POINTER(PVOID) BStoreLimit;
#endif
LCID ImpersonationLocale; // Current locale of impersonated user
ULONG IsImpersonating; // Thread impersonation status
PEBTEB_POINTER(PVOID) NlsCache; // NLS thread cache
PEBTEB_POINTER(PVOID) pShimData; // Per thread data used in the
shim
ULONG HeapVirtualAffinity;
PEBTEB_POINTER(HANDLE)
CurrentTransactionHandle;// reserved for TxF transaction context
PEBTEB_POINTER(PTEB_ACTIVE_FRAME)
ActiveFrame;
PEBTEB_POINTER(PVOID) FlsData;
BOOLEAN SafeThunkCall;
BOOLEAN BooleanSpare [3];
} PEBTEB_STRUCT(TEB),
*PEBTEB_STRUCT(PTEB);