腾讯管家攻防驱动分析-TsFltMgr


layout: wiki
title: 腾讯管家攻防驱动分析-TsFltMgr
categories: WindowsDriver
description: 腾讯管家攻防驱动分析-TsFltMgr
keywords:
url: https://lichao890427.github.io/ https://github.com/lichao890427/


  • TsFltMgr.sys分析
    • 一、驱动入口DriverEntry
      • 1.1 过滤模型
      • 1.2 检查当前系统是否为默认挂钩系统
      • 1.3 打开TsFltMgr日志记录
      • 1.4 控制信息
      • 1.5 全局表
      • 1.6 Proxy*函数模型
    • 二、驱动接口Interface
      • 2.1 DeviceExtension接口
      • 2.2 SetEvaluateTime
      • 2.3 SetDisablePrevFilter
      • 2.4 SetPostFilter
      • 2.5 ExecOriginFromPacket
      • 2.6 AddPrevFilter
      • 2.7 RemovePrevFilter
      • 2.8 GetCurrentHookInfo
    • 三、基础库
      • 3.1 获取注册表键值
      • 3.2 通过进程名获取进程ID
      • 3.3 Rabbit加密算法
    • 四、InlineHook KiFastCallEntry
      • 4.1 获取SSDT/SSSDT/Hook点
      • 4.2 从KiSystemService获取KiFastCallEntry
      • 4.3 获取SSSDT信息
      • 4.4 初始化InlineHook KiFastCallEntry跳转表
      • 4.5 获取系统服务号的2种方式
      • 4.6 InlineHook过程
      • 4.7 构造InlineHook跳转后的执行语句
      • 4.8 强制单核互斥执行指定Procedure
      • 4.9 进行SSDT hook
      • 4.10 对重要回调(进程回调、线程回调、映像加载回调)的挂钩
      • 4.11 Hook KeUserModeCallback
      • 4.12 交换内存
      • 4.13 获取函数Iat偏移
      • 4.14 另一种方式获取ShadowSSDT信息

TsFltMgr.sys分析

  该驱动为qq管家函数过滤驱动,提供SSDT、SSSDT、进程和线程回调等过滤操作,导出接口给TsKsp.sys使用,2者共同做函数过滤操作,TsFltMgr提供设置函数过滤的框架,而实际拦截过程在TsKsp中。设备名\Device\TsFltMgr ,符号名\DosDevices\TsFltMgr 。加密手段:Rabbit算法、MD5算法。通过InlineHook KifastCallEntry实现挂钩。

一、驱动入口DriverEntry

  • 创建\Device\TSSysKit设备和\DosDevices\TSSysKit符号链接
  • 设置DeviceExtension为通信接口(Interface函数指针)
  • 分别注册IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_DEVICE_CONTROL、IRP_MJ_SHUTDOWN(关机回调)派遣例程为,CreateCloseDispatch、DeviceIoControlDispatch、ShutdownDispatch
  • 注册”Boot驱动加载结束”回调DriverReinitializationRoutine
  • 为注册表日志记录分配资源RegLogSpace
  • 检查当前系统是否为注册表version键指定的系统,如果在列表中则在挂钩KiFastCallEntry时需要做额外工作
  • 设置注册表键IsBsod为1,用于检测该驱动是否引起蓝屏(正常关机置0)
  • 获取系统BuildNumber
  • 分配和设置”内核Api代理”结构
  • 挂钩KiFastCallEntry
  • 挂钩重要回调
  • 启动注册表日志记录
  • 挂钩KeUserModeCallback
  • 记录当前配置

1.1 过滤模型

[图片上传失败...(image-a25680-1516663378349)]

  • Ntdll.NtCreateFile通过Sysenter调用进入nt.KiFastCallEntry
  • 在nt.KiFastCallEntry 执行call ebx(原始为nt.NtCreateFile)前跳到TsFltMgr. InlineKiFastCallEntry
  • 执行进入TsFltMgr.HookFilter,在这里通过ServiceMapTable表映射到对应Dproxy元素,将Dproxy->ProxyNtCreateFile设置到ebx,将其设置为ebx
  • Nt.KiFastCallEntry执行call ebx,进入ProxyNtCreateFile
  • 构造FilterPacket结构(用于承载参数、原始api和PostFilterFunc执行的所有过滤函数都用到),依次执行Dproxy->PrevFilterSlot的16个过滤函数(PrevFilter是Tsksp事先设置好的)
  • 依次执行单个Tsksp.PrevFilter,进行真正的过滤或对packet. PostFilterSlot进行设置
  • 返回TsFltMgr.ProxyNtCreateFile,执行nt.NtCreateFile
  • 执行packet. PostFilterSlot的16个过滤函数(Tsksp)
  • 返回nt.KiFastCallEntry

1.2 检查当前系统是否为默认挂钩系统

BOOLEAN IsUnSupportedSystem()
{
/*注:\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\TSKS  version
    存放没有预存 函数调用号ServiceIndex 的系统版本列表 格式:
BuildNumber1;BuildNumber2;...
    对于这些版本在进行SSDT Hook时,会临时取得服务号
*/
    NTSTATUS status;
    ULONG BuildNumber = 0,MajorVersion,MinorVersion;
    const int BufSize = 1024;
    ULONG Size,Type;
    WCHAR BuildNumberStr[10] = {0};
    BOOLEAN Match = FALSE;
    UNICODE_STRING UBuildNumber;
    WCHAR* Buffer = (WCHAR*)ExAllocatePool(NonPagedPool,BufSize);
    status = GetRegDataWithSizeAndType(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\TSKSP",L"version",
        Buffer,BufSize,&Size,&Type);
    if(NT_SUCCESS(status) && Type == REG_SZ && Size)
    {
        Buffer[510] = 0;
        RtlInitUnicodeString(&UBuildNumber,BuildNumberStr);
        PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
        RtlIntegerToUnicodeString(BuildNumber,10,&UBuildNumber);
        if(wcsstr((wchar_t*)Buffer,UBuildNumber.Buffer))
            Match = TRUE;
    }
    ExFreePool(Buffer);
    return Match;
}

1.3 打开TsFltMgr日志记录

  在无保护情况下为\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TsFltMgr添加TsDbgLog键,内容设置为目标文件路径(例如??\C:\TsDbgLog.txt),如果不存在会自动创建文件,重启生效。内容示例:

[0x00000000] 2015.09.27 20:05:24.109    TS TsFltMgr DbgHelper
[0x00000001] 2015.09.27 20:06:13.750    [Sysnap DbgLog] Block--> TableIndex 0, Process spoolsv.exe[1800] 
[0x00000002] 2015.09.27 20:10:35.156    [Sysnap DbgLog] Block--> TableIndex 4, Process regedit.exe[2296] 
[0x00000003] 2015.09.27 20:13:46.500    [Sysnap DbgLog] Block--> TableIndex 4, Process regedit.exe[2296]
  • DriverReinitializationRoutine中做初始化,此时最后一个boot驱动初始化完毕
  • 在执行KiFastCallEntry hook时再次尝试启动打印日志线程
  • ExecPrevSlotFunc中,如果存在过滤函数进行了放行和拦截,都会打印日志

1.4 控制信息

  • 禁止hook
      \REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TsFltMgr dws=1
      \REGISTRY\MACHINE\SYSTEM\CurrentControlSet\services\QQSysMon\DWS dws!=0

  • 强制SSDT hook
      \REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TsFltMgr thm=1

  • 关机回调
      设置\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TsFltMgr IsBsod=0,以便下次启动检测是否TsFltMgr引起蓝屏

1.5 全局表

BuildNumber:
Win2000
    2195    1
WinXp
    2600    2
WinServer2003
    3790    3
WinVista
    6000    4
    6001    5
    6002    6
Win7
    7600    7
    7601    8
Win8
    8102    9
    8250    10
    8400    11
    8432    12
    8441    12
    8520    13
Win8.1
    9200    14
    9600    15
Win10
    9841    16
    9860    17
    9926    18
    10041   19
    10049   20
未知  0

enum
{
    WIN2000=1,
    WINXP,
    WINXPSP3,
    WINVISTA,
    WINVISTASP1,
    WINVISTASP2,
    WIN7,
    WIN7SP1,
    WIN8_8102,
    WIN8_8250,
    WIN8_8400,
    WIN8_8432,
    WIN8_8441=WIN8_8432,
    WIN8_8520,
    WIN81_9200,
    WIN81_9600,
    WIN10_9841,
    WIN10_9860,
    WIN10_9926,
    WIN10_10041,
    WIN10_10049,
    BUILDMAX,
};
enum
{
    SSDT=0,
    SSSDT=1,
    END=2,
    CALLBACK=3,
};

#define APINUMBER 105

struct SProxy
{
    ULONG ServiceTableType;//0:SSDT 1:Shadow SSDT 2:结束符
    PWCHAR ApiName;//函数名
    ULONG  ProxyFunc;//代理函数地址
    ULONG ServiceIndex[BUILDMAX];
    ULONG IndexInTable;//在全局表中的索引
};

struct DProxy
{
    ULONG ServiceTableType;//0:SSDT 1:Shadow SSDT 2:结束符 3:回调函数
    ULONG ServiceIndex;//服务号
    PWCHAR ApiName;//函数名
    ULONG TableIndex;//自定义序号
    BOOLEAN IsInitialized;
    ULONG PrevFilterRefCount;//引用计数
    ULONG PostFilterRefCount;//引用计数
    ULONG OriginFuncAddr;//原始函数地址
    ULONG ProxyFuncAddr;//代理函数地址
    PVOID Log;//用于记录日志
    KEVENT Lock;
    BOOLEAN DisablePrevFilter;//关闭Filter
    ULONG UsedSlotCount;// 当前使用的Slot个数
    FILTER_SLOT PrevFilterSlot[16];//过滤函数结构
};

struct FILTER_SLOT
{
    ULONG Tag;
    ULONG CallCount;
    ULONG DeleteCount;
    KTIMER Timer;
    ULONG Filter;
};

struct FilterPacket
{
    ULONG CurrentSlot;//当前Filter序号
    ULONG ParamNumber;//参数个数
    ULONG Params[12];//参数
    ULONG TagSlot[16];//标志过滤函数用,也可用于传递修改参数
    NTSTATUS Status;//执行结果
    ULONG OriginFuncAddr;//原始函数
    ULONG IndexInTable;//在DProxyTable中的索引
    ULONG Access;//访问权限
    ULONG PostFilterSlot[16];//过滤函数
    ULONG UsedSlotCount;//当前使用的Slot个数
};

TsFltMgr有3张表与函数过滤相关:
静态Api代理表SProxy  SProxyTable[APINUMBER+1]        用于初始化后面2个表
动态Api代理表DProxy* DProxyTable[APINUMBER+1]    用于Proxy*函数中进行实际过滤操作   方便用SProxy指定的序号配置
DProxy* ServiceMapTable[2][1024]        用于InlineHook KiFastCallEntry改变ebx,映射ServiceIndex到Proxy*函数。函数前1024个用于存储SSDT函数,后1024用于存储SSSDT函数

可以用简单的python命令自动获取到g_ProxyApiTable内容
addr=0x25200
index=0
while index < 106:
if Dword(addr) == 0:
type="SSDT"
elif Dword(addr) == 1:
type="SSSDT"
else:
type="END"
ApiName=GetString(Dword(addr+4),-1,ASCSTR_UNICODE)
ProxyFunc="Proxy"+ApiName
print "{\n\t%s,L\"%s\",%s,\n\t{" %(type,ApiName,ProxyFunc)
print "\t\t%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d" %(Dword(addr+12),Dword(addr+16),Dword(addr+20),Dword(addr+24),Dword(addr+28),Dword(addr+32),Dword(addr+36),Dword(addr+40),Dword(addr+44),Dword(addr+48),Dword(addr+52),Dword(addr+56),Dword(addr+60),Dword(addr+64),Dword(addr+68),Dword(addr+72),Dword(addr+76),Dword(addr+80),Dword(addr+84),Dword(addr+88),Dword(addr+92))
print "\t},%d\n}," %(Dword(addr+96))
addr=addr+100
index=index+1

