首页
社区
课程
招聘
[讨论]谁hook过shadow ssdt表的NtUserGetMessage?
发表于: 2016-12-21 10:30 5798

[讨论]谁hook过shadow ssdt表的NtUserGetMessage?

2016-12-21 10:30
5798
我今天hook了shadow ssdt 表的NtUserGetMessage, 但是在取消hook的时候就蓝屏了, 用KernelDetecive恢复就不会蓝屏, 但是我自己attach到csrss进程, 然后关闭保护, 然后取消hook就蓝屏了, 取消hook其他函数都没有蓝屏, 就这个函数在取消的时候蓝屏了, 这是为什么?
代码如下:

#pragma PAGEDCODE
void openProtection(){
        __asm //恢复页保护
        {
                mov eax,cr0
                or  eax,10000h //or eax,not 0FFFEFFFFh
                mov cr0,eax
                sti
        }
}

#pragma PAGEDCODE
void closeProtection(){
        __asm //去掉页面保护
        {
                cli
                mov eax,cr0
                and eax,not 10000h //and eax,0FFFEFFFFh
                mov cr0,eax       
        }
}

//获取csrss的进程id
HANDLE GetCsrssPid()
{
        HANDLE Process, hObject;
        HANDLE CsrId = (HANDLE)0;
        OBJECT_ATTRIBUTES obj;
        CLIENT_ID cid;
        UCHAR Buff[0x100];
        POBJECT_NAME_INFORMATION ObjName = (POBJECT_NAME_INFORMATION)&Buff;
        PSYSTEM_HANDLE_INFORMATION_EX Handles;
        ULONG r;
       
        Handles = (PSYSTEM_HANDLE_INFORMATION_EX)GetInfoTable(SystemHandleInformation);
       
        if (!Handles) return CsrId;
       
        for (r = 0; r < Handles->NumberOfHandles; r++)
        {
                if (Handles->Information[r].ObjectTypeNumber == 21) //Port object
                {
                        InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
                       
                        cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;
                        cid.UniqueThread = 0;
                       
                        if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid)))
                        {
                                if (NT_SUCCESS(ZwDuplicateObject(Process, (HANDLE)Handles->Information[r].Handle,NtCurrentProcess(), &hObject, 0, 0, DUPLICATE_SAME_ACCESS)))
                                {
                                        if (NT_SUCCESS(ZwQueryObject(hObject, ObjectNameInformation, ObjName, 0x100, NULL)))
                                        {
                                                if (ObjName->Name.Buffer && !wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20))
                                                {
                                                        CsrId = (HANDLE)Handles->Information[r].ProcessId;
                                                }
                                        }
                                       
                                        ZwClose(hObject);
                                }
                               
                                ZwClose(Process);
                        }
                }
        }
       
        ExFreePool(Handles);
        return CsrId;
}

