Visual Basic获取系统服务描述表入口地址方法 |
在《自动猎取 NT 系统服务 形容表与函数名映射表》一文中我 使用MS提供的DbgHelp库,从符号库文件中搜索KeServiceDescriptorTable和KeServiceDescriptorTableShadow符号,以猎取系统服务 形容表入口地址 。这种 步骤逻辑 方便,然而对不同操作系统版本的调试符号文件有依赖性,不 实用于作为工具被散发出去的程序 。 因此这儿给出另外一种从线程 本身的 特点着手猎取系统服务 形容表入口地址的 步骤 。 我们所说的线程,实际上分为核心态和消费者态两 部分 。Win32下这两者 根本上是1对1的关系, 其余平台如Solaris或Linux 2.6以往的版本则 使用不同的映射模型 。而Win32系统中核心态的线程,实际上也分为两类:工作线程和GUI线程 。前者是 构建核心线程的缺省类型,后者在线程第一次 使用Win32k.sys系统服务时自动转换,或者 使用PsConvertToGuiThread函数(ntos\ps\psquery.c:3247)显式转换 。两者中间的区别重要在于 使用的资源缺省大小不同,以及 使用的系统服务 形容表不同 。这也是为何系统服务 形容表要分为KeServiceDescriptorTable和KeServiceDescriptorTableShadow的缘由之一,后者包含前者没有的对GDI服务的入口函数地址,普通在Win32k.sys中实现 。核心线程对象的ETHREAD::KTHREAD::ServiceTable字段 保留了此线程 实用的系统调用服务表地址,此字段也被PsConvertToGuiThread函数用于推断线程类型 。 性能与windows xp/2003提供的IsGUIThread函数类型 。 使用上我们 可以 缔造一个线程,此线程不做任何实际工作,只不过依据我们要取哪个系统服务 形容表来决定是不是调用GDI函数,如 以下为 引用: class TGuiThread : public TThread { public: TGuiThread(void) : TThread(false) { FreeOnTerminate = false; } void __fastcall Execute(void) { ::GetDesktopWindow(); } }; 在需求猎取地址时,我们 可以 缔造一个此线程的实例, 而后通过其句柄猎取内核查象地址 。 以下为 引用: DWORD TServiceTableApplication::GetpKeServiceDescriptorTableAddress(void) const { std::auto_ptr GuiThread->WaitFor(); ::THandleTable tblHandles; PVOID pObj = NULL; TSystemHandleList& handles = tblHandles.HandleByProcessID[::GetCurrentProcessId()]; for(TSystemHandleCPtr itHandle = handles.begin(); itHandle != handles.end(); itHandle++) { if((HANDLE)itHandle->Handle == (HANDLE)GuiThread->Handle) { pObj = itHandle->Object; break; } } |