struct SProxy   SProxyTable[APINUMBER+1] = 
{
    {
        SSDT,L"ZwCreateKey",ProxyZwCreateKey,
        {
            1023,35,41,43,64,64,64,70,70,347,351,351,350,350,350,354,355,355,356,359,359
        },0
    },
    {
        SSDT,L"ZwTerminateProcess",ProxyZwTerminateProcess,
        {
            1023,224,257,266,338,334,334,370,370,35,35,35,35,35,35,35,36,36,36,36,36
        },1
    },
    {
        SSDT,L"ZwSetInformationFile",ProxyZwSetInformationFile,
        {
            1023,194,224,233,305,301,301,329,329,78,79,79,78,78,78,81,82,82,82,82,82
        },2
    },
    {
        SSDT,L"ZwWriteFile",ProxyZwWriteFile,
        {
            1023,237,274,284,359,355,355,396,396,4,5,5,5,5,5,6,7,7,7,7,7
        },3
    },
    {
        SSDT,L"ZwSetValueKey",ProxyZwSetValueKey,
        {
            1023,215,247,256,328,324,324,358,358,48,48,48,48,48,48,49,50,50,50,50,50
        },4
    },
    {
        SSDT,L"ZwWriteVirtualMemory",ProxyZwWriteVirtualMemory,
        {
            1023,240,277,287,362,358,358,399,399,1,2,2,2,2,2,3,4,4,4,4,4
        },5
    },
    {
        SSDT,L"ZwCreateFile",ProxyZwCreateFile,
        {
            1023,32,37,39,60,60,60,66,66,351,356,356,355,355,355,360,361,361,362,365,365
        },6
    },
    {
        SSDT,L"ZwOpenProcess",ProxyZwOpenProcess,
        {
            1023,106,122,128,194,194,194,190,190,220,222,222,221,221,221,224,225,225,226,227,227
        },7
    },
    {
        SSDT,L"ZwDeleteKey",ProxyZwDeleteKey,
        {
            1023,53,63,66,123,123,123,103,103,310,314,314,313,313,313,317,318,318,319,321,321
        },8
    },
    {
        SSDT,L"ZwDeleteValueKey",ProxyZwDeleteValueKey,
        {
            1023,55,65,68,126,126,126,106,106,307,311,311,310,310,310,314,315,315,316,318,318
        },9
    },
    {
        SSDT,L"ZwRequestWaitReplyPort",ProxyZwRequestWaitReplyPort,
        {
            1023,176,200,208,275,276,276,299,299,108,110,110,109,109,109,112,113,113,114,114,114
        },10
    },
    {
        SSDT,L"ZwQueryValueKey",ProxyZwQueryValueKey,
        {
            1023,155,177,185,252,252,252,266,266,143,145,145,144,144,144,147,148,148,149,149,149
        },11
    },
    {
        SSDT,L"ZwEnumerateValueKey",ProxyZwEnumerateValueKey,
        {
            1023,61,73,77,136,136,136,119,119,292,296,296,295,295,295,299,300,300,301,303,303
        },12
    },
    {
        SSDT,L"ZwCreateThread",ProxyZwCreateThread,
        {
            1023,46,53,55,78,78,78,87,87,330,334,334,333,333,333,337,338,338,339,342,342
        },13
    },
    {
        SSDT,L"ZwDuplicateObject",ProxyZwDuplicateObject,
        {
            1023,58,68,71,129,129,129,111,111,300,304,304,303,303,303,307,308,308,309,311,311
        },14
    },
    {
        SSDT,L"ZwLoadDriver",ProxyZwLoadDriver,
        {
            1023,85,97,101,165,165,165,155,155,255,257,257,256,256,256,259,260,260,261,263,263
        },15
    },
    {
        SSDT,L"ZwDeviceIoControlFile",ProxyZwDeviceIoControlFile,
        {
            1023,56,66,69,127,127,127,107,107,304,308,308,307,307,307,311,312,312,313,315,315
        },16
    },
    {
        SSDT,L"ZwAlpcSendWaitReceivePort",ProxyZwAlpcSendWaitReceivePort,
        {
            1023,1023,1023,1023,38,38,38,39,39,381,386,386,385,385,385,390,391,391,393,396,396
        },17
    },
    {
        SSDT,L"ZwSetSystemInformation",ProxyZwSetSystemInformation,
        {
            1023,208,240,249,321,317,317,350,350,56,56,56,56,56,56,57,58,58,58,58,58
        },18
    },
    {
        SSDT,L"ZwDeleteFile",ProxyZwDeleteFile,
        {
            1023,52,62,65,122,122,122,102,102,311,315,315,314,314,314,318,319,319,320,322,322
        },19
    },
    {
        SSDT,L"ZwOpenSection",ProxyZwOpenSection,
        {
            1023,108,125,131,197,197,197,194,194,216,218,218,217,217,217,220,221,221,222,222,222
        },20
    },
    {
        SSDT,L"ZwCreateSection",ProxyZwCreateSection,
        {
            1023,43,50,52,75,75,75,84,84,333,337,337,336,336,336,340,341,341,342,345,345
        },21
    },
    {
        SSDT,L"ZwSuspendThread",ProxyZwSuspendThread,
        {
            1023,221,254,263,335,331,331,367,367,38,38,38,38,38,38,38,39,39,39,39,39
        },22
    },
    {
        SSDT,L"ZwTerminateThread",ProxyZwTerminateThread,
        {
            1023,225,258,267,339,335,335,371,371,34,34,34,34,34,34,34,35,35,35,35,35
        },23
    },
    {
        SSDT,L"ZwSystemDebugControl",ProxyZwSystemDebugControl,
        {
            1023,222,255,264,336,332,332,368,368,37,37,37,37,37,37,37,38,38,38,38,38
        },24
    },
    {
        SSDT,L"ZwProtectVirtualMemory",ProxyZwProtectVirtualMemory,
        {
            1023,1023,137,143,210,210,210,215,215,194,196,196,195,195,195,198,199,199,200,200,200
        },38
    },
    {
        SSDT,L"ZwCreateSymbolicLinkObject",ProxyZwCreateSymbolicLinkObject,
        {
            1023,45,52,54,77,77,77,86,86,331,335,335,334,334,334,338,339,339,340,343,343
        },39
    },
    {
        SSDT,L"ZwSetContextThread",ProxyZwSetContextThread,
        {
            1023,1023,213,221,293,289,289,316,316,91,92,92,91,91,91,94,95,95,95,95,95
        },40
    },
    {
        SSDT,L"ZwRenameKey",ProxyZwRenameKey,
        {
            1023,1023,192,200,267,267,267,290,290,117,119,119,118,118,118,121,122,122,123,123,123
        },41
    },
    {
        SSDT,L"ZwOpenThread",ProxyZwOpenThread,
        {
            1023,111,128,134,201,201,201,198,198,214,214,214,213,213,213,216,217,217,218,218,218
        },42
    },
    {
        SSDT,L"ZwGetNextThread",ProxyZwGetNextThread,
        {
            1023,1023,1023,1023,372,368,368,140,140,271,271,271,270,270,270,273,274,274,275,277,277
        },43
    },
    {
        SSDT,L"ZwCreateThreadEx",ProxyZwCreateThreadEx,
        {
            1023,1023,1023,1023,388,382,382,88,88,333,333,333,332,332,332,336,337,337,338,341,341
        },44
    },
    {
        SSDT,L"ZwRestoreKey",ProxyZwRestoreKey,
        {
            1023,1023,204,212,279,280,280,302,302,105,107,107,106,106,106,109,110,110,111,111,111
        },55
    },
    {
        SSDT,L"ZwReplaceKey",ProxyZwReplaceKey,
        {
            1023,1023,193,201,268,268,268,292,292,115,117,117,116,116,116,119,120,120,121,121,121
        },56
    },
    {
        SSDT,L"ZwGetNextProcess",ProxyZwGetNextProcess,
        {
            1023,1023,1023,1023,371,367,367,139,139,270,272,272,271,271,271,274,275,275,276,278,278
        },45
    },
    {
        SSDT,L"ZwUnmapViewOfSection",ProxyZwUnmapViewOfSection,
        {
            1023,231,267,277,352,348,348,385,385,19,19,19,19,19,19,19,20,20,20,20,20
        },46
    },
    {
        SSDT,L"ZwAssignProcessToJobObject",ProxyZwAssignProcessToJobObject,
        {
            1023,18,19,21,42,42,42,43,43,377,382,382,381,381,381,386,387,387,389,392,392
        },47
    },
    {
        SSDT,L"ZwAllocateVirtualMemory",ProxyZwAllocateVirtualMemory,
        {
            1023,16,17,18,18,18,18,19,19,403,407,407,406,406,406,411,412,412,415,418,418
        },57
    },
    {
        SSDT,L"ZwFreeVirtualMemory",ProxyZwFreeVirtualMemory,
        {
            1023,71,83,87,147,147,147,131,131,278,281,281,280,280,280,284,285,285,286,288,288
        },58
    },
    {
        SSSDT,L"NtUserFindWindowEx",ProxyNtUserFindWindowEx,
        {
            1023,368,378,377,391,391,391,396,396,455,457,458,459,460,459,460,462,466,466,466,467
        },25
    },
    {
        SSSDT,L"NtUserBuildHwndList",ProxyNtUserBuildHwndList,
        {
            1023,302,312,311,322,322,322,323,323,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },26
    },
    {
        SSSDT,L"NtUserQueryWindow",ProxyNtUserQueryWindow,
        {
            1023,466,483,481,504,504,504,515,515,478,480,481,482,483,482,483,485,489,489,489,490
        },27
    },
    {
        SSSDT,L"NtUserGetForegroundWindow",ProxyNtUserGetForegroundWindow,
        {
            1023,393,404,403,418,418,418,423,423,426,428,429,430,430,429,430,431,435,435,435,435
        },28
    },
    {
        SSSDT,L"NtUserWindowFromPoint",ProxyNtUserWindowFromPoint,
        {
            1023,568,592,588,617,617,617,629,629,640,643,646,648,650,649,652,658,664,665,666,667
        },29
    },
    {
        SSSDT,L"NtUserSetParent",ProxyNtUserSetParent,
        {
            1023,510,529,526,550,550,550,560,560,582,585,587,589,591,590,593,595,601,602,603,604
        },30
    },
    {
        SSSDT,L"NtUserSetWindowLong",ProxyNtUserSetWindowLong,
        {
            1023,525,544,540,566,566,566,578,578,560,562,564,566,567,566,569,571,575,576,576,577
        },31
    },
    {
        SSSDT,L"NtUserMoveWindow",ProxyNtUserMoveWindow,
        {
            1023,449,465,464,484,484,484,495,495,499,501,502,503,504,503,505,507,511,511,511,512
        },32
    },
    {
        SSSDT,L"NtUserSetWindowPos",ProxyNtUserSetWindowPos,
        {
            1023,527,546,542,568,568,568,580,580,558,560,562,564,565,564,567,569,573,574,574,575
        },33
    },
    {
        SSSDT,L"NtUserSetWindowPlacement",ProxyNtUserSetWindowPlacement,
        {
            1023,526,545,541,567,567,567,579,579,559,561,563,565,566,565,568,570,574,575,575,576
        },34
    },
    {
        SSSDT,L"NtUserShowWindow",ProxyNtUserShowWindow,
        {
            1023,536,555,551,579,579,579,591,591,547,549,551,553,554,553,556,558,562,563,563,564
        },35
    },
    {
        SSSDT,L"NtUserShowWindowAsync",ProxyNtUserShowWindowAsync,
        {
            1023,537,556,552,580,580,580,592,592,546,548,550,552,553,552,555,557,561,562,562,563
        },36
    },
    {
        SSSDT,L"NtUserSendInput",ProxyNtUserSendInput,
        {
            1023,481,502,500,525,525,525,536,536,606,609,611,613,615,614,617,619,625,626,627,628
        },37
    },
    {
        SSSDT,L"NtUserSetWinEventHook",ProxyNtUserSetWinEventHook,
        {
            1023,533,552,548,576,576,576,588,588,550,552,554,556,557,556,559,561,565,566,566,567
        },49
    },
    {
        SSSDT,L"NtUserClipCursor",ProxyNtUserClipCursor,
        {
            1023,0,330,329,343,343,343,348,348,333,334,335,335,335,335,337,338,342,342,342,342
        },48
    },
    {
        SSSDT,L"NtUserSetWindowsHookEx",ProxyNtUserSetWindowsHookEx,
        {
            1023,530,549,545,573,573,573,585,585,553,555,557,559,560,559,562,564,568,569,569,570
        },50
    },
    {
        SSDT,L"ZwMakeTemporaryObject",ProxyZwMakeTemporaryObject,
        {
            1023,1023,105,110,174,174,174,164,164,246,248,248,247,247,247,250,251,251,252,254,254
        },59
    },
    {
        SSDT,L"ZwCreateUserProcess",ProxyZwCreateUserProcess,
        {
            1023,1023,1023,1023,1023,383,383,93,93,322,326,326,325,325,325,329,330,330,331,334,334
        },60
    },
    {
        SSSDT,L"NtUserMessageCall",ProxyNtUserMessageCall,
        {
            1023,444,460,459,479,479,479,490,490,504,506,507,508,509,508,510,512,516,516,516,517
        },61
    },
    {
        SSSDT,L"NtUserPostMessage",ProxyNtUserPostMessage,
        {
            1023,459,475,474,497,497,497,508,508,486,488,489,490,491,490,492,494,498,498,498,499
        },62
    },
    {
        SSSDT,L"NtUserPostThreadMessage",ProxyNtUserPostThreadMessage,
        {
            1023,460,476,475,498,498,498,509,509,485,487,488,489,490,489,491,493,497,497,497,498
        },63
    },
    {
        SSSDT,L"NtUserBuildHwndList_WIN8",ProxyNtUserBuildHwndList_WIN8,
        {
            1023,1023,1023,1023,1023,1023,1023,1023,1023,358,359,360,360,360,360,362,363,367,367,367,367
        },64
    },
    {
        SSDT,L"ZwFsControlFile",ProxyZwFsControlFile,
        {
            1023,1023,84,1023,150,150,150,134,134,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },65
    },
    {
        SSSDT,L"NtUserSetImeInfoEx",ProxyNtUserSetImeInfoEx,
        {
            1023,1023,517,1023,1023,1023,1023,550,550,1023,1023,1023,1023,1023,600,603,605,611,612,613,1023
        },66
    },
    {
        SSDT,L"ZwCreateProcessEx",ProxyZwCreateProcessEx,
        {
            1023,1023,48,50,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },72
    },
    {
        SSSDT,L"NtUserGetRawInputData",ProxyNtUserGetRawInputData,
        {
            1023,1023,428,1023,1023,1023,1023,448,448,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },67
    },
    {
        SSSDT,L"NtUserGetRawInputBuffer",ProxyNtUserGetRawInputBuffer,
        {
            1023,1023,427,1023,1023,1023,1023,447,447,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },68
    },
    {
        SSSDT,L"NtUserGetAsyncKeyState",ProxyNtUserGetAsyncKeyState,
        {
            1023,1023,383,1023,1023,1023,1023,402,402,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },69
    },
    {
        SSSDT,L"NtUserGetKeyState",ProxyNtUserGetKeyState,
        {
            1023,1023,416,1023,1023,1023,1023,436,436,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },70
    },
    {
        SSSDT,L"NtUserGetKeyboardState",ProxyNtUserGetKeyboardState,
        {
            1023,1023,414,1023,1023,1023,1023,434,434,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },71
    },
    {
        SSDT,L"ZwQueueApcThread",ProxyZwQueueApcThread,
        {
            1023,1023,180,1023,1023,1023,1023,269,269,1023,1023,1023,1023,1023,139,142,143,143,144,144,144
        },74
    },
    {
        SSDT,L"ZwSetSecurityObject",ProxyZwSetSecurityObject,
        {
            1023,1023,237,1023,1023,1023,1023,347,347,1023,1023,1023,1023,1023,59,60,61,61,61,61,61
        },75
    },
    {
        SSDT,L"ZwOpenFile",ProxyZwOpenFile,
        {
            1023,1023,116,1023,1023,1023,1023,179,179,1023,1023,1023,1023,1023,232,235,236,236,237,238,238
        },76
    },
    {
        SSDT,L"ZwQueueApcThreadEx",ProxyZwQueueApcThreadEx,
        {
            1023,1023,1023,1023,1023,1023,1023,270,270,1023,1023,1023,1023,1023,138,141,142,142,143,143,143
        },77
    },
    {
        SSDT,L"ZwCreateMutant",ProxyZwCreateMutant,
        {
            1023,1023,43,45,67,67,67,74,74,1023,1023,1023,1023,1023,346,350,351,351,352,355,355
        },78
    },
    {
        SSDT,L"ZwQuerySystemInformation",ProxyZwQuerySystemInformation,
        {
            1023,1023,173,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },79
    },
    {
        SSDT,L"ZwQueryIntervalProfile",ProxyZwQueryIntervalProfile,
        {
            1023,1023,158,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },80
    },
    {
        SSDT,L"ZwSetInformationProcess",ProxyZwSetInformationProcess,
        {
            1023,1023,228,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },81
    },
    {
        SSSDT,L"NtGdiAddFontMemResourceEx",ProxyNtGdiAddFontMemResourceEx,
        {
            1023,1023,4,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },82
    },
    {
        SSDT,L"ZwReplyWaitReceivePortEx",ProxyZwReplyWaitReceivePortEx,
        {
            1023,1023,196,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },83
    },
    {
        END,L"KeUserModeCallback",ProxyKeUserModeCallback,
        {
            1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },51
    },
    {
        SSDT,L"ZwOpenKey",ProxyZwOpenKey,
        {
            1023,1023,119,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },84
    },
    {
        SSDT,L"ZwMapViewOfSection",ProxyZwMapViewOfSection,
        {
            1023,1023,108,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },85
    },
    {
        SSDT,L"ZwSetIntervalProfile",ProxyZwSetIntervalProfile,
        {
            1023,1023,231,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },86
    },
    {
        SSSDT,L"NtGdiAddFontResourceW",ProxyNtGdiAddFontResourceW,
        {
            1023,1023,2,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },87
    },
    {
        SSSDT,L"NtGdiAddRemoteFontToDC",ProxyNtGdiAddRemoteFontToDC,
        {
            1023,1023,3,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },88
    },
    {
        SSDT,L"ZwQueryInformationProcess",ProxyZwQueryInformationProcess,
        {
            1023,1023,154,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },89
    },
    {
        SSDT,L"ZwQueryInformationThread",ProxyZwQueryInformationThread,
        {
            1023,1023,155,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },90
    },
    {
        SSDT,L"ZwCreateProfile",ProxyZwCreateProfile,
        {
            1023,1023,49,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },91
    },
    {
        SSDT,L"ZwVdmControl",ProxyZwVdmControl,
        {
            1023,1023,268,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },92
    },
    {
        SSDT,L"ZwCreateProcess",ProxyZwCreateProcess,
        {
            1023,1023,47,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },93
    },
    {
        SSSDT,L"NtGdiAddEmbFontToDC",ProxyNtGdiAddEmbFontToDC,
        {
            1023,1023,214,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },94
    },
    {
        SSDT,L"NtDebugActiveProcess",ProxyNtDebugActiveProcess,
        {
            1023,1023,57,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },95
    },
    {
        SSDT,L"NtAlpcCreatePort",ProxyNtAlpcCreatePort,
        {
            1023,1023,1023,1023,1023,1023,1023,23,23,1023,1023,1023,1023,1023,401,406,407,407,410,413,413
        },96
    },
    {
        SSDT,L"NtCreatePort",ProxyNtCreatePort,
        {
            1023,1023,46,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },97
    },
    {
        SSDT,L"ZwAdjustPrivilegesToken",ProxyZwAdjustPrivilegesToken,
        {
            1023,1023,11,1023,1023,1023,1023,12,12,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },98
    },
    {
        SSDT,L"ZwConnectPort",ProxyZwConnectPort,
        {
            1023,1023,31,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },99
    },
    {
        SSDT,L"ZwSecureConnectPort",ProxyZwSecureConnectPort,
        {
            1023,1023,210,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },100
    },
    {
        SSDT,L"ZwQueryKey",ProxyZwQueryKey,
        {
            1023,1023,160,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },101
    },
    {
        SSDT,L"ZwEnumerateKey",ProxyZwEnumerateKey,
        {
            1023,1023,71,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },102
    },
    {
        SSDT,L"ZwClose",ProxyZwClose,
        {
            1023,1023,25,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },103
    },
    {
        SSSDT,L"NtUserSystemParametersInfo",ProxyNtUserSystemParametersInfo,
        {
            1023,1023,559,1023,1023,1023,1023,559,595,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
        },104
    },
    {
        END,NULL,NULL,
        {
            -1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        },105
    }
};