BOOLEAN cancelShadowSSDTHook(){
        PEPROCESS crsEProc;
        if (!NT_SUCCESS(PsLookupProcessByProcessId((ULONG)GetCsrssPid(), &crsEProc)))
        {
                DbgPrint("PsLookupProcessByProcessId() error\n");
                return FALSE;
        }
        KeAttachProcess(crsEProc);
        closeProtection();
        *(ULONG *)(*(ULONG *)(getShadowSSDT() + 0x10) + index * 4) = beforeHook;
        openProtection();
        pShadowSSDTHookInfo->isHook = FALSE;
        KeDetachProcess();
        return TRUE;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (21)
雪    币: 3
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
上面的代码在执行cancelShadowSSDTHook()的时候就会蓝屏
2016-12-21 10:34
0
雪    币: 12876
活跃值: (9357)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
3
请用InterlockedExchange系列
2016-12-21 11:13
0
雪    币: 3
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
InterlockedExchange((volatile LONG *)(*(ULONG *)(getShadowSSDT() + 0x10) + pShadowSSDTHookInfo->index * 4), pShadowSSDTHookInfo->beforeHook);
是这样写吗? 这样写在取消hook的时候也蓝屏, 取消hook其他函数的时候, 就不会蓝屏, 取消hook NtUserPeekMessage都不蓝屏, 就在取消hookNtUserGetMessage的时候蓝屏,提升IRQL到 HIGH_LEVEL 31级别都不行。 我用Kernel Detective这个软件取消hook就不会蓝屏。
2016-12-21 11:37
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
5
你这又是一个老生常谈的问题啊!你着是多线程共享冲突啊!整个HOOK过程,连保证HOOK原子性操作的代码都没有!请记住,内核编程是在多线程环境的,内核编程任何时候都要考虑多线程共享冲突!你着程序问题非常简单,你HOOK时没有任何代码保证,被HOOK的程序段没有被执行,要是HOOK进行的时候,呗HOOK的程序正在执行,你等着,蓝屏绝对马上发生!同理,解除HOOK的时候,HOOK的程序正在执行的话,接触HOOK也会导致直接蓝屏!而且由于有些函数是阻塞式执行的,比如你的NtUserGetMessage函数,它是没有GUI消息的时候,是阻塞的,当有消息就立刻返回!要是,阻塞的NtUserGetMessage函数没有返回,而你的HOOK代码又在卸载之后,没有继续等待NtUserGetMessage返回,而是直接卸载驱动的话,你就等着蓝屏吧!
2016-12-21 12:28
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
这个方法没用的,乖乖的使用DPC和MDL的方法吧!使用DPC阻塞除了当前核心之外的其余的核心的运行,直到HOOK完成!使用MDL的方法对代码段进行修改!
2016-12-21 12:38
0
雪    币: 3
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
PMDL    MDSystemCall;
PVOID        MappedSCT;
#pragma PAGEDCODE
void openProtection(){
        if(MDSystemCall)
        {
        MmUnmapLockedPages(MappedSCT, MDSystemCall);
        IoFreeMdl(MDSystemCall);
     }
//         __asm //恢复页保护
//         {
//                 mov eax,cr0
//                 or  eax,10000h //or eax,not 0FFFEFFFFh
//                 mov cr0,eax
//                 sti
//         }
}

#pragma PAGEDCODE
void closeProtection(){
        MDSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable->ServiceTableBase, KeServiceDescriptorTable->NumberOfServices*4);
    if(!MDSystemCall){
                KdPrint(("分配mdl失败!"));
                return;
        }
    MmBuildMdlForNonPagedPool(MDSystemCall);
    MDSystemCall->MdlFlags = MDSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
    MappedSCT = MmMapLockedPages(MDSystemCall, KernelMode);
//         __asm //去掉页面保护
//         {
//                 cli
//                 mov eax,cr0
//                 and eax,not 10000h //and eax,0FFFEFFFFh
//                 mov cr0,eax       
//         }
}

