首页
社区
课程
招聘
[原创]Win8 32位中SSDT Shadow Hook的实现方法
发表于: 2013-12-9 17:31 58851

[原创]Win8 32位中SSDT Shadow Hook的实现方法

2013-12-9 17:31
58851
收藏
免费 5
支持
分享
最新回复 (61)
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
26
今天我有试了一下系统启动进程加载过程:
1.当刚开始加载系统时

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 856e0340  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 82603000  HandleCount: <Data Not Accessible>
    Image: System

PROCESS 865f68c0  SessionId: none  Cid: 01f4    Peb: 7fa03000  ParentCid: 0004
    DirBase: 28a04020  ObjectTable: 8b863980  HandleCount: <Data Not Accessible>
    Image: smss.exe   

//csrss.exe进程并没有启动,Win32k模块在系统中没有加载。
kd> lm vm win32k
start    end        module name    //这里可以看到确实win32k没有起来。
kd> lm
start    end        module name
770e0000 770e0000   ntdll      (no symbols)  

2系统继续进行加载:当加载到csrss子系统进程启动以后。再次查看win32模块,已经加载到了系统内核空间。但是当我们看查看当前进程时,依然是system系统进程,SessionId也是none。
这就证明上面这位他的观点还是有问题的。看来觉得Win32模块是否加载到内核空间不是根据那个进程是否是在Session 内进程,还是Session外进程决定的。决定Win32k加载的关键还是看启动顺序,也就是看Csrss进程是否启动了。如果csrss已经启动,那么win32k就在内核空间加载了。反正在它之前启动的模块将看不到Win32k模块在内核中。

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 856e0340  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 82603000  HandleCount: <Data Not Accessible>
    Image: System   

PROCESS 865f68c0  SessionId: none  Cid: 01f4    Peb: 7fa03000  ParentCid: 0004
    DirBase: 28a04020  ObjectTable: 8b863980  HandleCount: <Data Not Accessible>
    Image: smss.exe

PROCESS 86420c40  SessionId: 0  Cid: 0244    Peb: 7f525000  ParentCid: 01f4
    DirBase: 28a04040  ObjectTable: 8ee5cac0  HandleCount: <Data Not Accessible>
    Image: smss.exe

PROCESS 866367c0  SessionId: 0  Cid: 024c    Peb: 7f316000  ParentCid: 0244
    DirBase: 28a04060  ObjectTable: 8b8c10c0  HandleCount: <Data Not Accessible>
    Image: csrss.exe   //子系统已经可以在进程列表中查到了。

kd> !process -1 0    //即使是当前进程是System,也不影响Win32k的加载。
PROCESS 856e0340  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 82603000  HandleCount: <Data Not Accessible>
    Image: System

kd> lm vm win32k   //win32k也在内核中加载了。
start    end        module name
91c1c000 91f6d000   win32k     (private pdb symbols)  c:\symbols\win32k.pdb\B0A480ABE32A408296957A25097BEBAC2\win32k.pdb
    Loaded symbol image file: win32k.sys
    Image path: win32k.sys
    Image name: win32k.sys
    Timestamp:        Thu Jul 26 10:33:40 2012 (5010AC84)
    CheckSum:         0034BC9A
    ImageSize:        00351000
    Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4

3. 当KTHREAD的ServiceTable 不一定指向 Shadow地址,它可能指向Shadow也可能指向SSDT。那么决定它指向哪里的关键是什么呢?是看这个KTHREAD是否是GUI线程。判断这个KTHERAD是否是GUI线程的关键点之一就是它的Win32Thread成员是否为0。
这个观点是没有错的,所以我这个方法虽然有不足之处,但是总体方向是没问题的。希望能够给位网友在今后工作中有所帮助。至于其他人有好的方法,其实不用跟我争吵,快快拿出来共享就是了。多做对大家有益的事就好了。
2013-12-10 15:45
0
雪    币: 219
活跃值: (788)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
27
。。。  顶
2013-12-10 21:51
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
28
DebugMan现在没落了,很可惜,所以原帖估计是找不到了,不过楼主可以看看下面这篇文章