1.6 Proxy*函数模型

NPAGED_LOOKASIDE_LIST FilterLookAside;
BOOLEAN g_EvaluateTime;
//Proxy*函数模型  3参数函数为例
NTSTATUS __stdcall ProxyNtFunc(int param1,int param2,int param3)
{
    NTSTATUS status = STATUS_ACCESS_DENIED;
    ULONG Result;//自定义结果
    ULONGLONG Time = 0;
    DProxy* proxydata = DProxyTable[ENtFunc];
    FilterPacket* packet = ExAllocateFromNPagedLookasideList(&FilterLookAside);
    if(g_EvaluateTime)
        Time = KeQueryInterruptTime();
    if(!packet)
    {
        if(!proxydata->OriginFuncAddr)
            return status;
        return proxydata->OriginFuncAddr(param1,param2,param3);
    }
    packet->Params[0] = param1;
    packet->Params[1] = param2;
    packet->Params[2] = param3;
    packet->ParamNumber = 3;
    packet->OriginFuncAddr = proxydata->OriginFuncAddr;
    packet->IndexInTable = ENtFunc;
    InterlockedIncrement(&proxydata->PrevFilterRefCount);
    Result = ExecPrevFilter(packet,proxydata);//Prev过滤
    InterlockedDecrement(&proxydata->PrevFilterRefCount);
    if(Result == SYSMON_UNHANDLED)
    {
        if(packet->OriginFuncAddr)
        {
            status = packet->OriginFuncAddr(param1,param2,param3);
            packet->Status = status;
            InterlockedIncrement(&proxydata->PostFilterRefCount);
            Result = ExecPostFilter(packet);//Post过滤
            InterlockedDecrement(&proxydata->PostFilterRefCount);
        }
    }
    if(Result == SYSMON_HANDLED)
    {
        status = packet->Status;
    }
    if(g_EvaluateTime)
        EvaluateTime(proxydata,Time);
    ExDeleteNPagedLookasideList(packet);
    return status;
}

ULONG ExecPrevFilter(FilterPacket* packet,DProxy* proxydata)
{
    ULONG Result;
    if(!proxydata || !packet || packet->DisablePrevFilter)
        return SYSMON_UNHANDLED;
    for(int i=0;i<16;i++)
    {
        if(!proxydata->PrevFilterSlot[i].DeleteCount && proxydata->PrevFilterSlot[i].Filter && proxydata->SlotNum != 0)
        {
            InterlockedIncrement(&proxydata->PrevFilterSlot[i].CallCount);
            packet->CurrentSlot = i;
            Result = proxydata->PrevFilterSlot[i].Filter(packet);
            InterlockedDecrement(&proxydata->PrevFilterSlot[i].CallCount);
            if(packet->Access & 0x10)//如果权限被设置为放行
            {
                TsLogSprintfOutput(SysMonLogPt,"[Sysnap DbgLog] Modify--> TableIndex %d, Process %s[%d] ",
                    proxydata->TableIndex,PsGetProcessImageFileName(IoGetCurrentProcess()),PsGetCurrentProcessId());
            }
            switch(Result)
            {
            case SYSMON_FORBID:
                TsLogSprintfOutput(SysMonLogPt,"[Sysnap DbgLog] Block--> TableIndex %d, Process %s[%d] ",
                    proxydata->TableIndex,PsGetProcessImageFileName(IoGetCurrentProcess()),PsGetCurrentProcessId());
                return SYSMON_FORBID;
            case SYSMON_HANDLED:
                return SYSMON_HANDLED;
            case SYSMON_PASS:
            case SYSMON_PASS1:
                return SYSMON_UNHANDLED;
            default:
                break;
            }
        }
    }
}

ULONG ExecPostFilter(FilterPacket* packet)
{
    ULONG Result;
    if(!packet)
        return SYSMON_UNHANDLED;
    FILTER_SLOT* CurrentSlot = DProxyTable[packet->IndexInTable]->PrevFilterSlot;
    for(int i=0;i<16;i++)
    {
        if(!CurrentSlot [i].DeleteCount)
        {
            InterlockedIncrement(&CurrentSlot [i].CallCount);
            packet->CurrentSlot = i;
            Result = packet->PostFilterSlot(packet);
            InterlockedDecrement(&CurrentSlot [i].CallCount);
        }
        switch(Result)
        {
        case SYSMON_HANDLED:
            return SYSMON_HANDLED;
        case SYSMON_PASS:
        case SYSMON_PASS1:
        case SYSMON_FORBID:
            return SYSMON_UNHANDLED;
        default:
            break;
        }
    }
}

二、驱动接口Interface

2.1 DeviceExtension接口

DeviceObject->DeviceExtension结构:
+00h    TAG=’TSFL’
+14h    FARPROC Interface
FARPROC Interface(intindex)

NTSTATUS Interface(int index,FARPROC* outfunc)
{//注意下面的函数都是自己实现的穿透函数
    If(!outfunc)
        Return STATUS_UNSUCCESSFUL;
    switch(index)
    {
    case 0:
*outfunc = SetEvaluateTime;
        Break;
    case 1:
*outfunc = DisablePrevFilter;
        Break;
    case 2:
*outfunc = SetPostFilter;
        Break;
    case 3:
*outfunc = ExecOriginFromPacket;
        Break;
    case 4:
*outfunc = AddPrevFilter;
        Break;
    case 5:
*outfunc = RemovePrevFilter;
        Break;
    case 6:
*outfunc = GetCurrentHookInfo;
        Break;
    case 7:
*outfunc = GetDProxyTable;
        Break;
default:
        *outfunc = NULL;
        Break;
}
Return STATUS_SUCESS;
}

2.2 SetEvaluateTime

Void __stdcall SetEvaluateTime(bool EvaluateTime)
{//设置计算过滤函数执行耗时
    g_EvaluateTime = EvaluateTime;
}

2.3 SetDisablePrevFilter

Void __stdcall SetDisablePrevFilter(ULONG Index,BOOLEAN Disable)
{//设置是否执行PrevFilter(同时也是PostFilter)
    If(Index < APINUMBER)
{
    If(DProxyTable[Index])
        DProxyTable[Index]-> DisablePrevFilter = Disable;
}
}

2.4 SetPostFilter

Void __stdcall SetPostFilter(FilterPacket* Packet,FARPROC Filter,ULONG Tag)
{//设置PostFilter函数
    If(Packet)
{
    Packet->TagSlot[Packet->CurrentSlot] = Tag;//用于修改参数或区分Filter
    Packet->PostFilterSlot[Packet->CurrentSlot] = Filter;
    Packet->SlotCount++;
}
}

2.5 ExecOriginFromPacket

NTSTATUS __stdcall ExecOriginFromPacket(FilterPacket* Packet) 
{//执行Nt*原始函数
    If(!Packet || !Packet->OriginFuncAddr)
        Return STATUS_UNSUCCESSFUL;
    _asm
    {
        Mov eax, Packet->ParamNumber
        Test eax,eax
        Jbe tag1
        Lea ecx,[eax-1]
        Test ecx,ecx
        Jl tag1
        Lea edx,Packet->Params[ecx]//参数逐个压栈
Tag1:
        Mov eax,[edx]
        Push eax
        Sub ecx,1
        Sub edx,4
        Test ecx,ecx
        Jge tag2
Tag2:
        Call Packet->OriginFuncAddr
    }
}

2.6 AddPrevFilter

NTSTATUS __stdcall ExecOriginFromPacket(FilterPacket* Packet) 
{//执行Nt*原始函数
    If(!Packet || !Packet->OriginFuncAddr)
        Return STATUS_UNSUCCESSFUL;
    _asm
    {
        Mov eax, Packet->ParamNumber
        Test eax,eax
        Jbe tag1
        Lea ecx,[eax-1]
        Test ecx,ecx
        Jl tag1
        Lea edx,Packet->Params[ecx]//参数逐个压栈
Tag1:
        Mov eax,[edx]
        Push eax
        Sub ecx,1
        Sub edx,4
        Test ecx,ecx
        Jge tag2
Tag2:
        Call Packet->OriginFuncAddr
    }
}

