能力值:
( LV9,RANK:610 )
2 楼
好象一直以来我们所说的ShadowSSDT的概念和系统中的KeServiceDescriptorTableShadow有一点出入,我们所说的专指GUI ServiceTable这个表,而它实际上只是KeServiceDescriptorTableShadow的一部分而已
正常情况下,ETHREAD中的ServiceTable,要么指向KeServiceDescriptorTable,要么指向KeServiceDescriptorTableShadow
答问题一:KeServiceDescriptorTableShadow中其实是四张表(后两张无效),第一张和KeServiceDescriptorTable中的那个是一样的,叫做KiServiceTabe,第二张才是真正的GUI ServiceTable,名字叫W32pServiceTable,所以不论是不是GUI线程,它的ServiceTable其实都包含有KiServiceTable这张表,所以调用win32服务当然是没有问题的,比如调用CreateFile时KiFastCallEntry会根据NtCreateFile的ServiceIndex来判断应该使用哪张表,ServiceIndex大于0x1000则用第二张表
答问题二:
有个函数叫做PsConvertToGuiThread,用来完成你所说的工作~~
NTSTATUS
PsConvertToGuiThread(
VOID
)
/*++
Routine Description:
This function converts a thread to a GUI thread. This involves giving the
thread a larger variable sized stack, and allocating appropriate w32
thread and process objects.
*/
答问题三:
你说的是直接修改ETHREAD->ServiceTable这个字段的值吗?可以修改,在系统调用进入KiFastCallEntry时,会从当前线程的KTHREAD中取出这个表然后使用,如果修改的话,保证你提供的地址是有效的而且包含了正确的系统服务表就可以了,有一篇文章叫做《Hide your SSDT Hooks》,就是这么做的~~
能力值:
( LV5,RANK:70 )
3 楼
强大的achillis
能力值:
( LV3,RANK:20 )
4 楼
首先十分感谢一楼大牛的指导..
不过.我看了你的说法后.反而迷糊了..
为什么呢.
我的个人理解是. typedef struct _SYSTEM_SERVICE_TABLE
{
PVOID ServiceTableBase; // SSDT (System Service Dispatch Table)的基地址
PULONG ServiceCounterTableBase; // 用于checked builds, 包含SSDT中每个服务被调用的次数
ULONG NumberOfService; // 服务函数的个数, NumberOfService*4 就是整个地址表的大小
ULONG ParamTableBase; // SSPT (System Service Parameter Table)的基地址
} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
SYSTEM_SERVICE_TABLE ntoskrnl; // ntoskrnl.exe的服务函数
SYSTEM_SERVICE_TABLE win32k; // win32k.sys的服务函数,(gdi.dll/user.dll的内核支持)
SYSTEM_SERVICE_TABLE NotUsed1;
SYSTEM_SERVICE_TABLE NotUsed2;
} SYSTEM_DESCRIPTOR_TABLE, *PSYSTEM_DESCRIPTOR_TABLE; PSYSTEM_DESCRIPTOR_TABLE 才是真正的 KeServiceDescriptorTable (这也是系统导出的.可惜只导出部分) SSDT只是这个KSSDT中的第一项.(这也是为什么好多人偷懒.总喜欢直接强制转换指针.把KSSDT直接当SSDT用也是对的)..Shadow SSDT是这个表中的第二项..但很可惜.没导出.用的时候不能直接操作.得自己搜地址.赋值和强制转换一次才行. (比如 PShadowSSDT=(ShadowSSDT结构)地址.)..
所以.我看了Shadow SSDT Hook系列的文章后觉得.如果指向了ShadowSSDT就认为.是指向了.第二项...
看来或许我的理解是错的吧..是不是这个指针直接指向的是 KeSSDT.(也就是他们全部)..
如果是..那么就又迷糊了.既然都包含全部了.为什么说指向第一项SSDT为主的时候.ShadowSSDT地址却是无效的?(这也是ShadowSSDT HOOK文章上经常说的)..是不是因为它没导出?还是?
..至于第三个问题.我的本意是说.如果线程指向SSDT..我就把SSDT移动一个位置.把修改指向.不知道万一这个线程要求立刻切换到ShadowSSDT内.这个时候系统怎么才能知道该切换到那..呵呵..
不过我想到这里.感觉.如果是直接指向他们全部..那么就一切好说了.不知道是不是这样??谢谢.
能力值:
( LV9,RANK:610 )
5 楼
正常情况下,ETHREAD中的ServiceTable,要么指向KeServiceDescriptorTable,要么指向KeServiceDescriptorTableShadow ,注意这句话啊
ETHREAD->ServiceTable从来不会直接接向GUI的那张表,而是指向整体的KeServiceDescriptorTableShadow,所以你以前可能理解错了,自己用windbg观察就知道了
系统中既有KeServiceDescriptorTable也有KeServiceDescriptorTableShadow,他们各司其职,非GUI线程使用KeServiceDescriptorTable,GUI线程使用KeServiceDescriptorTableShadow,这是Windows的设计。非GUI线程如果要调用GUI服务就会用PsConvertToGuiThread把ETHREAD->ServiceTable切换为KeServiceDescriptorTableShadow,而GUI线程调用普通的Win32服务时并不需要切换,因为KeServiceDescriptorTableShadow中已经有个这张表,所以KeServiceDescriptorTableShadow可以看成是KeServiceDescriptorTable的增强版
KeServiceDescriptorTable中第二张表之所以无效,是因为非GUI线程根本不需要这张表,所以没有填充
你的第三个问题,描述得还是不太清楚啊。到底你要移动的是哪个?其实不管怎么怎么改,只要合乎系统定下的规则就可以
能力值:
( LV3,RANK:20 )
6 楼
嗯..我果然理解错误..呵呵..
感谢指导..我以为切换就是第一项和第二项的切换..
原来他们有两个整体...
那个KeServiceDescriptorTableShadow和KeServiceDescriptorTable结构一样
也是四项..只不过.前者以SSDT为主.后者以ShadowSSDT为主?.等需要调用SSDT内函数的时候..
系统就会用你说的函数自动完成转换对吧..
如果是这样.我就明白了.
第三个问题.主要是我理解上的错误..导致这个字段修改也是错误.呵呵..
我说的移动.意思是.如果指向KeServiceDescriptorTable..我就从内核文件中把这个
KeServiceDescriptorTable整个结构复制出去.换个地方放哪里.然后修改线程的指针指向到这个地方..
但是还是那个问题.就在这个时候线程要求立刻切换到KeServiceDescriptorTableShadow..怎么办?
就算我把KeServiceDescriptorTableShadow也复制出来.系统也不知道该往哪里切换啊..
怎么告诉系统如何切换?
能力值:
( LV9,RANK:610 )
7 楼
第三个问题,你那样搞的话还麻烦了,不如直接替换每张表的基址,这样不管系统怎么切换都逃不出你的手掌心~~
能力值:
( LV3,RANK:20 )
8 楼
嗯..谢谢了..这个思路也不错..直接把地址数组整个替换掉..呵呵...
可以结贴了...非常感激你....
能力值:
( LV2,RANK:10 )
9 楼
不知道你想干什么。Shadow SSDT的前16个字节就是SSDT