http://bbs.pediy.com/showthread.php?t=56955

好好看看第3种方法是什么?

然后再瞪大眼睛看一看这篇文章是什么时间发表的?

我说四年前还是保守了说的。。。

你没看到就等于不存在? 这是什么逻辑?
2013-12-10 22:34
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
29
win32k.sys与Session有关是铁打的事实,楼主要是真不想承认就算了。。。

有几个问题楼主可以回答一下:
1、谁加载了win32k.sys ?
2、是用什么方式加载的?(或者说调用哪个函数加载的) 加载时,当前进程是谁?
3、win32k.sys刚被加载完的时候(在上面那个关键的调用结束之后),加载者进程(记为进程A)是否可以访问win32k.sys的地址空间?(注意不能只看有没有加载,加载了也不代表你就能访问)
4、csrss.exe是在win32k.sys加载前启动的还是加载后启动的?
5、csrss.exe第一次运行时,在该进程中能否访问win32k.sys的地址空间? 此时A进程是否可以访问win32k.sys的地址空间?
6、winlogon.exe何时被启动? 此时进程A能否访问win32k.sys的地址空间?
7、经最终观察,在系统启动完成后(桌面加载完毕),进程A却无法访问win32k.sys的地址空间,是什么时候造成了这种变化?

楼主观察系统启动的时候,获取那些信息是在什么时候? 这个要非常精确才行,不然按你的分析,我完全都可以认为是System进程加载了win32k.sys呢!
2013-12-11 00:24
0
雪    币: 155
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
30
我就说至少有三四种嘛~
2013-12-11 00:38
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
31
3。从KTHREAD.ServiceTable里面搜索
如果是GUI线程 那么就是指向ServiceDescriptorTableShadow
其实个人更加倾向这个办法 稳定安全可靠,上面那个代码也许会受到以后系统代码变化影响 但是这个肯定不会

Copy code

    GetServiceDescriptorTableShadowAddress proc uses esi edi ebx

    local dwThreadId:DWORD

        xor ebx, ebx                ; = NULL. Assume ServiceDescriptorTableShadow will be not found

        mov eax, KeServiceDescriptorTable
        mov esi, [eax]

        ; Find KTHREAD.ServiceTable field
        ; For non-GUI threads this field == KeServiceDescriptorTable
        ; and it points to ServiceDescriptorTable
        ; For GUI threads
        ; ServiceDescriptorTableShadow

        invoke KeGetCurrentThread
        mov edi, 200h-4
        .while edi
            .break .if dword ptr [eax][edi] == esi
            dec edi
        .endw

        .if edi != 0
            ; edi = offset to ServiceTable field in KTHREAD structure
            mov dwThreadId, 080h
            .while dwThreadId < 400h
                push eax                    ; reserve DWORD on stack
                invoke PsLookupThreadByThreadId, dwThreadId, esp
                pop ecx                        ; -> ETHREAD/KTHREAD
                .if eax == STATUS_SUCCESS
                    push dword ptr [ecx][edi]
                    fastcall ObfDereferenceObject, ecx
                    pop eax
                    .if eax != esi
                        mov edx, MmSystemRangeStart
                        mov edx, [edx]
                        mov edx, [edx]
                        .if eax > edx        ; some stupid error checking
                            mov ebx, eax
                            invoke DbgPrint, $CTA0("FindShadowTable: Found in thread with ID: %X\n"), dwThreadId
                            .break
                        .endif
                    .endif
                .endif
                add dwThreadId, 4
            .endw
        .endif

        mov eax, ebx
        ret

    GetServiceDescriptorTableShadowAddress endp