2.7 RemovePrevFilter

void WaitStop(FILTER_SLOT* CurrentSlot)
{
    KeInitializeTimer(&CurrentSlot->Timer);
    Li.QuadPart = 1000000;
    while(CurrentSlot->CallCount)
    {
        KeSetTimer(&CurrentSlot->Timer,&Li,NULL);
        KeWaitForSingleObject(&CurrentSlot->Timer,Executive,KernelMode,FALSE,NULL);
    }
    KeCancelTimer(&CurrentSlot->Timer);
}

NTSTATUS __fastcall RemovePrevFilter(ULONG Index,FARPROC Filter)
{//从Index对应的函数过滤中查找删除Filter
    if(!Filter || Index >= APINUMBER)
        return STATUS_UNSUCCESSFUL;
    if(!DProxyTable[Index] || !DProxyTable[Index]->IsInitialized)
        return STATUS_UNSUCCESSFUL;
    for(int i=0;i<16;i++)
    {
        if(DProxyTable[Index]->PrevFilterSlot[i].Filter == Filter)
        {
            LARGE_INTEGER Li;
            FILTER_SLOT* CurrentSlot = &DProxyTable[Index]->PrevFilterSlot[i];
            CurrentSlot->DeleteCount = FALSE;
            InterlockedIncrement(&CurrentSlot->DeleteCount);
            WaitStop(CurrentSlot);
            InterlockedExchange(&CurrentSlot->Filter,NULL);
            InterlockedDecrement(&DProxyTable[Index]->UsedSlotCount);
            WaitStop(CurrentSlot);
            InterlockedDecrement(&CurrentSlot->DeleteCount);
            return STATUS_UNSUCCESSFUL;
        }
    }
    return STATUS_UNSUCCESSFUL;
}

2.8 GetCurrentHookInfo

NTSTATUS __stdcall GetCurrentHookInfo(PULONG pLastErrorCode,PULONG pserHookType,PULONG pOsVer,PULONG pHookErrorIndex)
{
    if(OsVer && !LastErrorCode && HookErrorIndex == -1)
    {
        if(pLastErrorCode)
            *pLastErrorCode = 0;//获取系统buildnumber
        if(pserHookType)
            *pserHookType = serHookType;
        if(pOsVer)
            *pOsVer = OsVer;
        if(pHookErrorIndex)
            *pHookErrorIndex = HookErrorIndex;
    }
    return STATUS_UNSUCCESSFUL;
}

LastErrorCode
0x01    ZwQuerySystemInformation获取失败
0x02    KeServiceDescriptorTable获取失败
0x04    KeAddSystemServiceTable获取失败
0x08    ShadowSSDT获取失败
0x10    MmUserProbeAddress获取失败
0x20    Int2E校验失败

InitState
0x01    ZwQuerySystemInformation获取成功
0x02    KeServiceDescriptorTable获取成功
0x04    ShadowSSDT获取成功
0x08    获取Inline Hook点成功

serHookType 对KiFastCallEntry做inline hook的类型
0.  Nonhook         HOOKTYPE_NONE
1.  Inlinehook          HOOKTYPE_INLINE
2.  SSDTHook            HOOKTYPE_SSDT
3.  金山共存Inlinehook  HOOKTYPE_KSINLINE

OsVer
BuildNumber:
Win2000
2195        1
WinXp
2600        2
WinServer2003
3790        3
WinVista
6000        4
6001        5
6002        6
Win7
7600        7
7601        8
Win8
8102        9
8250        10
8400        11
8432        12
8441        12
8520        13
Win8.1
9200        14
9600        15
Win10
9841        16
9860        17
9926        18
10041   19
10049   20
?? 0

HookErrorIndex
    -1

IsBsod
    记录蓝屏

三、基础库

3.1 获取注册表键值

NTSTATUS GetRegDataWithType(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutType)
{
    NTSTATUS status;
    HANDLE KeyHandle = NULL;
    ULONG ResultLength = 0;
    OBJECT_ATTRIBUTES Oa;
    UNICODE_STRING URegPath,UKeyName;
    PVOID ValueInfo;
    const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR[260]);
    if(!RegPath || !KeyName)
        return STATUS_INVALID_PARAMETER;
    InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
    status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
    ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
    if(NT_SUCCESS(status) && ValueInfo)
    {
        RtlZeroMemory(ValueInfo,BufSize);
        RtlInitUnicodeString(&UKeyName,KeyName);
        status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
        if(NT_SUCCESS(status))
        {
            PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
            if(OutType)
                *OutType = Info->Type;
            if(OutData)
                RtlCopyMemory(OutData,Info->Data,BufSizeDataLength?BufSize:Info->DataLength);
        }
    }
    if(KeyHandle)
        ZwClose(KeyHandle);
    if(ValueInfo)
        ExFreePool(ValueInfo);
    return status;
}

NTSTATUS GetRegDataWithSize(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutSize)
{
    NTSTATUS status;
    HANDLE KeyHandle = NULL;
    ULONG ResultLength = 0;
    OBJECT_ATTRIBUTES Oa;
    UNICODE_STRING URegPath,UKeyName;
    PVOID ValueInfo;
    const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR[260]);
    if(!RegPath || !KeyName)
        return STATUS_INVALID_PARAMETER;
    InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
    status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
    ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
    if(NT_SUCCESS(status) && ValueInfo)
    {
        RtlZeroMemory(ValueInfo,BufSize);
        RtlInitUnicodeString(&UKeyName,KeyName);
        status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
        if(NT_SUCCESS(status))
        {
            PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
            if(OutSize)
                *OutSize = Info->DataLength;
            if(OutData)
                RtlCopyMemory(OutData,Info->Data,BufSizeDataLength?BufSize:Info->DataLength);
        }
    }
    if(KeyHandle)
        ZwClose(KeyHandle);
    if(ValueInfo)
        ExFreePool(ValueInfo);
    return status;
}

NTSTATUS GetRegDataWithSizeAndType(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutSize,PULONG OutType)
{
    NTSTATUS status;
    HANDLE KeyHandle = NULL;
    ULONG ResultLength = 0;
    OBJECT_ATTRIBUTES Oa;
    UNICODE_STRING URegPath,UKeyName;
    PVOID ValueInfo;
    const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR[260]);
    if(!RegPath || !KeyName)
        return STATUS_INVALID_PARAMETER;
    InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
    status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
    ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
    if(NT_SUCCESS(status) && ValueInfo)
    {
        RtlZeroMemory(ValueInfo,BufSize);
        RtlInitUnicodeString(&UKeyName,KeyName);
        status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
        if(NT_SUCCESS(status))
        {
            PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
            if(OutSize)
                *OutSize = Info->DataLength;
            if(OutType)
                *OutType = Info->Type;
            if(OutData)
                RtlCopyMemory(OutData,Info->Data,BufSizeDataLength?BufSize:Info->DataLength);
        }
    }
    if(KeyHandle)
        ZwClose(KeyHandle);
    if(ValueInfo)
        ExFreePool(ValueInfo);
    return status;
}

3.2 通过进程名获取进程ID

HANDLE GetProcessIdByName(PWCHAR ProcessName)
{//根据进程名获取进程ID
    HANDLE ProcessId = 0;
    NTSTATUS status = STATUS_SUCCESS;
    SIZE_T size = 512;
    UNICODE_STRING UProcessName;
    LPVOID Buffer;
    RtlInitUnicodeString(&UProcessName,ProcessName);
    while(true)
    {
        Buffer = ExAllocatePool(PagedPool,size);
        if(!Buffer)
            return 0;
        status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,Buffer,size,NULL);
        if(status != STATUS_INFO_LENGTH_MISMATCH)
            break;
        ExFreePool(Buffer);
        size *= 2;
    }
    if(!NT_SUCCESS(Buffer))
        ExFreePool(Buffer);
    PSYSTEM_PROCESS_INFORMATION ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
    while(ProcessInfo->NextEntryOffset)
    {
        ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((UCHAR*)ProcessInfo + ProcessInfo->NextEntryOffset);
        if(RtlEqualUnicodeString(&UProcessName,&ProcessInfo->ImageName,TRUE)
            ProcessId = ProcessInfo->UniqueProcessId;
    }
    ExFreePool(Buffer);
    return ProcessId;
}

3.3 Rabbit加密算法

  Q管很多驱动中存在的用于传输时加密的可逆算法使用了Rabbit分组加密算法,可以分段加解密,加密过程和解密过程一致。根据驱动中加解密过程可以得到如下代码逻辑:

#define ld(x) ((x>>32)&0xFFFFFFFF)
#define hw(x) ((x>>16)&0xFFFF)
#define lw(x) (x&0xFFFF)
#define rotl(x,y) ((x<>(32-y)))

struct Rabbit
{
    unsigned int X[8];
    unsigned int C[8];
    unsigned int b;
};

bool Rabbit_nextState(Rabbit* rabbit);
bool Rabbit_Init(Rabbit* rabbit);
unsigned int Rabbit_toInt(unsigned char* key,int index);
bool Rabbit_SetKey(unsigned char* key,Rabbit* rabbit);

bool Rabbit_Init(Rabbit* rabbit)
{
    if(!rabbit)
        return false;
    for(int i=0;i<8;i++)
    {
        rabbit->C[i] = 0;
        rabbit->X[i] = 0;
        rabbit->b = 0;
    }
    return true;
}

unsigned int Rabbit_toInt(unsigned char* key,int index)
{
    if(!key)
        return 0;
    return key[index+3]|(key[index+2]<<8)|(key[index+1]<<16)|(key[index+0]<<24);
}

bool Rabbit_SetKey(unsigned char* key,Rabbit* rabbit)
{
    if(!key || !rabbit)
        return false;
    unsigned int K0 = Rabbit_toInt(key,0);
    unsigned int K1 = Rabbit_toInt(key,4);
    unsigned int K2 = Rabbit_toInt(key,8);
    unsigned int K3 = Rabbit_toInt(key,12);
    rabbit->X[0] = K3;
    rabbit->X[1] = (K0<<16)|(K1>>16);
    rabbit->X[2] = K2;
    rabbit->X[3] = (K3<<16)|(K0>>16);
    rabbit->X[4] = K1;
    rabbit->X[5] = (K2<<16)|(K3>>16);
    rabbit->X[6] = K0;
    rabbit->X[7] = (K1<<16)|(K2>>16);
    rabbit->C[0] = (K1<<16)|(K1>>16);
    rabbit->C[1] = ((K3&0xFFFF0000)|(K2&0xFFFF));
    rabbit->C[2] = (K0<<16)|(K0>>16);
    rabbit->C[3] = ((K2&0xFFFF0000)|(K1&0xFFFF));
    rabbit->C[4] = (K3<<16)|(K3>>16);
    rabbit->C[5] = ((K1&0xFFFF0000)|(K0&0xFFFF));
    rabbit->C[6] = (K2<<16)|(K2>>16);
    rabbit->C[7] = ((K0&0xFFFF0000)|(K3&0xFFFF));
    rabbit->b = 0;
    for(int i=0;i<4;i++)
    {
        Rabbit_nextState(rabbit);
    }
    for(int i=0;i<8;i++)
    {
        rabbit->C[i] ^= rabbit->X[(i+4)&7];
    }
    return true;
}


unsigned int Rabbit_u1(unsigned int n)
{
    unsigned int r0 = ((lw(n) * lw(n)) >> 17) + lw(n) * hw(n);
    unsigned int r1 = (r0 >> 15) + hw(n) * hw(n);
    unsigned int r2 = n * n;
    return r1 ^ r2;
//  _asm
//  {
//      mov esi,n
//      movzx edx,si
//      mov ecx,esi
//      shr ecx,0x10
//      push edi
//      mov eax, edx
//      imul eax, edx
//      mov edi, ecx
//      imul edi, edx
//      mov edx, ecx
//      imul edx, ecx
//      mov ecx, esi
//      imul ecx, esi
//      shr eax, 11h
//      add eax, edi
//      shr eax, 0Fh
//      add eax, edx
//      pop edi
//      xor eax, ecx
//  }
}

bool Rabbit_nextState(Rabbit* rabbit)
{
    unsigned int G[8]={0};
    unsigned int c_old[8];
    if(!rabbit)
        return false;
    memcpy(c_old,rabbit->C,sizeof(c_old));
    rabbit->C[0] += rabbit->b + 1295307597;
    rabbit->C[1] += (rabbit->C[0] < c_old[0]) - 749914925;
    rabbit->C[2] += (rabbit->C[1] < c_old[1]) + 886263092;
    rabbit->C[3] += (rabbit->C[2] < c_old[2]) + 1295307597;
    rabbit->C[4] += (rabbit->C[3] < c_old[3]) - 749914925;
    rabbit->C[5] += (rabbit->C[4] < c_old[4]) + 886263092;
    rabbit->C[6] += (rabbit->C[5] < c_old[5]) + 1295307597;
    rabbit->C[7] += (rabbit->C[6] < c_old[6]) - 749914925;
    rabbit->b = rabbit->C[7] < c_old[7];
    for(int i=0;i<8;i++)
    {
        G[i] = Rabbit_u1(rabbit->X[i]+rabbit->C[i]);
    }
    rabbit->X[0] = G[0] + rotl(G[7],16) + rotl(G[6],16);
    rabbit->X[1] = G[1] + rotl(G[0],8) + G[7];
    rabbit->X[2] = G[2] + rotl(G[1],16) + rotl(G[0],16);
    rabbit->X[3] = G[3] + rotl(G[2],8) + G[1];
    rabbit->X[4] = G[4] + rotl(G[3],16) + rotl(G[2],16);
    rabbit->X[5] = G[5] + rotl(G[4],8) + G[3];
    rabbit->X[6] = G[6] + rotl(G[5],16) + rotl(G[4],16);
    rabbit->X[7] = G[7] + rotl(G[6],8) + G[5];
    return true;
}

