首页
社区
课程
招聘
[原创]QQ电脑管家中的 Hook 过程分析
发表于: 2012-2-10 15:29 42533

[原创]QQ电脑管家中的 Hook 过程分析

2012-2-10 15:29
42533

QQ电脑管家中的 Hook 过程分析

作者:Fypher

最近对QQ电脑管家中的TsFltMgr.sys做了些分析,发现不少有用的东西,这里跟大家分享一下 TsFltMgr 对 KiFastCallEntry 的 Hook 过程。

虽然整个过程中并没有新的技术,但毕竟是面向市场的产品,从兼容性、安全性出发,工作过程中需要把问题考虑全面一些、处理问题时尽量细致,这些都是值得学习的地方。

我们从这个函数开始:

BOOLEAN StartWork()
{
    ULONG ulOsVersion;
    
    if (InitSafeBootMode)
        return FALSE;

    ulOsVersion = GetOsVersion();
    if (ulOsVersion !=  OS_VERSION_ERROR) 
    {
        ULONG ulKiFastCallEntry_Detour;

        if (!InitGlobalVars())
            return FALSE;

        if (!InitFakeSysCallTable())
            return FASLE;
    
        if ( ulOsVersion >= OS_VERSION_VISTA )
            ulKiFastCallEntry_Detour = (ULONG)KiFastCallEntry_Detour_AfterVista;
        else
            ulKiFastCallEntry_Detour = (ULONG)KiFastCallEntry_Detour_BeforeVista;

        return Hook(g_ulHookPoint, ulKiFastCallEntry_Detour);
    }

    return FALSE;
}
BOOLEAN InitGlobalVars() 
{
    ……
    // InitRegKeys();

    pSysMods = (BYTE *)GetSystemModules();    // 这个函数貌似有点小 bug
    pModInfo = (PSYSTEM_MODULE_INFORMATION)(pSysMods + 4);
    
    g_KernelBase = pModInfo->Base;
    g_KernelSize = pModInfo->Size;
    
    ExFreePool(pSysMods);
    
    RtlInitUnicodeString(&usRoutineName, L"KeServiceDescriptorTable");
    g_KeServiceDescriptorTable = (ULONG)MmGetSystemRoutineAddress(&usRoutineName);
    g_KiServiceTable = *(PULONG)g_KeServiceDescriptorTable;
    g_ServiceNumber = *(PULONG)(g_KeServiceDescriptorTable + 8);
    
    RtlInitUnicodeString(&usRoutineName, L"MmUserProbeAddress");
    g_MmUserProbeAddress = (ULONG)MmGetSystemRoutineAddress(&usRoutineName);
    
    ……

    // 从 KeAddSystemServiceTable 函数到开始做特征码搜索
    GetSSDTShadow(&g_ShadowServiceTable, &g_ShadowServiceNumber);

    g_ulHookPoint = FindHookPoint();          // 找 Hook 点
    g_JmpBack = g_ulHookPoint + 8;

    // 为什么要这样?看看 Detour 就明白了
    g_MmUserProbeAddress = *(PULONG)g_MmUserProbeAddress;
    
    ……
}
PBYTE GetSystemModules() {
    PBYTE pSysMods = NULL;
    ULONG ulSize = 0;
 
    ZwQuerySystemInformation(SystemModuleInformation, &ulSize, 0, &ulSize);

    pSysMods = (PULONG)ExAllocatePoolWithTag(PagedPool, ulSize, 'tPyF');
    
    if (pModInfo) 
    {
        NTSTATUS = ZwQuerySystemInformation(SystemModuleInformation, pSysMods, ulSize, NULL);
        if (!NT_SUCCESS( status ))
        {
            ExFreePool(pSysMods);
            pSysMods = NULL;
        }
    }
    return pSysMods;
}
ULONG FindHookPoint()  {
    ……
    ulKiSystemService = GetAddr_KiSystemService();
    if ( ulKiSystemService < g_KernelBase || ulKiSystemService > g_KernelBase + g_KernelSize )
        return 0;    
    
    for (ulAddr = ulKiSystemService; ulAddr < ulKiSystemService + 1024; ++ulAddr) {
        if (!ulAddr || !MmIsAddressValid((PVOID)ulAddr))
            break;
        if ( RtlCompareMemory((PVOID)ulAddr, &g_Signature, sizeof(g_Signature)) == sizeof(g_Signature) )
            return ulAddr;
    }
    return 0;
}

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