--------------------------------------------------------------------------
你是指的这种方法吧?
1。 这种方法如果不是看注释,你能看懂他的具体执行过程。
这个方法,可操作性太差了。不光是我,我估你在实际项目中都没法使用。当然我更没法学习这种方法了。

2。  ; For non-GUI threads this field == KeServiceDescriptorTable
这个方法的判断GUI线程的方法和我的方法不一样。他是比对ServiceTable是否为KeServiceDescriptorTable来判断THREAD是否是GUI线程的,而我的方法是判断THREAD中Win32Thread这个成员来判断GUI线程的。这个判断出发点就不同。这怎么能说是一种方法呢?

2013-12-11 11:31
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
32
从我分析的结果看,这位老兄的观点,System和smss是 Session外进程所以不能看到,win32k模块是完全错误的。
2013-12-11 11:41
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
33
smss加载了win32k,然后是csrss和winlogon, 具体细节不用我过多解释,自行查看wrk源码内容。要是仁兄能够认为是system加载的win32k,我真是无言以对了。
2013-12-11 11:45
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
34
不急不急,你先回答我提出的那些问题
2013-12-11 11:53
0
雪    币: 773
活跃值: (442)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
35
KeAddSystemServiceTable  加个特征码 照样取
2013-12-11 12:28
0
雪    币: 233
活跃值: (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
36
[QUOTE=啤酒肚;1246010]从我分析的结果看,这位老兄的观点,System和smss是 Session外进程所以不能看到,win32k模块是完全错误的。[/QUOTE]
kd> !process 0 0 system
PROCESS 85a67040  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 88403000  HandleCount: <Data Not Accessible>
    Image: System

kd> .process /i 85a67040; g
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
81d083a4 cc              int     3
kd> !process -1 0; lm m win32k
PROCESS 85a67040  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 88403000  HandleCount: <Data Not Accessible>
    Image: System

start    end        module name
8f845000 8fb96000   win32k     (export symbols)       win32k.sys
kd> dd poi(nt!KeServiceDescriptorTableShadow+10) l4
8fb37000  ???????? ???????? ???????? ????????

kd> !process 0 0 smss.exe
PROCESS 86fc4cc0  SessionId: none  Cid: 0200    Peb: 7f2cf000  ParentCid: 0004
    DirBase: 3e1be020  ObjectTable: 8c048580  HandleCount: <Data Not Accessible>
    Image: smss.exe

PROCESS 85b0bc00  SessionId: 1  Cid: 0298    Peb: 7f3ad000  ParentCid: 0200
    DirBase: 3e1be080  ObjectTable: 00000000  HandleCount:   0.
    Image: smss.exe

kd> .process /i 86fc4cc0; g
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
81d083a4 cc              int     3
kd> !process -1 0; lm m win32k
PROCESS 86fc4cc0  SessionId: none  Cid: 0200    Peb: 7f2cf000  ParentCid: 0004
    DirBase: 3e1be020  ObjectTable: 8c048580  HandleCount: <Data Not Accessible>
    Image: smss.exe

start    end        module name
8f845000 8fb96000   win32k     (export symbols)       win32k.sys
kd> dd poi(nt!KeServiceDescriptorTableShadow+10) l4
8fb37000  ???????? ???????? ???????? ????????

kd> .process /i 85b0bc00; g
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
81d083a4 cc              int     3
kd> !process -1 0; lm m win32k
PROCESS 85b0bc00  SessionId: 1  Cid: 0298    Peb: 7f3ad000  ParentCid: 0200
    DirBase: 3e1be080  ObjectTable: 00000000  HandleCount:   0.
    Image: smss.exe

start    end        module name
8f845000 8fb96000   win32k     (export symbols)       win32k.sys
kd> dd poi(nt!KeServiceDescriptorTableShadow+10) l4
8fb37000  8fa2a1a3 8fa8de22 8fa8e2bc 8fa8ff6d
2013-12-11 12:56
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
37
有结构体尽量用结构体,硬编码能不用就不用。
2013-12-11 18:43
0
雪    币: 241
活跃值: (55)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
38
看此,把所有进程/线程都遍历了,用的是pspcidtable:

...
...
thread id 4-1268, win32Thread 0, service table 0x81e9d600
thread id 1276-1272, win32Thread 2172687208, service table 0x81e9d5c0
process 0x8900a040 msdtc.exe, pid:1276, path C:\Windows\System32\msdtc.exe
thread id 1184-1280, win32Thread 0, service table 0x81e9d600
thread id 2004-1284, win32Thread 2705825120, service table 0x81e9d5c0
process 0x88e46040 vmtoolsd.exe, pid:1288, path C:\Program Files\VMware\VMware Tools\vmtoolsd.exe
thread id 1288-1292, win32Thread 2409460656, service table 0x81e9d5c0
thread id 1276-1296, win32Thread 2172688592, service table 0x81e9d5c0
thread id 788-1312, win32Thread 0, service table 0x81e9d600
thread id 788-1316, win32Thread 0, service table 0x81e9d600
thread id 996-1332, win32Thread 0, service table 0x81e9d600
thread id 996-1336, win32Thread 0, service table 0x81e9d600
thread id 2004-1340, win32Thread 2408911616, service table 0x81e9d5c0
thread id 344-1344, win32Thread 2409476528, service table 0x81e9d5c0
thread id 1424-1356, win32Thread 0, service table 0x81e9d600
thread id 996-1360, win32Thread 0, service table 0x81e9d600
thread id 996-1364, win32Thread 0, service table 0x81e9d600
thread id 3748-1368, win32Thread 0, service table 0x81e9d600
thread id 828-1372, win32Thread 2409427672, service table 0x81e9d5c0
thread id 728-1376, win32Thread 0, service table 0x81e9d600
thread id 996-1380, win32Thread 0, service table 0x81e9d600
thread id 1276-1400, win32Thread 0, service table 0x81e9d600
thread id 768-1412, win32Thread 0, service table 0x81e9d600
thread id 1288-1420, win32Thread 2409550632, service table 0x81e9d5c0
process 0x88e88040 MsMpEng.exe, pid:1424, path C:\Program Files\Windows Defender\MsMpEng.exe
thread id 1424-1428, win32Thread 2409487224, service table 0x81e9d5c0
thread id 1424-1436, win32Thread 0, service table 0x81e9d600
thread id 3748-1440, win32Thread 0, service table 0x81e9d600
thread id 1424-1444, win32Thread 0, service table 0x81e9d600
thread id 1424-1448, win32Thread 0, service table 0x81e9d600

...
...

所以,SSDT - 0x81e9d600,SSDT shadow - 0x81e9d5c0

lkd> dd KeServiceDescriptorTable
81e9d600  81d75e6c 00000000 000001b1 81d76534
81e9d610  00000000 00000000 00000000 00000000
81e9d620  00000003 00000000 00000000 00000000
81e9d630  00003000 00000000 e123a087 01cef63d
81e9d640  81e80120 801a0120 00000000 00000000
81e9d650  00000000 00000000 00000000 00000000
81e9d660  00000000 00000000 00000000 00000000
81e9d670  00000000 00000000 00000000 00000000

lkd> dd KeServiceDescriptorTableShadow
81e9d5c0  81d75e6c 00000000 000001b1 81d76534
81e9d5d0  8fd1f000 00000000 0000040c 8fd20448
81e9d5e0  00000040 a0ef3fff 81e73da0 89d6ed82
81e9d5f0  744ce155 00000423 00070001 00010001
81e9d600  81d75e6c 00000000 000001b1 81d76534
81e9d610  00000000 00000000 00000000 00000000
81e9d620  00000003 00000000 00000000 00000000
81e9d630  00003000 00000000 e123a087 01cef63d

Matched. Hooray~~
2013-12-12 08:55
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
39
两个问题:1.楼主的方法就是从KTHREAD中找ServiceTable,难道只是因为你判断GUI线程的依据不太一样,这就成了一种全新的方法?  
2.关于win32k.sys访问的事,我给出了自己的解释,别的同学也给出了实际观察结果,楼主敢不敢正面回应这些问题?
2013-12-12 09:25
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
40
1. 我已经说过了,你那个代码没有什么可操作性。虽然公布了KTHREAD->ServiceTable,但是那个代码基本上没法在项目中实际使用。那个代码几乎不可能抄袭。判断的方法不同当然是不同的方法了,这个不是我说了算的,大家的眼睛是雪亮的。

2. 你那些问题我已经回答了,至于需要回答的细致程度,这个因人而异。请自行查看wrk就是了。
2013-12-12 10:11
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
41
1.仅仅是判断方法不同就是全新方法? 这个说法你看大家认不认账?
2.请正面回答我提出的那几个问题,什么“自行查看wrk就可以了”这种话谁不会讲?
2013-12-12 11:45
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
42
当然了,方法有改进。
2013-12-12 11:50
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
43
楼主你这不是在打自己脸吗? 如果不是同一种方法,何谈改进? 既然说是改进,那你意思就是同一种方法喽?或者至少说,你的“方法”跟我提到的那种完全是同宗喽?  你不是一直说你创造了一种全新方法吗?



你的回答,随便看一看进程树或者百度一下就可以知道,敢不敢针对这几个问题一个一个列出来详细答案?  我比较鲁钝,你如果想告诉我wrk里有答案,那么请告诉我是哪个源文件哪个函数的哪一行?
2013-12-12 12:07
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
44
拿出小板凳看回复。
2013-12-12 12:54
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
45
这个我已经回答多次了,你那个方法没有可操作性。那个代码一大堆寄存器,
例如这几句:

.if eax != esi
                        mov edx, MmSystemRangeStart
                        mov edx, [edx]
                        mov edx, [edx]
                        .if eax > edx        ; some stupid error checking
                            mov ebx, eax
                            invoke DbgPrint, $CTA0("FindShadowTable: Found in thread with ID: %X\n"), dwThreadId
                            .break
                        .endif

你给我解释介绍这几句是什么意思? 这个代码你自己项目中估计都不会使用。这个方法有两个特点:一个是检测GUI线程方法,一个是取得shadow的地址。首先不说我没看过这个方法,第二个 这个方法的检测根本就和我的不同,50%跟我的方法不一样。这怎么能说是一种方法呢?

另外那个我已经回答你了。剩下就是体力活了,一个一个回答我还真没那个体力。你不会希望我一句一句给你读出来吧?
2013-12-12 14:16
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
46
1.话都已经说到这份儿上了,你还继续坚持说不是一种方法,你好好看看我说的那个帖子里人家的几种方法间有多大差别,到底什么叫“新的方法”?  
2.你如果还想认真讨论问题,就好好回答我的那些关于win32k的问题~  不敢谈细节,说是“体力活”? System和smss进程访问不了win32k,你连事实都理不清,还说什么呢?
2013-12-12 15:01
0
雪    币: 97
活跃值: (141)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
47
是不是一个新方法不是你说了算的,这个大家眼睛都是雪亮的。不要侮辱大家的智商。至于回不回答你的问题,是我的自由。你这是请教问题的态度吗?

要不你把我上面那段汇编翻译一下,我就回答你。
2013-12-12 15:23
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
48
连问题都不敢正面回答,看来是无法交流了,算了……
2013-12-12 15:41
0
雪    币: 33
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
49
mark
2013-12-13 19:59
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
50
MJ0011你好,能不能用回QIHOOCOM这个帐号,或者换一个其他别人不知道的马甲?您的这个帐号被人曝光了。

有了几千万还玩技术,真是值得晚辈们学习啊。
2013-12-13 20:24
0
游客
登录 | 注册 方可回帖
返回
//