bool Rabbit_toByte(unsigned int s,unsigned char* d)
{
    if(!d)
        return false;
    d[0] = (s>>24)&0xff;
    d[1] = (s>>16)&0xff;
    d[2] = (s>>8)&0xff;
    d[3] = (s)&0xff;
    return true;
}

bool Rabbit_EncryptBuf(Rabbit* rabbit,unsigned char* src,int srclen,unsigned char* dst,int dstlen)
{
    unsigned int K[4] = {0};
    unsigned char v[4] = {0};
    if(!rabbit || !src || !dst || srclen>dstlen || srclen<=0)
        return false;
    for(int i=0;iX[0]^(rabbit->X[5]>>16)^(rabbit->X[3]<<16)^Rabbit_toInt(src,i);
        K[1] = rabbit->X[2]^(rabbit->X[5]<<16)^(rabbit->X[7]>>16)^Rabbit_toInt(src,i+4);
        K[2] = rabbit->X[4]^(rabbit->X[7]<<16)^(rabbit->X[1]>>16)^Rabbit_toInt(src,i+8);
        K[3] = rabbit->X[6]^(rabbit->X[3]>>16)^(rabbit->X[1]<<16)^Rabbit_toInt(src,i+12);
        for(int j=0;j<4;j++)
        {
            Rabbit_toByte(K[j],v);
            *(unsigned int*)(dst+i+4*j) = *(unsigned int*)v;
        }
    }
    return true;
}

下面是一个实例:
unsigned char encrypt[448] =
    {//加密过的进程id
        0x30,0xa2,0xf6,0xa4,0xdb,0x6c,0xe9,0xa2,0x4d,0xdd,0x66,0x18,0xd1,0x8e,0xa9,0x8a,
        0x1c,0xa2,0xf6,0xa4,0xf3,0x6c,0xe9,0xa2,0x65,0xdd,0x66,0x18,0xc9,0x8e,0xa9,0x8a,
        0x08,0xa2,0xf6,0xa4,0x0b,0x6c,0xe9,0xa2,0xb5,0xdd,0x66,0x18,0x09,0x8e,0xa9,0x8a,
        0xc8,0xa2,0xf6,0xa4,0x43,0x6c,0xe9,0xa2,0xd5,0xdd,0x66,0x18,0x81,0x89,0xa9,0x8a,
        0x4c,0xa5,0xf6,0xa4,0xbf,0x6b,0xe9,0xa2,0x51,0xda,0x66,0x18,0xf5,0x89,0xa9,0x8a,
        0xc8,0xa5,0xf6,0xa4,0x43,0x6b,0xe9,0xa2,0xc5,0xda,0x66,0x18,0x6d,0x89,0xa9,0x8a,
        0x7c,0xa4,0xf6,0xa4,0x17,0x6a,0xe9,0xa2,0x89,0xdb,0x66,0x18,0x1d,0x88,0xa9,0x8a,
        0xc4,0xa4,0xf6,0xa4,0x5f,0x6a,0xe9,0xa2,0xf1,0xdb,0x66,0x18,0x55,0x88,0xa9,0x8a,
        0x14,0xa7,0xf6,0xa4,0xe7,0x69,0xe9,0xa2,0x79,0xd8,0x66,0x18,0xdd,0x8b,0xa9,0x8a,
        0x04,0xa7,0xf6,0xa4,0xf7,0x69,0xe9,0xa2,0x69,0xd8,0x66,0x18,0xcd,0x8b,0xa9,0x8a,
        0xf8,0xa7,0xf6,0xa4,0x13,0x69,0xe9,0xa2,0x85,0xd8,0x66,0x18,0x29,0x8b,0xa9,0x8a,
        0xe8,0xa7,0xf6,0xa4,0x2b,0x69,0xe9,0xa2,0xbd,0xd8,0x66,0x18,0x01,0x8b,0xa9,0x8a,
        0x64,0xa6,0xf6,0xa4,0x97,0x68,0xe9,0xa2,0x39,0xd9,0x66,0x18,0x85,0x8a,0xa9,0x8a,
        0xfc,0xa6,0xf6,0xa4,0x2b,0x68,0xe9,0xa2,0xbd,0xd9,0x66,0x18,0x09,0x8a,0xa9,0x8a,
        0xc8,0xa6,0xf6,0xa4,0x43,0x68,0xe9,0xa2,0xd5,0xd9,0x66,0x18,0x5d,0x8a,0xa9,0x8a,
        0x80,0xa6,0xf6,0xa4,0x17,0x6e,0xe9,0xa2,0xd1,0xdf,0x66,0x18,0x19,0x8c,0xa9,0x8a,
        0x90,0xa0,0xf6,0xa4,0x5f,0x6e,0xe9,0xa2,0x61,0xdf,0x66,0x18,0x81,0x8e,0xa9,0x8a,
        0xe0,0xa5,0xf6,0xa4,0x33,0x6b,0xe9,0xa2,0xa5,0xda,0x66,0x18,0xe1,0x88,0xa9,0x8a,
        0x80,0xa5,0xf6,0xa4,0xe7,0x6a,0xe9,0xa2,0x6d,0xdb,0x66,0x18,0x15,0x88,0xa9,0x8a,
        0xdc,0xa4,0xf6,0xa4,0x3f,0x6a,0xe9,0xa2,0x95,0xd8,0x66,0x18,0x7d,0x8b,0xa9,0x8a,
        0xa0,0xa7,0xf6,0xa4,0x77,0x69,0xe9,0xa2,0xed,0xd8,0x66,0x18,0xe9,0x8b,0xa9,0x8a,
        0x40,0xa7,0xf6,0xa4,0x8b,0x69,0xe9,0xa2,0xc9,0xdb,0x66,0x18,0x65,0x88,0xa9,0x8a,
        0xa4,0xa4,0xf6,0xa4,0x03,0x68,0xe9,0xa2,0x69,0xd9,0x66,0x18,0xd5,0x8a,0xa9,0x8a,
        0x78,0xa9,0xf6,0xa4,0x93,0x67,0xe9,0xa2,0x05,0xd6,0x66,0x18,0x91,0x85,0xa9,0x8a,
        0x50,0xa9,0xf6,0xa4,0xab,0x67,0xe9,0xa2,0xdd,0xd6,0x66,0x18,0x05,0x84,0xa9,0x8a,
        0x0c,0xab,0xf6,0xa4,0x6b,0x62,0xe9,0xa2,0xfd,0xd0,0x66,0x18,0xe9,0x83,0xa9,0x8a,
        0xa8,0xaf,0xf6,0xa4,0xb7,0x63,0xe9,0xa2,0xad,0xce,0x66,0x18,0xa1,0x9c,0xa9,0x8a,
        0x44,0xb2,0xf6,0xa4,0x7f,0x7c,0xe9,0xa2,0x15,0xca,0x66,0x18,0xb1,0x8d,0xa9,0x8a,
    };
    unsigned char decrypt[448]={0};//解密到目标内存
    Rabbit rabbit;
    Rabbit_Init(&rabbit);//初始化
    Rabbit_SetKey((unsigned char*)"0123456789ABCDEF",&rabbit);//加载密钥
    Rabbit_EncryptBuf(&rabbit,encrypt,448,decrypt,448);//加密/解密
    /*解密后的进程id
    00000344 00000358 0000035c 00000360
    00000368 00000370 00000374 00000378
    0000037c 00000388 000003a4 000003b8
    000003bc 000003c0 000003c4 00000430
    00000438 0000043c 00000440 00000444
    000004bc 000004c0 000004d4 000004dc
    00000508 00000594 00000598 000005ac
    000005b0 000005dc 000005e0 000005e4
    00000660 00000664 00000668 0000066c
    00000670 00000674 00000678 0000067c
    0000068c 00000690 00000694 00000698
    0000069c 000006a8 000006ac 000006b0
    00000710 00000714 00000728 00000734
    00000788 000007a8 000007ac 000007b8
    000007bc 000007c0 000007c4 000007ec
    000007f4 00000194 000001c0 000001a8
    000001e4 000001dc 00000170 00000330
    00000494 000004b0 000004b4 00000550
    000004f4 00000564 0000057c 000005a4
    000005a8 000005bc 00000684 000006cc
    000006d4 000006f4 000006fc 00000658
    00000634 00000608 000005d8 000005d4
    000005d0 00000780 00000778 00000764
    0000080c 00000810 00000814 00000820
    00000824 00000828 000008cc 000009b4
    00000a78 00000de8 00000eec 00000e58
    00000edc 00000c34 000010bc 00001110
    00001330 000013fc 00001404 00000000
*/

四、InlineHook KiFastCallEntry

  • 重置蓝屏死机计数 用于检测hook造成的蓝屏
  • 获取SSDT/SSSDT/ hook点
  • 分配跳转表ServiceMapTable
  • 改写KiFastCallEntry使跳转表生效
  • Hook重要回调
  • 开启日志记录
  • Hook KeUserModeCallback

4.1 获取SSDT/SSSDT/Hook点

ULONG InitState = 0;
ULONG LastErrorCode = 0;


UCHAR int2Ecode1[10] = {0x8B, 0xFC, 0x3B, 0x35, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x83};
UCHAR int2Ecode2[22] = {0x8B, 0xFC, 0xF6, 0x45, 0x72, 0x02, 0x75, 0x06, 0xF6, 0x45, 0x6C,
                        0x01, 0x74, 0x0C, 0x3B, 0x35, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x83};

ULONG GetHookPoint1()
{//检测系统原始KiFastCallEntry
    *(ULONG*)(int2Ecode2 + 4) = MmUserProbeAddress;//构造cmp esi,dword ptr ds:[MmUserProbeAddress]
    if(!MmUserProbeAddress)
        return 0;
    ULONG ptr = GetKiSystemServiceAddr();//KiFastCallEntry总在KiSystemService之后
    if(ptr < NtosBase || ptr > NtosBase+NtosSize)
        return 0;
    for(int offset = 0;offset < 1024;offset++,ptr++)
    {
        /*
            mov edi,esp
            cmp esi,dword ptr ds:[MmUserProbeAddress]
            jae ??
        */
        if(RtlCompareMemory(ptr,int2Ecode1,sizeof(int2Ecode1)) == sizeof(int2Ecode1))
            return ptr;
    }
    return 0;
}

ULONG GetHookPoint2()
{//检测是否被金山inline hook过得KiFastCallEntry
    *(ULONG*)(int2Ecode2 + 16) = MmUserProbeAddress;//构造cmp esi,dword ptr ds:[MmUserProbeAddress]
    if(!MmUserProbeAddress)
        return 0;
    ULONG ptr = GetKiSystemServiceAddr();
    if(ptr < NtosBase || ptr > NtosBase+NtosSize)
        return 0;
    for(int offset = 0;offset < 1024;offset++,ptr++)
    {
        /*
            mov edi,esp
            test byte ptr[ebp+72h],2
            jne $1
            test byte ptr[ebp+6Ch],1
            je ??
            $1:
            cmp esi,dword ptr ds:[MmUserProbeAddress]
            jae ??
        */
        if(RtlCompareMemory(ptr,int2Ecode2,sizeof(int2Ecode2)) == sizeof(int2Ecode2))
            return ptr;
    }
    return 0;
}

ULONG InitState = 0,LastErrorCode = 0,serHookType = 0;
ULONG NtosBase,NtosSize,SSDTBase,SSDTLimit,ShadowSSDTBase,ShadowSSDTLimit,Win32kBase,Win32kSize;
ULONG dwcsrssId;
ULONG BuildIndex;
PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
ULONG MmUserProbeAddress;

struct HOOKINFO
{
    ULONG InlinePoint;
    ULONG JmpBackPoint;
    UCHAR OriginCode[8];
};