收藏
免费 6
支持
分享
最新回复 (39)
雪    币: 107
活跃值: (404)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
看起来有点意思啊....学习了...
2012-2-10 16:05
0
雪    币: 348
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
我学习下,看着有点头大了!
2012-2-10 16:15
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
4
你说的“其实我觉得 Hook 过程不会有绝对的安全,比如此时有一个线程正在执行指令N,结果Hook操作导致指令N和指令N + 1被替换掉了。虽然Hook过程中可以保证该线程不去抢占调度,但该线程恢复时同样会造成BSOD。”

其实其实HOOK点就3个NOP比较有意思。跟HOOK安全相关,即使不提升IRQL直接HOOK也没问题,也能保证在千万级别的机器上HOOK安全
2012-2-10 16:22
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
5
框架其实没什么技术。主要是考虑了兼容,HOOK稳定,可调试,接口统一,扩展性,安全反注册回调,先捕获调用。
2012-2-10 16:29
0
雪    币: 4984
活跃值: (3355)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
重新获取一次 ulNumberOfActiveCpu
是因为msdn上已经说了“Callers must also be aware that the value returned by KeQueryActiveProcessors can change during runtime on versions of Windows that support hot-add CPU functionality.”
但是我奇怪,为什么不是再调用一次KeQueryActiveProcessors 重新获取下CpuAffinity?
2012-2-10 16:41
0
雪    币: 1015
活跃值: (235)
能力值: ( LV12,RANK:440 )
在线值:
发帖
回帖
粉丝
7
谢谢楼主的分享,支持一下!
2012-2-10 16:50
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
8
原来如此
2012-2-10 16:57
0
雪    币: 2308
活跃值: (2200)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
9
在DPC例程里面,IRQL本来就是DISPATCH_LEVEL,这里的OldIrql = KeRaiseIrqlToDpcLevel();是不是可以省略呢?
2012-2-10 17:06
0
雪    币: 544
活跃值: (264)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
10


上传的附件:
2012-2-10 17:16
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
11
[QUOTE=KiDebug;1043968]

[/QUOTE]

檫,下个版本去掉。之前记得把TAG神马的都去了。
2012-2-10 17:27
0
雪    币: 2308
活跃值: (2200)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
12

这个让我想起了以前360的某个版本里面的 88 xxx
2012-2-10 17:29
0
雪    币: 581
活跃值: (149)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
13
素啊,影响不好,学生时间写代码BY XXX的坏习惯得改改
2012-2-10 17:30
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
14
我觉得是可以去掉的……
2012-2-10 17:31
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
15
我也是看到调试信息发现是你写的
2012-2-10 17:34
0
雪    币: 227
活跃值: (66)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
16
路过学习大牛。。好像在qqtalk上见过楼主?
2012-2-10 19:02
0
雪    币: 2323
活跃值: (4113)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
17
最近研究QQ管家的怎么这么多呢?
2012-2-10 19:10
0
雪    币: 220
活跃值: (721)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
能把完整工程发上来就好了
2012-2-10 20:41
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
sysnap主刀啊,世界清静了。
2012-2-11 07:20
0
雪    币: 242
活跃值: (473)
能力值: ( LV11,RANK:188 )
在线值:
发帖
回帖
粉丝
20
幡然醒悟, 真聪明,是这样的7字节吗?
PUSH  EBP;
MOV   EBP, ESP;
SUB    ESP, 0x20;
PUSH  EBX;
2012-2-11 11:29
0
雪    币: 71
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
谢谢楼主的分享,支持一下!
2012-2-11 17:17
0
雪    币: 239
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
伸手党mark一下
2012-2-11 18:57
0
雪    币: 45
活跃值: (22)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
楼主分析的很详细,如看源码,多谢分享!
顶sysnap的技术处理。
2012-2-13 01:06
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
我学习下,看着有点头大了!
2012-2-13 14:02
0
雪    币: 589
活跃值: (119)
能力值: ( LV11,RANK:190 )
在线值:
发帖
回帖
粉丝
25
回帖学习~~
2012-2-14 12:58
0
游客
登录 | 注册 方可回帖
返回
//