我把去掉保护和开启保护的方法替换掉了, 可是还是HOOK其他方法没问题, hook NtUserGetMessage之后, 在DriverUnload中取消HOOK就蓝屏了,是不是NtUserGetMessage只能用内联hook啊?
2016-12-21 13:47
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
提高IRQL,用原子操作
2016-12-21 14:11
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
9
不够,不够!MDL只是解决了一部分问题!执行HOOK的程序要在DPC例程里完成!还有,过滤函数里要有一个调用计数,用来记录函数被调用的次数,先初始化计数为0,函数被调用时计数加一,函数调用完成时计数减一,在驱动卸载时,检查函数调用计数,如果这个计数不为0,就陷入延时等待,直到这个计数变为0为止!因为你不知道你的过滤函数什么时候调用完成,如果过滤函数没有完成,你就卸载驱动,那蓝屏是一定的了,所以需要一个计数,用来统计过滤函数调用次数!
2016-12-21 15:17
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
10
在使用MDL进行操作的时候。你需要保证原子性,也就是需要保证绝对的单线程环境,但是这里是代码是在内核执行的,所以不是单线程的,这就需要你自己编程来保证单线程!系统提供了DPC例程来保证单线程环境,不过很遗憾,DPC例程只能使得例程代码在但线程状态,不过有点好处,就是,系统保证DPC例程不会被打断,所以,我们只需要让所有可能使用的CPU核心处于我们的DPC例程里。这样我们强制全局都变成单线程的,而且是不可打断的状态!这时我们就可以方便的进行HOOK而不必担心多线程环境导致的问题了!当然,HOOK过程要快速完成,否则,系统会被一直拖着,无法运行的!
2016-12-21 15:29
0
雪    币: 209
活跃值: (1143)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
看你开关内存保护时无论是用cr0寄存器还是用MDL时都用了#pragma PAGEDCODE这句,
这是使用了分页内存吧,
在整个代码中都去掉#pragma PAGEDCODE,
全部用非分页内存试试!
2016-12-21 16:07
0
雪    币: 3
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
试过了, 我直接把头文件里面的#define PAGEDCODE改成了codseg()也不行
2016-12-21 18:26
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
13
不是分页内存的问题啦!你们仔细看看代码!代码卸载hook时,有没有确保被hook的函数全部返回呢?好像没有这个代码吧?那这样问题就知道了,他在卸载驱动时,被hook的代码没有返回,而卸载驱动后,由于被hook的函数返回了!回到的地方,代码却被卸载了!不蓝屏才怪!
2016-12-21 20:28
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
14
我都把问题直接告诉你了!根本就不是这个问题,你加那个有什么用啊!再说了,你的代码本身就要运行在非分页内存,这个代码吧程序放到分页内存中,本就是一个更大的错误!
2016-12-21 20:29
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
15
你还是去看《寒江独钓 Windows内核编程》这本书吧!这本书上有HOOK的章节,其中的注意事项中,就有你遇到的问题!和你本程序的问题一模一样,只是HOOK的函数不同而已!我怎么说你们都不明白,还不如去看看书上的例子呢!看看人家是怎么处理的,而你又是怎么处理的!学习下吧
2016-12-21 20:46
0
雪    币: 3
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
谢谢了, 差不多明白了, 在hook了之后, 我的新函数call了旧函数, 在旧函数返回之前, 我把驱动卸载了, 这时候旧函数ret回来, 可是这个时候驱动已经卸载了, 代码不存在了, 所以就蓝屏了
2016-12-21 21:05
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
17
差不多就是这个啦!当然,还有一些细节问题,你得注意啦!
2016-12-21 21:19
0
雪    币: 209
活跃值: (1143)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
加锁行不行:

KSPIN_LOCK spinlock;  //自旋锁必须是全局的,以防止多个CPU重入

KeInitializeSpinLock(&spinlock);  //初始化自旋锁

KeAcquireSpinLock(&spinlock, &irql);  //启用自旋锁

//这里执行想要的操作
UnHook();

KeReleaseSpinLock(&spinlock, irql);  //释放自旋锁
2016-12-21 23:16
0
雪    币: 12876
活跃值: (9357)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
19
call旧函数之前对引用计数+1,call完了把引用计数-1

卸载的时候等待直到引用计数为0

当然,直接用semaphore也可以
2016-12-21 23:35
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
20
楼主都知道问题在哪了,你还不明白么?楼主遇到的问题跟HOOK代码的重入无关,当然他的代码也有这个问题!他现在遇到的问题是楼主的新函数在call就函数没有完成之前就已经将代码卸载了,导致旧函数ret时回到了一个无效的地址!明白了么?
2016-12-21 23:36
0
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
21
对的,就是这样处理的!不过要使用InterLocked系列函数来操作引用计数哦!
2016-12-21 23:38
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
牛人啊学习
2017-1-1 23:48
0
游客
登录 | 注册 方可回帖
返回