HOOKINFO HookInfo1={0},HookInfo2={0};
/*
KiFastCallEntry+0xde:
    mov     ebx,dword ptr [edi+eax*4]
    jmp     81f9e3e0
    nop                                             =>  InlinePoint
    nop
    nop
    jmp     TsFltMgr+0x2300 (f8517300)
    jae     nt!KiSystemCallExit2+0x9f (8053e7ec)    =>  JmpBackPoint
    rep movs dword ptr es:[edi],dword ptr [esi]
    call    ebx

    OriginCode[8];
    8bfc            mov     edi,esp
    3b35549a5580    cmp     esi,dword ptr [nt!MmUserProbeAddress]
*/
NTSTATUS PrepareHook()
{
    RTL_PROCESS_MODULE_INFORMATION Win32kInfo,NtosInfo;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    ULONG ReturnLength = 0;
    ULONG OutData;
    LPVOID Buffer = NULL;
    RtlZeroMemory(&Win32kInfo,sizeof(Win32kInfo));
    RtlZeroMemory(&NtosInfo,sizeof(NtosInfo));
    InitState = 0;
    LastErrorCode = 0;
    status = GetRegDataWithType(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TsFltMgr", 
        L"thm", &OutData, 4, 0)
    if(NT_SUCCESS(status) && OutData == 1)
        serHookType = HOOKTYPE_SSDT;
    ZwQuerySystemInformation(SystemModuleInformation,&ReturnLength,0,&ReturnLength);
    if(ReturnLength)
        Buffer = ExAllocatePool(PagedPool,ReturnLength);
    if(Buffer)
        status = ZwQuerySystemInformation(SystemModuleInformation,Buffer,ReturnLength,NULL);
    if(!NT_SUCCESS(status))
    {
        ExFreePool(Buffer);
        Buffer = NULL;
    }
    if(Buffer)
    {
        RtlCopyMemory(&NtosInfo,((PRTL_PROCESS_MODULES)Buffer)->Modules,sizeof(NtosInfo));
        ExFreePool(Buffer);
        NtosBase = NtosInfo.ImageBase;
        NtosSize = NtosInfo.ImageSize;
        ULONG FuncAddr = MiLocateExportName(NtosBase,"KeServiceDescriptorTable");
        if(FuncAddr && MmIsAddressValid(FuncAddr))
        {
            PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable = (PKSERVICE_TABLE_DESCRIPTOR)FuncAddr;
            SSDTBase = KeServiceDescriptorTable[0].Base;
            SSDTLimit = KeServiceDescriptorTable[0].Limit;
            InitState |= 2;
            dwcsrssId = GetProcessIdByName(L"csrss.exe");
            if(GetProcessInfoByFileName("WIN32K.SYS",&Win32kInfo))
            {
                Win32kBase = Win32kInfo.ImageBase;
                Win32kSize = Win32kInfo.ImageSize;
                if(NT_SUCCESS(GetShadowSSDTInfo()))
                    InitState |= 4;
            }
            
            UNICODE_STRING UMmUserProbeAddress;
            RtlInitUnicodeString(&UMmUserProbeAddress,L"MmUserProbeAddress");
            ULONG MmUserProbeAddress = MmGetSystemRoutineAddress(&UMmUserProbeAddress);
            if(MmUserProbeAddress && MmIsAddressValid(MmUserProbeAddress))
            {
                HookInfo1.InlinePoint = GetHookPoint1();
                if(HookInfo1.InlinePoint)
                    HookInfo1.JmpBackPoint = HookInfo1.InlinePoint + 8;
                else
                {
                    HookInfo2.InlinePoint = GetHookPoint2();
                    if(HookInfo2.InlinePoint)
                        HookInfo2.JmpBackPoint = HookInfo2.InlinePoint + 6;
                }
                if(HookInfo1.InlinePoint == 0 && HookInfo2.InlinePoint == 0)
                {
                    LastErrorCode |= 0x20;
                    return status;
                }
                InitState |= 8;
                MmUserProbeAddress = *(ULONG*)MmUserProbeAddress;
                status = STATUS_SUCCESS;
            }
            else
            {
                LastErrorCode |= 0x10;
            }
        }
        else
        {
            LastErrorCode |= 2;
        }
    }
    else
    {
        LastErrorCode |= 1;
    }
    return status;
}

4.2 从KiSystemService获取KiFastCallEntry

struct IDTR
{
    USHORT IDTLimit;
    PKIDTENTRY IDTBase;
};
ULONG GetKiSystemServiceAddr()
{
    IDTR idt = {0};
    RTL_PROCESS_MODULE_INFORMATION NtosInfo,Win32kInfo;
    RtlZeroMemory(&NtosInfo,sizeof(NtosInfo));
    __sidt(&idt);
    if(idt.IDTBase)
    {
        KIDTENTRY int2e = idt.IDTBase[0x2E];
        if(MmIsAddressValid(int2e))
            return MAKEULONG(int2e.ExtendedOffset,int2e.Offset);
    }
    return 0;
}

4.3 获取SSSDT信息

NTSTATUS GetShadowSSDTInfo()
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PVOID pt = MiLocateExportName(NtosBase, "KeAddSystemServiceTable");
    PMDL mdl = NULL;
    if(pt && !MmIsAddressValid(pt))
    {//页换出
        mdl = MmCreateMdl(NULL,pt,0x1000);
        if(mdl)
        {
            MmProbeAndLockPages(mdl,KernelMode,IoReadAccess);
        }
    }
    if(!pt || !MmIsAddressValid(pt))
    {
        LastErrorCode |= 4;
        goto END;
    }

    switch(BuildIndex)
    {
    case WIN2000:
    case WINXP:
    case WINXPSP3:
    case WINVISTA:
    case WINVISTASP1:
    case WINVISTASP2:
    case WIN7:
    case WIN7SP1:
        for(int i=0;i<256;i++)
        {
            if(MmIsAddressValid(pt) && *(USHORT*)pt == 0x888D)
            {//8d88603f5580    lea     ecx,nt!KeServiceDescriptorTableShadow 
                PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2);
                ShadowSSDTBase = Table[1].Base;
                ShadowSSDTLimit = Table[1].Limit;
                status = STATUS_SUCCESS;
            }
        }
        break;
    case WIN8_8102:
    case WIN8_8250:
    case WIN81_9200:
    case WIN81_9600:
        for(int i=0;i<256;i++)
        {
            if(MmIsAddressValid(pt) && *(USHORT*)pt == 0xB983)
            {//83b9603f558083  cmp     dword ptr nt!KeServiceDescriptorTableShadow
                PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2);
                if(KeServiceDescriptorTable == Table)
                {
                    ShadowSSDTBase = Table[1].Base;
                    ShadowSSDTLimit = Table[1].Limit;
                    status = STATUS_SUCCESS;
                }
            }
        }
        break;
    case WIN10_9841:
    case WIN10_9860:
    case WIN10_9926:
    case WIN10_10041:
    case WIN10_10049:
        for(int i=0;i<256;i++)
        {
            if(MmIsAddressValid(pt) && *(USHORT*)pt == 0x3D83)
            {//833d90d28d8100  cmp     dword ptr [nt!KeServiceDescriptorTableShadow+0x10],0
                PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2) - 16;
                if(KeServiceDescriptorTable == Table)
                {
                    ShadowSSDTBase = Table[1].Base;
                    ShadowSSDTLimit = Table[1].Limit;
                    status = STATUS_SUCCESS;
                }
            }
        }
        break;
    }
    if(!ShadowSSDTBase)
        LastErrorCode |= 8;
END:
    if(mdl)
    {
        MmUnlockPages(mdl);
        IoFreeMdl(mdl);
    }
}

4.4 初始化InlineHook KiFastCallEntry跳转表

BOOLEAN InitProxyTable()
{
    ULONG BuildIndex = GetBuildNumberAsIndex();
    for(int i = 0;i < APINUMBER;i++)
    {
        for(int j = 0;j < BUILDMAX;j++)
        {
            if(SProxyTable[i].ServiceIndex[j] == 0)
                SProxyTable[i].ServiceIndex[j] = 1023;//置为无效
        }
    }
    if(GetServiceIndex("ZwCreateKey") == -1)
    {//不能获取到服务号
        if(NtosBase)
        {
            for(int i = 0;i < APINUMBER;i++)
            {
                if(SProxyTable[i].ServiceTableType == END)
                    break;
                else if(SProxyTable[i].ServiceTableType == SSDT)
                {
                    if(SProxyTable[i].ApiName)
                    {
                        UNICODE_STRING UApiName;
                        ANSI_STRING AApiName;
                        RtlInitUnicodeString(&UApiName,SProxyTable[i].ApiName);
                        if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
                        {
                            GetServiceIndexFromNtos(AApiName.Buffer);
                            RtlFreeAnsiString(AApiName);
                        }
                    }               
                }
            }
        }
    }
    else
    {//能获取到服务号   由于SProxyTable已存服务号,所以下面代码本身无效
        for(int i = 0;i < APINUMBER;i++)
        {
            if(SProxyTable[i].ServiceTableType == END)
                break;
            if(SProxyTable[i].ServiceTableType == SSDT)
            {
                if(SProxyTable[i].ApiName)
                {
                    UNICODE_STRING UApiName;
                    ANSI_STRING AApiName;
                    RtlInitUnicodeString(&UApiName,SProxyTable[i].ApiName);
                    if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
                    {
                        ULONG Index = GetServiceIndexFromNtdll(AApiName.Buffer);
                        if(Index != -1)
                            SProxyTable[i].ServiceIndex[BuildIndex] = Index;
                        RtlFreeAnsiString(AApiName);
                    }
                }
            }
        }
    }
    return TRUE;
}

int AllocHookTable()
{//已知系统情况下初始化代理表,直接使用ServiceIndex
    ULONG BuildIndex = GetBuildNumberAsIndex();
    DProxy* Proxydata = NULL;
    ULONG Count = 0;//未成功布置的代理函数个数
    if(BuildIndex >= 0 && BuildIndex < BUILDMAX)
    {
        InitProxyTable();
        for(int i=0;iIsInitialized = FALSE;
                        Proxydata->ApiName = SProxyTable[i].ApiName;
                        Proxydata->TableIndex = SProxyTable[i].IndexInTable;
                        Proxydata->ProxyFuncAddr = SProxyTable[i].ProxyFunc;
                        Proxydata->ServiceIndex = -1;
                        KeInitializeEvent(Proxydata->Lock,SynchronizationEvent,FALSE);
                        DProxyTable[SProxyTable[i].IndexInTable] = Proxydata;
                        ULONG ServiceType = SProxyTable[i].ServiceTableType;
                        ULONG ServiceIndex = SProxyTable[i].ServiceIndex[BuildIndex];
                        if(ServiceType >= 2 ||  ServiceIndex== -1 || ServiceIndex >= 1024)
                        {
                            Count++;
                        }
                        else
                        {
                            ServiceMapTable[ServiceType][ServiceIndex] = Proxydata;
                            Proxydata->ServiceTableType = ServiceType;
                            Proxydata->ServiceIndex = ServiceIndex;
                        }
                    }
                }
            }
        }
        return Count;
    }
    return APINUMBER;//返回未成功代理的个数
}

int AllocHookTableU()
{//未知系统情况下初始化代理表,临时从Ntos模块获取ServiceIndex
    
    if(!NtosBase)
        return 0;//返回成功布置代理的个数
    for(int i=0;iIsInitialized = FALSE;
                            Proxydata->ApiName = SProxyTable[i].ApiName;
                            Proxydata->TableIndex = SProxyTable[i].IndexInTable;
                            Proxydata->ProxyFuncAddr = SProxyTable[i].ProxyFunc;
                            Proxydata->ServiceIndex = -1;
                            KeInitializeEvent(Proxydata->Lock,SynchronizationEvent,FALSE);
                            DProxyTable[SProxyTable[i].IndexInTable] = Proxydata;
                            ULONG ServiceType = SProxyTable[i].ServiceTableType;
                            ULONG ServiceIndex = SProxyTable[i].ServiceIndex[BuildIndex];
                            if(ServiceType >= 2 ||  ServiceIndex== -1 || ServiceIndex >= 1024)
                            {
                                Count++;
                                ServiceMapTable[ServiceType][ServiceIndex] = Proxydata;
                                Proxydata->ServiceTableType = ServiceType;
                                Proxydata->ServiceIndex = ServiceIndex;
                            }
                        }
                    }
                }
            }
        }
    }
    return Count;
}

4.5 获取系统服务号的2种方式

ULONG GetServiceIndexFromNtdll(PCHAR ApiName)
{
    ULONG result = -1;
    RTL_PROCESS_MODULE_INFORMATION ProcessInfo;
    ULONG Index;
    RtlZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
    if(GetProcessInfoByFileName("ntdll.dll",&ProcessInfo) && ProcessInfo.ImageBase && ApiName)
    {
        Index = MiLocateExportName(ProcessInfo.ImageBase,ApiName);
        if(Index)
        {
            result = *(ULONG*)(Index+1);
        }
    }
    return result;
}

ULONG GetServiceIndexFromNtos(PCHAR ApiName)
{
    ULONG result = -1;
    ULONG Index = MiLocateExportName(ProcessInfo.ImageBase,ApiName);
    if(Index)
    {
        result = *(ULONG*)(Index+1);
    }
    if(Index & 0xFFFFC000)
    {
        result = -1;
    }
    return result;
}

4.6 InlineHook过程

NTSTATUS DoInlineHook()
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    ULONG MajorVersion = 0,MinorVersion = 0,BuildNumber = 0;
    PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
    if(serHookType == HOOKTYPE_SSDT || !(InitState & 8))//外部hook或没找到hook挂载点
        return status;
    if(HookInfo1.InlinePoint)
    {//如果为默认方式hook
        if(GetBuildNumberAsIndex() >= WINVISTA)
            status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry1);
        else
            status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry2);
        if(NT_SUCCESS(status))
            serHookType = HOOKTYPE_INLINE;
    }
    else if(HookInfo2.InlinePoint)
    {//如果为金山共存方式hook
        if(GetBuildNumberAsIndex() >= WINVISTA)
            status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry3);
        else
            status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry4);
        if(NT_SUCCESS(status))
            serHookType = HOOKTYPE_KSINLINE;
    }
    if(NT_SUCCESS(status))
    {
        for(int i=0;iServiceTableType == SSDT || DProxyTable[i]->ServiceTableType == SSSDT))
                DProxyTable[i]->IsInitialized = TRUE;
        }
    }
}

NTSTATUS DoInlineHookU()
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    ULONG MajorVersion = 0,MinorVersion = 0,BuildNumber = 0;
    PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
    if(serHookType == HOOKTYPE_SSDT || !(InitState & 8))//采用外部hook或没找到hook挂载点
        return status;
    if(HookInfo1.InlinePoint)
    {//如果为默认方式hook
        if(GetBuildNumberAsIndex() >= WINVISTA)
            status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry1);
        else
            status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry2);
        if(NT_SUCCESS(status))
            serHookType = HOOKTYPE_INLINE;
    }
    else if(HookInfo2.InlinePoint)
    {//如果为金山共存方式hook
        if(GetBuildNumberAsIndex() >= WINVISTA)
            status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry3);
        else
            status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry4);
        if(NT_SUCCESS(status))
            serHookType = HOOKTYPE_KSINLINE;
    }
    if(NT_SUCCESS(status))
    {
        for(int i=0;iServiceTableType == SSDT || DProxyTable[i]->ServiceTableType == SSSDT))
                DProxyTable[i]->IsInitialized = TRUE;
        }
    }
}

NTSTATUS ModifyAndHook(ULONG InlinePoint,FARPROC JmpToFunc)
{//HOOKTYPE_INLINE 更改KiFastCallEntry
    NTSTATUS status;
    PVOID MappedAddress = NULL;
    if(!InlinePoint || !InlineHookFunc)
        return STATUS_UNSUCCESSFUL;
    PMDL mdl = GetWritablePage(InlinePoint,16,&MappedAddress);
    /*
        改写                      为
        mov edi,esp                     nop
        cmp esp,dword ptr ds:[?]        nop
                                        nop
                                        jmp ?
    */
    if(!mdl)
        return STATUS_UNSUCCESSFUL;
    ULONG data[3] = {InlinePoint,JmpToFunc,MappedAddress};
    status = MakeJmp(data,DoHook);
    MmUnlockPages(mdl);
    IoFreeMdl(mdl);
    return status;
}

NTSTATUS ModifyAndHookK(ULONG InlinePoint,FARPROC JmpToFunc)
{//HOOKTYPE_KSINLINE 更改KiFastCallEntry
    NTSTATUS status;
    PVOID MappedAddress = NULL;
    if(!InlinePoint || !InlineHookFunc)
        return STATUS_UNSUCCESSFUL;
    PMDL mdl = GetWritablePage(InlinePoint,16,&MappedAddress);
    if(!mdl)
        return STATUS_UNSUCCESSFUL;
    ULONG data[3] = {InlinePoint,JmpToFunc,MappedAddress};
    status = MakeJmp(data,DoHookK);
    MmUnlockPages(mdl);
    IoFreeMdl(mdl);
    return status;
}

NTSTATUS DoHook(ULONG* data)
{//HOOKTYPE_INLINE
    ULONGLONG shellcode;
    if(!data)
        return STATUS_UNSUCCESSFUL;
    *(ULONGLONG*)(HookInfo1.OriginCode) = *(ULONGLONG*)data[0];//保存原始8字节
    *(ULONG*)((UCHAR*)&shellcode+4) = data[1] - data[0] - 8;//填写偏移 jmp offset
    *(ULONG*)((UCHAR*)&shellcode) = 0xE9909090;//写入新8字节
    /*
        构造
        nop
        nop
        nop
        jmp ????
    */
    InterlockedCompareExchange64((LONGLONG*)data[2],shellcode,*(LONGLONG*)data[2]);
    return STATUS_SUCCESS;
}

NTSTATUS DoHookK(ULONG* data)
{//HOOKTYPE_KSINLINE
    ULONGLONG shellcode;
    if(!data)
        return STATUS_UNSUCCESSFUL;
    *(ULONGLONG*)(HookInfo1.OriginCode) = *(ULONGLONG*)data[0];//保存原始8字节
    *(USHORT*)((UCHAR*)&shellcode+6) = 0x0675;
    *(ULONG*)((UCHAR*)&shellcode+2) = data[1] - data[0] - 8;//填写偏移 jmp offset
    *(ULONG*)((UCHAR*)&shellcode) = 0xE990;//写入新8字节
    InterlockedCompareExchange64((LONGLONG*)data[2],shellcode,*(LONGLONG*)data[2]);
    return STATUS_SUCCESS;
}

PMDL GetWritablePage(PVOID VirtualAddress,ULONG Length,PVOID* pMappedAddress)
{
    PMDL mdl = IoAllocateMdl(VirtualAddress,Length,FALSE,TRUE,NULL);
    if(mdl)
    {
        MmProbeAndLockPages(mdl,KernelMode,IoWriteAccess);
        PVOID NewAddr = MmGetSystemAddressForMdlSafe (Mdl, NormalPagePriority);
        if(!NewAddr)
        {
            MmUnlockPages(mdl);
            IoFreeMdl(mdl);
            mdl = NULL;
        }
        if(NewAddr)
            *pMappedAddress = NewAddr;
    }
    return mdl;
}

4.7 构造InlineHook跳转后的执行语句

ULONG Filter(ULONG ServiceIndex,ULONG OriginFunc,ULONG Base)
{
    if(ServiceIndex >= 1024)
        return OriginFunc;
    ULONG TableType;
    if(Base == SSDTBase && ServiceIndex <= SSDTLimit)
    {
        TableType = SSDT;
    }
    else if(KeServiceDescriptorTable && KeServiceDescriptorTable->Base == Base && ServiceIndex <= SSDTLimit)
    {
        TableType = SSDT;
    }
    else if(Base == ShadowSSDTBase && ServiceIndex <= ShadowSSDTLimit)
    {
        TableType = SSSDT;
    }
    else
    {
        return OriginFunc;
    }
    if(ServiceMapTable[TableType][ServiceIndex])
    {
        ULONG NewAddr = ServiceMapTable[TableType][ServiceIndex]->ProxyFuncAddr;
        if(NewAddr)
        {
            ServiceMapTable[TableType][ServiceIndex]->OriginFuncAddr = OriginFunc;
            return NewAddr;
        }
    }
    return OriginFunc;
}

void __declspec(naked) InlineKiFastCallEntry1()
{
    /*  HOOKTYPE_INLINE   >=VISTA
        输入
        eax=ServiceIndex
        edx=OriginFunc
        edi=SSDTBase
        输出
        edx=FuncAddr  最终函数调用地址
    */
    _asm
    {
        pushf;
        pusha;
        push edi;
        push edx;
        push eax;
        call Filter;
        mov [esp+0x14],eax;//改栈中的edx
        popa;
        popf;
        mov edi,esp;
        cmp esi,MmUserProbeAddress;
        push dword ptr HookInfo1.JmpBackPoint;
        retn;//跳回JmpBackPoint
    }
}

void __declspec(naked) InlineKiFastCallEntry2()
{
    /*  HOOKTYPE_INLINE   

4.8 强制单核互斥执行指定Procedure

struct SpinData
{
    KSPIN_LOCK SpinLock;
    ULONG SpinRefCount;
}g_Spin = {0};
KDPC Dpc[32];

void DpcRoutine(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)
{
    KIRQL OldIrql;
    SpinData* spin = (SpinData*)DeferredContext;zh
    _disable();
    OldIrql = KeRaiseIrqlToDpcLevel();
    InterlockedIncrement(spin->SpinRefCount);
    KeAcquireSpinLockAtDpcLevel(spin->SpinLock);
    KeReleaseSpinLockFromDpcLevel(spin->SpinLock);
    KeLowerIrql(OldIrql);
    _enable();
}

NTSTATUS MakeJmp(ULONG* data,FARPROC addr)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    ULONG ulCurrentCpu = 0;
    KIRQL OldIrql,NewIrql;
    KAFFINITY CpuAffinity;
    if(!addr)
        return status;
    CpuAffinity = KeQueryActiveProcessors();
    for(int i = 0;i < 32;i++)
    {
        if((CpuAffinity >> i) & 1)
            ulCurrentCpu++;
    }
    if(ulCurrentCpu == 1)//单核
    {
        _disable();
        OldIrql = KeRaiseIrqlToDpcLevel();
        status = addr(data);
        KeLowerIrql(OldIrql);
        _enable();
    }
    else//多核  将除当前cpu以外的cpu用自旋锁锁住
    {
        SpinData* pSpinData = &g_Spin;
        ULONG ulNumberOfActiveCpu = 0;
        KeInitializeSpinLock(&g_Spin.SpinLock);
        for(int i = 0;i < 32;i++)
        {
            KeInitializeDpc(&Dpc[i],DpcRoutine,&pSpinData);
        }
        pSpinData->SpinRefCount = 0;
        _disable();
        NewIrql = KeAcquireSpinLock(&g_Spin.SpinLock);
        ulCurrentCpu = KeGetCurrentProcessorNumber();
        for(int i = 0;i < 32;i++)
        {
            if((CpuAffinity >> i) & 1)
                ulNumberOfActiveCpu++;
            if(i != ulCurrentCpu)
            {
                KeSetTargetProcessorDpc(Dpc[i],i);
                KeSetImportanceDpc(Dpc[i],HighImportance);
                KeInsertQueueDpc(Dpc[i],NULL,NULL);
            }
            KeInitializeDpc(&Dpc[i],DpcRoutine,&pSpinData);
        }
        //此时只有一个核在工作
        for(int i = 0;i < 16;i++)//尝试16次
        {
            for(int count = 1000000;count > 0;count--);//延时
            if(g_Spin.SpinRefCount == ulNumberOfActiveCpu - 1)//等待DpcRoutine全部执行到死锁
            {
                status = addr(data);
                break;
            }
        }
        KeReleaseSpinLock(&g_Spin.SpinLock,NewIrql);//恢复多核运行
        _enable();
    }
    return status;
}

4.9 进行SSDT hook

  在注册表Services\TsFltMgr thm=1的情况下,或者Inline hook KiFastCallEntry失败的情况下,会进行SSDT表 hook

NTSTATUS BeginSSDTHook()
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    int result = -1;
    PVOID MappedAddress = NULL;
    PMDL mdl = NULL;
    if(serHookType == HOOKTYPE_INLINE || serHookType == HOOKTYPE_KSINLINE)//已成功inline hook
        return STATUS_UNSUCCESSFUL;
    serHookType = HOOKTYPE_SSDT;
    for(int i = 0;i <= APINUMBER;i++)
    {
        if(DProxyTable[i] && DProxyTable[i]->ServiceIndex != -1 && !DProxyTable[i]->IsInitialized)
        {
            if(DProxyTable[i]->ServiceTableType == SSDT)
            {
                int index = DProxyTable[i]->ServiceIndex;
                if(index != 1023 && DProxyTable[i]->ProxyFunc && SSDTBase)
                {
                    PVOID MappedAddress = NULL;
                    PMDL mdl = GetWritablePage(SSDTBase,4*SSDTLimit,&MappedAddress);
                    if(mdl)
                    {
                        DProxyTable[i]->OriginFuncAddr = ((ULONG*)SSDTBase)[index];
                        ((ULONG*)MappedAddress)[index] = DProxyTable[i]->ProxyFunc;
                        MmUnlockPages(mdl);
                        IoFreeMdl(mdl);
                        result = index;
                    }
                }
            }
            else if(DProxyTable[i]->ServiceTableType == SSSDT)
            {
                int index = DProxyTable[i]->ServiceIndex;
                if(index != 1023 && DProxyTable[i]->ProxyFunc && ShadowSSDTBase)
                {
                    HANDLE CurProcessId = PsGetCurrentProcessId();
                    HANDLE SmssProcessId = GetProcessIdByName(L"smss.exe");
                    if(!dwcsrssId)//如果没有获取到csrss.exe的id
                    {
                        if(CurProcessId == SmssProcessId)//使用smss.exe的SSSDT
                        {
                            mdl = GetWritablePage(ShadowSSDTBase,4*ShadowSSDTLimit,&MappedAddress);
                            if(mdl)
                            {
                                DProxyTable[i]->OriginFuncAddr = ((ULONG*)ShadowSSDTBase)[index];
                                ((ULONG*)MappedAddress)[index] = DProxyTable[i]->ProxyFunc;
                                MmUnlockPages(mdl);
                                IoFreeMdl(mdl);
                                result = index;
                            }
                        }
                    }
                    else
                    {//附加到csrss.exe
                        PVOID attachobj = AttachDriverToProcess(dwcsrssId);
                        if(attachobj)
                        {
                            mdl = GetWritablePage(ShadowSSDTBase,4*ShadowSSDTLimit,&MappedAddress);
                            if(mdl)
                            {
                                DProxyTable[i]->OriginFuncAddr = ((ULONG*)ShadowSSDTBase)[index];
                                ((ULONG*)MappedAddress)[index] = DProxyTable[i]->ProxyFunc;
                                MmUnlockPages(mdl);
                                IoFreeMdl(mdl);
                                result = index;
                            }
                            DetachDriverFromProcess(attachobj);
                        }
                    }
                }   
            }
            if(result != -1)
                DProxyTable[i]->IsInitialized = TRUE;
        }
    }
    return STATUS_SUCCESS;
}

struct AttachData
{
    KAPC_STATE ApcState;
    PVOID Process;
};

PVOID AttachDriverToProcess(HANDLE ProcessId)
{
    PVOID Process = NULL;
    AttachData* Buffer = NULL;
    if(ProcessId == PsGetCurrentProcessId())
        return 0xEEEEDDDD;//自身标识
    if(ProcessId && NT_SUCCESS(PsLookupProcessByProcessId(ProcessId,&Process)))
    {
        Buffer = (AttachData*)ExAllocatePool(PagedPool,sizeof(AttachData));
        if(!Buffer)
        {
            ObDereferenceObject(Process);
            return NULL;
        }
        Buffer->Process = Process;
        KeStackAttachProcess(Process,&Buffer->ApcState)
    }
}

NTSTATUS DetachDriverFromProcess(PVOID Buffer)
{
    if(Buffer && (ULONG)Buffer != 0xEEEEDDDD)
    {
        AttachData* data = (AttachData*)Buffer;
        KeUnstackDetachProcess(&data->ApcState);
        ObDereferenceObject(data->Process);
        ExFreePool(Buffer);
    }
}

4.10 对重要回调(进程回调、线程回调、映像加载回调)的挂钩

/*
    Sproxy Index:
    普通api使用index 0-0x33 0x37-0x48 0x4A-0x69
    52    CreateNotifyRoutine
    53    ThreadNofify
    54    ImageNotify
    73    CreateNotifyRoutine2
*/
enum
{
    INDEX_KECALLBACK = 51,
    INDEX_PROCESS = 52,
    INDEX_THREAD = 53,
    INDEX_IMAGE = 54,
    INDEX_PROCESSEX = 73,
};

NTSTATUS HookImportantNotify()
{
    if(!DProxyTable[INDEX_PROCESS])
    {
        DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
        if(Proxydata)
        {
            Proxydata->IsInitialized = FALSE;
            Proxydata->ApiName = "ProcessNotify";
            Proxydata->TableIndex = INDEX_PROCESS;
            Proxydata->ProxyFuncAddr = CreateNotifyRoutine1;
            Proxydata->ServiceIndex = -1;
            KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
            DProxyTable[INDEX_PROCESS] = Proxydata;
        }
    }
    if(DProxyTable[INDEX_PROCESS] && !DProxyTable[INDEX_PROCESS]->IsInitialized)
    {
        DProxyTable[INDEX_PROCESS]->ServiceTableType = CALLBACK;
        if(NT_SUCCESS(PsSetCreateProcessNotifyRoutine(CreateProcessNotify,FALSE)))
            DProxyTable[INDEX_PROCESS]->IsInitialized = TRUE;
    }
    if(!DProxyTable[INDEX_PROCESSEX])
    {
        DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
        if(Proxydata)
        {
            Proxydata->IsInitialized = FALSE;
            Proxydata->ApiName = "ProcessNotifyEx";
            Proxydata->TableIndex = INDEX_PROCESSEX;
            Proxydata->ProxyFuncAddr = CreateNotifyRoutine1Ex;
            Proxydata->ServiceIndex = -1;
            KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
            DProxyTable[INDEX_PROCESSEX] = Proxydata;
        }
    }
    if(DProxyTable[INDEX_PROCESSEX] && !DProxyTable[INDEX_PROCESSEX]->IsInitialized)
    {
        DProxyTable[INDEX_PROCESSEX]->ServiceTableType = CALLBACK;
        if(NT_SUCCESS(PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyEx,FALSE)))
            DProxyTable[INDEX_PROCESSEX]->IsInitialized = TRUE;
    }
    if(!DProxyTable[INDEX_THREAD])
    {
        DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
        if(Proxydata)
        {
            Proxydata->IsInitialized = FALSE;
            Proxydata->ApiName = "ThreadNotify";
            Proxydata->TableIndex = INDEX_THREAD;
            Proxydata->ProxyFuncAddr = CreateThreadNotify;
            Proxydata->ServiceIndex = -1;
            KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
            DProxyTable[INDEX_THREAD] = Proxydata;
        }
    }
    if(DProxyTable[INDEX_THREAD] && !DProxyTable[INDEX_THREAD]->IsInitialized)
    {
        DProxyTable[INDEX_THREAD]->ServiceTableType = CALLBACK;
        if(NT_SUCCESS(PsSetCreateThreadNotifyRoutine(CreateThreadNotify,FALSE)))
            DProxyTable[INDEX_THREAD]->IsInitialized = TRUE;
    }
    if(!DProxyTable[INDEX_IMAGE])
    {
        DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
        if(Proxydata)
        {
            Proxydata->IsInitialized = FALSE;
            Proxydata->ApiName = "ImageNotify";
            Proxydata->TableIndex = INDEX_IMAGE;
            Proxydata->ProxyFuncAddr = LoadImageNotify;
            Proxydata->ServiceIndex = -1;
            KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
            DProxyTable[INDEX_IMAGE] = Proxydata;
        }
    }
    if(DProxyTable[INDEX_IMAGE] && !DProxyTable[INDEX_IMAGE]->IsInitialized)
    {
        DProxyTable[INDEX_IMAGE]->ServiceTableType = CALLBACK;
        if(NT_SUCCESS(PsSetLoadImageNotifyRoutine(LoadImageNotify,FALSE)))
            DProxyTable[INDEX_IMAGE]->IsInitialized = TRUE;
    }
}

4.11 Hook KeUserModeCallback

NTSTATUS HookKeUserModeCallback()
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    if(!Win32kBase)
        return status;
    OBJECT_ATTRIBUTES Oa;
    IO_STATUS_BLOCK IoStatusBlock;
    HANDLE SectionHandle = NULL;
    ULONG ViewSize = 0;
    HANDLE FileHandle = NULL;
    PVOID BaseAddress = 0x5000000;
    UNICODE_STRING UKeUserModeCallback;
    if(!DProxyTable[INDEX_KECALLBACK])
    {
        DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
        if(Proxydata)
        {
            Proxydata->IsInitialized = FALSE;
            Proxydata->ApiName = "ImageNotify";
            Proxydata->TableIndex = INDEX_KECALLBACK;
            Proxydata->ProxyFuncAddr = ProxyKeUserModeCallback;
            Proxydata->ServiceIndex = -1;
            KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
            DProxyTable[INDEX_KECALLBACK] = Proxydata;
        }
    }
    RtlInitUnicodeString(&UKeUserModeCallback,L"\\SystemRoot\\System32\\Win32k.sys");
    InitializeObjectAttributes(&Oa,L"KeUserModeCallback",OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);
    status = ZwOpenFile(&FileHandle,GENERIC_READ,&Oa,&IoStatusBlock,FILE_SHARE_READ,FILE_SYNCHRONOUS_IO_NONALERT);
    if(NT_SUCCESS(status))
    {
        Oa.ObjectName = NULL;
        status = ZwCreateSection(&SectionHandle,SECTION_MAP_EXECUTE,&Oa,NULL,PAGE_WRITECOPY,SEC_IMAGE);
        if(NT_SUCCESS(status))
        {
            status = ZwMapViewOfSection(&SectionHandle,NtCurrentProcess(),&BaseAddress,0,0,NULL,&ViewSize,ViewUnmap,0,PAGE_EXECUTE);
            if(!NT_SUCCESS(status))
            {
                BaseAddress = NULL;
                ZwMapViewOfSection(&SectionHandle,NtCurrentProcess(),&BaseAddress,0,0,NULL,&ViewSize,ViewUnmap,0,PAGE_EXECUTE);
            }
        }
    }
    if(BaseAddress)
    {
        if(!DProxyTable[INDEX_KECALLBACK]->IsInitialized)
        {
            ULONG IatOffset = GetProcOffsetFromIat(BaseAddress);
            DProxyTable[INDEX_KECALLBACK]->OriginFuncAddr = ExchangeMem(IatOffset,Win32kBase,ProxyKeUserModeCallback);
            if(DProxyTable[INDEX_KECALLBACK]->OriginFuncAddr)
            {
                DProxyTable[INDEX_KECALLBACK]->IsInitialized;
                status = STATUS_SUCCESS;
            }
        }
        ZwUnmapViewOfSection(NtCurrentProcess(),BaseAddress);
    }
    return status;
}

4.12 交换内存

ULONG ExchangeMem(ULONG Offset,ULONG BaseAddress,ULONG NewValue)
{//替换基址BaseAddress 偏移Offset 处的ULONG数据,返回原始数据
    HANDLE CurProcessId = PsGetCurrentProcessId();
    HANDLE SmssProcessId = GetProcessIdByName(L"smss.exe");
    ULONG OriginValue = 0;
    PMDL mdl = NULL;
    if(!dwcsrssId)//如果没有获取到csrss.exe的id
    {
        if(CurProcessId == SmssProcessId)//使用smss.exe的SSSDT
        {
            mdl = GetWritablePage(BaseAddress+Offset,16,&MappedAddress);
            if(mdl)
            {
                OriginValue = InterlockedExchange(MappedAddress,NewValue);
                MmUnlockPages(mdl);
                IoFreeMdl(mdl);
            }
        }
    }
    else
    {//附加到csrss.exe
        PVOID attachobj = AttachDriverToProcess(dwcsrssId);
        if(attachobj)
        {
            mdl = GetWritablePage(BaseAddress+Offset,4,&MappedAddress);
            if(mdl)
            {
                OriginValue = InterlockedExchange(MappedAddress,NewValue);
                MmUnlockPages(mdl);
                IoFreeMdl(mdl);
            }
            DetachDriverFromProcess(attachobj);
        }
    }
    return OriginValue;
}

4.13 获取函数Iat偏移

ULONG GetProcOffsetFromIat(PVOID ImageBase,PCHAR ModuleName,PCHAR ApiName)
{//ImageBase当前进程映像基址  ModuleName导入模块映像基址  ApiName导入函数名
    ANSI_STRING AApiName;
    UNICODE_STRING UApiname;
    PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
    ULONG ObjProcAddr;
    ULONG Offset = 0;
    PCHAR ImportedName;
    PIMAGE_THUNK_DATA FunctionNameList;
    RtlInitAnsiString(&AApiName,ApiName);
    if(!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UApiname,&AApiName,TRUE)))
        return 0;
    ObjProcAddr = MmGetSystemRoutineAddress(&UApiname);
    RtlFreeUnicodeString(&UApiname);
    ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ImageBase,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT);
    if(!ImportModuleDirectory)
        return 0;
    for (;(ImportModuleDirectory->Name != 0) && (ImportModuleDirectory->FirstThunk != 0);ImportModuleDirectory++)
    {
        ImportedName = (PCHAR)ImageBase + ImportModuleDirectory->Name;
        if(!stricmp(ModuleName,ImportedName))
        {
            FunctionNameList = (PIMAGE_THUNK_DATA)((UCHAR*)ImageBase+ImportModuleDirectory->FirstThunk);
            while(*FunctionNameList != 0)
            {
                if((*FunctionNameList) & 0x80000000)
                {
                    if(FunctionNameList->u1.Function == ObjProcAddr)
                        return (UCHAR*)FunctionNameList - (UCHAR*)ImageBase;
                }
                else
                {
                    IMAGE_IMPORT_BY_NAME *pe_name = (IMAGE_IMPORT_BY_NAME*)((PCHAR)ImageBase + *FunctionNameList);
                    if(pe_name->Name[0] == 'K' && !stricmp(pe_name->Name,"KeUserModeCallback"))
                        return (UCHAR*)FunctionNameList - (UCHAR*)ImageBase;
                }
                FunctionNameList++;
            }
        }
    }
    return 0;
}

4.14 另一种方式获取ShadowSSDT信息

  当常规方式获取SSSDT失败时,会临时设置ZwSetSystemInformation的过滤函数捕获系统设置服务表(SYSTEM_INFORMATION_CLASS =SystemExtendServiceTableInformation),

void TryAnotherWayToGetShadowSSDT()
{
    AddPrevFilter(EZwSetSystemInformation,ZwSetSystemInformationFilter1,0,0,NULL);
}

ULONG OldKeAddSystemServiceTable;

ULONG __stdcall ZwSetSystemInformationFilter1(FilterPacket* Packet)
{//改EAT以获取SSSDT
    if(!ShadowSSDTBase && Packet->Params[0] == SystemExtendServiceTableInformation && !OldKeAddSystemServiceTable)
    {
        OldKeAddSystemServiceTable = ExchangeEat(NtosBase,NewKeAddSystemServiceTable);
        if(OldKeAddSystemServiceTable)
        {
            Packet->TagSlot[Packet->CurrentSlot] = 0xABCDEEEE;//用于标记
            Packet->PostFilterSlot[Packet->CurrentSlot] = ZwSetSystemInformationFilter2;
            Packet->UsedSlotCount++;
        }
    }
    return SYSMON_PASSTONEXT;
}

ULONG __stdcall ZwSetSystemInformationFilter2(FilterPacket* Packet)
{//获取之后恢复EAT
    if(Packet->TagSlot[Packet->CurrentSlot] == 0xABCDEEEE)//检查标记
    {
        if(serHookType != 1 && serHookType != 3)//是否SSDT型Hook
        {
            BeginSSDTHook();
        }
    }
    return SYSMON_PASSTONEXT;
}

BOOLEAN __stdcall KeAddSystemServiceTable(PULONG_PTR Base,PULONG Count,ULONG Limit,PUCHAR Number,ULONG Index)
{//获取SSSDT
    RTL_PROCESS_MODULE_INFORMATION ProcessInfo;
    RtlZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
    if(!ShadowSSDTBase && GetProcessInfoByFileName("win32k.sys",&ProcessInfo) &&
        Base >= ProcessInfo.ImageBase && Base <= ProcessInfo.ImageBase+ProcessInfo.ImageSize)
    {
        Win32kBase = ProcessInfo.ImageBase;
        Win32kSize = ProcessInfo.ImageSize;
        ShadowSSDTBase = Base;
        ShadowSSDTLimit = Limit;
        ExchangeEat(NtosBase,OldKeAddSystemServiceTable);
    }
    return  OldKeAddSystemServiceTable(Base,Count,Limit,Number,Index);
}

ULONG ExchangeEat(ULONG ImageBase,ULONG NewFunc)
{
    PVOID Address = MiLocateExportName(ImageBase,"KeAddSystemServiceTable");
    if(Address)
    {
        return ExchangeMem(0,Address,NewFunc);
    }
    return 0;
}

你可能感兴趣的:(腾讯管家攻防驱动分析-TsFltMgr)