QQ管家驱动分析

QQ管家驱动分析

TsDefenseBt.sys分析

  该驱动主要用于和各类竞品做对抗用,本文为2015.7.23版本的Tsdefensebt.sys的分析。该驱动使用TsFltMgr和TsSysKit提供的接口,和另外几个驱动一样存在验签名机制。

驱动入口DriverEntry

1.设置ZwQueryValueKey的PrevFilter为ZwQueryValueKeyHooker

  • ZwQueryValueKeyHooker中拦截Service.exe对qqpcrtp服务的查询

2.检查HookPort, 360SelfProtection若存在则设置360存在标志位,baidu标志位默认设置为存在

  • 若baidu存在,则解除baidu驱动进程创建、映像加载、线程创建回调
  • 若360存在,则对TsDefensebt本身做ObOpenObjectByName的IAT hook,并记录iat信息(防止360 hook),初始化360tray.exe, zhudongfangyu.exe, 360se.exe, 360chrome.exe, wscript.exe到进程id监视表

3.获取系统api真实地址

4.获取关机回调队列头

5.获取TsSyskit接口

6.设置UnloadDispatch,CreateDispatch,CloseDispatch,IoCtlDispatch,ShutdownDispatch

7.挂钩进程创建为NtCreateProcessNotifyHooker1

  • 若360存在则挂钩NtSetValueKey为NtSetValueKeyHooker,挂钩ZwRequestWaitReplyPort为ZwRequestWaitReplyPortHooker,挂钩ZwAlpcSendWaitReceivePort为ZwAlpcSendWaitReceivePortHooker,挂钩ZwWriteVirtualMemory为ZwWriteVirtualMemoryHooker,挂钩ZwCreateThread为ZwCreateThreadHooker,挂钩ObReferenceObjectByHandle为FakeObReferenceObjectByHandle

8.注册注册表回调CmCallback

9.创建TSDFStategy设备,作为穿透驱动第二通道

10.保存TsDefenseBt映像起始地址处4096字节

  • 若ShutdownTime被修改,若360存在则从SysOpt.ini删除指定的启动项,若baidu存在则删除服务项BDMWrench,BDArKit,BDSGRTP,BDMiniDlUpdate,bd0001,bd0002,bd0003,bd0004,BDDefense,BDEnhanceBoost,BDFileDefend,BDMNetMon,BDSafeBrower,BDSandBox,Bprotect,Bhbase,Bfmon,Bfilter

11.加密TsDefenseBt->DriverObject->DriverSection中存储的驱动路径

Ntfs创建回调NtfsFsdCreateHooker

  • 若当前进程为360Tray.exe, Zhudongfangyu.exe, 360se.exe, 360chrome.exe, rundll32.exe, 360tray.exe,目标目录为
appdata\roaming\microsoft\windows\start menu\programs\startup
\「开始」菜单\程序\启动
\local settings\defend
\local\defend

且目标文件为.lnk后缀则拒绝

  • 若当前进程为svchost.exe,目标目录为\360safe\则拒绝

  • 若当前进程为explorer.exe或runonce.exe,目标路径为\360safe\且目标文件为.lnk .slnk .flnk .plnk .zlnk .xlnk .qlnk .qqlnk则拒绝

  • 若当前进程为360tray.exe或zhudongfangyu.exe,目标路径为\360safe\且目标文件为.lnk .slnk .flnk .plnk .zlnk .xlnk .qlnk .qqlnk则拒绝;目标匹配

\*\WINDOWS\TEMP\*.EXE, 
\*\LOCAL SETTINGS\TEMP\*.EXE,
\*\LOCAL\TEMP\*.EXE, 
\*\LOCAL*\F9\*.EXE,
\*\APPDATA\SAFERUN\*.EXE\*\APPDATA\*\*.EXE*\PROGRAMDATA\*\*.EXE

则拒绝

  • 若当前进程为cmd.exe 360se.exe wscript.exe 360chrome.exe,且目标文件为360tray.exe zhudongfangyu.exe则拒绝

RegisterShutdown

  • 重置TsDefenseBt关机回调
  • 若发现ShutdownTime被修改则执行ClearThread
  • 将\Driver\WMIxWDM,\Driver\mountmgr,\FileSystem\RAW,\Driver\volmgr,\Driver\ksecdd,\Driver\BDArKit关机回调置无效
  • 设置注册表\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows键回调为RegisterShutdown

ClearThread

  • 若360存在则清除SysOpt.ini指定的启动项
  • 删除baidu注册表项

ShutdownDispatch

  • 打开360文件并并存储句柄
\safemon\safeloader.exe, 
\safemon\BAK_safeloader.exe, 
\safemon\ok_safeloader.exe, 
\safemon\zz_safeloader.exe, 
\safemon\agesafe.exe, 
\safemon\sssafefix.exe,
\safemon\safe505.exe
  • 创建ClearThread线程
  • 删除360注册表项
  • 删除360快捷方式(文件和注册表)
  • 删除360服务项
  • 删除baidu注册表项

UnloadDispatch

  • 删除ZwQueryValueKey的PrevFilter

CreateDispatch

  • 检查进程是否处于监视列表
  • 检查进程是否为Ts文件,并加入监视列表

CloseDispatch

IoCtlDispatch

IoCtlCode= 0x222044 TSDFStategy 记录文件注册表(加密)数据用于增删查改
IoCtlCode= 0x222048 文件、注册表穿透操作新通道
IoCtlCode= 0x222054\|0x222058 穿透加载驱动新通道
IoCtlCode= 0x222014 设置开自保
IoCtlCode= 0x222004 用于同步
IoCtlCode= 0x222028\| 0x22202C 设置注册表服务项标识位
IoCtlCode= 0x222030 设置关自保

删除360注册表项

删除

\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
\Registry\Machine\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run
\Registry\Machine\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\RunOnce

\Registry\User下每个用户的

\Software\Microsoft\Windows\CurrentVersion\Run
\Software\Microsoft\Windows\CurrentVersion\RunOnce
\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run
\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer\RunOnce

下的键:

Fix360Safe
"{7B03EE23-306B-47a7-B9A5-4B4783FBB2A6}"
"{7A03EE23-306B-47a7-B9A5-4B4783FBB2A6}"
Repair360Safe
360安全卫士应急修复
360Safe安全卫士应急修复
360应急修复程序
360SafeEmergencyRepair
Safe安全卫士应急修复
360卫士自我修复程序
应急修复360卫士程序
360卫士用户应急自修复程序
360卫士应急自修复程序
360卫士应急自修复程序7896
360安全卫士应急修复工具
360安全卫士异常修复工具
360卫士异常修复工具
360卫士异常应急修复工具
360卫士异常应急修复程序
360卫士异常应急修复服务程序
360卫士应急修复服务程序
360卫士应急修复服务工具
360安全卫士应急修复服务工具
360安全卫士异常应急修复服务工具
360安全卫士异常应急修复服务程序
360安全卫士修复服务工具
360安全卫士修复服务工具7787
3-6-0安全卫士-异常应急修复-Fix2
3-6-0-F-i-x-3
360卫士异常应急修复服务程序7xi
360卫士异常应急修复服务程序Ok
360卫士-异常应急修复服务程序
卫士-修复程序
360-卫士-修复程序
卫士-360-修复
360-Tray-修复
tray-360-修复
修复-tray-360
卫士安全修复应急
卫士修复安全应急
修复安全卫士应急
异常安全卫士应急修复
360安全卫士应急修复异常组件程序
"My360Helper"
"MyDefend360"
"36ORepair"
"Safe360Tray"
"360Safe360TrayFix"
"360SafeTrayFix"
"360SafeTrayFix123"
"360SafeTrayFix1"
"360SafeTrayFix2"
"Rep36O"
"Rep36Osafes"
"Rep36OFixsafe"
"360SafeTrayFix3"
"Defend360TrayFix"
"360Safe_TrayFix"
"36OFix_360safe"
"36OFix_360safe1"
"36OFix_safe"
"3 6 0 F i x"
"3 6 O F i x"
"3-6-O-F-i-x"
"3-6-0 F-i-x"
"36 0 Fi x"
"36 0 F i-x"
"360-Fi-x"
"-360Fix-"
"-3 6-0 F-i x-"
"-3-6-0 F-i x-"
"-3-6-0F-i x-"
"3-6-0-Fix-0"
"360fiix_69"
"360fiix_419"
"fixfixfixfix"
"QFiPCTray"
"QFiPCTray_1"
"PCTray360"
"PCFTray360"
"OKJPCTray"
"sdCFTrayJHSDSDF"
"TrayFixSVC"
"Traydsfsdffs"
"FTrayPCsss"
"120FTray"
"361FTray"
"361FTrayFix"
"GFFsFTray"
"s1aGFFsFTray"
"31aGFFsFTray"
"31FixQFTray"
"FwwwixQFTray"
"DdFFdOTA"
"AlchemistFAA"
"BearFixAW"
"DestroyerUHSFSS"
"AxeWUDIZHAN"
"spiderManSAD"
"BaneZhiYuan"
"ursaXiongZi"
"BMShouWangZ"
"gondarSanJin"
"KunkkaChuanZhang"
"Azwraithnver"

和项:

"360_FIX*"
"360FIX*"
"3-60FIX*"
"360FIIX*"
"QFIPCTRAY*"
  • 删除\REGISTRY\MACHINE\SOFTWARE\Classes\CLSID\{FC6354A7-BACD-47C3-A989-312F7FADA3E2}\LocalServer32
  • 删除TSDFStategy指定的键值

解除baidu驱动回调

  • 分别对\Driver\BDMWrench,\Driver\BDArKit,\Driver\bd0001,\Driver\bd0002,\FileSystem\bd0003,\Driver\bd0004,\Driver\BdSandBox,\Driver\BDMNetMon几个驱动,从映像起始地址处4096字节范围内,以1为步长的4096个地址,做摘除进程回调、映像加载回调、线程回调操作

删除360快捷方式

  • 删除\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders, Common Startup键,以及\Registry\User下每个用户\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellFolders, Startup键 (lnk文件及注册表):
\safe505.lnk
\safeFY.lnk
\FYFY.lnk
\OKFOU.lnk
\OKFix.lnk
\OKZFix.lnk
\OKAgeFix.lnk
\sssafeFix.lnk
\SafeFix360.lnk
\ss360safeFix.lnk
\yy360safeFix.lnk
\Fixs360safeFix.lnk
\FixMy360safe.lnk
\MyFix360safe.lnk
\ProFixSafe.lnk
\DoFix360Safe.lnk
\RunHelper60safe.lnk
\360
\360safe.lnk
\360trayfix.lnk
\360
\360safe505Fixs.lnk
\360safe110Fixs.lnk
\safe505110Fixs.lnk

删除360服务项

360FixSvc
3600FixSvc
360SFixSvc
Fix360SafeService
SafeFix
360XFixSvc
Fix360Service
360FixService
360FixSafe
FixSafeService
RepairSafezage
360csvcsFix
360Fixcsvcs
360ServiceFixs
360SafeFixService
360SafeFixOk
360Fix360Safe
360Fix360tray
Fix360trayService
360Fix360trayService
360Fix360trayServices
360Fix360trayServicess
360Fix360trayFix
360trayFixService
360trayFixsSvc
360trayFixsSvcx
360trayRunFix
360trayRunFixs
360traysRunFix
360sRunFix
360ssxxaRunFix
360stxaFix
FixSafe360
FixsvcSafe360
FixsvcServiceSafe360
FixServiceSafe360tary
FixSafe360taryServices
505Fix360Safe
505360Safe
repair505
505repair
saferepair
repairtray
repair360
startrep
SoS360Safe
S0S360Safe
360Sos
36OSosSafe
36OOKS0SSafe
360OKS0SSafe
3600KSOSSafe
36O0OKSOSafe
36000KSOSSafe
36000OKSOSSafe
36O00OKSOSSafe
36O00OsKSOSSafe
36O0OOKSOSSafe
36O00OsKSOSSafe
3605050Safe
36OSOSFixSafe

删除baidu注册表项

"BDMWrench"
"BDArKit"
"BDSGRTP"
"BDMiniDlUpdate"
"bd0001"
"bd0002"
"bd0003"
"bd0004"
"BDDefense"
"BDEnhanceBoost"
"BDFileDefend"
"BDMNetMon"
"BDSafeBrower"
"BDSandBox"
"Bprotect"
"Bhbase"
"Bfmon"
"Bfilter"

NtCreateProcessNotifyHooker1

  • 若当前进程为360tray.exe, zhudongfangyu.exe, 360se.exe, 360chrome.exe, wscript.exe则添加到进程id监视表safemonfilehandle
  • 若360存在,且目标进程为\SystemRoot\system32\sc.exe或\SystemRoot\system32\rundll32.exe则添加到监视列表
  • 若目标进程为explorer.exe且当前进程为Userinit.exe或Taskmgr.exe则删除进程id监视表safemonfilehandle
  • 若目标文件为Userinit.exe,则打开360文件\safemon\safeloader.exe,\safemon\BAK_safeloader.exe, \safemon\ok_safeloader.exe,\safemon\zz_safeloader.exe, \safemon\agesafe.exe,\safemon\sssafefix.exe, \safemon\safe505.exe并存储句柄
  • 若目标进程为baiduprotect.exe
若当前进程为explorer.exe或svchost.exe且目标进程为safe505.exe\
若当前进程为runonce.exe且目标进程为360tray.exe
若当前进程为360se.exe或360chrome.exe且目标进程为360tray.exe,zhudongfangyu.exe, safe505.exe, liveupdate360.exe:
若目标进程为safe505.exe, safefix.exe, safeloader.exe, 360xfix505.exe:
若目标进程为
\360safe\softmgr\softmanager.exe
\360safe\safemon\360realpro.exe	
\360safe\uninst.exe
\360safe\utils\filesmasher.exe
\360safe\utils\360fileunlock.exe
\360safe\360shellpro.exe
\360safe\360safe.exe
\360safe\mobilemgr\360mobilemgr.exe
\360safe\360apploader.exe
\360safe\deepscan\dsmain.exe
\360safe\safemon\360tray.exe

则强制结束进程

  • 若创建目标进程为explorer.exe或winlogon.exe,则
  • 若baidu存在则解除baidu驱动回调
  • 若360存在则删除360启动项和快捷方式
  • 若结束目标进程为explorer.exe或winlogon.exe,则
  • 若baidu存在则解除baidu驱动回调
  • 若360存在则:执行FuckCompeete1,删除360启动项和快捷方式;清除SysOpt.ini指定的启动项;删除\Registry\User下每个用户\Software\Microsoft\Windows\CurrentVersion\Run和\Software\Microsoft\Windows\CurrentVersion\RunOnce的360safetray和360sd项;删除360服务项;删除baidu服务项^_^

FuckCompete1:将\\FileSystem\\360boost的关机回调设置为无效;挂钩Ntfs创建例程;重置自身关机回调;创建随机名驱动及设备执行并设置其关机回调为ShutdownDispatch

NtSetValueKeyHooker

若系统关机/注销,且ValueName存在360或当前进程为zhudongfangyu.exe,且目标注册表路径为:

\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost
\REGISTRY\*\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN*
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\360
\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\CONTROL\SESSION MANAGER
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer
\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\*
\REGISTRY\*\SOFTWARE\CLASSES\CLSID\*\LOCALSERVER32*

则拒绝

ZwRequestWaitReplyPortHooker/ZwAlpcSendWaitReceivePortHooker

  • 若当前进程为360se.exe或360chrome.exe,目标进程为360tray.exe或zhudongfangyu.exe则拒绝
  • 若当前进程为zhudongfangyu.exe或wmiprvse.exe系统正在关机,或当前进程为360tray.exe,且目标操作存在关键字Win32_Service, Create, :\\WINDOWS\\system32\\svchost.exe –k, Win32_Process, Defend360, Fix360, FixRundll, \SoftMgr\, 360Safe, .dll, .dat, .exe, .cp, DllGetClassObject, 360csvcs, RERDVGYBHNJ, REPA, REPAIR则拒绝

NtWriteVirtualMemoryHooker/NtCreateThreadHooker

  • 若当前进程为360se.exe或360chrome.exe且目标进程为explorer.exe,则拒绝(explorer.exe被注入)

FakeObReferenceObjectByHandle

  • 若当前进程为zhudongfangyu.exe且目标对象路径为
\*\WINDOWS\CURRENTVERSION\RUN
\*\WINDOWS\CURRENTVERSION\RUN\*
\*\WINDOWS\CURRENTVERSION\RUNONCE
\*\WINDOWS\CURRENTVERSION\RUNONCE\*
\*\CURRENTVERSION\SVCHOST
\*\SYSTEM\CONTROLSET*\SERVICES\QQ*
\*\SYSTEM\CONTROLSET*\SERVICES\TS*

则拒绝

  • 若当前进程为zhudongfangyu.exe, 360tray.exe, svchost.exe,且目标对象位于监视链表中则拒绝
  • 若系统正在关机或注销:
若当前进程为services.exe, svchost.exe且目标路径为
\\REGISTRY\\MACHINE\\SYSTEM\\*CONTROLSET*\\SERVICES\\*FIX*SERV*
\\REGISTRY\\MACHINE\\SYSTEM\\*CONTROLSET*\\SERVICES\\*FIX*SAFE*
\\REGISTRY\\*\\SOFTWARE\\CLASSES\\CLSID\\*\\LOCALSERVER32*

则拒绝

若当前进程为zhudongfangyu.exe, 360tray.exe,且目标对象路径为

\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost
\REGISTRY\*\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN*
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\360
\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\CONTROL\SESSION MANAGER
\REGISTRY\MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer
\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\*
\REGISTRY\*\SOFTWARE\CLASSES\CLSID\*\LOCALSERVER32*

则拒绝

CmCallback

  • 若存在修改ShutdownTime的行为,则执行FuckCompete1:
    • 将\FileSystem\360boost关机回调置无效
    • 挂钩NtfsFsdCreate或NtfsCreateDispatch为NtfsFsdCreateHooker
    • 设置监视\Registry\Machine\System\CurrentControlSet\Control\Windows,回调设置为RegisterShutdown
    • 创建随机名驱动及设备执行并设置其关机回调为ShutdownDispatch

TsKsp.sys分析

  该驱动为qq管家函数过滤驱动,跟TsFltMgr.sys搭配,TsFltMgr主要完成KiFastCallEntry的挂钩和提供设置过滤函数的接口,而该驱动主要用于配置拦截规则,用前者提供的接口设置真正的过滤函数,并在过滤函数中进行规则匹配以决定拦截行为。并提供一系列接口函数和控制码用于控制规则和内部数据。设备名\Device\TSKSP,符号链接名\DosDevices\TSKSP,加密手段:Rabbit算法、MD5算法。通过InlineHook KifastCallEntry实现挂钩。

驱动入口DriverEntry

  • 获取TsFltMgr接口,初始化注册表信息、规则、操作系统版本等信息
  • 创建\Device\TSKSP设备和\DosDevices\TSSysKit符号链接
  • 初始化接口
  • 注册IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_DEVICE_CONTROL、IRP_MJ_SHUTDOWN派遣例程
  • 保存Ntfs和Fastfat派遣函数
  • 设置保护关键目录和注册表项
  • 挂钩各个过滤函数
  • 挂钩KeUserModeCallback和重要回调
  • 开自保

派遣例程

IRP_MJ_CREATE

  • 检查驱动加载者是否有Ts签名

IRP_MJ_SHUTDOWN

  • 设置\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TSCPM\目录的LastShutdownFlag和LastShutdownTime
  • 清空\REGISTRY\MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN\QQDisabled下的值

监控函数

  Ts进程:位于Q管目录或签名为Q管文件签名的进程,按规则判断:上抛给主防主防进程判断;默认情况下若发起者为Ts进程的都放过

使用AddPrevFilter接口设置的过滤函数有:

NtAllocateVirtualMemory
	若发起者为非TS进程而目标为TS进程,则设置PostFilter
	若发起者为非TS进程而目标为非TS进程,则放行
	若发起者为非TS进程而目标为未知进程,则查询虚拟内存监视链表,对比进程路径,按是否Ts进程分别处理
在PostFilter中记录得到的地址信息

NtAlpcCreatePort
	若发起者为非Ts进程,且不是csrss, services, smss, svchost, lsass, lsm,且操作为修改DNS解析器,则上抛主防根据规则判断

NtAlpcSendWaitReceivePort
	若发起者为非lsass非csrss非Ts进程,修改SAM信息,则上抛主防根据规则判断
	若发起者为非Ts进程,触发csrss进程结束/winlogon关机,则上抛主防根据规则判断
	若发起者为非Ts进程,操作驱动服务端口ntsvcs,则按服务号处理:
RcloseServiceHandle	执行功能,并将服务从监视列表中移除
RdeleteService, RsetServiceObjectSecurity, RchangeServiceConfigW,RchangeServiceConfigA,RChangeServiceConfig2A,
RChangeServiceConfig2W, RcontrolService,RcontrolServiceExA,RcontrolServiceExW	如果目标服务为QQPCRTP, TSKSP, TsFltMgr, QQSysMon, TSSysKit, TSSysFix则拒绝,否则执行功能
RopenServiceW,RopenServiceA	执行功能并上报主防
RcreateServiceW,RCreateServiceA 查注册表匹配树并根据结果选择执行功能且加入监控列表或上抛主防根据规则判断
RstartServiceW,RStartServiceA 	查注册表匹配树,上抛主防加载驱动事件,并根据结果放行或不执行,从监控列表中删除

NtAssignProcessToJobObject
	若发起者为非TS进程而目标为TS进程,则拒绝

NtCreateFile
	穿透实现NtCreateFile

NtCreateMutant
	添加PostFilter,在PostFilter中,若发起这为非Ts进程且目标Object处于g_StorageList[14]中则上抛主防判断

NtCreateKey
	若发起者为非主防进程,则在注册表键值匹配ACL树(RegMonTree)中查找,并根据结果上抛主防根据规则判断

NtCreateProcessEx
	添加PostFilter,在PostFilter中,将进程添加到进程监控链表并上报给主防

NtCreatePort
若发起者为非Ts进程,且不是csrss, services, smss, svchost, lsass, lsm,且操作为修改DNS解析器,则上抛主防根据规则判断

NtCreateSection
	满足DesiredAccess=SECTION_ALL_ACCESS,SectionPageProtection=PAGE_EXECUTE,AllocationAttributes=SEC_IMAGE时:
		设置PostFilter;若目标文件为Ts文件,则检查应用层回溯栈,如果存在CreateProcessInternalW,则在启动参数增加CREATE_PRESERVE_CODE_AUTHZ_LEVEL位


NtCreateThread 
	若发起者为非主防进程,且该线程不是进程第一个线程,且目标进程为Ts进程,则拒绝
若发起者为非主防进程,且该线程不是进程第一个线程,且目标进程为非Ts进程,则上抛主防根据规则判断

NtCreateThreadEx
	若发起者为非主防进程,且该线程不是进程第一个线程,且目标进程为Ts进程,则拒绝
若发起者为非主防进程,且该线程不是进程第一个线程,且目标进程为非Ts进程,则上抛主防根据规则判断

NtCreateSymbolicLinkObject
	若目标对象为\Device\PhysicalMemory则拒绝
	否则查询ACL表,若不符合则记录最近创建的4个符号名,若符合则上抛主防根据规则判断

NtCreateUserProcess
	若目标文件为Ts文件,则检查应用层回溯栈,如果存在CreateProcessInternalW,则在启动参数增加CREATE_PRESERVE_CODE_AUTHZ_LEVEL位

NtDeleteKey
	若目标在g_StorageList[9]中则拒绝
	若目标在注册表监控树中,若符合则上抛主防根据规则判断

NtDeleteValueKey
	若目标在g_StorageList[9]中则拒绝
	若目标在注册表监控树中,若符合则上抛主防根据规则判断

NtDeviceIoControlFile
	IoControlCode=0x8FFF23C8或0x8FFF23CC,目标驱动为\Driver\NDProxy,则上抛主防根据规则判断	IoControlCode=0x2A0000(IOCTL_SWENUM_INSTALL_INTERFACE)则将该服务项添加到监视
	IoControlCode=0x980C8(FSCTL_SET_ZERO_DATA)
	IoControlCode=0x2D1400(IOCTL_STORAGE_QUERY_PROPERTY), 0x700A0(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX), 0x170002(IOCTL_NDIS_QUERY_GLOBAL_STATS), 0x4D008(IOCTL_SCSI_MINIPORT), 0x900c0(FSCTL_CREATE_OR_GET_OBJECT_ID), 0x90073(FSCTL_GET_RETRIEVAL_POINTERS), 0x7c088(SMART_RCV_DRIVE_DATA), 0x74080(SMART_GET_VERSION) 则上抛主防根据规则判断
	IoControlCode=0xA8730154, 0xA8730010 则采用不同解密密钥解密出PEPROCESS地址,若对应进程路径文件在内存操作监视链表中则拒绝

NtDuplicateObject (发起者,源进程,目标进程互不相同)
	若源进程和目标进程为本进程,且Options=DUPLICATE_SAME_ACCESS则放行
	若发起者为TS, csrss, services, smss, svchost, lsass, lsm进程则放行
	源进程为Ts进程,且”发起进程-源进程”对处于监视列表中则拦截,否则放行
	源进程为非Ts进程,目标进程为Ts进程,且非QQPCSoftGame, QQPCSoftMgr, QQPCClinic, QQPCExternal,则检查”发起进程-目标进程”对是否处于监视列表中,若存在则拦截,否则放行
	源进程为非Ts进程,目标进程为普通进程或QQPCSoftGame, QQPCSoftMgr, QQPCClinic, QQPCExternal:
		源进程和目标进程不同,或Options=DUPLICATE_SAME_ACCESS:
			源进程为发起进程,且源句柄类型为Process/Thread则拦截
			源进程不同于发起进程,则用本进程作为目标进程执行函数得到目标句柄:
				若执行成功且目标句柄类型为Process/Thread则拦截
				若执行返回STATUS_INSUFFICIENT_RESOURCES且获取进程句柄数无效则拦截
	其余情况放行

NtEnumerateValueKey
	执行函数,若KeyValueInformationClass=KeyValueFullInformation且发起进程为explorer:
		则只能枚举出子项\REGISTRY\MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN\QQDISABLED

NtFreeVirtualMemory
	若发起进程为非Ts进程且目标进程为Ts进程则设置PostFilter,在PostFilter中吧释放的内存从监视数据中去除

NtFsControlFile
	若发起进程为非Ts进程,非lsass, csrss,则监视FsControlCode=0x11C017决定是否上抛主防

NtGetNextThread
	若发起进程为非主防进程且目标进程为Ts进程则拒绝执行
	若发起进程为非主防进程且目标进程为非Ts进程则将访问权限限制为SYNCHRONIZE|THREAD_QUERY_INFORMATION|THREAD_GET_CONTEXT

NtGetNextProcess
	设置PostFilter

NtLoadDriver
	若发起进程为非Ts进程,则将驱动文件信息上抛主防判断

NtMakeTemporaryObject
	若目标对象为Section类型,且对象名路径在\knowndlls\下则拒绝,否则放行

NtOpenFile
	穿透实现NtOpenFile

NtOpenProcess
	若全局开关“监视打开进程”开启,则设置PostFilter,重置AccessMask参数并执行函数,在PostFilter中将发起线程加入监控链表中
	若全局开关“监视打开进程”关闭:
若发起进程为非Ts进程:
			若目标进程为QQPCFileSafe.exe, QQPCSoftGame.exe, QQPCSoftMgr.exe, QQPCExternal.exe, QQPCClinic.exe则上抛主防判断
			若发起进程为svchost且目标进程为QQPCRtp.exe则上抛主防判断,若不符合条件则修改AccessMask标志位
			若发起进程为lsass且目标进程为QQPCTray.exe则上抛主防判断,若不符合条件则修改AccessMask标志位
			若发起进程为service且目标进程为Ts进程则上抛主防判断,若不符合条件则修改AccessMask标志位
			若不满足上述条件,且不在g_StorageList[15]中,则上抛主防判断,否则修改AccessMask
		若发起进程为Ts进程,或发起进程与目标进程相同,则修改AccessMask

NtOpenThread
	若全局开关“监控打开线程”开启,则设置PostFilter,重置AccessMask参数并执行函数,在PostFilter中将发起线程加入监控链表中
	若全局开关“监视打开进程”关闭:
		若发起进程为非Ts进程,且目标进程为Ts进程,则根据发起进程权限判断是否修改AccessMask

NtOpenSection
	若发起进程为非主防进程,且DesiredAccess有写权限,且目标对象为\device\physicalmemory则上抛主防根据规则判断

NtProtectVirtualMemory
	若发起者为非TS进程而目标为TS进程,则上抛主防根据规则进行判断

NtQueueApcThread
	若发起者为非TS进程而目标为TS进程,则拒绝
	若发起者为非TS进程而目标为非TS进程,则查询ACL表上抛主防根据规则判断

NtQueueApcThreadEx
	若发起者为非TS进程而目标为TS进程,则拒绝
	若发起者为非TS进程而目标为非TS进程,则查询ACL表上抛主防根据规则判断

NtReplaceKey
	若发起者为非Ts进程:
目标注册表键路径匹配g_StorageList[9],则拒绝
		目标注册表键路径匹配SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN,则拒绝
		其他情况由注册表监控树获取权限并上抛主防根据规则判断

NtRequestWaitReplyPort
	若发起者为非lsass非csrss非Ts进程,修改SAM信息,则上抛主防根据规则判断
	若发起者为非Ts进程,触发csrss进程结束/winlogon关机,则上抛主防根据规则判断
	若发起者为非Ts进程,操作驱动服务端口ntsvcs,则按服务号处理:
RcloseServiceHandle	执行功能,并将服务从监视列表中移除
RdeleteService, RsetServiceObjectSecurity, RchangeServiceConfigW,RchangeServiceConfigA,RChangeServiceConfig2A,
RChangeServiceConfig2W, RcontrolService,RcontrolServiceExA,RcontrolServiceExW	如果目标服务为QQPCRTP, TSKSP, TsFltMgr, QQSysMon, TSSysKit, TSSysFix则拒绝,否则执行功能
RopenServiceW,RopenServiceA	执行功能并上报主防
RcreateServiceW,RCreateServiceA 查注册表匹配树并根据结果选择执行功能且加入监控列表或上抛主防根据规则判断
RstartServiceW,RStartServiceA 	查注册表匹配树,上抛主防加载驱动事件,并根据结果放行或不执行,从监控列表中删除

NtRestoreKey
	若发起者为非Ts进程:
目标注册表键路径匹配g_StorageList[9],则拒绝
		目标注册表键路径匹配SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN,则拒绝
		其他情况由注册表监控树获取权限并上抛主防根据规则判断

NtSetContextThread
	若发起者为非TS进程而目标为TS进程,则查询ACL表并上抛主防根据规则进行判断

NtSetInformationFile
	若发起者为主防进程则放过
	若FileInformationClass=FileDispositionInformation:
		检查目标文件权限并上抛主防根据规则判断
	若FileInformationClass= FileRenameInformation:
		检查源文件和目标文件权限并上抛主防根据规则判断
	若FileInformationClass= FileLinkInformation:
		检查目标文件权限并上抛主防根据规则判断
若FileInformationClass= FileEndOfFileInformation:
		检查目标文件权限并上抛主防根据规则判断
若FileInformationClass= FileAllocationInformation:
		检查目标文件权限并上抛主防根据规则判断
	其他FileInformationClass放行

NtSetSecurityObject
	若发起者为非Ts进程,目标对象为以下之一则拒绝,否则放过:
		\REGISTRY\MACHINE\SYSTEM\ControlSet001\services\TSSysKit
		\REGISTRY\MACHINE\SYSTEM\ControlSet002\services\TSSysKit
		\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\services\TSSysKit
		\REGISTRY\MACHINE\SYSTEM\ControlSet001\services\TSKSP
		\REGISTRY\MACHINE\SYSTEM\ControlSet002\services\TSKSP
		\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\services\TSKSP
		\REGISTRY\MACHINE\SYSTEM\ControlSet001\services\QQPCRTP
		\REGISTRY\MACHINE\SYSTEM\ControlSet002\services\QQPCRTP
		\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\services\QQPCRTP

NtSetSystemInformation
	若SystemInformationClass=SystemExtendServiceTableInformation:
		若发起者为非Ts进程且驱动文件存在则上抛主防根据规则进行判断
	若SystemInformationClass= SystemRegistryAppendStringInformation:
		若发起者为非Ts进程且目标注册表路径匹配g_StorageList[9],若键值路径匹配\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\CONTROL\SESSION MANAGER下的PendingFileRenameOperations,或PendingFileRenameOperations2,则根据文件监控树中的重命名前文件和重命名后文件的访问权限上抛主防判断,否则根据注册表监控树上抛主防判断

NtSetValueKey
	若发起者为非Ts进程,且目标对象路径匹配\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TSKSP*或\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\QQPCRTP,且目标注册表键名为Start(服务启动类型),则上抛主防根据规则进行判断,根据结果选择是否执行
	若发起者为非Ts进程,且目标进程不是service,若匹配g_StorageList[9]则根据注册表监控树的访问权限上抛主防判断
	若键值路径匹配\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\CONTROL\SESSION MANAGER下的PendingFileRenameOperations,或PendingFileRenameOperations2,则根据文件监控树中的重命名前文件和重命名后文件的访问权限上抛主防判断,否则根据注册表监控树上抛主防判断

	上抛判断前,会做清理以下键值以反调试:
	\Registry\Machine\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\QQPCTray.exe
\Registry\Machine\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\QQPCRTP.EXE
\Registry\Machine\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\QQPCUPDATE.EXE
\Registry\Machine\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\QQPCAddWidget.exe
\Registry\Machine\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\QQPCMgr_tz_Setup.exe
\Registry\Machine\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\QQPCMgr.exe
\Registry\Machine\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\QQPConfig.exe

NtSuspendThread
	若发起者为非Ts进程且目标进程为Ts进程则上抛主防根据规则判断
	若发起者为非Ts进程且目标进程为非Ts进程则放过

NtSystemDebugControl
	若Command=SysDbgWriteVirtual或SysDbgWritePhysical则上抛主防根据规则判断

NtTerminateProcess
	若发起者为非Ts进程且目标进程为Ts进程:
		若目标进程权限不足则放过
		若发起进程在g_StorageList[11]中则上抛主防根据规则判断
	若发起者为非Ts进程且目标进程为非Ts进程:
		若目标进程id在g_StorageList[1]中或权限不足则上抛主防根据规则判断
		若目标进程不是taskmgr则放过,否则上抛主防根据规则判断

NtTerminateThread
	若发起者为非TS进程而目标为TS进程,则拒绝
	若发起者为非TS进程而目标为非TS进程,则查询ACL表上抛主防根据规则判断

NtUnmapViewOfSection
	若发起者为非主防进程,且目标进程为Ts进程,则拒绝
	若发起者为非主防进程,且目标进程为非Ts进程,则上抛主防根据规则判断

NtUserClipCursor
	若发起者为非主防进程,且激活窗口属于Ts进程,则匹配预设进程名,若匹配则跳过执行,否则放行

NtUserGetAsyncKeyState
	若发起者为普通进程,执行功能,若键’0’-‘9’,’A’-‘Z’, 数字键盘’0’~’9’被按下,则上抛主防根据规则重置结果

NtUserGetKeyboardState
	若发起者为普通进程,执行功能,若键’0’-‘9’,’A’-‘Z’, 数字键盘’0’~’9’被按下,则上抛主防根据规则重置结果

NtUserGetKeyState
	若发起者为普通进程,执行功能,若键’0’-‘9’,’A’-‘Z’, 数字键盘’0’~’9’被按下,则上抛主防根据规则重置结果

NtUserGetRawInputBuffer
	若发起者为普通进程,执行功能,若键’0’-‘9’,’A’-‘Z’, 数字键盘’0’~’9’被按下,则上抛主防根据规则重置结果

NtUserGetRawInputData
	若发起者为普通进程,执行功能,若键’0’-‘9’,’A’-‘Z’, 数字键盘’0’~’9’被按下,则上抛主防根据规则重置结果

NtUserMessageCall
	若dwType=FNID_SENDMESSAGECALLPROC, FNID_SENDMESSAGE, FNID_SENDNOTIFYMESSAGE, FNID_SENDMESSAGECALLBACK则跳过执行
	若发起进程为普通进程,且uMsg=WM_GETTEXT或WM_SETTEXT则执行函数,若获取的字符串在列表中则上报主防

NtUserPostMessage
	若发起进程不属于smss, lsass, lsm则上报主防进程
	捕获uMsg= WM_KEYFIRST, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP, BM_CLICK, WM_COMMAND, WM_NOTIFY 
	若uMsg=WM_COMMAND,则监视指定控件通知码
	若发起进程不同于目标窗口所属进程则决定是否上报主防
	若发起进程为非主防进程,且目标线程不同于发起线程,则关注uMsg=WM_KEYDOWN, WM_LBUTTONDOWN, BM_CLICK, WM_CLOSE, WM_SYSCOMMAND, SC_CLOSE, WM_SETREDRAW, WM_SHOWWINDOW, WM_NCDESTROY, WM_DESTROY, WM_SETTEXT, IE_DOCOMMAND, IE_GETCOMMAND, IE_GETCOUNT, WM_COMMAND
	若uMsg=WM_SYSCOMMAND或SC_CLOSE且发起者为explorer则放行,否则跳过执行

NtUserPostThreadMessage
	若发起进程不属于smss, lsass, lsm则上报主防进程
	捕获uMsg= WM_KEYFIRST, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONUP, BM_CLICK, WM_COMMAND, WM_NOTIFY 
	若uMsg=WM_COMMAND,则监视指定控件通知码
	若发起进程不同于目标窗口所属进程则决定是否上报主防
	若发起进程为非主防进程,且目标线程不同于发起线程,则关注uMsg=WM_KEYDOWN, WM_LBUTTONDOWN, BM_CLICK, WM_CLOSE, WM_SYSCOMMAND, SC_CLOSE, WM_SETREDRAW, WM_SHOWWINDOW, WM_NCDESTROY, WM_DESTROY, WM_SETTEXT, IE_DOCOMMAND, IE_GETCOMMAND, IE_GETCOUNT, WM_COMMAND,若匹配则根据情况跳过执行

NtUserSendInput
	若发起进程不属于smss, lsass, lsm则上报主防进程
	若发起进程为非主防进程则跳过执行

NtUserSetImeInfoEx
	先执行函数以获取文件名
	若输入法序号不存在于\Registry\Machine\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\或子项为空,且发起进程为非Ts进程,则根据注册表监控树上抛主防根据规则决定是否放行
	若输入法文件不为msctfime.ime/ msctf.dll,则根据注册表监控树上抛主防根据规则决定是否放行,否则放行
执行KeUserModeCallback前对该函数做还原inline hook处理

NtUserSetWindowsHookEx
	若发起者为非Ts进程,ThreadId不为NULL,且目标进程为Ts进程,则拒绝
	若发起者为非Ts进程,ThreadId不为NULL,且目标进程为System进程,若ModuleName为shell32.dll, msctf.dll, ieframe.dll, mshtml.dll, dinput8.dll, browseui.dll则放过,否则上抛主防根据规则判断
	若发起者为非Ts进程,ThreadId为NULL,且目标进程为Ts进程,则按全局键盘钩子上抛主防根据规则判断
放行WH_KEYBOARD_LL类hook

NtUserSetWindowLong
	若nCmdShow为SW_SHOWMINNOACTIVE或SW_FORCEMINIMIZE且目标窗口属于QQ.exe则上报给主防
	若发起进程为主防进程则放过
若目标窗口属于Ts进程则跳过执行

NtUserSetWindowPos
	若nCmdShow为SW_SHOWMINNOACTIVE或SW_FORCEMINIMIZE且目标窗口属于QQ.exe则上报给主防
	若发起进程为主防进程则放过
若目标窗口属于Ts进程则跳过执行

NtUserSetWinEventHook
	若发起进程为Ts进程则放过
	若dwflags不包含WINEVENT_INCONTEXT则放过
	若发起进程等同目标进程则放过
	若目标进程为Ts进程,则上抛主防根据规则判断

NtUserShowWindow
	若nCmdShow为SW_SHOWMINNOACTIVE或SW_FORCEMINIMIZE且目标窗口属于QQ.exe则上报给主防
	若发起进程为主防进程则放过
	若nCmdShow不为SW_HIDE, SW_SHOWMINIMIZED, SW_MINIMIZE, SW_SHOWMINNOACTIVE, SW_FORCEMINIMIZE则放过
若目标窗口属于Ts进程则跳过执行

NtUserShowWindowAsync
	若发起进程为主防进程则放过
	若nCmdShow不为SW_HIDE, SW_SHOWMINIMIZED, SW_MINIMIZE, SW_SHOWMINNOACTIVE, SW_FORCEMINIMIZE则放过
若目标窗口属于Ts进程则跳过执行

NtWriteVirtualMemory
	若发起者为普通进程,若目标进程为Ts进程,则拒绝;若目标进程为普通进程,则在用户态回溯栈中判定是否由CreateProcess发起 ,并根据ACL表上抛主防根据规则决定是否放行
	
KeUserModeCallback
	若ApiNumber=__ClientLoadLibrary:
若发起者为主防进程,跳过执行
若目标文件和事先传入(IoCtlCode=0x22E0E8)的Ts dll文件匹配则跳过执行
若目标文件在g_StorageList[13]中则跳过执行
若开启白名单且目标文件不在g_StorageList[16]中则跳过执行
若目标文件在g_StorageList[5]中且发起进程为Ts进程则跳过执行,否则放过
	若ApiNumber== __fnHkINLPKBDLLHOOKSTRUCT:
若发起者为普通进程,执行功能,若键’0’-‘9’,’A’-‘Z’, 数字键盘’0’~’9’被按下,则上抛主防根据规则重置结果
	若ApiNumber== __ClientImmLoadLayout
		先执行函数以获取文件名
		若输入法序号不存在于\Registry\Machine\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\或子项为空,且发起进程为非Ts进程,则根据注册表监控树上抛主防根据规则决定是否放行
		若输入法文件不为msctfime.ime/ msctf.dll,则根据注册表监控树上抛主防根据规则决定是否放行,否则放行
执行KeUserModeCallback前对该函数做还原inline hook处理

1.4重要回调的挂钩

PsSetCreateProcessNotifyRoutine
	将新增加的进程信息加入(ProcInfoList)链表
	若为创建进程:
        清除关键Ts文件映像劫持,即\Registry\Machine\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options下的QQPCTray.exe, QQPCRTP.EXE, QQPCUPDATE.EXE, QQPCAddWidget.exe, QQPCMgr_tz_Setup.exe, QQPCMgr.exe, QQPConfig.exe
    若为删除进程:
        清除进程相关信息
        若进程为主防进程,则清除和关闭消息通信,进行清理工作
        上报进程退出
PsSetCreateProcessNotifyRoutineEx
	若CreateInfo为空则获取父进程id后交给CreateProcessNotify处理
	将新增加的进程信息加入(ProcExInfoList)链表
PsSetLoadImageNotifyRoutine
	若为系统模块,若为TesSafe.sys则记录该模块信息
	若为普通模块,加载进程为若为Ts进程,且和目标模块exe相同,则清空PEB结构中的ShimData数据

一些用到的数据

BuildNumber[21] => UNKNOWN, 2195, 2600, 3790, 6000, 6001, 6002, 7000|7600, 7601, 8102, 8250, 8400, 8432|8441, 8520, 9200, 9600, 9841, 9860, 9926, 10041, 10049
ApiName[15] => NtUserFindWindowEx, NtUserBuildHwndList, NtUserQueryWindow, NtUserGetForegroundWindow, NtUserSetParent, NtUserSetWindowLong, NtUserMoveWindow, NtUserSetWindowPos, NtUserSetWindowPlaceMent, NtUserShowWindow, NtUserShowWindowAsync, NtUserSendInput, NtUserMessageCall, NtUserPostMessage, NtUserPostThreadMessage
Index[BuildNumber][ApiName]=
0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,
0x170,0x12e,0x1d2,0x189,0x1fe,0x20d,0x1c1,0x20f,0x20e,0x218,0x219,0x1e1,0x1bc,0x1cb,0x1cc,
0x17a,0x138,0x1e3,0x194,0x211,0x220,0x1d1,0x222,0x221,0x22b,0x22c,0x1f6,0x1cc,0x1db,0x1dc,
0x179,0x137,0x1e1,0x193,0x20e,0x21c,0x1d0,0x21e,0x21d,0x227,0x228,0x1f4,0x1cb,0x1da,0x1db,
0x187,0x142,0x1f8,0x1a2,0x226,0x236,0x1e4,0x238,0x237,0x243,0x244,0x20d,0x1df,0x1f1,0x1f2,
0x187,0x142,0x1f8,0x1a2,0x226,0x236,0x1e4,0x238,0x237,0x243,0x244,0x20d,0x1df,0x1f1,0x1f2,
0x187,0x142,0x1f8,0x1a2,0x226,0x236,0x1e4,0x238,0x237,0x243,0x244,0x20d,0x1df,0x1f1,0x1f2,
0x18c,0x143,0x203,0x1a7,0x230,0x242,0x1ef,0x244,0x243,0x24f,0x250,0x218,0x1ea,0x1fc,0x1fd,
0x18c,0x143,0x203,0x1a7,0x230,0x242,0x1ef,0x244,0x243,0x24f,0x250,0x218,0x1ea,0x1fc,0x1fd,
0x1c7,0x166,0x1de,0x1aa,0x246,0x230,0x1f3,0x22e,0x22f,0x223,0x222,0x25e,0x1f8,0x1e6,0x1e5,
0x1c9,0x167,0x1e0,0x1ac,0x249,0x232,0x1f5,0x230,0x231,0x225,0x224,0x261,0x1fa,0x1e8,0x1e7,
0x1ca,0x168,0x1e1,0x1ad,0x24b,0x234,0x1f6,0x232,0x233,0x227,0x226,0x263,0x1fb,0x1e9,0x1e8,
0x1cb,0x168,0x1e2,0x1ae,0x24d,0x236,0x1f7,0x234,0x235,0x229,0x228,0x265,0x1fc,0x1ea,0x1e9,
0x1cc,0x168,0x1e3,0x1ae,0x24f,0x237,0x1f8,0x235,0x236,0x22a,0x229,0x267,0x1fd,0x1eb,0x1ea,
0x1cb,0x168,0x1e2,0x1ad,0x24e,0x236,0x1f7,0x234,0x235,0x229,0x228,0x266,0x1fc,0x1ea,0x1e9,
0x1cc,0x16a,0x1e3,0x1ae,0x251,0x239,0x1f9,0x237,0x238,0x22c,0x22b,0x269,0x1fe,0x1ec,0x1eb,
0x1ce,0x16b,0x1e5,0x1af,0x253,0x23b,0x1fb,0x239,0x23a,0x22e,0x22d,0x26b,0x200,0x1ee,0x1ed,
0x1d2,0x16f,0x1e9,0x1b3,0x259,0x23f,0x1ff,0x23d,0x23e,0x232,0x231,0x271,0x204,0x1f2,0x1f1,
0x1d2,0x16f,0x1e9,0x1b3,0x25a,0x240,0x1ff,0x23e,0x23f,0x233,0x232,0x272,0x204,0x1f2,0x1f1,
0x1d2,0x16f,0x1e9,0x1b3,0x25b,0x240,0x1ff,0x23e,0x23f,0x233,0x232,0x273,0x204,0x1f2,0x1f1,
0x1d3,0x16f,0x1ea,0x1b3,0x25c,0x241,0x200,0x23f,0x240,0x234,0x233,0x274,0x205,0x1f3,0x1f2,
	__ClientLoadLibrary在KeUserModeCallBack中的ApiNumber	ImmLoadLayoutIndex[BuildNumber] =
-1, -1, 84, -1, -1, -1, -1, 82, 82, -1, -1, -1, -1, -1, 84, 88, -1, -1, -1, -1, -1
	KeyboardLL在KeUserModeCallBack中的ApiNumber  HookKeyboardLLIndex[BuildNumber] =
-1, -1, 45, -1, -1, -1, -1, 45, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
对象例程相对于对象类型结构偏移 ObjectProcedureOffset [BuildNumber] =
-1, -1, 140, 140, 88, 88, 88, 88, 88, -1, -1, -1, -1, -1, 88, 88, 88, 88, 88, 88, -1
	ShimData成员相对PEB结构偏移	
-1, -1, 488, -1, -1, -1, -1, 488, 488, -1, 488, 488, -1, -1, 488, 488, -1, -1, 0, 0, 0
	KeUserModeCallBack的ImmLoadLayout功能号中模块路径相对InputBuffer偏移 ClientLoadLibraryNameOffset[BuildNumber] =0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 48, 28, 0

OBJECT_TYPE_INITIALIZER 挂钩

  和TsSyskit中类似,只不过Tsksp中,采用的是Proxy~Hooker的方式,将Proxy替换OpenProcedure,为每种Procedure预留5个函数槽用于存放过滤函数,只要有一个失败则返回失败。Proxy结构数组我在IDA中标记为ObjectProceduresProxy,依次为Event, File, Process, Thread, Mutant, Section的Proxy结构:

struct ObjectProcedureStruct
{
	ULONG ObType;//标识对象类型
/*
0 ExEventObjectType
1 PsProcessType
2 PsThreadType
3 IoFileObjectType
4 ExMutantObjectType
5 MmSectionObjectType
*/
	ULONG ProcIndex;//标识函数类型
/*
0 DumpProcedure
1 OpenProcedure
2 CloseProcedure
3 DeleteProcedure
4 ParseProcedure
5 SecurityProcedure
6 QueryNameProcedure
7 OkayToCloseProcedure
*/
	ULONG Proxy[21];//存放代理函数地址,分21个操作系统版本
}

  再用一个数组存储对应的过滤函数:ULONG ObjectProceduresD(ynamic)Filter[6][8][5],6对应ObType,8对应ProcIndex,5为函数槽个数,数组中的数据,是从静态结构模板中导入的,该静态模板结构沿用了ObjectProcedureStruct结构。TsKsp中最终只对6种对象类型的OpenProcedure做了挂钩。

代理函数逻辑:

NTSTATUS __stdcall ProcedureProxy(OB_OPEN_REASON OpenReason, PEPROCESS Process, PVOID Object, ACCESS_MASK GrantedAccess, ULONG HandleCount)
{
	NTSTATUS status = STATUS_SUCCESS;
	for(int i=0;i<5;i++)
	{
		if(ObjectProceduresDFilter[ObType][ProcType][i])
			Status = ObjectProceduresDFilter[ObType][ProcType][i](OpenReason,Process,Object,GrantedAccess,HandleCount);
		if(!NT_SUCCESS(status))
			break;
    }
    return status;
}

PROCINFO结构

用于存储当前系统进程信息

struct PROCINFO
{
	HANDLE ProcessId;
	ULONG ProcDir;//标志目录属性
	ULONG ProcType;//标志进程类型
	ULONG Access;//标志访问权限
	WCHAR Path[260];
	ULONG IsSignMatch;
	ULONG Index;
}

ProcDir域:
“System”, “Idle”		4
Ts进程				2
普通进程			1

ProcType域:
“System”				-3
“Idle”				-2
普通进程			-1
“csrss”				0
“services”			1
“smss”				2
“explorer”			3
“winlogon”			4
“svchost”				5
“lsass”				6
“lsm”				7
“taskmgr”			8

Access域:(访问权限)
0x1	通信
0x2	进程线程创建打开,驱动加载,内存操作
0x4	结束进程
0x8	注册表创建打开设置
0x10	设置文件属性
0x100	窗口交互类

“System”,”Idle”,Ts进程		0x1FF
“svchost”,”csrss”,“lsm”,”lsass”	0x107
“smss”						0x10
“services”					0x8
普通进程					0x0

对重要进程访问控制权限的设定:
PROCINFO信息是在进程创建时构造的,对于重要系统进程会单独进行初始化(InitCriticalProcessList)

name=csrss.exe,access=0x107,index=0
name=services.exe,access=0x8,index=1
name=smss.exe,access=0x10,index=2
name=Explorer.exe,access=0x0,index=3
name=winlogon.exe,access=0x0,index=4
name=svchost.exe,access=0x107,index=5
name=lsass.exe,access=0x107,index=6
name=lsm.exe,access=0x107,index=7
name=taskmgr.exe,access=0x2,index=8

具体如TsKsp Log.txt进程结构信息所示

控制信息

ACL访问控制列表

struct ACLTable		进程相关ProcessAclTable
+00h    BYTE* arr   BYTE AclTable [dimen3][dimen2][dimen1]
+04h    int dimen1  源进程类型相关    PROCINFO->ProcDir
    普通        1
    同目录      2
    "Idle"      4
    "System"    4
+08h    int dimen2  目标进程类型相关    PROCINFO->ProcDir
    普通        1
    同目录      2
    "Idle"      4
    "System"    4
+0Ch    int dimen3  
进程相关:
    ZwTerminateProcess		3
    ZwCreateThread			6
    ZwCreateThreadEx			6
    ZwTerminateThread		7
    ZwQueueApcThread		9
    ZwQueueApcThreadEx		9
    ZwSetContextThread		10
    ZwAllocateVirtualMemory	11
    ZwFreeVirtualMemory		11  
ZwWriteVirtualMemory		11
+10h	bool inited

文件也有类似的访问控制表

匹配树

TsKsp中存在注册表权限匹配树,和文件权限匹配树,结构为树+链表:

struct TreeData
{
	PWCHAR MatchString;
	BOOLEAN HasVal;
	ULONG* Val1;
	ULONG Val2;
	TreeData* Next;
};

struct MatchTree
{
	PWCHAR MatchString;
	MatchTree* Left;
	MatchTree* Right;
	TreeData* Data;
	BOOLEAN HasVal;
};

void TranverseData(TreeData* data,int depth)
{
	while(data)
	{
		for(int i=0;i<depth;i++)
			DbgPrint("\t");
		DbgPrint("access=%x %x\n",*(ULONG*)data->Val1,data->Val2);	
		if(data->MatchString)
		{
			for(int i=0;i<depth;i++)
				DbgPrint("\t");
			DbgPrint("-%ws",data->MatchString);
		}
		data=data->Next;
	}
}

void TranverseTree(MatchTree* node,int depth)
{
	if(node)
	{
		if(node->MatchString)
		{
			for(int i=0;i<depth;i++)
				DbgPrint("\t");
			DbgPrint("+%ws\n",node->MatchString);
		}
		TranverseData(node->Data,depth+1);
		TranverseTree(node->Left,depth+1);
		TranverseTree(node->Right,depth);
	}
}
main()
{
    MatchTree* node=*(MatchTree**)(Base+0x2C908);
    TranverseTree(node,0);
}

得到结果见TsKspLog.txt 匹配树结构——注册表 和 匹配树结构——文件

全局开关DriverSwitch

DriverSwitch[0] & 1			监视消息和Section
DriverSwitch[0] & 2			监视窗口控件消息
DriverSwitch[0] & 4			监视硬件IOCTL
DriverSwitch[0] & 8			是否在创建/打开文件时将读权限设置为读|删除
DriverSwitch[0] & 0x100		拦截LPC某消息
DriverSwitch[0] & 0x200		在进程操作中通过文件号打开NTFS分区文件
DriverSwitch[1] & 4			是否允许任务管理器结束进程
DriverSwitch[1] & 8			监视键盘状态
DriverSwitch[1] & 0x40		监视加载输入法文件
DriverSwitch[1] & 0x80		监视访问系统文件保护 sfc 
DriverSwitch[2] & 0x100		监视Ole LPC
DriverSwitch[1] & 0x200		打开进程和注册表时是否允许发起者为普通进程
DriverSwitch[1] & 0x400		监视csrss process shutdown
DriverSwitch[1] & 0x1000	监视服务操作的进程是否为敏感进程
DriverSwitch[2] & 0x2000	监视操作虚拟内存目标进程为系统线程
DriverSwitch[1] & 0x4000	是否使用回调式进程虚拟内存记录监视虚拟内存;是否监视创建非系统线程
DriverSwitch[1] & 0x8000	监视对象操作的总开关,已包括Process, Thread, Mutant, Section, File, Event对象
DriverSwitch[1] & 0x20000	是否启用创建进程监视链表MonCreateProcessList
DriverSwitch[1] & 0x80000	监视内存映射
DriverSwitch[1] & 0x100000	监视窗口消息
DriverSwitch[1] & 0x200000	监视打开文件对象
DriverSwitch[1] & 0x800000	监视打开进程
DriverSwitch[1] & 0x1000000	监视NDIS 0Day Attack
DriverSwitch[1] & 0x2000000	是否打开监视注册表、进程、线程、文件等函数的总开关,包括
ZwCreateKey,ZwDeleteKey,ZwDeleteValueKey,ZwCreateThread,
ZwDeviceIoControlFile,ZwQueueApcThread,ZwSetInformationFile,ZwSetSecurityObject,ZwSetSystemInformation,
ZwCreateFile,ZwOpenFile,ZwSetValueKey,ZwSuspendThread,ZwSystemDebugControl,ZwTerminateProcess,
ZwTerminateThread,ZwDuplicateObject,ZwEnumerateValueKey,ZwOpenProcess,ZwOpenSection,ZwQueueApcThreadEx
DriverSwitch[1] & 0x8000000	设置打开进程的PostFilter
DriverSwitch[1] & 0x10000000	监视打开线程对象
DriverSwitch[1] & 0x20000000	允许从存储的进程链表获取签名信息

DriverSwitch[2] & 0x10		监视打开Event, Mutant对象
DriverSwitch[2] & 0x80		是否检查权限时使用PROCESSINFO的签名位IsSignMatch
DriverSwitch[2] & 0x100		检测Ole LPC通信
DriverSwitch[2] & 0x200		检测父进程创建时间逻辑
DriverSwitch[2] & 0x400    	监视虚拟内存的创建、写入和释放
DriverSwitch[2] & 0x800 		监视winlogon shutdown
DriverSwitch[2] & 0x1000		监视打开Mutant对象
DriverSwitch[2] & 0x2000		是否允许操作System进程虚拟内存
DriverSwitch[2] & 0x80000		监视操作SAM
DriverSwitch[2] & 0x8000000	监视操作栈区虚拟内存
DriverSwitch[2] & 0x40000000	监视用户态模块加载

MaskForDriverSwitch[14] 用于生成特定组合的DriverSwitch,见IoCtlCode == 0x22E410,数据:

0,0x22b8
1,0x21fc
2,0x2199
3,0x26b8
4,0x22b7
5,0x22b5
6,0x22b6
7,0x26b9
8,0x219a
9,0x22b3
10,0x26ba
11,0x26bd
12,0x26bb
13,0x26be

0x22E410控制码接收4字节数据mask,根据mask生成对应DriverSwitch

BOOL SwitchControl(ULONG mask)
{
	int bit;
	int val;
	int index;
	BOOL set = FALSE;
	switch((mask >> 28) & 7)// 28~30 bit
	{
	case 0:
		for(bit=0;bit<14;bit++)
		{
			if(MaskForDriverSwitch[bit] == mask & 0xFFFFFFF)
				break;
		}
		if(bit<14)
		{
			set = TRUE;
			if((mask & 0x80000000) == 0)
				DriverSwitch[0] &= ~(1<<bit);
			else
				DriverSwitch[0] |= 1<<bit;
		}
	case 2:
		val = mask & 0xFFFFFFF;
		if(val <= 0x65)
		{
			set = TRUE;
			index = val >> 5;
			bit = val & 0x1F;
			if((mask & 0x80000000) == 0)
				DriverSwitch[index] &= ~(1<<bit);
			else
				DriverSwitch[index] |= 1<<bit;
		}
	}
}

自保开关影响的函数和功能

  在DriverEntry中,将\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\QQSysMon\spvalue的值若为0或1,则开启自保。另外可以在Q管界面常规设置选择自保护以手动方式开关自保,对应的程序QQPConfig.exe每次启动时会从TsKsp读取自保位(控制码0x22E0A0),设置完毕时发送给TsKsp(控制码0x22E070)

NtSetInformationFile	
影响Class=FileDispositionInformation, FileRenameInformation, FileLinkInformation, FileEndOfFileInformation, FileAllocationInformation的判断
NtCreateSymbolicLinkObject
NtDeviceIoControlFile
	影响IoCtlCode=FSCTL_SET_ZERO_DATA的判断
NtSetSystemInformation	
	影响Class=SystemRegistryAppendStringInformation重启替换/删除注册表键的判断
	影响Class=SystemExtendServiceTableInformation 加载可执行映像的判断
NtSetValueKey	
影响重启替换/删除注册表键的判断
NtRestoreKey
NtOpenProcess
NtOpenThread
NtUser*
NtRequestWaitReplyPort/NtAlpcSendWaitReceivePort
	影响RChangeServiceConfig, RDeleteService, RSetServiceObjectSecurity, 
NtAssignProcessToJobObject
NtCreateMutant
NtCreateThread\NtCreateThreadEx
NtDeleteKey
NtDeleteValueKey
NtSetValueKey
NtDuplicateObject
NtGetNextProcess
NtOpenProcess
NtOpenThread
NtProtectVirtualMemory
NtQueueApcThread\NtQueueApcThreadEx
NtSetContextThread
NtSetSecurityObject
NtSuspendThread
NtTerminateProcess
NtUnmapViewOfSection
NtWriteVirtualMemory
KeUserModeCallback
	影响ApiNumber=ClientLoadLibrary,若加载Ts文件的判断
CreateProcessNofity/ CreateProcessNotifyEx
	影响每次创建进程是否清除注册表调试键
	影响每次创建进程是否清除注册表调试键
LoadImageNotify
	影响加载用户态映像的判断
Object-OpenProcedure
影响Event, File, Mutant, Process, Thread 对象的过滤
LPC通信中访问\RPC Control\IcaApi

规则判断

  • 获取规则组号
int __stdcall GetRuleGroup(int mIndex, int nIndex, wchar_t *chname, wchar_t *enname)  根据传递的中英文字符串(说明,路径等)参数匹配出组号
mIndex 一级序号
 0 进程线程
 1 文件
 3 其他
nIndex 二级序号  通过FuncTypeToNum转换
  mIndex=0时,为进程/线程操作
3  TerminateProcess
4  CreateProcess
5  QueryProcess
6  CreateThread
7  TerminateThread
8  SuspendThread
9  QueueApcThread
10 SetContextThread
  mIndex=2时,为注册表操作
0  NtCreateKey	
2  NtSetValueKey	
3  NtDeleteValueKey	
4  NtDeleteKey	
	5  NtRestoreKey	
	6  默认	
mIndex=3时,为文件操作
	0  FileEndOfFileInformation/FileAllocationInformation 
	1  FileDispositionInformation
2  FileLinkInformation 
	3  FileRenameInformation 
	5  重启删除/重命名文件	
	6  默认	
  mIndex=4  
取消进程钩子
  mIndex=5
1  QueueApcThread 
2  RChangeServiceConfig
3  RDeleteService
7  NtUserSendInput
8  HardwareIoctl
10 Ole LPC
chname 中文类型说明
enname 英文类型说明
  • 将规则id, 源进程id, 目标进程id, 源进程路径, 目标进程路径等信息序列化(SerialData)到上抛消息结构中

  • 设置事件等待主防读取并取得判断结果

实例:

kd> dd tsksp+29960
b2cbd960 00000012 8149b648 00000140 8149c000
b2cbd970 00000000 00000000 0000001d 81487508

见TsKsp Log.txt 规则判断

黑白名单g_StorageList

  共有17个,!list -t _LIST_ENTRY.Flink -x "dd @$extret+8 " tsksp+252A8+index*0x30,每种类型的链表对应不同Index,都用同样的数据结构存储

Struct MonitorDataHead
{
	ULONG Index;//功能序号
	SPIN_LOCK Lock;//用于同步
	PVOID PData;//存储下面17种继承于LIST_ENTRY的数据结构
	ULONG OffsetToHead;//每种结构List成员相对于PData的偏移
	ULONG DataSize;//每种结构数据大小
	ULONG InsertRoutine;//插入元素例程
	ULONG DeleteRoutine;//删除元素例程
	ULONG FindRoutine;//查找元素例程
	ULONG FindWrapperRoutine;//互斥查找元素例程
	ULONG DeleteAllRoutine;//清空数据例程
	ULONG CompareRoutine;//比较元素例程
}

Index=0  sizeof=528		结束进程名黑名单	关自保或进程文件为普通文件生效
	+00	LIST_ENTRY List
	+08	WCHAR ProcessName[260]

Index=1  sizeof=12		结束进程ID黑名单	关自保或进程文件为普通文件生效
	+00	LIST_ENTRY List
	+08	HANDLE ProcessId			进程Id

Index=2	sizeof=528		未知
	+00	LIST_ENTRY List
	+08	WCHAR ProcessName[260]	进程名

Index=3	sizeof=12		未知
	+00	LIST_ENTRY List
	+08	HANDLE ProcessId			进程Id

Index=4  sizeof=536		未知
	+00	LIST_ENTRY List
	+08 	WCHAR ProcessName[260]		进程名
	+210 IsWild//是否为通配符

Index=5	sizeof=528  	ClientLoadLibrary加载模块白名单			SelfProcInjectAllow
	+00	LIST_ENTRY List
	+08	WCHAR ImagePath[260]		映像路径

C:\Program Files\Tencent\QQPCMgr\11.1.16892.209\QMForbiddenWinKey.dll
C:\WINDOWS\system32\mshtml.dll
C:\WINDOWS\system32\IEUI.dll
C:\WINDOWS\system32\ieframe.dll
C:\WINDOWS\system32\uxtheme.dll
C:\WINDOWS\system32\browseui.dll

Index=6	sizeof=528			未知
	+00	LIST_ENTRY List
	+08	WCHAR [260]

Index=7	sizeof=1048				未知
	+00	LIST_ENTRY List
	+08	WCHAR [260]
	+210 WCHAR [260]

Index=8	sizeof=528			操作虚拟内存,创建进程,创建内存映射文件 目标黑名单 
	+00	LIST_ENTRY List
	+08	WCHAR  FileName[260]	文件名

Index=9	sizeof=12			注册表操作黑名单	
LIST_ENTRY
WCHAR[260]	KeyPathPattern		键路径模式
WCHAR[260]	ValueNamePattern		键值模式

\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TSKSP*, *
\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\QQPCRTP*, *
\REGISTRY\MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN, QQPCTRAY
\REGISTRY\MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN\QQDISABLED, *
\REGISTRY\USER\S-*\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\RUN\QQDISABLED, *
	\REGISTRY\MACHINE\SOFTWARE\TENCENT\QQPCMGR\SYSTEMOPTIMIZE\DISABLED, *
	\REGISTRY\MACHINE\SOFTWARE\TENCENT\QQPCMGR\SYSTEMOPTIMIZE\DISABLEDSVC, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TSDEFENSEBT*, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\QQSYSMON*, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TFSFLT*, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TSSYSKIT*, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TSFLTMGR*, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TSSK*, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TSNETMON*, *
	\REGISTRY\USER\QMCONFIG*, *
	\REGISTRY\MACHINE\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION\UNINSTALL\QQPCMGR*, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\TSSYSFIX*, *
	\REGISTRY\MACHINE\SYSTEM\*CONTROLSET*\SERVICES\ANTIRK*, *

Index=10	sizeof=536				文件
	+00	LIST_ENTRY List
	+08	WCHAR  FileName[260]	文件/路径名
	+210 BOOL IsDir
	+214
	
Index=11	sizeof=528	结束进程查询名单		CTSKspWrap::AddSelfProcTeminateQuery
	+00	LIST_ENTRY List
	+08	WCHAR FilePath [260]	文件名

	C:\Program Files\Tencent\QQPCMgr\11.1.16892.209

Index=12	sizeof=528		未知
	+00	LIST_ENTRY List
	+08	WCHAR [260]

Index=13	sizeof=528		__ClientLoadLibrary   __ClientLoadLibrary发起进程黑名单
	+00	LIST_ENTRY List
	+08	FileName [260]		文件名

TASLogin.exe
Client.exe
SoapUI_4_6_4.exe
QQPCLeakScan.exe
navicat.exe
NativeWeb.exe
phpstorm.exe
ugraf.exe
League of Legends.exe
dnf.exe
tgp_daemon.exe
my.exe
pycharm.exe
bugreport.exe
QQPetBear.exe
TXPlatform.exe
xmind.exe
tencentdl.exe
_INS5576._MP

Index=14	sizeof=536			打开对象目标黑名单				SyncObjProtect
LIST_ENTRY	List
POBJECT_NAME_INFORMATION ObjInfo		对象路径
 WCHAR ObjectPath[260]

04CE0CB6-CDF3-4a4b-8B9D-292A455FAF5B
04CE0CB6-CDF3-4a4b-8B9D-292A455F
AF5B
QDOCTOR_2
QDOCTOR_1
QDOCTOR_0
qpcmgr\10002_0_80
ENCENT_QMTAV_TSCAN_HANG

Index=15	sizeof=1072			打开进程/复制句柄发起进程白名单			SelfProcAllow
LIST_ENTRY	List
ULONG 	Enable??
ULONG		SourceFilePathLen			
WCHAR[261] SourceProcessFilePath		源进程路径
ULONG	Target FilePathLen
WCHAR[261]	TargetProcessFilePath	目标进程路径
 ACCESS_MASK GrantedAccess

Index=16	528	ImageName	 __ClientLoadLibrary发起进程白名单
	+00	LIST_ENTRY List
	+08	FileName [260]		模块文件名

wuauclt.exe
MiniThunderPlatform.exe
RtxLite.exe
DriveTheLife.exe
115chrome.exe
adownloader.exe
2345Explorer.exe
MyIE9.exe
krbrowser.exe
Ruiying.exe
csbrowser.exe
114Web.exe
114IE.exe
WebGamegt.exe
Coral.exe
TangoWeb.exe
tango3.exe
TaoBrowser.exe
YY.exe
Android PC Suite.exe
wandoujia2.exe
DriverGenius.exe
DTLSoftManage.exe
sdDown.exe
VDisk.exe
klive.exe
Kanbox.exe
sedown.exe
Alibrowser.exe
BaiduHi.exe
LiveUpdate360.exe
flashgetmini.exe
flashget3.exe
idman.exe
Explorer.exe
QQBrowserExtHost.exe
QBDownloader.exe
FoxMail.exe
ieuser.exe
TTraveler.exe
rtx.exe
tm.exe
fetion.exe
msnmsgr.exe
outlook.exe
UDownSrv.exe
UDown.exe
WebThunder.exe
MiniThunder.exe
Thunder5.exe
ThunderMini.exe
DUTool.exe
RaySource.exe
peer.exe
Thunder.exe
ThunderService.exe
thunderplatform.exe
minimule.exe
emule.exe
QQDownload.exe
baidubrowser.exe
liebao.exe
QQBrowser.exe
360chrome.exe
360se.exe
webkit2webprocess.exe
safari.exe
huaer.exe
saayaa.exe
twchrome.exe
firefox.exe
thooe.exe
theworld.exe
myiq.exe
greenbrowser.exe
ybrowser.exe
115br.exe
opera.exe
chrome.exe
maxthon.exe
sogouexplorer.exe

上抛消息结构

分析出来的上抛数据类型如下:

Type			Id
ProcessId		0		进程Id
ChildProcessId	1		子进程Id
SrcFilePath		4		源文件路径
ChildFilePath	5		子进程路径
RegPathName	6		注册表路径
RegKeyName	7		注册表键
RegData		8		注册表数据
ObjFilePath	9		目标文件路径
RuleId		10		规则id
ChName		11		中文描述
EnName		12		英文描述
??			13
ProcessData	14
ChildData		15
ProcessIndex	17		进程序号
RegKeyType	18		注册表数据类型
RegDataSize	19		注册表数据大小

  过滤函数中,根据条件进行筛选以后,遇到符合条件的消息,先根据特征获取消息序号,然后在GroupAccessList中查找进程对应该消息号的权限,之后根据捕获类型构造消息结构,SerialData函数将必要的数据按上述类型序列化到缓冲区,之后将消息添加进消息队列中,并设置写信号,等待主防进程读取,上抛过程可以是同步或者异步方式。

SENDMSG		sizeof=0x1000
+000		ULONG Size//0x1000
+004		SENDMSG* self
+008		struct	REPLYMSG*	sizeof=0x1000
		+000		
		+004		SENDMSG* notifymsg;
		+00C		UCHAR[6] MsgTypeString;//”REPLY”
		+018		PKEVENT Event
		+01C		HANDLE ThreadId
+00C		UCHAR[7]	MsgTypeString;//”NOTIFY”
+01C		ULONG nIndex//事件类型标识
+020		ULONG pIndex//事件类型标识
+024		PKEVENT Event
+028		HANDLE ThreadId//待检测线程id
+02C		ULONG 请求结果类型//=0 不请求
+030		BOOL 主防是否需要给出结果
+034		ULONG MsgSize//串行化后总长度
+038		PBYTE data[0xFC8] 串行化数据  格式“类型-大小-数据[]”

其他

读取ini文件

  • 标记为和应用层api的名字相同(GetPrivateProfile*)的函数,函数调用类型基本相同
  • GetPrivateProfileInt, 从Ini文件中获取整型值
  • GetPrivateProfileIntEncrypt从Ini文件中解密并获取整型值
  • GetPrivateProfileString从Ini文件中获取字符串
  • GetPrivateProfileStringEncrypt 从Ini文件中解密并获取字符串

主防QMHIPSService通信日志

  • 可以打印出QMHIPSService与Tsksp.sys进行DeviceIoControl通信日志
  • HKEY_LOCAL_MACHINE\Software\Tencent\QQPCMgr下新建EnableLogToView的Dword键,设置为0xFFFFFFFF,即可打开Magic debuge,xp下主防的日志在\Documents and Settings\All Users\Application Data\Tencent\QQPCMgr\TrojanLog\qqpcrtp_qmhipsservice.log

对Q管签名的破解

  Q管签名验证,存在于除TsFltMgr之外的所有驱动中(boot start),代码已经在TsSysKit分析文中给出,过程如下:

  1. 读取PE,以IMAGE_DOS_HEADER->e_res2[0-1] 的DWORD值作为文件偏移,取该处128字节,通常在文件尾
  2. 用这128字节密文解密出24字节信息:
+00 被加密数据的文件偏移,通常是代码段起始
+04 被加密数据的信息长度,通常到加密前的文件结束位置
+08 BYTE\[16\] 文件内容经过MD5变种算法加密出的16字节密钥
  1. 对被加密数据重新MD5校验,将结果和16字节密钥对比

  由于算法可逆性未知,128字节密文不易从自己构造的24字节原始信息恢复,因此我的破解方法是取最小的具有Ts签名的文件尾项数据,插在PE开头,原先PE段相应移位,这样便可以通过Ts签名校验。代码为SignAsTsFile.cpp
  影响到PROCINFO的IsSignMatch成员,该标志为Ts文件签名通过标志,由DriverSwitch开关控制,访问权限没有"Q管目录文件"级别高,影响到的函数有:

  • NtDuplicateObject 放行执行者
  • 虚拟内存操作 保护目标
  • 允许输入法注入
  • NtCreateThreadEx放行执行者
  • NtSuspendThread放行执行者
  • NtGetNextThread放行执行者
  • NtTerminateProcess 放行执行者
  • NtTerminateThread 放行执行者
  • NtQueueApcThread放行执行者
  • NtQueueApcThreadEx放行执行者
  • NtUserSetWinEventHook放行执行者
  • NtUserSetWinEventHookEx放行执行者 保护目标
  • SetSystemInformation 放行执行者
  • NtSetContextThread放行执行者
  • NRestoreKey放行执行者
  • NtSetValueKey 放行执行者
  • NtCreateThread保护目标
  • NtUnmapViewOfSection放行执行者
  • NtCreateSymbolicLinkObject放行执行者
  • OpenObject放行执行者
  • NtSetSecurityObject放行执行者
  • NtAlpcCreatePort 放行执行者
  • NtCreatePort 放行执行者
  • NtAssignProcessToJobObject放行执行者
  • NtLoadDriver放行执行者

接口和控制码

导出接口

ULONG_PTR __stdcall Interface(int Index)
{
	Swtich(index)
	{
		Case 1:
			return GetProcInfoById;// 函数指针,用于通过进程Id拷贝PROCINFO结构,如前所述
		Case 2:
			return &EnableUpThrow;//用于控制是否将驱动事件上抛给主防消息并按规则处理,影响大部分过滤函数
		Case 3:
				return &SelfProtectSwitch;//自保开关,影响的过滤函数见“自保开关影响的函数和功能”一节
		Case 4:
			return &MonitorSwitch;
	/*
	ULONG[0]:进程,线程,钩子操作开关,影响的过滤函数有:NtTerminateProcess, NtCreateThread, NtTerminateThread, NtSetContextThread, NtCreateThreadEx, NtQueueApcThread, NtQueueApcThreadEx, NtUserSetWinEventHook, NtUserSetWindowsHookEx
	ULONG[1]: 注册表操作开关,影响的过滤函数有:NtRestoreKey, NtSetValueKey, NtCreateKey, NtDeleteKey, NtDeleteValueKey, NtLoadDriver, NtSystemDebugControl, NtSetSystemInformation
	ULONG[2]: 文件,设备操作,影响的过滤函数有:NtSetInformationFile, NtCreateSymbolinkObject, NtDeviceIoControlFile
	*/
		Case 5:
			return &SetFileSwitch;//文件操作开关,若关闭则用Tsksp内置规则,否则交给文件过滤驱动分析逻辑
		Case 6:
			return GetProcDir;//函数指针,用于通过进程Id获取ProcDir属性,如前所述
		Default:
			return NULL;
	}
}

控制码

0x22E004		挂钩KeUserModeCallBack并返回结果
	Buffer=		sizeof=4
	+00	BOOL ret

0x22E008		未实现

0x22E010		增加结束进程名黑名单元素 g_StorageList[0]
	Buffer=		sizeof=0x208
	+00	WCHAR ProcessName[260]

0x22E014		删除结束进程名黑名单元素 g_StorageList[0]
	Buffer=		sizeof=0x208
	+00	WCHAR ProcessName[260]

0x22E01C		设置进程线程钩子操作开关MonitorSwitch		如前所述
	Buffer=		sizeof=0xC
	+00	ULONG Data[3]

0x22E020		未知

0x22E028		添加结束进程ID黑名单元素
	Buffer=		sizeof=4
	+00	HANDLE ProcessId

0x22E02C		删除结束进程ID黑名单元素
	Buffer=		sizeof=4
	+00	HANDLE ProcessId

0x22E030		添加g_StorageList[2]元素

0x22E034		删除g_StorageList[2]元素

0x22E038		增加允许自注入名单g_StorageList[5]		CTSKspWrap::AddSelfProcInjectAllow
	Buffer=		sizeof=0x208
	+00	WCHAR ImagePath[260]

0x22E03C		删除ClientLoadLibrary加载模块白名单元素	
	Buffer=		sizeof=0x208
	+00	WCHAR  FilePath[260]	

0x22E040		挂钩KeUserModeCallback

0x22E044		添加g_StorageList[4]元素

0x22E048		删除g_StorageList[4]元素

0x22E04C 	添加g_StorageList[6]元素

0x22E064		DriverEntry中若KeUserModeCallback挂钩失败,则IRP_MJ_ DEVICE_CONTROL派遣例程只接受该控制码,用于获取挂钩信息
	Buffer=		sizeof=4
	+00	ULONG //0挂钩成功		2挂钩失败

0x22E050		删除g_StorageList[6]元素

0x22E054		添加g_StorageList[7]元素

0x22E058		删除g_StorageList[7]元素

0x22E05C		重置关闭自保状态
	Buffer=		sizeof=4
	+00	ULONG  1重置  2关闭	

0x22E060		设置检测发送消息开关SendInputSwitch	CTSKspWrap::SetSendInputSwitch
	Buffer=		sizeof=4
	+00	ULONG => SendInputSwitch		
	该标志位影响的过滤函数有:NtUserSendInput, NtUserMessageCall, NtUserPostmessage, NtUserPostThreadMessage

0x22E064
	Buffer=		sizeof=4
	+00	ULONG status;//	KeUserModeCallback挂钩结果

0x22E06C		添加g_StorageList[12]元素

0x22E070		设置自保开关SelfProtectSwitch	CTSKspWrap::SetSelfProtectState
	Buffer=		sizeof=4
	+00	ULONG => SelfProtectSwitch	

0x22E074		传入%SystemRoot%\system32\advapi32.dll		CreateServiceA地址		CTSKspWrap::AddApiAddress
	Buffer=		sizeof=4
	+00	ULONG	Addr

0x22E078		传入%SystemRoot%\system32\advapi32.dll		CreateServiceW地址		CTSKspWrap::AddApiAddress
	Buffer=		sizeof=4
	+00	ULONG	Addr

0x22E07C		传入%SystemRoot%\system32\rpcrt4.dll		NdrClientCall2地址		CTSKspWrap::AddApiAddress
	Buffer=		sizeof=4
	+00	ULONG	Addr

0x22E080		增加自结束进程查询名单		CTSKspWrap::AddSelfProcTeminateQuery
	Buffer=		sizeof=0x208
	+00	WCHAR  FilePath[260]	

0x22E084		增加注册表监控项	CTSKspWrap::AddRegMonitor		
	Buffer=		sizeof=0x418
+000h   WCHAR		RegPath[260]
+208h   WCHAR		KeyName[260]         
+410h   HANDLE	ProcessHandle
+414h   DWORD	Access

0x22E08C		根据id设置PROCINFO的ProcDir域
	Buffer=		sizeof=8
	+0	HANDLE ProcessId
	+4	ULONG ProcDir

0x22E090			CTSKspWrap::AddFileGroup
	Buffer=		sizeof=0x212
	+00	ULONG Access
	+08	WCHAR [260]	匹配路径

0x22E094				CTSKspWrap::AddProcPrivilege
	
0x22E09C		初始化驱动同步		CTSKspWrap::InitDriverSync
	Buffer=		sizeof=4
	+00	ULONG =>  InitDriverSync

0x22E0A0		获取自保开关状态			CTSKspWrap::GetSelfProtectState
	Buffer=		sizeof=4
	+00	ULONG Data <= SelfProtectSwitch

0x22E0C4		和驱动建立连接的过程中,发给驱动的用于通知主防驱动已经写完消息等待读取的同步信号
	Buffer=		sizeof=4
	+00	PKSEMAPHORE	MsgWriteLock

0x22E0C8		主防向驱动索取消息结构		CTSKspWrap::DriverGetMessage
	Buffer=		sizeof=0x1000

0x22E0CC		驱动返回消息	CTSKspWrap::DriverReplyMessage

0x22E0D0		通知驱动主防进程退出,做清理工作		CTSKspWrap::CloseDriverEvent
	
0x22E0D8		   穿透创建服务加载驱动
    buffer=     sizeof=0x91C
    +000    WCHAR ImagePath[260] 驱动文件路径
    +208    DWORD Type  驱动注册表Type项
    +20C    DWORD Start 驱动注册表项Start类型
    +210    DWORD flag  (决定是否设置注册表Tag和Group信息)
    +214    ???
    +468    DWORD Tag 驱动注册表Tag项
    +46C    WCHAR DisplayName[300] 驱动注册表项DisplayName
    +6C4    WCHAR ServiceName[300] 驱动服务名

0x22E0DC		下发要监控的线程Id给驱动,存储于ThreadIdSlot,该结构在创建/打开文件操作中生效
	Buffer=		sizeof=4
	+00	HANDLE ThreadId	

0x22E0E0		取消要监控的线程Id,修改ThreadIdSlot
	Buffer=		sizeof=4
	+00	HANDLE ThreadId

0x22E0E4 	重置全局访问控制表ACL =>AclTable  三维数组,详述见全局访问控制表章节
	Buffer=		sizeof=0x10
	+00	ULONG dimen1//第一维大小
	+04	ULONG dimen2//第二维大小
	+08	ULONG dimen3//第三维大小
	+0C	PBYTE data//数据基址

0x22E0E8		添加__ClientLoadLibrary发起进程黑名单元素 g_StorageList[13]		CTSKspWrap::SetIoControl
	Buffer=		sizeof=0x208
+00	FileName [260]		模块文件名

0x22E0EC		删除__ClientLoadLibrary发起进程黑名单元素 g_StorageList[13]
	Buffer=		sizeof=0x208
+00	FileName [260]		模块文件名

0x22E0F0		设置要监控的模块路径		CTSKspWrap::SetIoControl
	Buffer=		sizeof=0x208
+00	DllPath [260]		模块文件名

0x22E100		设置进程信息
	Buffer=		sizeof=0xC
	+00	HANDLE ProcessId	in
	+04	ULONG ProcDir		out
	+08	ULONG 			out

0x22E104		是否开启验证父进程和子进程创建时间逻辑
	Buffer=		sizeof=4
	+00	BOOLEAN VerifyTime//0不开启 	1开启

0x22E108		添加__ClientLoadLibrary发起进程白名单项g_StorageList[16]		CTSKspWrap::SetIoControl
	Buffer=		sizeof=0x208
+00	FileName [260]		模块文件名

0x22E10C		开启__ClientLoadLibrary发起进程白名单项g_StorageList[16]的验证

0x22E110		删除__ClientLoadLibrary发起进程白名单项g_StorageList[16]		CTSKspWrap::SetIoControl
	Buffer=		sizeof=0x208
+00	FileName [260]		模块文件名

0x22E114		关闭__ClientLoadLibrary发起进程白名单项g_StorageList[16]的验证

0x22E400		增加监控条目		信息添加到数组,做第一次规则匹配		CTSKspWrap::AddMonitorItem
	Buffer=		sizeof>0x10
	+00	USHORT  cbSize
	+02	USHORT	0/1
	+04	USHORT	2	
	+06	USHORT	GroupInfoSize//组信息结构大小
	+08	USHORT	Type	//组类型 	0进程线程	1文件	2??		3其他
	+10	UBYTE[]	组信息

0x22E404	增加”规则组进程访问权限”信息	信息添加到二级链表,做第二次规则匹配
	Buffer=		sizeof>0x10
	+00	USHORT  cbSize
	+02	USHORT	0/1
	+04	USHORT	2	
	+06	USHORT	GroupInfoSize//进程相关的权限信息结构大小
	+10	UBYTE[]	组信息

	内部存储结构:
	+00  LIST_ENTRY ListEntry
	+08  LIST_ENTRY ChildListEntry
		+00	LIST_ENTRY ListEntry
			+08 	ULONG	uMinRuleNum
			+0C	ULONG	uMaxruleNum
			+10	ULONG	Access;//0放过   非0拦截
	+10  HANDLE ProcessId
	
	保存在内存中的结构为RuleGroupInfo[4]  每个结构由成员个数(=n)和基地址2个ULONG组成,每个基地址存放着n个下列子结构:
00	ULONG ruleid          
04	ULONG mid            
08	ULONG subid          
0C	ULONG val4           
10	WCHAR* matchfirst      
14	WCHAR* matchsecond  
	详细情况后面有详述

0x22E410		设置全局开关DriverSwitch		DriverSwitch见全局开关章节		CTSKspWrap::SetDriverSwitch
	Buffer=		sizeof=4
	+00	ULONG mask
	
0x22E414		监视操作窗口标题,将新标题字符串加入监视列表白名单
Buffer=		sizeof>0
+00	WCHAR[??]	窗口标题
	
0x22E418		获取在NtRequestWaitReplyPort和NtAlpcSendWaitReceivePort通信中使用IWbemInterface通信的进程
	Bufer=		sizeof=8
	+00	HANDLE ProcessId
	+04	0

0x22E41C		增加打开对象目标黑名单项g_StorageList[14],见“黑白名单”一节		CTSKspWrap::AddSyncObjProtect
	Buffer=		sizeof=0x208
	+00	WCHAR ObjectPath[260]

0x22E420		增加打开进程/复制句柄发起进程白名单项	g_StorageList[15] ,见“黑白名单”一节		CTSKspWrap::AddSelfProcAllow
	Buffer=		sizeof=0x430
	+000	LIST_ENTRY	List
	+008	ULONG	Enable??
	+00C	ULONG	SourceFilePathLen			
	+010	WCHAR	SourceProcessFilePath[261]
	+21C	ULONG	TargetFilePathLen
	+220	WCHAR	TargetProcessFilePat[261]
	+42C	ACCESS_MASK	GrantedAccess

0x22E420		由进程Id获取进程加载序号,PROCESSINFO的Index域
	Buffer=		sizeof=8
	+0	HANDLE ProcessId  <=>	ULONG Index

0x22E424		由进程Id获取进程文件全路径
	Buffer=		sizeof= in 4 	out 0x104
	+0	HANDLE ProcessId	<=>	

基础库

由进程Id获取文件对象

BOOLEAN GetSectionObjectOffset()
{
	UCHAR Inst1[]={0x8B, 0xFF, 0x55, 0x8B, 0xEC, 0x8B, 0x45, 0x08, 0x8B, 0x80};
	UCHAR Inst2[]={0x8B, 0x44, 0x24, 0x04, 0x8B, 0x80};
	BOOLEAN result = FALSE;
	ULONG_PTR SectionBaseOffset = 0;
	PsGetProcessSectionBaseAddress = MmGetSystemRoutineAddress(&uName);
	if(PsGetProcessSectionBaseAddress && MmIsAddressValid(PsGetProcessSectionBaseAddress))
	{
		if(MmIsAddressValid((PVOID)((char*)PsGetProcessSectionBaseAddress + 14)) &&
			RtlCompareMemory((PVOID)Inst1, PsGetProcessSectionBaseAddress, sizeof(Inst1)) == sizeof(Inst1))
		{
			/*
				nt!PsGetProcessSectionBaseAddress:
				805287da 8bff            mov     edi,edi
				805287dc 55              push    ebp
				805287dd 8bec            mov     ebp,esp
				805287df 8b4508          mov     eax,dword ptr [ebp+8]
				805287e2 8b803c010000    mov     eax,dword ptr [eax+13Ch]
				805287e8 5d              pop     ebp
			*/
			SectionBaseOffset = *(ULONG*)((char*)PsGetProcessSectionBaseAddress + 10);
		}
		else if(MmIsAddressValid((PVOID)((char*)PsGetProcessSectionBaseAddress + 10)) &&
			RtlCompareMemory((PVOID)Inst2, PsGetProcessSectionBaseAddress, sizeof(Inst2)) == sizeof(Inst2))
			//and BuildNumber==2600
		{
			SectionObjectOffset = *(ULONG*)((char*)PsGetProcessSectionBaseAddress + 6);
		}
		if(SectionBaseOffset >= 276)
		{
			SectionObjectOffset = SectionBaseOffset - 4;
			result = TRUE;
		}
	}
	return result;
}

NTSTATUS GetFileObjectByProcessId(HANDLE ProcessId, PFILE_OBJECT* pFileObject)
{//法一 借助PEPROCESS结构
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	PEPROCESS Process = NULL;
	if(!pFileObject)
		return status;
	if(NT_SUCCESS(PsLookupProcessByProcessId(ProcessId,&Process)))
	{
		if(MajorVersion == 1 || MajorVersion == 2)
		{
			PSECTION Section = *(PSECTION*)((char*)Process + SectionObjectOffset);
			if(Section && MmIsAddressValid(Section) && Section->Segment && MmIsAddressValid(Section->Segment) &&
				Section->Segment->ControlArea && MmIsAddressValid(Section->Segment->ControlArea))
			{
				*pFileObject = Section->Segment->ControlArea->FilePointer;
				if(*pFileObject)
				{
					ObReferenceObject(*pFileObject);
					status = STATUS_SUCCESS;
				}
			}
		}
		else if(MajorVersion == 5)
		{
			if(!PsReferenceProcessFilePointer)
				PsReferenceProcessFilePointer = (ULONG)MmGetSystemRoutineAddress(&uName);
			if(PsReferenceProcessFilePointer)
				status = ((NTSTATUS (__stdcall*)(PEPROCESS,PFILE_OBJECT*))PsReferenceProcessFilePointer)(Process,pFileObject);
		}
	}
	if(Process)
		ObDereferenceObject(Process);
	return status;
}

NTSTATUS GetPebBaseByProcessObject(PEPROCESS Process, PVOID *PebBaseAddr)
{
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	HANDLE ProcessHandle = NULL;
	PROCESS_BASIC_INFORMATION ProcessInformation;
	if(NT_SUCCESS(ObOpenObjectByPointer(Process, OBJ_KERNEL_HANDLE, NULL,0, NULL, KernelMode, &ProcessHandle)) &&
		ZwQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &ProcessInformation, sizeof(ProcessInformation), NULL) &&
		ProcessInformation.PebBaseAddress)
	{
		*PebBaseAddr = ProcessInformation.PebBaseAddress;
		status = STATUS_SUCCESS;
	}
	if(ProcessHandle)
		ZwClose(ProcessHandle);
	return status;
}

PFILE_OBJECT GetFileObjectByProcessId(HANDLE ProcessId)
{//法二 借助PEB命令行
	PEPROCESS Process = NULL;
	PPEB PebBaseAddr = NULL;
	BOOLEAN Attached = FALSE;
	HANDLE FileHandle = NULL;
	PVOID Buffer = NULL;
	PFILE_OBJECT FileObject = NULL;
	UNICODE_STRING ImagePathName;
	UNICODE_STRING FullPath;
	OBJECT_ATTRIBUTES Oa;
	UNICODE_STRING Prefix = RTL_CONST_STRING(L"\??\");
	IO_STATUS_BLOCK IoStatus;
	if(KeGetCurrentIrql() == PASSIVE_LEVEL && 
		NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process)) &&
		NT_SUCCESS(GetPebBaseByProcessObject(Process, (PVOID*)&PebBaseAddr)))
	{
		KeAttachProcess(Process);
		Attached = TRUE;
		__try
		{
			ProbeForRead(PebBaseAddr,0x1D8,1);
			ProbeForRead(PebBaseAddr->ProcessParameters,0x90,1);
			ImagePathName = PebBaseAddr->ProcessParameters->ImagePathName;
			if(ImagePathName.Length != 0 && ImagePathName.Length < 0xFFF8)
			{
				if((char*)ImagePathName.Buffer < (char*)PebBaseAddr->ProcessParameters)// 如果该成员是偏移而不是指针
					ImagePathName.Buffer = (PWSTR)((ULONG)ImagePathName.Buffer + PebBaseAddr->ProcessParameters);
				ProbeForRead(ImagePathName.Buffer,ImagePathName.Length,1);
				ULONG FullLen = ImagePathName.Length;
				if(!RtlPrefixUnicodeString(&Prefix, &ImagePathName, TRUE))
					FullLen += 8;
				Buffer = ExAllocatePool(NonPagedPool, FullLen);
				if(Buffer)
				{
					RtlZeroMemory(Buffer,FullLen);
					FullPath.Buffer = (PWCH)Buffer;
					FullPath.MaximumLength = FullLen;
					if(FullLen != ImagePathName.Length)
						RtlAppendUnicodeStringToString(&FullPath,&Prefix);
					RtlAppendUnicodeStringToString(&FullPath,&ImagePathName);
				}
			}
		}
		__except(0)
		{
			Attached = FALSE;
		}
		InitializeObjectAttributes(&Oa,&FullPath,OBJ_KERNEL_HANDLE,NULL,NULL);
		if(NT_SUCCESS(ZwOpenFile(&FileHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &Oa, &Ios,
			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE)))
			ObReferenceObjectByHandle(FileHandle, 0, *IoFileObjectType, KernelMode, (PVOID*)&FileObject, NULL);
	}
	if(Attached)
		KeDetachProcess();
	if(FileHandle)
	{
		ZwClose(FileHandle);
		FileHandle = NULL;
	}
	if(Process)
	{
		ObDereferenceObject(Process);
		Process = NULL;
	}
	if(Buffer)
		ExFreePool(Buffer);
	return FileObject;
}

由线程句柄获取进程对象

PEPROCESS GetProcessObjectFromThreadHandle(HANDLE ThreadHandle)
{
	PETHREAD Thread = NULL;
	PEPROCESS Process = NULL;
	if(ThreadHandle)
	{
		if(NT_SUCCESS(ObReferenceObjectByHandle(ThreadHandle, 0, *PsThreadType, 
			IsKernelHandle(ThreadHandle)?KernelMode:UserMode, (PVOID*)&Thread, NULL)))
		{
			Process = IoThreadToProcess(Thread);
			ObDereferenceObject(Thread);
		}
	}
	return Process;
}

由线程对象获取进程Id

NTSTATUS GetProcIdFromProcessObject(PEPROCESS Process,PHANDLE pProcessId)
{
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	HANDLE ProcessHandle = NULL;
	PROCESS_BASIC_INFORMATION ProcessInformation;
	if(NT_SUCCESS(ObOpenObjectByPointer(Process, OBJ_KERNEL_HANDLE, NULL,0, NULL, KernelMode, &ProcessHandle)) &&
		ZwQueryInformationProcess(ProcessHandle, ProcessBasicInformation, &ProcessInformation, sizeof(ProcessInformation), NULL))
	{
		*pProcessId = ProcessInformation.UniqueProcessId;
		status = STATUS_SUCCESS;
	}
	if(ProcessHandle)
		ZwClose(ProcessHandle);
	return status;
}

NTSTATUS GetThreadProcessId(PETHREAD Thread,PHANDLE pProcessId)
{
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	PVOID PsGetThreadProcessId = NULL;
	ULONG OffsetEprocessToThreadObject = 0x22C;
	if(MmIsAddressValid(Thread))
	{
		PsGetThreadProcessId = MmGetSystemRoutineAddress(&uName);
		if(PsGetThreadProcessId)
		{
			*pProcessId = ((HANDLE (__stdcall*)(PETHREAD))PsGetThreadProcessId)(Thread);
			status = STATUS_SUCCESS;
		}
		if(!NT_SUCCESS(status))
		{
			ULONG Addr = (ULONG)Thread + OffsetEprocessToThreadObject;
			if(Addr && MmIsAddressValid((PVOID)Addr))
			{
				PEPROCESS Process = *(PEPROCESS*)Addr;
				if(Process && MmIsAddressValid(Process))
				{
					if(NT_SUCCESS(GetProcIdFromProcessObject(Process, pProcessId)))
					{
						status = STATUS_SUCCESS;
					}
				}
			}
		}
	}
	return status;
}

4.4 由Ntfs文件索引号获取文件对象

PFILE_OBJECT GetRealFileObject(HANDLE ProcessId,PFILE_OBJECT FileObject)
{
	UNICODE_STRING uNtfs = RTL_CONSTANT_STRING(L"\\Ntfs");
	PDRIVER_OBJECT NtfsDrvObj = NULL;
	PDEVICE_OBJECT NtfsDevObj = NULL,fsDevObj = NULL;
	PFILE_OBJECT NtfsFileObj = NULL,ObjFileObj = NULL,RealFileObj = NULL;
	NTSTATUS status;
	PFILE_OBJECT Ntfs;
	BOOLEAN Real=FALSE;

	//检查是否文件属于NTFS文件系统
	status = IoGetDeviceObjectPointer(&uNtfs,0,&NtfsFileObj,&NtfsDevObj);
	if(NT_SUCCESS(status) && NtfsFileObj && MmIsAddressValid(NtfsFileObj) && MmIsAddressValid(NtfsFileObj->DeviceObject))
		NtfsDrvObj = NtfsFileObj->DeviceObject->DriverObject;
	fsDevObj = IoGetBaseFileSystemDeviceObject(FileObject);//FileSystem\Ntfs
	if(fsDevObj && MmIsAddressValid(fsDevObj) && fsDevObj->DriverObject == NtfsDevObj)
	{
		FILE_STANDARD_INFORMATION StandardInfo;
		ULONG RetLen;
		status = IoQueryFileInformation(FileObject,FileStandardInformation,sizeof(StandardInfo),&StandardInfo,&RetLen);
		if(NT_SUCCESS(status))
		{
			if(StandardInfo.NumberOfLinks > 1)
			{
				ObjFileObj = GetFileObjectByProcessId(ProcessId);
				if(ObjFileObj && ObjFileObj->FsContext != FileObj->FsContext)
				{
					//2种方式的FsContext不同,说明可能被拦截,下面采用Ntfs文件号获取
					Real = TRUE;
					ObDereferenceObject(ObjFileObj);
				}
			}
		}
	}
	if(!Real)
	{
		//获取该文件Ntfs文件号
		FILE_INTERNAL_INFORMATION InternalInfo;
		ULONG RetLen;
		PVOID Buf = ExAllocatePool(PagedPool,1024);
		status = IoQueryFileInformation(FileObj,FileInternalInformation,sizeof(InternalInfo),&InternalInfo,&RetLen);
		if(NT_SUCCESS(status) && Buf)
		{
			//获取父目录信息
			RtlZeroMemory(Buf,1024);
			POBJECT_NAME_INFORMATION DeviceName = (POBJECT_NAME_INFORMATION)Buf;
			OBJECT_ATTRIBUTES Oa;
			IO_STATUS_BLOCK IoStatus;
			HANDLE DeviceHandle = NULL;
			HANDLE FileHandle = NULL;
			status = ObQueryNameString(FileObj->DeviceObject,Buf,1024,RetLen);
			if(NT_SUCCESS(status) && DeviceName->Name.Buffer)
			{
				InitializeObjectAttributes(&Oa,&DeviceName->Name,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
				status = ZwOpenFile(&DeviceHandle , 0, &Oa, &IoStatus, 0, FILE_NON_DIRECTORY_FILE);
				if(NT_SUCCESS(status))
				{
					UNICODE_STRING InnerFileName = {sizeof(InternalInfo), sizeof(InternalInfo), &InternalInfo};
					InitializeObjectAttributes(&Oa, &InnerFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, DeviceHandle, NULL);
					status = ZwOpenFile(FileHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &Oa, &IoStatus, 
						FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_BY_FILE_ID | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
					if(NT_SUCCESS(status))
					{
						//用文件索引号打开文件成功
						ObReferenceObjectByHandle(FileHandle, 0, *IoFileObjectType, KernelMode, &RealFileObj);
					}
				}
			}
			if(FileHandle)
				ZwClose(FileHandle);
			if(DeviceHandle)
				ZwClose(DeviceHandle);
		}
		if(Buf)
			ExFreePool(Buf);
	}
	return RealFileObj;
}

长度反汇编引擎,用于获取指令长度

int DisasmLen(unsigned char* bytecode)
{
	unsigned long decode1[256][7]=
	{
		{0x00,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x01,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x02,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x03,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x04,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x05,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x06,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x07,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x08,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x09,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x0a,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x0b,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x0c,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x0d,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x0e,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x0f,0x03,0x03,0x02,0x00,0x00,0x00,},
		{0x10,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x11,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x12,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x13,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x14,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x15,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x16,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x17,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x18,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x19,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x1a,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x1b,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x1c,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x1d,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x1e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x1f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x20,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x21,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x22,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x23,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x24,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x25,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x26,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x27,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x28,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x29,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2c,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2d,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2e,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2f,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x30,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x31,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x32,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x33,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x34,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x35,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x36,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x37,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x38,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x39,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x3a,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x3b,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x3c,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x3d,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x3e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x3f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x40,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x41,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x42,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x43,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x44,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x45,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x46,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x47,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x48,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x49,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x4a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x4b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x4c,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x4d,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x4e,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x4f,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x50,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x51,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x52,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x53,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x54,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x55,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x56,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x57,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x58,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x59,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x5a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x5b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x5c,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x5d,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x5e,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x5f,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x60,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x61,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x62,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x63,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x64,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x65,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x66,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x67,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x68,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x69,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x6a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x6b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x6c,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x6d,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x6e,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x6f,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x70,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0x71,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0x72,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0x73,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0x74,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x75,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x76,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x77,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x78,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x79,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x7a,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x7b,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x7c,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x7d,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x7e,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x7f,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x80,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x81,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x82,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x83,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x84,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x85,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x86,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x87,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x88,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x89,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x8a,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x8b,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x8c,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x8d,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x8e,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x8f,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0x90,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x91,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x92,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x93,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x94,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x95,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x96,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x97,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x98,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x99,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x9a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x9b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x9c,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x9d,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x9e,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x9f,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xa0,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xa1,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xa2,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xa3,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xa4,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xa5,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xa6,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xa7,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xa8,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xa9,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xaa,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xab,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xac,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xad,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xae,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xaf,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb0,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb1,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb2,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb3,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb4,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb5,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb6,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb7,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xb8,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xb9,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xba,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xbb,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xbc,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xbd,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xbe,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xbf,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xc0,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xc1,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xc2,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xc3,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xc4,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xc5,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xc6,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xc7,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xc8,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xc9,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xca,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xcb,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xcc,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xcd,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xce,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xcf,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xd0,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xd1,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd2,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd3,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd4,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd5,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd6,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd7,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd8,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd9,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xda,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xdb,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xdc,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xdd,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xde,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xdf,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe0,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe1,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe2,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe3,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe4,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe5,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe6,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe7,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe8,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe9,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xea,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xeb,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xec,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xed,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xee,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xef,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf0,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf1,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf2,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf3,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf4,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf5,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf6,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf7,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf8,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xf9,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xfa,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xfb,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xfc,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xfd,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xfe,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xff,0x01,0x01,0x00,0x00,0x00,0x00,},
	};

	unsigned long decode2[256][7]=
	{
		{0x00,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x01,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x02,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x03,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x04,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x05,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x06,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x07,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x08,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x09,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x0a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x0b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x0c,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x0d,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x0e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x0f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x10,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x11,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x12,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x13,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x14,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x15,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x16,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x17,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x18,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x19,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x1a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x1b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x1c,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x1d,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x1e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x1f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x20,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x21,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x22,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x23,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x24,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x25,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x26,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x27,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x28,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x29,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x2c,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x2d,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x2e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x2f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x30,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x31,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x32,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x33,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x34,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x35,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x36,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x37,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x38,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x39,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x3a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x3b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x3c,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x3d,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x3e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x3f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x40,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x41,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x42,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x43,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x44,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x45,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x46,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x47,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x48,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x49,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x4a,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x4b,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x4c,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x4d,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x4e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x4f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x50,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x51,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x52,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x53,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x54,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x55,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x56,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x57,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x58,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x59,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x5a,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x5b,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x5c,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x5d,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x5e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x5f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x60,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x61,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x62,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x63,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x64,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x65,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x66,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x67,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x68,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0x69,0x06,0x04,0x01,0x00,0x04,0x00,},
		{0x6a,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x6b,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0x6c,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x6d,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x6e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x6f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x70,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x71,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x72,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x73,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x74,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x75,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x76,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x77,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x78,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x79,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x7a,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x7b,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x7c,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x7d,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x7e,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x7f,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0x80,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0x81,0x06,0x04,0x01,0x00,0x04,0x00,},
		{0x82,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0x83,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0x84,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x85,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x86,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x87,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x88,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x89,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x8a,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x8b,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x8c,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x8d,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x8e,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x8f,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0x90,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x91,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x92,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x93,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x94,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x95,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x96,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x97,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x98,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x99,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x9a,0x07,0x05,0x00,0x00,0x00,0x01,},
		{0x9b,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x9c,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x9d,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x9e,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0x9f,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xa0,0x05,0x03,0x00,0x00,0x00,0x02,},
		{0xa1,0x05,0x03,0x00,0x00,0x00,0x02,},
		{0xa2,0x05,0x03,0x00,0x00,0x00,0x02,},
		{0xa3,0x05,0x03,0x00,0x00,0x00,0x02,},
		{0xa4,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xa5,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xa6,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xa7,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xa8,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xa9,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0xaa,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xab,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xac,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xad,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xae,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xaf,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xb0,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xb1,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xb2,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xb3,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xb4,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xb5,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xb6,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xb7,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xb8,0x05,0x03,0x00,0x00,0x00,0x08,},
		{0xb9,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0xba,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0xbb,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0xbc,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0xbd,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0xbe,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0xbf,0x05,0x03,0x00,0x00,0x00,0x00,},
		{0xc0,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xc1,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xc2,0x03,0x03,0x00,0x00,0x00,0x00,},
		{0xc3,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xc4,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xc5,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xc6,0x03,0x03,0x01,0x00,0x01,0x00,},
		{0xc7,0x06,0x04,0x01,0x00,0x04,0x00,},
		{0xc8,0x04,0x04,0x00,0x00,0x00,0x00,},
		{0xc9,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xca,0x03,0x03,0x00,0x00,0x00,0x01,},
		{0xcb,0x01,0x01,0x00,0x00,0x00,0x01,},
		{0xcc,0x01,0x01,0x00,0x00,0x00,0x01,},
		{0xcd,0x02,0x02,0x00,0x00,0x00,0x01,},
		{0xce,0x01,0x01,0x00,0x00,0x00,0x01,},
		{0xcf,0x01,0x01,0x00,0x00,0x00,0x01,},
		{0xd0,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd1,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd2,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd3,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd4,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xd5,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xd6,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xd7,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xd8,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xd9,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xda,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xdb,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xdc,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xdd,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xde,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xdf,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xe0,0x02,0x02,0x00,0x01,0x00,0x04,},
		{0xe1,0x02,0x02,0x00,0x01,0x00,0x04,},
		{0xe2,0x02,0x02,0x00,0x01,0x00,0x04,},
		{0xe3,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0xe4,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xe5,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xe6,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xe7,0x02,0x02,0x00,0x00,0x00,0x00,},
		{0xe8,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0xe9,0x05,0x03,0x00,0x01,0x00,0x00,},
		{0xea,0x07,0x05,0x00,0x00,0x00,0x01,},
		{0xeb,0x02,0x02,0x00,0x01,0x00,0x00,},
		{0xec,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xed,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xee,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xef,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf0,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf1,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf2,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf3,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf4,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf5,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf6,0x00,0x00,0x00,0x00,0x00,0x00,},
		{0xf7,0x00,0x00,0x00,0x00,0x00,0x00,},
		{0xf8,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xf9,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xfa,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xfb,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xfc,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xfd,0x01,0x01,0x00,0x00,0x00,0x00,},
		{0xfe,0x02,0x02,0x01,0x00,0x00,0x00,},
		{0xff,0x02,0x02,0x01,0x00,0x00,0x00,},
	};

	unsigned char decode3[256]=
	{
		0x00,0x00,0x00,0x00,0x11,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x24,0x00,0x00,
		0x00,0x00,0x00,0x00,0x11,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x24,0x00,0x00,
		0x00,0x00,0x00,0x00,0x11,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x24,0x00,0x00,
		0x00,0x00,0x00,0x00,0x11,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x24,0x00,0x00,
		0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,
		0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,
		0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,
		0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,
		0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04,
		0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04,
		0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04,
		0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x04,0x04,0x04,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	};

	unsigned char* ptr = bytecode;
	unsigned long len = 0,var2 = 0,var3 = 0, decodel[7]={0};
	unsigned long* pdecode = 0;

	switch(*ptr)
	{
	case 0xF:
		ptr++;
		len = 1;
		pdecode = &decode1[*ptr][0];
		break;
	case 0x26:
	case 0x2E:
	case 0x36:
	case 0x3E:
	case 0x64:
	case 0x65:
		len = 1;
		ptr++;
		break;
	case 0x66:
		len = 1;
		var3 = 1;
		ptr++;
		break;
	case 0x67:
		len = 1;
		var2 = 1;
		ptr++;
		break;
	case 0xF0:
	case 0xF2:
	case 0xF3:
		len = 1;
		ptr++;
		break;
	case 0xF6:
		decodel[0] = 0xF6;
		if(*(ptr+1) & 0x38)
		{
			decodel[1] = 2;
			decodel[2] = 2;
			decodel[3] = 1;
			decodel[5] = 0;
		}
		else
		{
			decodel[1] = 3;
			decodel[2] = 3;
			decodel[3] = 1;
			decodel[5] = 1;
		}
		pdecode = decodel;
		break;
	case 0xF7:
		decodel[0] = 0xF6;
		decodel[3] = 1;
		if(*(ptr+1) & 0x38)
		{
			decodel[1] = 6;
			decodel[2] = 4;
			decodel[5] = 4;
		}
		else
		{
			decodel[1] = 2;
			decodel[2] = 2;
			decodel[5] = 0;
		}
		pdecode = decodel;
		break;
	default:
		break;
	}
	if(!pdecode)
		pdecode = decode2[*ptr];
	if(pdecode[6] & 2)
	{
		if(var2 == 0)
			len += pdecode[1];
		else
			len += pdecode[2];
	}
	else
	{
		if(var3 == 0)
			len += pdecode[1];
		else
			len += pdecode[2];
	}

	if(pdecode[3])
	{
		unsigned char var4 = ptr[pdecode[3]];
		len += decode3[var4] & 0xF;
		if((decode3[var4] & 0x10) && (ptr[pdecode[3] + 1] & 7) == 5)
		{
			switch(var4 & 0xC0)
			{
			case 0x40:
				len++;
				break;
			case 0x00:
			case 0x80:
				len += 4;
				break;
			default:
				break;
			}
		}
	}
	return len;
}

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
  • 记录当前配置

过滤模型

  • 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

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

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;
}

打开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中,如果存在过滤函数进行了放行和拦截,都会打印日志

控制信息

  • 禁止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引起蓝屏

全局表

系统Build号与全局表索引对应关系
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
	}
};

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

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;
}

SetEvaluateTime

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

SetDisablePrevFilter

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

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++;
	}
}

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
	}
}

AddPrevFilter

NTSTATUS __stdcall AddPrevFilter(ULONG Index,FARPROC Filter,ULONG Tag,ULONG PreferSlot,PULONG OutSlot)
{
	/*
		Index :Nt函数在全局表DProxyTable中的索引
		Filter:要设置的过滤函数
		Tag:标志过滤函数(可用于保存参数)
		PreferSlot:优先选用的函数槽
		OutSlot:实际选用的函数槽
*/
	if(!Filter || Index >= APINUMBER || PreferSlot >= 16)
		return STATUS_UNSUCCESSFUL;
	if(!DProxyTable[Index] || !DProxyTable[Index]->IsInitialized)
		return STATUS_UNSUCCESSFUL;
	if(DProxyTable[Index]->PrevFilterSlot[PreferSlot].Filter)
	{//若函数槽已被占用
		for(int i=0;i<16;i++)
		{
			if(!DProxyTable[Index]->PrevFilterSlot[i].Filter)
			{
				DProxyTable[Index]->PrevFilterSlot[i].Tag = Tag;
				InterlockedExchange(&DProxyTable[Index]->PrevFilterSlot[i].Filter,Filter);
				InterlockedIncrement(&DProxyTable[Index]->UsedSlotCount);
				if(OutSlot)
					*OutSlot = i;
				return STATUS_SUCCESS;
			}
		}
	}
	else
	{
		DProxyTable[Index]->PrevFilterSlot[i].Tag = Tag;
		InterlockedExchange(&DProxyTable[Index]->PrevFilterSlot[i].Filter,Filter);
		InterlockedIncrement(&DProxyTable[Index]->UsedSlotCount);
		if(OutSlot)
			*OutSlot = i;
		return STATUS_SUCCESS;
	}
	return STATUS_UNSUCCESSFUL;
}

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;
}

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
	记录蓝屏

GetDProxyTable

Dproxy** GetDProxyTable()
{
	Return DProxyTable;
}

基础库

获取注册表键值

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,BufSize<Info->DataLength?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,BufSize<Info->DataLength?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,BufSize<Info->DataLength?BufSize:Info->DataLength);
		}
	}
	if(KeyHandle)
		ZwClose(KeyHandle);
	if(ValueInfo)
		ExFreePool(ValueInfo);
	return status;
}

通过进程名获取进程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;
}

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<<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;i<srclen;i+=16)
	{
		Rabbit_nextState(rabbit);
		K[0] = rabbit->X[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

获取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;
}

从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;
}

获取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);
	}
}

初始化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;i<APINUMBER;i++)
		{
			if(SProxyTable[i].ServiceTableType == END)
				break;
			if(SProxyTable[i].ServiceIndex[BuildIndex] != 1023)
			{
				if(SProxyTable[i].ApiName && SProxyTable[i].ProxyFunc && SProxyTable[i].IndexInTable < APINUMBER)
				{
					Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
					if(Proxydata)
					{
						Proxydata->IsInitialized = 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;i<APINUMBER;i++)
	{
		if(SProxyTable[i].ServiceTableType == END)
			break;
		else if(SProxyTable[i].ServiceTableType == SSDT)
		{
			if(SProxyTable[i].ApiName)
			{
				PUNICODE_STRING UApiName;
				ANSI_STRING AApiName;
				ULONG Index = -1;
				RtlInitUnicodeString(&UApiName,SProxyTable[i].ApiName);
				if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
				{
					Index = GetServiceIndexFromNtos(AApiName.Buffer);
					RtlFreeAnsiString(&AApiName);
				}
				if(Index != -1)
				{
					if(SProxyTable[i].ApiName && SProxyTable[i].ProxyFunc && SProxyTable[i].IndexInTable < APINUMBER)
					{
						Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
						if(Proxydata)
						{
							Proxydata->IsInitialized = 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;
}

获取系统服务号的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;
}

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;i<APINUMBER;i++)
		{
			if(DProxyTable[i] != 0 && (DProxyTable[i]->ServiceTableType == 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;i<APINUMBER;i++)
		{
			if(DProxyTable[i] != 0 && (DProxyTable[i]->ServiceTableType == 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;
}

构造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   <VISTA
		输入
		eax=ServiceIndex
		edx=OriginFunc
		edi=SSDTBase
		输出
		ebx=FuncAddr  最终函数调用地址
	*/
	_asm
	{
		pushf;
		pusha;
		push edi;
		push edx;
		push eax;
		call Filter;
		mov [esp+0x10],eax;//改栈中的ebx
		popa;
		popf;
		mov edi,esp;
		cmp esi,MmUserProbeAddress;
		push dword ptr HookInfo1.JmpBackPoint;
		retn;
	}
}

void __declspec(naked) InlineKiFastCallEntry3()
{
	/*  HOOKTYPE_KSINLINE   <VISTA
		输入
		eax=ServiceIndex
		edx=OriginFunc
		edi=SSDTBase
		输出
		edx=FuncAddr  最终函数调用地址    (KiFastCallEntry后面mov ebx,edx)
	*/
	_asm
	{
		pushf;
		pusha;
		push edi;
		push edx;
		push eax;
		call Filter;
		mov [esp+0x14],eax;//改栈中的edx
		popa;
		popf;
		mov edi,esp;
		test byte ptr [ebp+0x72],2;
		push dword ptr HookInfo2.JmpBackPoint;
		retn;//跳回JmpBackPoint
	}
}

void __declspec(naked) InlineKiFastCallEntry4()
{
	/*  HOOKTYPE_KSINLINE   <VISTA
		输入
		eax=ServiceIndex
		edx=OriginFunc
		edi=SSDTBase
		输出
		ebx=FuncAddr  最终函数调用地址
	*/
	_asm
	{
		pushf;
		pusha;
		push edi;
		push edx;
		push eax;
		call Filter;
		mov [esp+0x14],eax;//改栈中的edx
		popa;
		popf;
		mov edi,esp;
		test byte ptr [ebp+0x72],2;
		push dword ptr HookInfo2.JmpBackPoint;
		retn;//跳回JmpBackPoint
	}
}

强制单核互斥执行指定Procedure

truct 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;
}

进行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);
	}
}

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

/*
	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;
	}
}

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;
}

交换内存

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;
}

获取函数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;
}

另一种方式获取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;
}

TsSysKit.sys分析

  该驱动为qq管家穿透驱动,提供文件、注册表穿透,和解锁文件、驱动加载、句柄、进程等操作,导出接口给其他驱动使用,设备名\\Device\\TSSysKit,符号名\\DosDevices\\TSSysKit。加密手段:Rabbit算法、MD5算法。

驱动入口DriverEntry

  • 获取系统版本_1
  • 获取EPROCESS的ObjectTypeIndex (win7以前 0x1C win8 0x1F Win8.1 0x1E)
  • 创建\Device\TSSysKit设备和\DosDevices\TSSysKit符号链接
  • 设置DeviceExtension为通信接口(Interface函数指针)
  • 注册IRP_MJ_CREATE、IRP_MJ_CLOSE、IRP_MJ_DEVICE_CONTROL派遣例程为DefaultDispatch
  • 获取CmpKeyObject、DeviceObject的OBJECT_TYPE_INITIALIZER GetCmpKeyObjectInitializerFunc GetDeviceObjectInitializerFunc
  • 获取ZwQueryVirtualMemory、IoVolumeDeviceToDosName、PsGetProcessSectionBaseAddress地址和NtQueryVirtualMemory的index
  • 检测加载者是否为Ntos (CheckIopLoadDriver)
  • 执行开机删除操作(DoDeleteJob) 删除ShutdownRecord.ini指定的文件

检测加载者是否为Ntos,顺带保存IopLoadDriver

int CheckIopLoadDriver()
{
	unsigned int IopLoadDriverNext; // esi@2
	PRTL_PROCESS_MODULES modules; // ebx@5
	int IopLoadDriver; // esi@8
	PVOID Base; // eax@9
	PVOID Callers[4]; // [sp+8h] [bp-18h]@1
	BOOL ret; // [sp+18h] [bp-8h]@1
	ULONG SystemInformationLength; // [sp+1Ch] [bp-4h]@1

	Callers[0] = 0;
	Callers[1] = 0;
	Callers[2] = 0;
	Callers[3] = 0;
	ret = 0;
	SystemInformationLength = 0;
	::IopLoadDriver = 0;
	if ( RtlWalkFrameChain(Callers, 4u, 0) == 4 ) 
		// [0]=RtlWalkFrameChain next
		// [1]=DriverEntry
		// [2]=IopLoadDriver
		// [3]=IopInitializeSystemDrivers
	{
		IopLoadDriverNext = Callers[3];
		if ( MmIsAddressValid(Callers[3]) )
		{
			if ( IopLoadDriverNext >= MmUserProbeAddress && *(IopLoadDriverNext - 5) == 0xE8u )// call ***
			{
				SystemInformationLength = sizeof(SYSTEM_MODULE_INFORMATION) + 3 * sizeof(RTL_PROCESS_MODULE_INFORMATION);
				modules = ExAllocatePoolWithTag(0, SystemInformationLength, '!KIT');
				if ( modules )
				{
					memset(modules, 0, SystemInformationLength);
					if ( ZwQuerySystemInformation(SystemModuleInformation,modules,SystemInformationLength,&SystemInformationLength) >= 0 )
					{
						if ( modules->NumberOfModules )
						{
							IopLoadDriver = *(IopLoadDriverNext - 4) + IopLoadDriverNext;
							if ( MmIsAddressValid(IopLoadDriver) )
							{
								Base = modules->Modules[0].ImageBase;
								if ( IopLoadDriver >= Base && IopLoadDriver <= (Base + modules->Modules[0].ImageSize) )
								{                               // 检测IopLoadDriver是否在ntos中
									::IopLoadDriver = IopLoadDriver;
									ret = 1;
								}
							}
						}
					}
					ExFreePool(modules);
				}
			}
		}
	}
	return ret;
}

执行删除任务 DoDeleteJob,如果腾讯安装目录存在ShutdownRecord.ini文件则删除该文件,解析文件列表中指定的文件并逐个删除,其中解析ini的api、文件操作都是自己实现的。删除方式采用NtSetInformationFile 置FileDispositionInformation。ShutdownRecord.ini格式:

[DELETEFILECOUNT]
Count=3
[DELETEFILELIST]
0=0.txt
1=1.txt
2=2.txt

enum
{
	WIN2000=1,
	WINXP=2,
	WINXPSP3=3,
	WINVISTA=4,
	WIN7=5,
	WIN8=7,
	WIN8_1=8,
	WIN10=9,
	UNKNOWN=10,
};

驱动接口Interface

DeviceExtension接口

DeviceObject->DeviceExtension(=Interface) 通过制定序号返回对应函数指针,穿透函数内部在ObOpenObjectByName前后会保存和恢复注册表Objectinitializer:

FARPROC Interface(intindex)
{//注意下面的函数都是自己实现的穿透函数
    switch(index)
    {
    case 1:
        return NtOpenKey;
    case 2:
        return NtQueryValueKey;
    case 3:
        return NtSetValueKeyEx;
    case 4:
        return NtDeleteValueKey;
    case 5:
        return NtDeleteKey;
    case 20:
        return IopCreateFile;
    case 21:
        return NtReadFile;
    case 22:
        return NtWriteFile;
    case 23:
        return NtSetInformationFile;
    case 24:
        return NtQueryInformationFile;
    case 25:
        return NtQueryDirectoryFile;
    }
}

函数原型:

0NTSTATUS __stdcall NtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, PULONG Disposition)
1NTSTATUS __stdcall NtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes)
2NTSTATUS __stdcall NtQueryValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, PVOID KeyValueInformation, ULONG Length, PULONG ResultLength)
3NTSTATUS __stdcall NtSetValueKeyEx(HANDLE Handle, PUNICODE_STRING ValueName, ULONG Type, PVOID Data, ULONG DataSize)
NtSetValueKey的用法类似,只是没有TitleIndex这个参数
4NTSTATUS __stdcall NtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName)
5NTSTATUS __stdcall NtDeleteKey(HANDLE KeyHandle)
20NTSTATUS __stdcall IopCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG Disposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength, CREATE_FILE_TYPE CreateFileType, PVOID ExtraCreateParameters, ULONG Options, ULONG InternalFlags, PVOID DeviceObject)
21NTSTATUS __stdcall NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
22NTSTATUS __stdcall NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
23NTSTATUS __stdcall NtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOL DelCurrentFile)
24NTSTATUS __stdcall NtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOL DelCurrentFile)
25NTSTATUS __stdcall NtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan)

与WRK代码异同点:
  注册表穿透操作是使用Cm函数实现Nt函数,而文件穿透操作则基本和WRK代码一致,Iop*函数最大程度的实现内联。 这些实现中和WRK主要区别在于:去掉了AccessMode=UserMode分支、和ObReferenceObjectByName调用前后重置ObjectInitializer NtReadFile实现额外处理了IoCallDriver返回文件锁定(STATUS_FILE_LOCK_CONFLICT)的处理,此时通过创建文件映射实现读取

重置/保存注册表对象ObjectInitialzer例程

enum
{
	EClose,
	EDelete,
	EParse,
	ESecurtiy,
	EQueryName,
	EOpen,
};
BOOLEAN ReplaceObjectinitializer(int Type,FARPROC* OutFunc,BOOLEAN ResetOrRestore)
{//重置/保存注册表对象ObjectInitialzer例程,用于ObOpenObjectByName执行前后
	FARPROC* Initailier = NULL;
	if(Type <0 || Type >= ECmMax)
	{
		if(!RegObjectInitialzer[Type] || !CmpKeyObjectType || !OutFunc)
			return 0;
	}
	if(VersionIndex >= WIN2000 && VersionIndex <= WINXPSP3)
	{
		switch(Type)
		{
			case EClose:
				Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.CloseProcedure;
				break;
			case EDelete:
				Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.DeleteProcedure;
				break;
			case EParse:
				Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.ParseProcedure;
				break;
			case ESecurity:
				Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.SecurityProcedure;
				break;
			case EQueryName:
				Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.QueryNameProcedure;
				break;
			case EOpen:
				Initailier = &((POBJECT_TYPE_XP)CmpKeyObjectType)->TypeInfo.OpenProcedure;
				break;
		}
	}
	else if(VersionIndex >= WINVISTA && VersionIndex <= WIN10)
	{
		switch(Type)
		{
		case EClose:
			Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.CloseProcedure;
			break;
		case EDelete:
			Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.DeleteProcedure;
			break;
		case EParse:
			Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.ParseProcedure;
			break;
		case ESecurity:
			Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.SecurityProcedure;
			break;
		case EQueryName:
			Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.QueryNameProcedure;
			break;
		case EOpen:
			Initailier = &((POBJECT_TYPE_WIN7)CmpKeyObjectType)->TypeInfo.OpenProcedure;
			break;
		}
	}
	if(ResetOrRestore)
	{//Get
		if(*Initailier != RegObjectInitialzer[Type])
		{
			*OutFunc = *Initailier;
			*Initailier = RegObjectInitialzer[Type];
			return TRUE;
		}
	}
	else
	{//Set
		if(*OutFunc != *Initailier)
		{
			*Initailier = *OutFunc;
			return TRUE;
		}
	}
	return FALSE;
}

NtCreateKey

TSTATUS __stdcall NtCreateKey(PHANDLE KeyHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,ULONG TitleIndex,PUNICODE_STRING Class,ULONG CreateOptions,PULONG Disposition)
{//
	NTSTATUS            status;
	KPROCESSOR_MODE     mode;
	CM_PARSE_CONTEXT    ParseContext;
	PCM_KEY_BODY        KeyBody = NULL;
	HANDLE              Handle = 0;
	UNICODE_STRING      CapturedObjectName = {0};
	FARPROC				SavedInitializer = NULL;
	BOOL				NeedRestore = FALSE;

	RtlZeroMemory(&ParseContext,sizeof(ParseContext));
	if (ARGUMENT_PRESENT(Class)) 
	{
		ParseContext.Class = *Class;
	}
	if ((CreateOptions & (REG_LEGAL_OPTION | REG_OPTION_PREDEF_HANDLE)) != CreateOptions) 
	{
		return STATUS_INVALID_PARAMETER;
	}
	ParseContext.TitleIndex = 1;
	ParseContext.CreateOptions = CreateOptions;
	ParseContext.Disposition = 0L;
	ParseContext.CreateLink = FALSE;
	ParseContext.PredefinedHandle = NULL;
	ParseContext.CreateOperation = TRUE;
	ParseContext.OriginatingPoint = NULL;
	if(ReplaceObjectinitializer(EParse,&SavedInitializer,1))//还原为系统默认值
		NeedRestore = TRUE;
	status = ObOpenObjectByName(ObjectAttributes,CmpKeyObjectType,mode,NULL,DesiredAccess,(PVOID)&ParseContext,&Handle);
	if(NeedRestore)
		ReplaceObjectinitializer(EParse,&SavedInitializer,0);
	if (status==STATUS_PREDEFINED_HANDLE) 
	{
		if(VersionIndex < WINVISTA)
		{
			status = ObReferenceObjectByHandle(Handle,0,CmpKeyObjectType,KernelMode,(PVOID *)(&KeyBody),NULL);
			if (NT_SUCCESS(status)) 
			{
				HANDLE TempHandle;
				TempHandle = (HANDLE)LongToHandle(KeyBody->Type);
				ObDereferenceObject(KeyBody);
				ZwClose(Handle);
				*KeyHandle = TempHandle;
				status = STATUS_SUCCESS;
			}
		}
		else
		{
			TempHandle = (HANDLE)LongToHandle(KeyBody->Type);
			ObDereferenceObject((PVOID)KeyBody);
			NtClose(Handle);
			*KeyHandle = ParseContext.OriginatingPoint;
			status = STATUS_SUCCESS;
		}
	}
	if (ARGUMENT_PRESENT(Disposition)) 
	{
		*Disposition = ParseContext.Disposition;
	}
	return status;
}
NTSTATUS __stdcall NtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes)
{
	CM_PARSE_CONTEXT	ParseContext;
	PVOID				Context;
	HANDLE				Handle =0;
	NTSTATUS			status = STATUS_SUCCESS;
	PCM_KEY_BODY		KeyBody;
	FARPROC				SavedInitializer = NULL;
	BOOL				NeedRestore = FALSE;
	RtlZeroMemory(&ParseContext,sizeof(CM_PARSE_CONTEXT));
	Context = VersionIndex!=WIN2000?&ParseContext:NULL;
	ParseContext.CreateOperation = FALSE;
	if(ReplaceObjectinitializer(EParse,&SavedInitializer,1))//还原为系统默认值
		NeedRestore = TRUE;
	status = ObOpenObjectByName(ObjectAttributes,CmpKeyObjectType,KernelMode,NULL,DesiredAccess,(PVOID)&Context,&Handle);
	if(NeedRestore)
		ReplaceObjectinitializer(EParse,&SavedInitializer,0);
	if (status==STATUS_PREDEFINED_HANDLE) 
	{
		status = ObReferenceObjectByHandle(Handle,0,CmpKeyObjectType,KernelMode,(PVOID *)(&KeyBody),NULL);
		if (NT_SUCCESS(status)) 
		{
			*KeyHandle = (HANDLE)LongToHandle(KeyBody->Type);
			ObDereferenceObject((PVOID)KeyBody);
			if(*KeyHandle) 
			{
				status = STATUS_SUCCESS;
			} 
			else 
			{
				status = STATUS_OBJECT_NAME_NOT_FOUND;
			}
		}
		ZwClose(Handle);
	} 
	else if (NT_SUCCESS(status)) 
	{
		*KeyHandle = Handle;
	}
	return status;
}

NtQueryValueKey

NTSTATUS __stdcall NtQueryValueKey(HANDLE KeyHandle,PUNICODE_STRING ValueName,KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
    PVOID KeyValueInformation,ULONG Length,PULONG ResultLength)
{
    NTSTATUS    status;
    PCM_KEY_BODY   KeyBody = NULL;
    KPROCESSOR_MODE mode;
	UNICODE_STRING LocalValueName = {0};
    if(!ValueName || (KeyValueInformationClass != KeyValueBasicInformation && KeyValueInformationClass != KeyValueFullInformation
		&& KeyValueInformationClass != KeyValuePartialInformation && KeyValueInformationClass != KeyValueFullInformationAlign64 &&
		KeyValueInformationClass != KeyValuePartialInformationAlign64))
		return STATUS_INVALID_PARAMETER;
	if(CmMatchData[VersionIndex][ECmQueryValueKey].InitFlag && CmMatchData[VersionIndex][ECmQueryValueKey].FuncAddr)
	{
		mode = KeGetPreviousMode();
		status = ObReferenceObjectByHandle(KeyHandle,KEY_QUERY_VALUE,CmpKeyObjectType,mode,(PVOID *)(&KeyBody),NULL);
		LocalValueName = *ValueName;
		if (NT_SUCCESS(status)) 
		{
			switch(VersionIndex)
			{
			case WIN2000:
			case WINXP:
			case WINXPSP3:
				CmMatchData[VersionIndex][ECmQueryValueKey].FuncAddr(KeyBody->KeyControlBlock,LocalValueName,
					KeyValueInformationClass,KeyValueInformation,Length,ResultLength);
				break;
			case WINVISTA:
			case WIN7:
			case WIN7_1:
				CmMatchData[VersionIndex][ECmQueryValueKey].FuncAddr(KeyBody,KeyValueInformationClass,KeyValueInformation
					Length,ResultLength,LocalValueName);
				break;
			case WIN8:
				CmMatchData[VersionIndex][ECmQueryValueKey].FuncAddr(KeyBody,LocalValueName,KeyValueInformationClass,
					KeyValueInformation,Length,ResultLength);
				break;
			case WIN8_1:
			case WIN10:
				CmMatchData[VersionIndex][ECmQueryValueKey].FuncAddr(KeyBody,KeyValueInformationClass,KeyValueInformation,
					Length,ResultLength,LocalValueName);
				break;
			default:
				status = STATUS_NOT_SUPPORTED;
				break;
			}
		}
	}
	else
	{
		status = STATUS_NOT_SUPPORTED;
	}
	if(KeyBody)
		ObDereferenceObject(KeyBody);
	return status;
}

NtSetValueKeyEx

NTSTATUS __stdcall NtSetValueKeyEx(HANDLE KeyHandle,PUNICODE_STRING ValueName,ULONG Type,PVOID Data,ULONG DataSize)
{
	NTSTATUS    status;
	PCM_KEY_BODY   KeyBody = NULL;
	KPROCESSOR_MODE mode;
	UNICODE_STRING LocalValueName = {0};
	PWSTR CapturedName=NULL;
	OBJECT_HANDLE_INFORMATION HandleInformation = {0};
	if(CmMatchData[VersionIndex][ECmQueryValueKey].InitFlag && CmMatchData[VersionIndex][ECmQueryValueKey].FuncAddr)
	{
		mode = KeGetPreviousMode();
		status = ObReferenceObjectByHandle(KeyHandle,KEY_SET_VALUE,CmpKeyObjectType,mode,(PVOID *)(&KeyBody),&HandleInformation);
		LocalValueName = *ValueName;
		if (NT_SUCCESS(status)) 
		{
			switch(VersionIndex)
			{
				switch(VersionIndex)
				{
				case WIN2000:
				case WINXP:
				case WINXPSP3:
					CmMatchData[VersionIndex][ECmSetValueKey].FuncAddr(KeyBody->KeyControlBlock,&LocalValueName,Type,Data,DataSize);
					break;
				case WINVISTA:
				case WIN7:
				case WIN7_1:
				case WIN8:
				case WIN8_1:
					CmMatchData[VersionIndex][ECmSetValueKey].FuncAddr(KeyBody,&LocalValueName,Type,Data,DataSize,0,
						HandleInformation.HandleAttributes & 4);
					break;
				case WIN10:
					CmMatchData[VersionIndex][ECmSetValueKey].FuncAddr(KeyBody,&LocalValueName,Type,Data,DataSize,0,
						HandleInformation.HandleAttributes & 4);
					break;
				default:
					status = STATUS_NOT_SUPPORTED;
					break;
			}
		}
	}
	else
	{
		status = STATUS_NOT_SUPPORTED;
	}
	if(KeyBody)
		ObDereferenceObject(KeyBody);
	return status;
}

NtDeleteValueKey

NTSTATUS __stdcall NtDeleteValueKey(HANDLE KeyHandle,PUNICODE_STRING ValueName)
{
	NTSTATUS    status;
	PCM_KEY_BODY   KeyBody = NULL;
	KPROCESSOR_MODE mode;
	UNICODE_STRING LocalValueName = {0};
	PWSTR CapturedName=NULL;
	OBJECT_HANDLE_INFORMATION HandleInformation = {0};
	if(CmMatchData[VersionIndex][ECmDeleteValueKey].InitFlag && CmMatchData[VersionIndex][ECmDeleteValueKey].FuncAddr)
	{
		mode = KeGetPreviousMode();
		status = ObReferenceObjectByHandle(KeyHandle,KEY_SET_VALUE,CmpKeyObjectType,mode,(PVOID *)(&KeyBody),&HandleInformation);
		LocalValueName = *ValueName;
		if (NT_SUCCESS(status)) 
		{
			switch(VersionIndex)
			{
				case WIN2000:
				case WINXP:
				case WINXPSP3:
					CmMatchData[VersionIndex][ECmDeleteValueKey].FuncAddr(KeyBody->KeyControlBlock,LocalValueName);
					break;
				case WINVISTA:
				case WIN7:
				case WIN7_1:
					CmMatchData[VersionIndex][ECmDeleteValueKey].FuncAddr(KeyBody,KeyHandle,HandleInformation.HandleAttributes & 4,LocalValueName);
					break;
				case WIN8:
					CmMatchData[VersionIndex][ECmDeleteValueKey].FuncAddr(KeyBody,LocalValueName,KeyHandle,HandleInformation.HandleAttributes & 4);
					break;
				case WIN8_1:
				case WIN10:
					CmMatchData[VersionIndex][ECmDeleteValueKey].FuncAddr(KeyBody,&LocalValueName,Type,Data,DataSize,0,
						HandleInformation.HandleAttributes & 4);
					break;
				default:
					status = STATUS_NOT_SUPPORTED;
					break;
			}
		}
	}
	else
	{
		status = STATUS_NOT_SUPPORTED;
	}
	if(KeyBody)
		ObDereferenceObject(KeyBody);
	return status;
}

NtDeleteKey

NTSTATUS __stdcall NtDeleteKey(HANDLE KeyHandle)
{
	NTSTATUS    status;
	PCM_KEY_BODY   KeyBody = NULL;
	KPROCESSOR_MODE mode;
	UNICODE_STRING LocalValueName = {0};
	PWSTR CapturedName=NULL;
	OBJECT_HANDLE_INFORMATION HandleInformation = {0};
	if(CmMatchData[VersionIndex][ECmDeleteKey].InitFlag && CmMatchData[VersionIndex][ECmDeleteKey].FuncAddr)
	{
		mode = KeGetPreviousMode();
		status = ObReferenceObjectByHandle(KeyHandle,KEY_SET_VALUE,CmpKeyObjectType,mode,(PVOID *)(&KeyBody),&HandleInformation);
		LocalValueName = *ValueName;
		if (NT_SUCCESS(status)) 
		{
			switch(VersionIndex)
			{
			case WIN2000:
			case WINXP:
			case WINXPSP3:
			case WINVISTA:
			case WIN7:
			case WIN7_1:
			case WIN8:
			case WIN8_1:
			case WIN10:
				CmMatchData[VersionIndex][ECmDeleteKey].FuncAddr(KeyBody);
				break;
			default:
				status = STATUS_NOT_SUPPORTED;
				break;
			}
		}
	}
	else
	{
		status = STATUS_NOT_SUPPORTED;
	}
	if(KeyBody)
		ObDereferenceObject(KeyBody);
	return status;
}

IopCreateFile代码基本和WRK一致,区别在于2点:

  • OPEN_PACKET结构不同
  • ObOpenObjectByName调用之前会将IoFileObjectType的ObjectInitailier重置为系统初始值
// WIN2000
// WINXP
// WINXPSP3
#pragma pack(push)
#pragma pack(8)
typedef struct _OPEN_PACKET_XP
{
	CSHORT Type;
	CSHORT Size;
	PFILE_OBJECT FileObject;
	NTSTATUS FinalStatus;
	ULONG_PTR Information;
	ULONG ParseCheck;
	PFILE_OBJECT RelatedFileObject;
	LARGE_INTEGER AllocationSize;
	ULONG CreateOptions;
	USHORT FileAttributes;
	USHORT ShareAccess;
	PVOID EaBuffer;
	ULONG EaLength;
	ULONG Options;
	ULONG Disposition;
	PFILE_BASIC_INFORMATION BasicInformation;
	PFILE_NETWORK_OPEN_INFORMATION NetworkInformation;
	CREATE_FILE_TYPE CreateFileType;
	PVOID ExtraCreateParameters;
	BOOLEAN Override;
	BOOLEAN QueryOnly;
	BOOLEAN DeleteOnly;
	BOOLEAN FullAttributes;
	PDUMMY_FILE_OBJECT LocalFileObject;
	BOOLEAN TraversedMountPoint;
	ULONG           InternalFlags;
	PDEVICE_OBJECT  TopDeviceObjectHint;
} OPEN_PACKET_XP, *POPEN_PACKET_XP;
#pragma pack(pop)

// WINVISTA
// WIN7
// WIN7_1
#pragma pack(push)
#pragma pack(8)
typedef struct _OPEN_PACKET_WIN7
{
	CSHORT Type;
	CSHORT Size;
	PFILE_OBJECT FileObject;
	NTSTATUS FinalStatus;
	ULONG_PTR Information;
	ULONG ParseCheck;
	PFILE_OBJECT RelatedFileObject;
	POBJECT_ATTRIBUTES OriginalAttributes;
	LARGE_INTEGER AllocationSize;
	ULONG CreateOptions;
	USHORT FileAttributes;
	USHORT ShareAccess;
	PVOID EaBuffer;
	ULONG EaLength;
	ULONG Options;
	ULONG Disposition;
	PFILE_BASIC_INFORMATION BasicInformation;
	PFILE_NETWORK_OPEN_INFORMATION NetworkInformation;
	CREATE_FILE_TYPE CreateFileType;
	PVOID MailslotOrPipeParameters;
	BOOLEAN Override;
	BOOLEAN QueryOnly;
	BOOLEAN DeleteOnly;
	BOOLEAN FullAttributes;
	PDUMMY_FILE_OBJECT LocalFileObject;
	ULONG           InternalFlags;
	IO_DRIVER_CREATE_CONTEXT  DriverCreateContext;
} OPEN_PACKET_WIN7, *POPEN_PACKET_WIN7;
#pragma pack(pop)
// WIN8
// WIN8_1
// WIN10
#pragma pack(push)
#pragma pack(8)
typedef struct _OPEN_PACKET_WIN8
{
	CSHORT Type;
	CSHORT Size;
	PFILE_OBJECT FileObject;
	NTSTATUS FinalStatus;
	ULONG_PTR Information;
	ULONG ParseCheck;
	union
	{
		PFILE_OBJECT RelatedFileObject;
		PDEVICE_OBJECT ReferencedDeviceObject;
	};
	POBJECT_ATTRIBUTES OriginalAttributes;
	LARGE_INTEGER AllocationSize;
	ULONG CreateOptions;
	USHORT FileAttributes;
	USHORT ShareAccess;
	PVOID EaBuffer;
	ULONG EaLength;
	ULONG Options;
	ULONG Disposition;
	PFILE_BASIC_INFORMATION BasicInformation;
	PFILE_NETWORK_OPEN_INFORMATION NetworkInformation;
	CREATE_FILE_TYPE CreateFileType;
	PVOID MailslotOrPipeParameters;
	BOOLEAN Override;
	BOOLEAN QueryOnly;
	BOOLEAN DeleteOnly;
	BOOLEAN FullAttributes;
	PDUMMY_FILE_OBJECT LocalFileObject;
	ULONG           InternalFlags;
	KPROCESSOR_MODE AccessMode;
	IO_DRIVER_CREATE_CONTEXT  DriverCreateContext;
} OPEN_PACKET_WIN8, *POPEN_PACKET_WIN8;
#pragma pack(pop)

控制码

能力:

  • 解锁文件
  • 驱动加载
  • 句柄操作
  • 进程打开、结束
  • 注册表穿透操作

IRP_MJ_DEVICE_CONTROL => 调用DeviceIoControl派遣(DeviceIoControlDispatch)

TSSysKit x86 IoControlCode对应表

0x221C00
    解锁文件
    buffer=     sizeof=0x804
    +00 NTSTATUS status     out
    +04 WCHAR FileName[1024]    in
0x221C04
0x221C08
0x221C0C
0x221C10
0x221C14
    尚未实现
0x222004
    普通结束进程
    buffer=     sizeof=4
    +00 DWORD ProcessId
0x222008
    穿透NtDeleteKey
    buffer=     sizeof=8
    +00 NTSTATUS status     out
    +04 HANDLE  KeyHandle   in
0x22200C
    穿透NtDeleteValueKey        成员含义见NtDeleteValueKey
    buffer=     sizeof=0xC
    +00 NTSTATUS status     out
    +04 HANDLE  KeyHandle   in
    +08 PUNICODE_STRING ValueName   in
0x222010
    通过进程id或进程对象名(只能选一)穿透打开进程NtOpenProcess   成员含义见NtOpenProcess
    buffer=     sizeof=0x18
    +00 NTSTATUS status     out
    +04 HANDLE ProcessHandle    out
    +08 ACCESS_MASK DesiredAccess in
    +0C POBJECT_ATTRIBUTES ObjectAttributes in
    +10 PCLIENT_ID ClientId
0x222404
    普通关闭句柄NtClose
    buffer=     sizeof=8
    +00 NTSTATUS status     out
    +04 HANDLE Handle   in
0x222408
    穿透创建注册表项NtCreateKey         成员含义见NtCreateKey
    buffer=     sizeof=0x20
    +00 HANDLE  KeyHandle   out
    +04 NTSTATUS status     out     注意status不是第一成员了!!
    +08 ULONG Disposition   out
    +0C ACCESS_MASK DesiredAccess   in
    +10 POBJECT_ATTRIBUTES ObjectAttributes in
    +14 ULONG TitleIndex    in
    +18 PUNICODE_STRING Class   in
    +1C ULONG CreateOptions in
0x22240C
    穿透打开注册表项NtOpenKey           成员含义见NtOpenKey
    buffer=     sizeof=0x10
    +00 HANDLE  KeyHandle   out
    +04 NTSTATUS status     out     注意status不是第一成员了!!
    +08 ACCESS_MASK DesiredAccess   in
    +0C POBJECT_ATTRIBUTES ObjectAttributes in
0x222410
    同0x222008  NtDeleteKey
	buffer=		sizeof=8
	+00	NTSTATUS status
	+04	HANDLE KeyHandle
0x222414
    穿透删除注册表项NtDeleteValueKey	成员含义见NtDeleteValueKey
	buffer=		sizeof=0xC
	+00	NTSTATUS status     out 
	+04	HANDLE  KeyHandle   in
	+08	PUNICODE_STRING ValueName	in
0x222418
    穿透设置注册表项NtSetValueKeyEx     成员含义见NtSetValueKey
    buffer=     sizeof=0x1C
    +00 NTSTATUS status     out 
    +04 HANDLE  KeyHandle   in
    +08 PUNICODE_STRING ValueName	in
    +0C ULONG TitleIndex	未使用
    +10 ULONG   Type	in
    +14 PVOID   Data	in
    +18 ULONG   DataSize	in
0x22241C
    穿透设置注册表项NtQueryValueKey     成员含义见NtQueryValueKey
    buffer=     sizeof=0x1C
    +00 DWORD ResultLength  out
    +04 NTSTATUS status     out     注意status不是第一成员了!!
    +08 HANDLE  KeyHandle   in
    +0C PUNICODE_STRING ValueName
    +10 ULONG Type          out     KeyValueInformation->DataLength
    +14 PVOID Data          out     KeyValueInformation->Data
    +18 ULONG DataLength    out     KeyValueInformation->DataLength
0x222420
    穿透枚举注册表项NtEnumerateKey      成员含义见NtEnumerateKey
    buffer=     sizeof=0x1C
    +00 NTSTATUS status     out
    +04 DWORD ResultLength  out
    +08 HANDLE KeyHandle        in
    +0C ULONG Index             in
    +10 KEY_INFORMATION_CLASS KeyInformationClass   in
    +14 PVOID KeyInformation    in
    +18 ULONG Length
0x222424
    NtEnumerateValueKey     成员含义见NtEnumerateValueKey
    buffer=		sizeof=0x1C
    +00 NTSTATUS status     out
    +04 ULONG ResultLength  out
    +08 HANDLE KeyHandle    in
    +0C ULONG Index     in
    +10 KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass    in
    +14 PVOID KeyValueInformation   out
    +18 ULONG Length    in
0x222428
    TsSysKit驱动是否初始化
    *(DWORD*)buffer => SomeFlag
    *(DWORD*)buffer <= IsTsSysKitInit 
0x22242C
    穿透创建服务加载驱动
    buffer=     sizeof=0x91C
    +000    WCHAR ImagePath[260] 驱动文件路径
    +208    DWORD Type  驱动注册表Type项
    +20C    DWORD Start 驱动注册表项Start类型
    +210    DWORD flag  (决定是否设置注册表Tag和Group信息)
    +214    ???
    +468    DWORD Tag 驱动注册表Tag项
    +46C    WCHAR DisplayName[300] 驱动注册表项DisplayName
    +6C4    WCHAR ServiceName[300] 驱动服务名
0x222430
    获取操作系统版本
    buffer=RTL_OSVERSIONINFOEXW     sizeof=0x11C
0x222800
0x222804
    2个初始化TSSysKit的通道
0x224008
	+00	DWORD Tag=0x20120502
	+04	DWORD =0
0x22400C
	穿透创建文件
	Buffer=	sizeof=0x30	具体参数含义见NtCreateFile
	+00	NTSTATUS status     out
	+04	PHANDLE FileHandle 
	+08	ACCESS_MASK DesiredAccess 
	+0C	POBJECT_ATTRIBUTES ObjectAttributes 
	+10	PIO_STATUS_BLOCK IoStatusBloc
	+14	PLARGE_INTEGER AllocationSize 
	+18	ULONG FileAttributes
	+1C	ULONG ShareAccess
	+20	ULONG CreateDisposition
	+24	ULONG CreateOptions
	+28	PVOID EaBuffer 
	+2C	ULONG EaLength 
0x224010
	穿透打开文件
	Buffer=	sizeof=0x1C 	具体参数含义见NtOpenFile
	+00	NTSTATUS status     out
	+04	PHANDLE FileHandle
	+08	PHANDLE FileHandle
	+0C	POBJECT_ATTRIBUTES ObjectAttributes
	+10	PIO_STATUS_BLOCK IoStatusBlock
	+14	ULONG ShareAccess
	+18	ULONG OpenOptions
0x224014
	穿透读取文件
	Buffer=	sizeof=0x28		具体参数含义见NtReadFile
	+00	NTSTATUS status     out
	+04	HANDLE FileHandle	in
	+08	HANDLE Event		in
	+0C	PIO_APC_ROUTINE ApcRoutine	in
	+10	PVOID ApcContext			in
	+14	PIO_STATUS_BLOCK IoStatusBlock	in
	+18	PVOID Buffer		out
	+1C	ULONG Length		in
	+20	PLARGE_INTEGER ByteOffset	
	+24	PULONG Key
0x224018
	穿透写入文件
	Buffer=	sizeof=0x28		具体参数含义见NtWriteFile
	+00	NTSTATUS status     out
	+04	HANDLE FileHandle	in
	+08	HANDLE Event		in
	+0C	PIO_APC_ROUTINE ApcRoutine	in
	+10	PVOID ApcContext			in
	+14	PIO_STATUS_BLOCK IoStatusBlock	in
	+18	PVOID Buffer		out
	+1C	ULONG Length		in
	+20	PLARGE_INTEGER ByteOffset	
	+24	PULONG Key
0x22401C
    普通关闭句柄NtClose
    buffer=     sizeof=8
    +00 NTSTATUS status     out
    +04 HANDLE Handle   in
0x224020
	穿透设置文件
	Buffer=	sizeof=0x1C       具体参数含义见NtSetInformationFile
	+00	NTSTATUS status;
	+04	HANDLE FileHandle			in
	+08	PIO_STATUS_BLOCK IoStatus		out	
	+0C	PVOID FileInformation		in
	+10	ULONG Length			in
	+14	FILE_INFORMATION_CLASS FileInformationClass	in
	+18	BOOL DelCurrentFile		in
0x224024
	穿透查询文件
	Buffer=	sizeof=0x1C       具体参数含义见NtQueryInformationFile
	+00	NTSTATUS status				out
	+04	HANDLE FileHandle			in
	+08	PIO_STATUS_BLOCK IoStatus		out	
	+0C	PVOID FileInformation		in
	+10	ULONG Length			in
	+14	FILE_INFORMATION_CLASS FileInformationClass	in
	+18	BOOL DelCurrentFile		in
0x224028
	尚未实现
0x22402C
	穿透查询目录
	Buffer=	sizeof=0x30	具体参数含义见NtQueryDirectoryFile
	+00	NTSTATUS status		out
	+04	HANDLE FileHandle	in
	+08	HANDLE Event		in
	+0C 	PIO_APC_ROUTINE ApcRoutine	未使用
	+10	PVOID ApcContext	未使用
	+14 	PIO_STATUS_BLOCK IoStatus		out
	+18	PVOID FileInformation	in
	+1C	ULONG Length		in
	+20	FILE_INFORMATION_CLASS FileInformationClass	in
	+24	BOOLEAN ReturnSingleEntry		in
	+28	PUNICODE_STRING FileName	in
	+2C	BOOLEAN RestartScan	in
0x228404
	穿透查询文件属性
	Buffer=	sizeof=0xC		具体参数含义见NtQueryAttributesFile
	+0	NTSTATUS status		out
	+4	POBJECT_ATTRIBUTES ObjectAttributes		in			路径前缀匹配\??\c:
	+8	FILE_NETWORK_OPEN_INFORMATION networkInformation	out
0x221C00解锁文件
	见3.13 解锁文件
0x222004
	普通结束进程
0x22242C
	穿透创建服务加载驱动
BOOLEAN TerminateProcessById(HANDLE ProcessId)
{
	BOOLEAN Result = FALSE;
	PEPROCESS Process = NULL;
	HANDLE ProcessHandle = NULL;
	if(NT_SUCCESS(PsLookupProcessByProcessId(ProcessId,&Process)) &&
		NT_SUCCESS(ObOpenObjectByPointer(Process,0,NULL,PROCESS_ALL_ACCESS,NULL,KernelMode,&ProcessHandle)) &&
		NT_SUCCESS(ZwTerminateProcess(ProcessHandle,0)))
	{
		Result = TRUE;
	}
	if(Process)
	{
		ObDereferenceObject(Process);
		Process = NULL;
	}
	if(ProcessHandle)
		ZwClose(ProcessHandle);
	return Result;
}
struct LOADDRIVERSTRUCT
{
	WCHAR ImagePath[260]; //驱动文件路径
	DWORD Type;  //驱动注册表Type项
	DWORD Start; //驱动注册表项Start类型
	WCHAR Group[300];//驱动注册表Group名
	DWORD Tag; //驱动注册表Tag项
	WCHAR DisplayName[300]; //驱动注册表项DisplayName
	WCHAR ServiceName[300]; //驱动服务名
};

#define MakeUnicodeString(X) {sizeof(X),sizeof(X)+2,X}
UNICODE_STRING UImagePath=MakeUnicodeString(L"ImagePath");
UNICODE_STRING UType=MakeUnicodeString(L"Type");
UNICODE_STRING UStart=MakeUnicodeString(L"Start");
UNICODE_STRING UGroup=MakeUnicodeString(L"Group");
UNICODE_STRING UDisplayName=MakeUnicodeString(L"DisplayName");
UNICODE_STRING UErrorControl=MakeUnicodeString(L"ErrorControl");
UNICODE_STRING UTag=MakeUnicodeString(L"Tag");
UNICODE_STRING UZwLoadDriver=MakeUnicodeString(L"ZwLoadDriver");

struct LOADDRIVERPARAM
{
	WORK_QUEUE_ITEM WorkItem;
	KEVENT Event;
	ULONG mem1;
	PUNICODE_STRING DriverServiceName;
	NTSTATUS Status;
};

void LoadDriverWorker(LOADDRIVERPARAM* WorkItem)
{
	NTSTATUS status = STATUS_UNSUCCESSFUL,outstatus;
	HANDLE KeyHandle = NULL;
	OBJECT_ATTRIBUTES Oa;
	if(WorkItem)
	{
		InitializeObjectAttributes(&Oa,WorkItem->DriverServiceName,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);
		status = NtOpenKey(&KeyHandle,KEY_READ,&Oa);//穿透
		if(NT_SUCCESS(status))
		{//xp win7的IopLoadDriver 为不同的调用方式
			if(VersionInfo < WINVISTA)
			{//NTSTATUS __stdcall IopLoadDriver(HANDLE KeyHandle, BOOLEAN CheckForSafeBoot, BOOLEAN IsFilter, NTSTATUS *DriverEntryStatus)
				IopLoadDriver(KeyHandle,HANDLE_FLAG_INHERIT,FALSE,&outstatus);
				if(status == STATUS_FAILED_DRIVER_ENTRY)
					status = outstatus;
				else if(status == STATUS_DRIVER_FAILED_PRIOR_UNLOAD)
					status = STATUS_OBJECT_NAME_NOT_FOUND;
			}
			else
			{//NTSTATUS __userpurge IopLoadDriver<eax>(HANDLE KeyHandle<ecx>, BOOLEAN CheckForSafeBoot, BOOLEAN IsFilter, NTSTATUS *DriverEntryStatus)  第一参用ecx传值

				status = IopLoadDriver(KeyHandle,HANDLE_FLAG_INHERIT,FALSE,&outstatus);////事先获取的函数指针,见1.1
			}
		}
	}
	WorkItem->Status = status;
	KeSetEvent(WorkItem->Event,0,FALSE);
}

NTSTATUS LoadDriverEx(PUNICODE_STRING DriverServiceName)
{
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	LOADDRIVERPARAM LoadDriver;
	if(IopLoadDriver)//事先获取的函数指针,见1.1
	{
		LoadDriver.DriverServiceName = DriverServiceName;
		LoadDriver.mem1 = 0;
		KeInitializeEvent(&LoadDriver.Event,NotificationEvent,FALSE);
		ExInitializeWorkItem(&LoadDriver,LoadDriverWorker,&LoadDriver);
		ExQueueWorkItem(&LoadDriver.WorkItem,DelayedWorkQueue);
		KeWaitForSingleObject(&LoadDriver.Event,UserRequest,KernelMode,FALSE,NULL);
		return LoadDriver.Status;
	}
	else
	{
		FARPROC ZwLoadDriver = MmGetSystemRoutineAddress(&UZwLoadDriver);
		if(ZwLoadDriver)
			return ZwLoadDriver(DriverServiceName);
	}
	return status;
}

NTSTATUS CreateServiceAndLoadDriver(DWORD InLen,LOADDRIVERSTRUCT* Data)
{//InLen = IrpSp->Parameters.DeviceIoControl.InputBufferLength
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	UNICODE_STRING DriverServicePath;
	UNICODE_STRING ServiceName;
	OBJECT_ATTRIBUTES Oa;
	WCHAR* Buf = NULL;
	HANDLE KeyHandle = NULL;
	const int BufLen = 520;
	ULONG ErrorControl = SERVICE_ERROR_NORMAL;
	ULONG Disposition = REG_OPENED_EXISTING_KEY;
	if(!SeSinglePrivilegeCheck(SE_LOAD_DRIVER_PRIVILEGE,UserMode))
		return STATUS_PRIVILEGE_NOT_HELD;
	if(VersionInfo < WINXP)
		return STATUS_NOT_SUPPORTED;
	if((Data->Type & SERVICE_DRIVER) && Data->ServiceName && Data->ImagePath && Data->DisplayName)
	{
		RtlInitUnicodeString(&ServiceName,Data->ServiceName);
		Buf = (WCHAR*)ExAllocatePool(NonPagedPool,BufLen);
		RtlZeroMemory(Buf,BufLen);
		wcscpy(Buf,L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
		DriverServicePath.Length = 2*wcslen(Buf);
		DriverServicePath.MaximumLength = BufLen;
		DriverServicePath.Buffer = Buf;
		status = RtlAppendUnicodeStringToString(&DriverServicePath, &ServiceName);
		if(NT_SUCCESS(status))
		{
			InitializeObjectAttributes(&Oa,&DriverServicePath,OBJ_CASE_INSENSITIVE,NULL,NULL);
			status = ZwCreateKey(&KeyHandle,KEY_READ|KEY_SET_VALUE, &Oa, 0,NULL, 0, &Disposition);//穿透
		}
		if(NT_SUCCESS(status))
		{
			status = ZwSetValueKeyEx(KeyHandle,&UImagePath,REG_SZ,Data->ImagePath,2*wcslen(Data->ImagePath)+2);//穿透
		}
		if(NT_SUCCESS(status))
		{
			status = ZwSetValueKeyEx(KeyHandle,&UType,REG_DWORD,Data->Type,sizeof(DWORD));
		}
		if(NT_SUCCESS(status))
		{
			status = ZwSetValueKeyEx(KeyHandle,&UStart,REG_DWORD,Data->Start,sizeof(DWORD));
		}
		if(NT_SUCCESS(status))
		{
			status = ZwSetValueKeyEx(KeyHandle,&UDisplayName,REG_SZ,Data->DisplayName,2*wcslen(Data->DisplayName)+2);
		}
		if(NT_SUCCESS(status))
		{//此处q管源码有bug
			status = ZwSetValueKeyEx(KeyHandle,&UGroup,REG_SZ,Data->Group,2*wcslen(Data->Group)+2);
		}
		if(NT_SUCCESS(status))
		{
			status = ZwSetValueKeyEx(KeyHandle,&UTag,REG_DWORD,Data->Tag,sizeof(DWORD));
		}
		if(NT_SUCCESS(status))
		{
			status = ZwSetValueKeyEx(KeyHandle,&UErrorControl,REG_DWORD,ErrorControl,sizeof(DWORD));
		}
		if(NT_SUCCESS(status))
		{
			ZwFlushKey(KeyHandle);
			status = LoadDriverEx(&DriverServicePath);
		}
	}
	if(KeyHandle)
	{
		ZwClose(KeyHandle);
		KeyHandle = NULL;
	}
	if(Buf)
		ExFreePool(Buf);
}

TSSysKit x64 IoControlCode对应表

0x22200C
	穿透创建文件
	Buffer=	sizeof=0x50	具体参数含义见NtCreateFile
	+00	NTSTATUS status     out
	+08	PHANDLE FileHandle 
	+10	ACCESS_MASK DesiredAccess 
	+18	POBJECT_ATTRIBUTES ObjectAttributes 
	+20	PIO_STATUS_BLOCK IoStatusBloc
	+28	PLARGE_INTEGER AllocationSize 
	+30	ULONG FileAttributes
	+34	ULONG ShareAccess
	+38	ULONG CreateDisposition
	+3C	ULONG CreateOptions
	+40	PVOID EaBuffer 
	+48	ULONG EaLength 
0x222010
	穿透打开文件
	Buffer=	sizeof=0x30 	具体参数含义见NtOpenFile
	+00	NTSTATUS status     out
	+08	PHANDLE FileHandle
	+10	PHANDLE FileHandle
	+18	POBJECT_ATTRIBUTES ObjectAttributes
	+20	PIO_STATUS_BLOCK IoStatusBlock
	+28	ULONG ShareAccess
	+2C	ULONG OpenOptions
0x222014
	穿透读取文件
	Buffer=	sizeof=0x50		具体参数含义见NtReadFile
	+00	NTSTATUS status     out
	+08	HANDLE FileHandle	in
	+10	HANDLE Event		in
	+18	PIO_APC_ROUTINE ApcRoutine	in
	+20	PVOID ApcContext			in
	+28	PIO_STATUS_BLOCK IoStatusBlock	in
	+30	PVOID Buffer		out
	+38	ULONG Length		in
	+40	PLARGE_INTEGER ByteOffset	
	+48	PULONG Key
0x222018
	穿透写入文件
	Buffer=	sizeof=0x50		具体参数含义见NtWriteFile
	+00	NTSTATUS status     out
	+08	HANDLE FileHandle	in
	+10	HANDLE Event		in
	+18	PIO_APC_ROUTINE ApcRoutine	in
	+20	PVOID ApcContext			in
	+28	PIO_STATUS_BLOCK IoStatusBlock	in
	+30	PVOID Buffer		out
	+38	ULONG Length		in
	+40	PLARGE_INTEGER ByteOffset	
	+48	PULONG Key
0x22201C
    普通关闭句柄NtClose
    buffer=     sizeof=0x10
    +00 NTSTATUS status     out
    +04 HANDLE Handle   in
0x222020
	穿透设置文件
	Buffer=	sizeof=0x30       具体参数含义见NtSetInformationFile
	+00	NTSTATUS status;
	+08	HANDLE FileHandle			in
	+10	PIO_STATUS_BLOCK IoStatus		out	
	+18	PVOID FileInformation		in
	+20	ULONG Length			in
	+24	FILE_INFORMATION_CLASS FileInformationClass	in
	+28	BOOL DelCurrentFile		in
0x222024
	穿透查询文件
	Buffer=	sizeof=0x30       具体参数含义见NtQueryInformationFile
	+00	NTSTATUS status				out
	+08	HANDLE FileHandle			in
	+10	PIO_STATUS_BLOCK IoStatus		out	
	+18	PVOID FileInformation		in
	+20	ULONG Length			in
	+24	FILE_INFORMATION_CLASS FileInformationClass	in
	+28	BOOL DelCurrentFile		in
0x222028
	尚未实现
0x22202C	
	穿透查询目录
	Buffer=	sizeof=0x58	具体参数含义见NtQueryDirectoryFile
	+00	NTSTATUS status		out
	+08	HANDLE FileHandle	in
	+10	HANDLE Event		in
	+18 	PIO_APC_ROUTINE ApcRoutine	未使用
	+20	PVOID ApcContext	未使用
	+28 	PIO_STATUS_BLOCK IoStatus		out
	+30	PVOID FileInformation	in
	+38	ULONG Length		in
	+3C	FILE_INFORMATION_CLASS FileInformationClass	in
	+40	BOOLEAN ReturnSingleEntry		in
	+48	PUNICODE_STRING FileName	in
	+50	BOOLEAN RestartScan	in
0x222030
	获取内部版本号
	buffer=		sizeof=8
	+0	<=	0x20110929i64
0x222034	
	穿透查询文件属性
	Buffer=	sizeof=0x18		具体参数含义见NtQueryAttributesFile
	+00	NTSTATUS status		out
	+08	POBJECT_ATTRIBUTES ObjectAttributes		in			路径前缀匹配\??\c:
	+10	FILE_NETWORK_OPEN_INFORMATION networkInformation	out
0x222038	
    解锁文件
    buffer=     sizeof=0x804
    +00 NTSTATUS status     out
    +04 WCHAR FileName[1024]    in
0x222144
	普通关闭句柄NtClose
    buffer=     sizeof=0x10
    +00 NTSTATUS	status out
    +08 HANDLE		Handle in
0x222148
    穿透创建注册表项NtCreateKey         成员含义见NtCreateKey
    buffer=     sizeof=0x20
    +00 HANDLE  KeyHandle   out
    +04 NTSTATUS status     out     注意status不是第一成员了!!
    +08 ULONG Disposition   out
    +0C ACCESS_MASK DesiredAccess   in
    +10 POBJECT_ATTRIBUTES ObjectAttributes in
    +14 ULONG TitleIndex    in
    +18 PUNICODE_STRING Class   in
    +1C ULONG CreateOptions in
0x22214C
    穿透打开注册表项NtOpenKey           成员含义见NtOpenKey
    buffer=     sizeof=0x20
    +00 HANDLE  KeyHandle   out
    +08 NTSTATUS status     out     注意status不是第一成员了!!
    +10 ACCESS_MASK DesiredAccess   in
    +18 POBJECT_ATTRIBUTES ObjectAttributes in
0x222150
	穿透删除注册表项NtDeleteKey			成员含义见NtDeleteKey
	buffer=		sizeof=0x10
	+00	NTSTATUS status
	+08	HANDLE KeyHandle
0x222154
    穿透删除注册表项NtDeleteValueKey	成员含义见NtDeleteValueKey
	buffer=		sizeof=0x18
	+00	NTSTATUS status     out 
	+08	HANDLE  KeyHandle   in
	+10	PUNICODE_STRING ValueName	in
0x222158
	穿透设置注册表项NtSetValueKeyEx     成员含义见NtSetValueKey
    buffer=     sizeof=0x30
    +00 NTSTATUS status     out 
    +08 HANDLE  KeyHandle   in
    +10 PUNICODE_STRING ValueName	in
    +18 ULONG TitleIndex	未使用
    +1C ULONG   Type	in
    +20 PVOID   Data	in
    +28 ULONG   DataSize	in
0x22215C
    穿透设置注册表项NtQueryValueKey     成员含义见NtQueryValueKey
    buffer=     sizeof=0x30
    +00 DWORD ResultLength  out
    +04 NTSTATUS status     out     注意status不是第一成员了!!
    +08 HANDLE  KeyHandle   in
    +10 PUNICODE_STRING ValueName
    +18 ULONG Type          out     KeyValueInformation->DataLength
    +20 PVOID Data          out     KeyValueInformation->Data
    +28 ULONG DataLength    out     KeyValueInformation->DataLength
0x222160
	穿透枚举注册表项NtEnumerateKey      成员含义见NtEnumerateKey
	buffer=		sizeof=0x28
    +00 NTSTATUS status     out
    +04 ULONG ResultLength  out
    +08 HANDLE KeyHandle    in
    +10 ULONG Index     in
    +14 KEY_INFORMATION_CLASS KeyValueInformationClass    in
    +18 PVOID KeyInformation   out
    +20 ULONG Length    in
0x222164
    穿透枚举注册表项NtEnumerateValueKey     成员含义见NtEnumerateValueKey
    buffer=		sizeof=0x28
    +00 NTSTATUS status     out
    +04 ULONG ResultLength  out
    +08 HANDLE KeyHandle    in
    +10 ULONG Index     in
    +14 KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass    in
    +18 PVOID KeyValueInformation   out
    +20 ULONG Length    in
0x222284
    通过进程id或进程对象名(只能选一)穿透打开进程NtOpenProcess   成员含义见NtOpenProcess
    buffer=     sizeof=0x30
    +00 NTSTATUS status     out
    +08 HANDLE ProcessHandle    out
    +10 ACCESS_MASK DesiredAccess in
    +18 POBJECT_ATTRIBUTES ObjectAttributes in
    +20 PCLIENT_ID ClientId
0x222288
	buffer=     sizeof=4
    +00 DWORD ProcessId
0x222430
    获取操作系统版本
    buffer=RTL_OSVERSIONINFOEXW     sizeof=0x11C
0x222800
0x222804
    2个初始化TSSysKit的通道
0x222808
	获取CPUID信息
	buffer=		sizeof=0x38
	+00	ULONG Fn0000_0000_EBX	EBX EDX ECX 组成"GenuineIntel"或"AuthenticAMD"
	+04	ULONG Fn0000_0000_EDX
	+08 ULONG Fn0000_0000_ECX
	+10	ULONG CpuType   0:未知    1:INTEL    2:AMD
	+14	BOOLEAN VMBit	是否支持vm   Intel Virutalization Technology / AMD Secure Virtual Machine
	+18	ULONGLONG MSR3A  Intel  IA32_FEATURE_CONTROL   MSR(0x3A)  / AMD Read NX support 
	+20	ULONGLONG  NXsupport        Intel CR4  / AMD Msr(0xC0000080)
	+28 ULONGLONG VMXONBit  Intel MSR(0x3A) activate VMXON outside of SMX mode  /  AMD Msr(0xC0010114)
	+30	ULONG NRIP    Fn8000_000A_EDX&4

默认派遣例程

IRP_MJ_CREATE

  • 检查当前所属进程是否有腾讯标记 (CheckDriverLoaderValid)
  • 重置驱动注册表项信息 (ResetRegServiceInfo)
  • 随机化EPROCESS的ImageFileName(RandomImageNameToHide)

根据进程id结束进程

void TerminateProcessById(HANDLE ProcessId)
{
	PEPROCESS Process = NULL;
	HANDLE ProcessHandle = NULL;
	NTSTATUS status = PsLookupProcessByProcessId(ProcessId,&Process);
	if(NT_SUCCESS(status))
	{
		status = ObOpenObjectByPointer(Process,0,NULL,PROCESS_ALL_ACCESS,0,NULL,&ProcessHandle);
		if(NT_SUCCESS(status))
		{
			status = ZwTerminateProcess(ProcessHandle,0);
		}
	}
	if(Process)
	{
		ObDereferenceObject(Process);
		Process = NULL;
	}
	if(ProcessHandle)
		ZwClose(ProcessHandle);

检测PE格式合法性

bool CheckNtImageValid(LPVOID ImageAddress)
{
	if(ImageAddress && MmIsAddressValid(ImageAddress))
	{
		PIMAGE_DOS_HEADER DosHeader = (IMAGE_DOS_HEADER)ImageAddress;
		if(MmIsAddressValid(&DosHeader->e_lfanew) && DosHeader->e_magic == 'ZM')
		{
			PIMAGE_NT_HEADERS NtHeader = (PIMAGE_NT_HEADERS)((BYTE*)DosHeader + DosHeader->e_lfanew);
			if(NtHeader && MmIsAddressValid(NtHeader) && NtHeader->Signature == 'EP')
				return true;
		}
	}
}

获取当前进程进程名

typedef ULONG DWORD;
typedef struct _MEMORY_BASIC_INFORMATION 
{
	PVOID BaseAddress;
	PVOID AllocationBase;
	DWORD AllocationProtect;
	SIZE_T RegionSize;
	DWORD State;
	DWORD Protect;
	DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
typedef struct _MEMORY_SECTION_NAME
{
	UNICODE_STRING SectionFileName;
	WCHAR NameBuffer[0];
} MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;

extern "C" PVOID __stdcall PsGetProcessSectionBaseAddress(PEPROCESS Process);
extern "C" NTSTATUS __stdcall ZwQueryVirtualMemory(HANDLE ProcessHandle,PVOID BaseAddress,MEMORY_INFORMATION_CLASS MemoryInformationClass,
	PVOID MemoryInformation,SIZE_T MemoryInformationLength,PSIZE_T ReturnLength);
#define MEM_IMAGE 0x1000000 

bool GetCurrentProcessName(PVOID Buffer,SIZE_T Length)
 {
	 NTSTATUS status;
	if(!Buffer || !Length)
		return;
	UNICODE_STRING UIoVolumeDeviceToDosName;
	PVOID ImageBase = PsGetProcessSectionBaseAddress(IoGetCurrentProcess());
	PVOID SectionName = ExAllocatePool(NonPagedPool,Length + sizeof(MEMORY_SECTION_NAME));
	if(!SectionName)
		return;
	if(ImageBase)
	{
		MEMORY_BASIC_INFORMATION BasicInfo;
		status = ZwQueryVirtualMemory(NtCurrentProcess(),ImageBase,MemoryBasicInformation,&BasicInfo,sizeof(BasicInfo),NULL);
		if(NT_SUCCESS(status) && BasicInfo.Type == MEM_IMAGE)
		{
			status = ZwQueryVirtualMemory(NtCurrentProcess(),ImageBase,MemorySectionName,SectionName,Length + sizeof(MEMORY_SECTION_NAME),NULL);
			if(NT_SUCCESS(status))
			{
				wcsncpy((WCHAR*)Buffer,((PMEMORY_SECTION_NAME)SectionName)->SectionFileName.Buffer,Length);
				return true;
			}
		}
	}
	return false;
}

由进程ID获取进程设备名

bool GetProcessNameById(HANDLE ProcessId,PVOID Buffer,SIZE_T Length)
{
	NTSTATUS status;
	if(ProcessId == (HANDLE)4)
	{
		wcsncpy((WCHAR*)Buffer,L"System",Length);
	}
	else if(ProcessId == PsGetCurrentProcessId())
	{
		GetCurrentProcessName(Buffer,Length);
	}
	else
	{
		PEPROCESS Process = NULL;
		if(NT_SUCCESS(PsLookupProcessByProcessId(ProcessId,&Process)))
		{
			KAPC_STATE KApc;
			KeStackAttachProcess(Process,&KApc);
			GetCurrentProcessName(Buffer,Length);
			KeUnstackDetachProcess(&KApc);
			ObDereferenceObject(&Process);
		}
		
	}
	return true;
}

设备名转DOS路径

NTSTATUS GetDeviceDosName(WCHAR* DeviceName,WCHAR* DosName,DWORD Len)
{
	NTSTATUS status;
	//检查设备路径
	if(!DeviceName || !DosName)
		return STATUS_INVALID_PARAMETER;
	if(wcsnicmp(DeviceName, L"\\Device\\", 8u))
		return STATUS_INVALID_PARAMETER_1;
	WCHAR* ptr = wcsstr(DeviceName + 8,L"\\");
	if(!ptr)
		return STATUS_UNSUCCESSFUL;
	int len = ptr - DeviceName;
	PVOID Buffer = ExAllocatePool(NonPagedPool,2*len+2);
	if(!Buffer)
		return;
	wcsncpy((WCHAR*)Buffer,DeviceName,len);
	//根据设备名获取设备对象
	PDEVICE_OBJECT DeviceObject;
	UNICODE_STRING UDeviceName;
	PFILE_OBJECT FileObject;
	RtlInitUnicodeString(&UDeviceName,(WCHAR*)Buffer);
	//GetDeviceObjectByName
	status = IoGetDeviceObjectPointer(&UDeviceName,0,&FileObject,&DeviceObject);
	if(NT_SUCCESS(status))
	{
		if(DeviceObject->Type == FILE_DEVICE_DISK)
		{
			UNICODE_STRING RootDeviceDosName;
			status = IoVolumeDeviceToDosName(DeviceObject,&RootDeviceDosName);
			if(NT_SUCCESS(status))
			{
				wcsncpy(DosName,RootDeviceDosName.Buffer,RootDeviceDosName.Length);
				ExFreePool(RootDeviceDosName.Buffer);
				int len2 = wcslen((WCHAR*)Buffer);//拼接全路径
				wcsncat(DosName,DeviceName+len2,Len);
			}
		}
		else if(DeviceObject->Type == FILE_DEVICE_NETWORK_FILE_SYSTEM)
		{
			wcsncpy(DosName,L"\\",Len);
			int len2 = wcslen((WCHAR*)Buffer);
			wcsncat(DosName,DeviceName+len2,Len);
		}
		else
		{
			status = STATUS_DEVICE_DATA_ERROR;
		}
		ObReferenceObject(FileObject);
		ObReferenceObject(DeviceObject);
	}
	ExFreePool(Buffer);
}

得到EPROCESS对应ImageDosPath

void GetProcessDosPathByObject(PEPROCESS Process,LPVOID Buffer,ULONG Len)
{
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	HANDLE ProcessHandle = NULL;
	HANDLE FileHandle = NULL;
	const int FileBufSize = 4096;
	PUNICODE_STRING pFilePath = ExAllocatePoolWithTag(NonPagedPool,FileBufSize);
	if(!pFilePath)
		return;
	status = ObOpenObjectByPointer(Process,OBJ_KERNEL_HANDLE,NULL,0,NULL,KernelMode,&ProcessHandle);
	if(NT_SUCCESS(status))
	{
		status = NtQueryInformationProcess(ProcessHandle,ProcessImageFileName,pFilePath,FileBufSize,NULL);
		if(NT_SUCCESS(status) && MmIsAddressValid(pFilePath->Buffer))
		{
			OBJECT_ATTRIBUTES oa;
			IO_STATUS_BLOCK IoStatusBlock;
			InitializeObjectAttributes(&oa,pFilePath,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
			status = IoCreateFile(&FileHandle,GENERIC_READ | SYNCHRONIZE,&oa,&IoStatusBlock,NULL,FILE_ATTRIBUTE_NORMAL,
				FILE_SHARE_READ,FILE_OPEN,FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,NULL,0,CreateFileTypeNone,
				NULL,IO_NO_PARAMETER_CHECKING);
			if(NT_SUCCESS(status))
			{// GetProcessDosPathByHandle
				OBJECT_HANDLE_INFORMATION HandleInformation;
				PFILE_OBJECT FileObject = NULL;
				UNICODE_STRING DriveDosName = {0};
				status = ObReferenceObjectByHandle(FileHandle,0,NULL,KernelMode,(PVOID*)&FileObject,&HandleInformation);
				if(NT_SUCCESS(status) && FileObject != NULL && MmIsAddressValid(FileObject) && MmIsAddressValid(FileObject->FileName.Buffer))
				{
					if(IoGetRelatedDeviceObject(FileObject))
					{
						status = RtlVolumeDeviceToDosName(FileObject->DeviceObject,&DriveDosName);//获取盘符
						if(NT_SUCCESS(status) && DriveDosName.Buffer && DriveDosName.Length + FileObject->FileName.Length < Len)
						{
							memcpy(Buffer,DriveDosName.Buffer,DriveDosName.Length);
							memcpy((char*)Buffer+DriveDosName.Length,FileObject->FileName.Buffer,FileObject->FileName.Length);
						}
					}
					ObDereferenceObject(FileObject);
					if(DriveDosName.Buffer)
						ExFreePool(DriveDosName.Buffer);
				}
			}
		}
	}

	if(FileHandle)
		NtClose(FileHandle);
	if(ProcessHandle)
		NtClose(ProcessHandle);
	ExFreePool(pFilePath);
}

随机化程序名机制

Void RandomImageNameToHide()
{
ANSI_STRING QQEXEA,IMAGENAMEA;
	char* ImageName;
	RtlInitAnsiString(&QQEXEA,"QQPCRTP.EXE");
	ImageName = PsGetProcessImageFileName(IoGetCurrentProcess());
	RtlInitAnsiString(&IMAGENAMEA,ImageName);
	if(!RtlCompareString(&IMAGENAMEA,&QQEXEA,TRUE))
	{
		LARGE_INTEGER Time,LocalTime;
		TIME_FIELDS TimeFields;
		KeQuerySystemTime(&Time);
		ExSystemTimeToLocalTime(&Time,&LocalTime);
		RtlTimeToTimeFields(&LocalTime,&TimeFields);
		ImageName[TimeFields.Second % 5] = (TimeFields.Second % 26) + 'A';
	}
}

根据进程文件名获取进程信息

Bool GetProcessInfoByFileName(char* FileName, PVOID Buffer,int Size)
{
	ULONG InfoLen;
	PVOID Modules;
	NTSTATUS status;
	BOOL Find = FALSE;
	ZwQuerySystemInformation(SystemModuleInformation,&InfoLen,0,&InfoLen);
	modules = ExAllocatePool(PagedPool,InfoLen);
	If(!modules)
		Return FALSE;
	status = ZwQuerySystemInformation(SystemModuleInformation, modules,InfoLen);
	If(NT_SUCCESS(status))
	{
		For(int i=0;i<modules-> NumberOfModules;i++)
		{
			Int offset = modules->Modules[i].OffsetToFileName;
			If(!stricmp(modules->Modules[i].FullPathName[offset],FileName)
			{
				Memcpy(Buffer, &modules->Modules[i],Size);
				Find = TRUE;
				Break;
			}
		}
	}
	ExFreePool(modules);
	Return FALSE;
}

两种方式调用内核函数:

// 法一:以ZwQueryVirtualMemory为例
UNICODE_STRING FuncName;
FARPROC fZwQueryVirtualMemory;
RtiInitUnicodeString(&FuncName, L”ZwQueryVirtualMemory”);
fZwQueryVirtualMemory = MmGetSystemRoutineAddress(&FuncName);

// 法二:
RTL_PROCESS_MODULE_INFORMATION ImageInfo;
RtlZeroMemory(&ImageInfo,sizeof(ImageInfo));
If(GetProcessInfoByFileName(“ntdll.dll”,&ImageInfo,sizeof(ImageInfo)))
NtQueryVirtualMemorySSDTIndex = GetSSDTApiIndex(ImageInfo.ImageBase,"NtQueryVirtualMemory");

// 用法:
ZwQueryVirtualMemoryEx(...)
{
	_asm
	{
		Push ebp
		Mov ebp,esp
		Mov eax, fZwQueryVirtualMemory
		Test eax,eax
		Jz $+3
		Pop ebp
		Jmp eax
		Cmp NtQueryVirtualMemorySSDTIndex,-1
		Jz $+6
		Pop ebp
		Jmp TAG
		Mov eax,C0000001h
		Pop ebp
		Retn 18h
TAG:
		Mov eax, NtQueryVirtualMemorySSDTIndex
		Lea edx,dword ptr [esp+4]
		Int 2Eh
		Retn 18h
	}
}

判断一段地址有效性

BOOLEAN CheckAddressValid(PVOID VirtualAddress, int Length)
{
	int result;
	if ( VirtualAddress )
		result = MmIsAddressValid(VirtualAddress) && MmIsAddressValid(VirtualAddress + Length);
	else
		result = 0;
	return result;
}

获取对象类型

POBJECT_TYPE GetTypeFromObject(PVOID Object)
{//从对象获取对象类型
	UNICODE_STRING UObGetObjectType;
	POBJECT_TYPE ObjectType;
	RtlInitUnicodeString(&UObGetObjectType,L"ObGetObjectType");
	PVOID ObGetObjectType = MmGetSystemRoutineAddress(&UObGetObjectType);
	if(ObGetObjectType)
	{
		ObjectType = ((POBJECT_TYPE (__stdcall*)(PVOID ))ObGetObjectType)(Object);
	}
	else//Vista以前
	{
		ObjectType = ((OBJECT_HEADER*)OBJECT_TO_OBJECT_HEADER(Object))->Type;
	}
}

检测腾讯程序合法性

  对当加载驱动的进程进行md5校验,如果校验失败则拒绝加载;从\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TSKSP\\InstallDir获取q管安装目录

void CheckTsFileValid(PEPROCESS Process)
{
	NTSTATUS status;
	const int BufSize = 522;
	WCHAR CurProcFileDosName[260];
	WCHAR* FileDosName = (WCHAR*)ExAllocatePool(NonPagedPool,BufSize);
	WCHAR* FileFullName = (WCHAR*)ExAllocatePool(NonPagedPool,520);
	if(FileDosName && FileFullName)
	{
		memset(FileDosName,0,BufSize);
		if(GetProcessDosPathByObject(Process,FileDosName,520))
		{
			status = GetProcessNameById(PsGetCurrentProcessId(),CurProcFileDosName,520);
			if(NT_SUCCESS(status) && !wcsicmp(CurProcFileDosName,FileDosName))
			{
				UNICODE_STRING UFileFullName;
				OBJECT_ATTRIBUTES oa;
				HANDLE FileHandle;
				IO_STATUS_BLOCK IoStatusBlock;
				RtlZeroMemory(FileFullName,520);
				wnsprintfW(FileFullName,259,L"\\??\\%ws",FileDosName);
				InitializeObjectAttributes(&oa,FileFullName,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
				status = IoCreateFile(&FileHandle,GENERIC_READ | SYNCHRONIZE,&oa,&IoStatusBlock,NULL,FILE_ATTRIBUTE_NORMAL,
					FILE_SHARE_READ,FILE_OPEN,FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,NULL,0,CreateFileTypeNone,
					NULL,IO_NO_PARAMETER_CHECKING);
				if(NT_SUCCESS(status))
				{
					FILE_STANDARD_INFORMATION FileInformation;
					status = ZwQueryInformationFile(FileHandle,&IoStatusBlock,&FileInformation,sizeof(FileInformation),FileStandardInformation);
					if(NT_SUCCESS(status) && FileInformation.EndOfFile.LowPart < 0xA00000)
					{
						PVOID Buffer = ExAllocatePool(NonPagedPool,FileInformation.EndOfFile.LowPart);
						if(Buffer)
						{
							status = ZwReadFile(FileHandle,NULL,NULL,NULL,&IoStatusBlock,Buffer,FileInformation.EndOfFile.LowPart,NULL,NULL);
							if(NT_SUCCESS(status) && CheckNtImageValid(Buffer))
							{
								ULONG SecretDataOffset = *(ULONG*)((PIMAGE_DOS_HEADER)Buffer)->e_res2;
								/************************************************************************/
								/* 下面将Buffer+SecretDataOffset处的128字节数据进行md5校验,原始数据如下*/
								// b8 92 77 ac 41 ee 20 b1-0d 0c ce d7 a2 95 b3 96
								// 46 3f 16 ba 72 4d b9 df-2c 2f a5 f9 d2 63 3c 35
								// 06 45 a2 dc bf 5c a7 6f-89 d5 45 e2 2b db 30 75
								// d3 76 93 84 9b fc e4 62-ed 21 d5 6a db 90 84 df
								// fc 1f ba 07 8d fd 7f 6d-f8 67 41 34 cc f3 e2 4a
								// 04 73 8b 8a f6 7c 2c d5-10 21 cf 25 80 18 fc be
								// 9f 5f c8 ea 47 c8 95 5a-79 07 be 54 9c 0d 12 36
								// 0c f6 9a e6 71 0d c1 27-29 c2 9d e8 7e f0 b7 05
								/************************************************************************/
								//.........................省略md5计算过程
							}
							ExFreePool(Buffer);
						}
					}
					ZwClose(FileHandle);
				}
			}
		}
	}
	if(FileDosName)
		ExFreePool(FileDosName);
	if(FileFullName)
		ExFreePool(FileFullName);
}

解锁文件

  设置文件属性为FILE_ATTRIBUTE_NORMAL;执行IopCloseFile IRP_MJ_LOCK_CONTROL IRP_MN_UNLOCK_ALL;从句柄表中找到所有文件对象,如果路径匹配则关闭句柄CmCloseHandle

typedef NTSTATUS EndSetFileAttributes ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context )
{
	Irp->UserIosb->Status = Irp->IoStatus.Status;
	Irp->UserIosb->Information = Irp->IoStatus.Information;
	KeSetEvent(Irp->UserEvent, 0, FALSE);
	IoFreeIrp(Irp);
	return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS ResetFileAttributes(HANDLE FileHandle)
{//设置文件属性为NORMAL
	NTSTATUS status;
	PDEVICE_OBJECT pDevObj = NULL;
	PIRP pIrp = NULL;
	KEVENT Event;
	IO_STATUS_BLOCK ios = {0};
	FILE_BASIC_INFORMATION BasicInfo;
	PIO_STACK_LOCATION IrpSp;
	status = ObReferenceObjectByHandle(FileHandle,0,*IoFileObjectType,KernelMode,&FileObject,NULL);
	if(NT_SUCCESS(status))
	{
		pDevObj = IoGetRelatedDeviceObject(FileObject);//穿透
		pIrp = IoAllocateIrp(pDevObj->StackSize,TRUE);
		if(pIrp)
		{
			KeInitializeEvent(&Event,SynchronizationEvent,FALSE);
			RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
			BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
			pIrp->AssociatedIrp.SystemBuffer = (PVOID)&BasicInfo;
			pIrp->UserEvent = &Event;
			pIrp->UserIosb = &ios;
			pIrp->Tail.Overlay.OriginalFileObject = FileObject;
			pIrp->Tail.Overlay.Thread = KeGetCurrentThread();
			pIrp->RequestorMode = 0;
			IrpSp = IoGetNextIrpStackLocation( pIrp );
			IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
			IrpSp->DeviceObject = pDevObj;
			IrpSp->FileObject = FileObject;
			IrpSp->Parameters.SetFile.Length = sizeof(BasicInfo);
			IrpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
			IrpSp->Parameters.SetFile.FileObject = FileObject;
			IrpSp->CompletionRoutine = EndSetFileAttributes;
			IrpSp->Context = NULL;
			IrpSp->Control = SL_INVOKE_ON_CANCEL|SL_INVOKE_ON_SUCCESS|SL_INVOKE_ON_ERROR;
			IoCallDriver(pDevObj,Irp);
			KeWaitForSingleObject(&Event,0,KernelMode,FALSE,NULL);
			ObDereferenceObject(FileObject);
		}
		else
		{
			status = STATUS_INSUFFICIENT_RESOURCES;
		}
	}
	if ( FileObject )
		ObDereferenceObject(FileObject);
	return status;
}

void UnlockFileThread(PVOID StartContext)
{//关闭系统对象句柄
	CmpSetHandleProtection(&Ohfi,FALSE);
	if(StartContext)
		NtClose(StartContext);
	PsTerminateSystemThread(0);
}

void TryUnlockFile(PFILE_OBJECT FileObject)
{//解锁文件
	SYSTEM_HANDLE_INFORMATION HandleInformation1;
	ULONG RetLen = 0;
	PVOID Buffer;
	ZwQuerySystemInformation(SystemHandleInformation,&HandleInformation1,sizeof(HandleInformation1),&RetLen);
	if(RetLen)
	{
		POBJECT_NAME_INFORMATION ObjectNameInfo1 = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool,2056);
		POBJECT_NAME_INFORMATION ObjectNameInfo2 = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool,2056);
		ObjectNameInfo1->Name.Length = 2048;
		ObjectNameInfo2->Name.Length = 2048;
		Buffer = ExAllocatePool(PagedPool,RetLen+4096);

		status = ObQueryNameString(FileObject,ObjectNameInfo2,ObjectNameInfo2->Name.Length,&RetLen);
		if(NT_SUCCESS(status) && Buffer && ObjectNameInfo1)
		{
			status = ZwQuerySystemInformation(SystemHandleInformation,Buffer,RetLen+4096,&RetLen);
			if(NT_SUCCESS(status))
			{
				UCHAR ObjectTypeIndex = 0;
				PSYSTEM_HANDLE_INFORMATION HandleInformation2 = (PSYSTEM_HANDLE_INFORMATION)Buffer;
				for(int i=0;i<HandleInformation2->NumberOfHandles;i++)
				{
					if(HandleInformation2->Handles[i].Object == FileObject)
					{
						ObjectTypeIndex = HandleInformation2->Handles[i].ObjectTypeIndex;
						Break;
					}
				}
				if(ObjectTypeIndex)
				{
					for(int i=0;i<HandleInformation2->NumberOfHandles;i++)
					{
						if(HandleInformation2->Handles[i].ObjectTypeIndex == ObjectTypeIndex)
						{
							CLIENT_ID ClientId;
							HANDLE TargetProcessHandle = NULL;
							HANDLE CurrentProcessHandle = NULL;
							HANDLE TargetHandle = NULL;
							PVOID TargetFileObject = NULL;
							OBJECT_ATTRIBUTES oa;
							ULONG RetLen;
							InitializeObjectAttributes(&oa,NULL,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
							ClientId.UniqueProcess = HandleInformation2->Handles[i].UniqueProcessId;
							ClientId.UniqueThread = 0;
							status = ZwOpenProcess(&CurrentProcessHandle,PROCESS_ALL_ACCESS, &oa, &ClientId);
							if(NT_SUCCESS(status))
							{
								InitializeObjectAttributes(&oa,NULL,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
								ClientId.UniqueProcess = PsGetCurrentProcessId();
								ClientId.UniqueThread = 0;
								status = ZwOpenProcess(&TargetProcessHandle,PROCESS_ALL_ACCESS, &oa, &ClientId);
								if(NT_SUCCESS(status))
								{//从引用到该对象的进程复制一份句柄到当前进程
									status = ZwDuplicateObject(CurrentProcessHandle,HandleInformation2->Handles[i].HandleValue,TargetProcessHandle,&TargetHandle,0,0,DUPLICATE_SAME_ACCESS);
									if(NT_SUCCESS(status) && TargetHandle)
									{
										status = ObReferenceObjectByHandle(TargetHandle,GENERIC_READ,IoFileObjectType,0,&TargetFileObject,0);
										if(NT_SUCCESS(status) && MmIsAddressValid(TargetFileObject) && TargetFileObject->DeviceObject->DeviceType == FILE_DEVICE_DISK)
										{
											status = ObQueryNameString(TargetFileObject,ObjectNameInfo1,ObjectNameInfo1->Name.Length,&RetLen);
											if(NT_SUCCESS(status))
											{
												__try
												{
													if(RtlEqualUnicodeString(ObjectNameInfo1,ObjectNameInfo2,TRUE))
													{
														PEPROCESS Process = NULL;
														KAPC_STATE ApcState;
														HANDLE ProcessId = HandleInformation2->Handles[i].UniqueProcessId;
														HANDLE ObjectHandle = HandleInformation2->Handles[i].HandleValue;
														OBJECT_HANDLE_FLAG_INFORMATION Ohfi;
														if(ProcessId != 0 && ProcessId != 4 && ProcessId != 8)
														{
															status = PsLookupProcessByProcessId(ProcessId,&Process);
															if(NT_SUCCESS(status))
															{
																KeStackAttachProcess(Process,&ApcState);
																CmpSetHandleProtection(&Ohfi,FALSE);
																ZwClose(ObjectHandle);
																KeUnstackDetachProcess(&ApcState);
																if(Process)
																{
																	ObDereferenceObject(Process);
																	Process = NULL;
																}
															}
														}
													}
													else
													{
														HANDLE ThreadHandle = DecodeKernelHandle(HandleInformation2->Handles[i].HandleValue);
														PsCreateSystemThread(&ThreadHandle,THREAD_ALL_ACCESS,NULL,NULL,NULL,UnlockFileThread,ThreadHandle);
														ZwWaitForSingleObject(ThreadHandle,FALSE,NULL);
														ZwClose(ThreadHandle);
													}
												}
												__finally
												{
												}
											}
										}
									}
								}
							}


							if (TargetProcessHandle)
							{
								ZwClose(TargetProcessHandle);
								TargetProcessHandle = 0;
							}
							if ( CurrentProcessHandle )
							{
								ZwClose(CurrentProcessHandle);
								CurrentProcessHandle = 0;
							}
							if ( TargetHandle )
							{
								ZwClose(TargetHandle);
								TargetHandle = 0;
							}
							if ( TargetFileObject )
							{
								ObfDereferenceObject(TargetFileObject);
								TargetFileObject = 0;
							}
						}
					}
				}
			}
		}
		if(Buffer)
			ExFreePool(Buffer);
		if(ObjectNameInfo1)
			ExFreePool(ObjectNameInfo1);
		if(ObjectNameInfo2)
			ExFreePool(ObjectNameInfo2);
	}
}

NTSTATUS UnlockFile(PUNICODE_STRING FileDosPath)
{//关闭句柄、解除引用、解锁文件
	IO_STATUS_BLOCK IoStatusBlock = {0};
	OBJECT_ATTRIBUTES oa;
	NTSTATUS status;
	HANDLE FileHandle = NULL;
	PFILE_OBJECT FileObject = NULL;
	InitializeObjectAttributes(&oa,FileDosPath,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
	//穿透IopCreateFile得到FileHandle
	status = ResetFileAttributes(FileHandle);
	if(NT_SUCCESS(status) )
	{
		status = ObReferenceObjectByHandle(FileHandle,0,*IoFileObjectType,KernelMode,&FileObject,NULL);
		if(NT_SUCCESS(status))
		{
			IopDeleteFile(FileObject);
			TryUnlockFile(FileObject);
			FileHandle = NULL;
			ObDereferenceObject(FileObject);
		}
	}
	else if(status == STATUS_DELETE_PENDING)
	{
		TryUnlockFile(FileObject);
		status = STATUS_SUCCESS;
		FileHandle = NULL;
	}
	if(FileHandle)
		ZwClose(FileHandle);
	return status;
}

获取ObjectInitializer

获取RegObjectInitializer:

  • 获取操作系统版本并转化为数组下标[0-9]
  • 获取\Registry\Machine\SYSTEM对应KeyObject,得到其POBJECT_TYPE,判断是否为”Key”类型
  • 获取Ntos地址,获取CmpKeyObjectType的ParseProcedure,检测是否在Ntos中
  • 获取PCM_KEY_BODY->KeyControlBlock-> KeyHive的偏移,为获取GetCellRoutine
  • Hook GetCellRoutine为NewGetCellRoutine
  • 创建线程依次执行ZwSetValueKey ZwQueryValueKey ZwEnumerateValueKey ZwEnumerateKey ZwDeleteValueKey ZwDeleteKey,触发GetCellRoutine
  • NewGetCellRoutine中在回溯栈中查找对应Zw匹配机器码,符合则取得相应Cm地址
  • 解除Hook

获取DriverObjectInitializer和DeviceObjectInitializer:

  • 获取操作系统版本并转化为数组下标[0-9]
  • 获取DriverObject,得到其POBJECT_TYPE,判断是否为”Device”类型
  • 分别获取DriverObjectType和DeviceObjectType的ObjectInitializer

VersionIndex对照表

major   minor   build   out
*       *               10
5       1               1
5       2               2/3
5       *               10
6       0               4
6       1               5
6       2       8102    7
6       2       9200    8
6       2       *       10      
6       3       9600    9
6       3       *       10  

获取注册表OBJECT_TYPE,匹配对象类型,使用\\Registry\\Machine\\SYSTEM注册表对象

POBJECT_TYPE GetRegKeyType()
{
	UNICODE_STRING RegPath,FuncName;
	OBJECT_ATTRIBUTES Oa;
	HANDLE KeyHandle = NULL;
	ULONG Disposition;
	PCM_KEY_BODY KeyBody;
	POBJECT_TYPE ObjType = NULL;
	FARPROC ObGetObjectType;
	NTSTATUS status;
	RtlInitUnicodeString(&RegPath,L"\\Registry\\Machine\\SYSTEM");
	InitializeObjectAttributes(&Oa,&RegPath,ExGetPreviousMode() != KernelMode?OBJ_CASE_INSENSITIVE :
		OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);		
	status = ZwCreateKey(&KeyHandle,KEY_QUERY_VALUE,&Oa,0,NULL,REG_OPTION_NON_VOLATILE,&Disposition);
	if(NT_SUCCESS(status))
	{
		status = ObReferenceObjectByHandle(KeyHandle,GENERIC_READ,NULL,KernelMode,&KeyBody,NULL);
		if(NT_SUCCESS(status))
		{
			RtlInitUnicodeString(&FuncName,L"ObGetObjectType");
			ObGetObjectType = MmGetSystemRoutineAddress(&FuncName);
			if(ObGetObjectType)
			{
				ObjType = ((POBJECT_TYPE (__stdcall*)(PVOID))ObGetObjectType)(KeyBody);
			}
			else if(VersionIndex < 5)//win7 之前
			{
				ObjType = ((OBJECT_HEADER*)OBJECT_TO_OBJECT_HEADER(Object))->Type;
			}
			ObDereferenceObject(KeyBody);
		}
		ZwClose(KeyHandle);
	}
	return ObjType;
}

typedef struct _OBJECT_TYPE_XP
{
	ERESOURCE Mutex;
	LIST_ENTRY TypeList;
	UNICODE_STRING Name;  
	PVOID DefaultObject;
	ULONG Index;
	ULONG TotalNumberOfObjects;
	ULONG TotalNumberOfHandles;
	ULONG HighWaterNumberOfObjects;
	ULONG HighWaterNumberOfHandles;
	OBJECT_TYPE_INITIALIZER TypeInfo;
	ERESOURCE ObjectLocks[ OBJECT_LOCK_COUNT ];
} OBJECT_TYPE_XP, *POBJECT_TYPE_XP;

typedef struct _OBJECT_TYPE_WIN7
{
	LIST_ENTRY TypeList;
	UNICODE_STRING Name;
	PVOID DefaultObject;
	ULONG Index;
	ULONG TotalNumberOfObjects;
	ULONG TotalNumberOfHandles;
	ULONG HighWaterNumberOfObjects;
	ULONG HighWaterNumberOfHandles;
	OBJECT_TYPE_INITIALIZER TypeInfo;
	EX_PUSH_LOCK TypeLock;
	ULONG Key;
	LIST_ENTRY CallbackList;
} OBJECT_TYPE_WIN7, *POBJECT_TYPE_WIN7;

BOOLEAN CmpRegKeyType(POBJECT_TYPE ObjType)
{
	UNICODE_STRING ObjTypeName;
	RtlInitUnicodeString(&ObjTypeName,L"Key");
	PUNICODE_STRING SrcTypeName;
	if(VersionIndex >= 1 && VersionIndex <= 3)//xp 2000
	{
		POBJECT_TYPE_XP _ObjType = (POBJECT_TYPE_XP)ObjType;
		if(!IsAddressRegionValid(&_ObjType->Name,sizeof(UNICODE_STRING)))
			return FALSE;
		SrcTypeName = &ObjType->Name;
	}
	else if(VersionIndex >= 4 && VersionIndex <= 9)//vista及之后
	{
		POBJECT_TYPE_WIN7 _ObjType = (POBJECT_TYPE_WIN7)ObjType;
		if(!IsAddressRegionValid(&_ObjType->Name,sizeof(UNICODE_STRING)))
			return FALSE;
		SrcTypeName = &ObjType->Name;
	}
	else
	{
		return FALSE;
	}
	if(IsAddressRegionValid(SrcTypeName->Buffer,SrcTypeName->Length))
		return RtlCompareUnicodeString(&ObjTypeName,SrcTypeName,TRUE) == 0;
	return FALSE;
}

获取ParseProcedure

FARPROC RegObjectInitialzer[6];
FARPROC FileObjectInitialzer[6];
// 0 CloseProcedure
// 1 DeleteProcedure
// 2 ParseProcedure
// 3 SecurityProcedure
// 4 QueryNameProcedure
// 5 OpenProcedure

BOOLEAN GetParseProcedure(POBJECT_TYPE ObjectType)
{
	PVOID modules;
	ULONG InfoLen = 0;
	OB_PARSE_METHOD Proc = NULL;
	ULONG_PTR NtosBegin = 0;
	ULONG_PTR NtosEnd = 0;
	RtlZeroMemory(RegObjectInitialzer,sizeof(RegObjectInitialzer));
	if(!ObjectType)
		return FALSE;
	ZwQuerySystemInformation(SystemModuleInformation,&InfoLen,0,&InfoLen);
	if(InfoLen == 0)
		return FALSE;
	modules = ExAllocatePool(PagedPool,InfoLen);
	if(!modules)
		return FALSE;
	status = ZwQuerySystemInformation(SystemModuleInformation,modules,&InfoLen);
	if(NT_SUCCESS(status) && modules->NumberOfModules)
	{
		NtosBegin = modules->Modules[0].ImageBase;
		NtosEnd = NtosBegin + modules->Modules[0].ImageSize;
		if(VersionIndex >= 1 && VersionIndex <= 3)//xp 2000
		{
			POBJECT_TYPE_XP _ObjType = (POBJECT_TYPE_XP)ObjType;
			Proc = _ObjType->TypeInfo.ParseProcedure;
		}
		else if(VersionIndex >= 4 && VersionIndex <= 9)//vista及之后
		{
			POBJECT_TYPE_WIN7 _ObjType = (POBJECT_TYPE_WIN7)ObjType;
			Proc = _ObjType->TypeInfo.ParseProcedure;
		}
	}
	ExFreePool(Modules);
	if(Proc && Proc >= NtosBegin && Proc <= NtosEnd)
	{
		RegObjectInitialzer[2] = Proc;
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

获取GetCellRoutine偏移,Hook GetCellRoutine

BOOLEAN GetCellRoutineOffset()
{
  ULONG result = 0;
  switch ( VersionIndex )
  {
    case WIN2000:
    case WINXP:
    case WINXPSP3:
    case WINVISTA:
    case 6:
      CellRoutineOffset = 16;
      Return true;
    case WIN7:
    case WIN8:
    case WIN8_1:
    case WIN10:
      CellRoutineOffset = 20;
	Return true;
    default:
      return result;
  }
  return result;
}

Hook和UnHook GetCellRoutine

volatile ULONG HookCellRoutineRefCount = 0;
volatile ULONG EnterCellRoutineRefCount = 0;
ULONG_PTR OldGetCellRoutine = 0;
BOOLEAN IsGetCell = FALSE;
ULONG_PTR pGetCellRoutine = 0;

BOOLEAN HookCellRoutine(BOOLEAN Hook)
{

	OBJECT_ATTRIBUTES Oa;
	UNICODE_STRING RegPath;
	NTSTATUS status;
	HANDLE KeyHandle = NULL;
	PCM_KEY_BODY KeyBody = NULL;
	BOOLEAN success = FALSE;

	while(InterlockedCompareExchange(&HookCellRoutineRefCount,1,0))//同步
	{
		LARGE_INTEGER Interval;
		Interval.QuadPart = -10000i64 * 100;
		KeDelayExecutionThread(KernelMode,FALSE,&Interval);
	}

	if(Hook)
	{
		if((CellRoutineBit & 0x111111) == 0x111111)
		{
			RtlInitUnicodeString(&RegPath);
			InitializeObjectAttributes(&Oa,&RegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
			status = ZwOpenKey(&KeyHandle,KEY_ALL_ACCESS,&Oa);
			if(NT_SUCCESS(status))
			{
				status = ObReferenceObjectByHandle(KeyHandle,KEY_SET_VALUE,*CmKeyObjectType,KernelMode,&KeyBody,NULL);
				if(NT_SUCCESS(status))
				{
					ULONG_PTR pGetCellRoutine = (ULONG_PTR)&((HHIVE*)((BYTE*)KeyBody->KeyControlBlock + CellRoutineOffset))->GetCellRoutine;
					OldGetCellRoutine = InterlockedExchange(pGetCellRoutine,NewGetCellRoutine);
					IsGetCell = TRUE;
					success = TRUE;
				}
			}
			if(KeyBody)
				ObReferenceObjectByHandle(KeyBody);
			if(KeyHandle)
				ZwClose(KeyHandle);
		}
	}
	else//UnHook
	{
		if(IsGetCell && OldGetCellRoutine && pGetCellRoutine)
		{
			int count = 0;
			InterlockedExchange(pGetCellRoutine,OldGetCellRoutine);
			do 
			{
				LARGE_INTEGER Interval;
				Interval.QuadPart = -10000i64 * 50;
				KeDelayExecutionThread(KernelMode,FALSE,&Interval);
				InterlockedExchange(&count,EnterCellRoutineRefCount);
			} while (count);
			OldGetCellRoutine = 0;
			pGetCellRoutine = 0;
			IsGetCell = FALSE;
			success = TRUE;
		}
	}
	InterlockedExchange(&HookCellRoutineRefCount,0);
	return success;
}

创建系统线程获取Cm*函数

int CmIndex;
/*
	CmQueryValueKey 0
	CmSetValueKey 1
	CmDeleteValueKey 2
	CmDeleteKey 3
	CmEnumerateKey 4
	CmEnumerateValueKey 5
*/
BOOLEAN SetCmTrap()
{//通过注册表操作触发已经Hook的ObjectInitializer
	WCHAR ValueName[] = L"100000";
	WCHAR KeyPath[] = L"\\Registry\\Machine\\SYSTEM\\00000";
	OBJECT_ATTRIBUTES Oa;
	UNICODE_STRING UKeyPath,UValueName;
	LARGE_INTEGER CurrentTime,LocalTime;
	HANDLE KeyHandle = NULL;;
	NTSTATUS status;
	DWORD RetLen;
	TIME_FIELDS TimeFields;
	ULONG Disposition;
	BOOLEAN result = FALSE;
	KeQuerySystemTime(&CurrentTime);
	ExSystemTimeToLocalTime(&CurrentTime,LocalTime);
	RtlTimeToTimeFields(&LocalTime,&TimeFields);
	ValueName[0] += TimeFields.Milliseconds % 9;
	ValueName[1] += TimeFields.Second % 8;
	ValueName[3] += TimeFields.Minute % 7;
	ValueName[4] += TimeFields.Milliseconds % 9;
	ValueName[5] += TimeFields.Second % 8;
	KeyPath[25] += TimeFields.Second % 9;
	KeyPath[26] += TimeFields.Milliseconds % 8;
	KeyPath[27] += TimeFields.Second % 7;
	KeyPath[28] += TimeFields.Milliseconds % 9;
	KeyPath[29] += TimeFields.Minute % 8;
	RtlInitUnicodeString(&UKeyPath,KeyPath);
	InitializeObjectAttributes(&Oa,UKeyPath,OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE,NULL,NULL);
	status = ZwCreateKey(&KeyHandle,KEY_ALL_ACCESS,&Oa,0,NULL,REG_OPTION_NON_VOLATILE,&Disposition);
	if(NT_SUCCESS(status))
	{
		RtlInitUnicodeString(&UValueName,ValueName);
//和NewGetCellRoutine配合使用
		CmIndex = ECmSetValueKey;
		ZwSetValueKey(KeyHandle,&UValueName,0,REG_SZ,ValueName,wcslen(ValueName)+2);
		CmIndex = ECmQueryValueKey;
		ZwQueryValueKey(KeyHandle,&UValueName,KeyValuePartialInformation,NULL,0,&RetLen);
		CmIndex = ECmEnumerateValueKey;
		ZwEnumerateValueKey(KeyHandle,0,KeyValueBasicInformation,NULL,0,&RetLen);
		CmIndex = ECmEnumerateKey;
		ZwEnumerateKey(KeyHandle,0,KeyValueBasicInformation,NULL,0,&RetLen);
		CmIndex = ECmDeleteValueKey;
		ZwDeleteValueKey(KeyHandle,&UValueName);
		CmIndex = ECmDeleteKey;
		ZwDeleteKey(KeyHandle);
		result = TRUE;
	}
	CmIndex = ECmMax;
	if(KeyHandle)
		ZwClose(KeyHandle);
	return result;
}

BOOLEAN CheckAndGetCmInnerFunc(ULONG Address,int CmIndex)							--
{//通过回溯查找cm*地址
/*
对比call   nt!CmSetValueKey之前偏移0x25的机器码:
80619a1f 7c1f            jl      nt!NtSetValueKey+0x234 (80619a40)
80619a21 53              push    ebx
80619a22 ff7518          push    dword ptr [ebp+18h]
80619a25 ff7514          push    dword ptr [ebp+14h]
80619a28 8d45c4          lea     eax,[ebp-3Ch]
80619a2b 50              push    eax
80619a2c ff7704          push    dword ptr [edi+4]
80619a2f e88e0b0100      call    nt!CmSetValueKey (8062a5c2)

CmInnerFuncs
b2e4c640  00 00 00 00 00 00 00 00-7c 00 53 ff 75 00 ff 75  ........|.S.u..u
b2e4c650  00 8d 45 00 50 ff 77 00-01 00 00 00 02 00 00 00  ..
*/
	UCHAR Code[32];
	if(!Address || Address - 0x2F <= 0x7FFFFFFF || !IsAddressRegionValid(Address-0x2F,0x2F))
		return FALSE;
	if(CmMatchData[VersionIndex][CmIndex].CodeMask)
	{
		RtlCopyMemory(Code,Address-0x25,sizeof(Code));
		for(int i=31;i>=0;i--)
		{
			ULONG bit = CmMatchData[VersionIndex][CmIndex].CodeMask >> (31-i);
			if(bit & 1)
			{
				if(CmMatchData[VersionIndex][CmIndex].ByteCode[i] != Code[i])
					return FALSE;
			}
			else if(bit == 0)
			{
				CmMatchData[VersionIndex][CmIndex].FuncAddr = Address+*(ULONG_PTR*)(Address-1);
				CellRoutineBit |= CmMatchData[VersionIndex][CmIndex].CmFlag;
				CmMatchData[VersionIndex][CmIndex].InitFlag = TRUE;
				return TRUE;
			}
		}
	}

	return FALSE;
}

BOOLEAN GetCmFuncsByIndex(ULONG Esp,int CmIndex)
{
	if(!Esp)
		return FALSE;
	for(int i=0;i<100;i++)
	{
		if(!IsAddressRegionValid(Esp,4))
			break;
		if(Esp >= NtosBegin && Esp <= NtosEnd && CheckAndGetCmInnerFunc(Esp,CmIndex))
			return TRUE;
		Esp += 4;
	}
	return FALSE;
}

--x64 下的情况 
CM_MATCH_DATA Ano[]=
{
	{7, 1},
	0, NULL, NCmSetValueKey, 0xFFFFFFFF,
	{
		0x90,0x00,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x74,0x24,0x20,0x4C,0x8B,
		0x4C,0x24,0x60,0x44,0x8B,0xC7,0x48,0x8D,0x54,0x24,0x50,0x48,0x8B,0x4C,0x24,0x48,
	},
	{9, 0},
	0, NULL, 0, 0,
	{
		0,
	}
}

BOOLEAN CheckAndGetCmInnerFunc(ULONG Address,int CmIndex)							
{//通过回溯查找cm*地址
	UCHAR Code[32];
	if(!Address || Address - 0x2F <= 0x7FFFFFFF || !IsAddressRegionValid(Address-0x2F,0x2F))
		return FALSE;
	if(CmMatchData[VersionIndex][CmIndex].CodeMask)
	{
		RtlCopyMemory(Code,Address-0x25,sizeof(Code));
		for(int i=31;i>=0;i--)
		{
			ULONG bit = CmMatchData[VersionIndex][CmIndex].CodeMask >> (31-i);
			if(bit & 1)
			{
				if(CmMatchData[VersionIndex][CmIndex].ByteCode[i] != Code[i])
					goto CompareAnother;
			}
			else if(bit == 0)
			{
				CmMatchData[VersionIndex][CmIndex].FuncAddr = Address+*(ULONG_PTR*)(Address-1);
				CellRoutineBit |= CmMatchData[VersionIndex][CmIndex].CmFlag;
				CmMatchData[VersionIndex][CmIndex].InitFlag = TRUE;
				return TRUE;
			}
		}
	}
	return FALSE;
CompareAnother:

	for(int j=0;Ano[j].Version[0] != 9;j++)
	{
		if(Ano[j].Version[0] == VersionIndex && Ano[j].Version[1] == CmIndex)
		{
			for(int i=31;i>=0;i--)
			{
				ULONG bit = Ano[j].CodeMask >> (31-i);
				if(bit & 1)
				{
					if(Ano[j].ByteCode[i] != Code[i])
						goto CompareAnother;
				}
				else if(bit == 0)
				{
					CmMatchData[VersionIndex][CmIndex].FuncAddr = Address+*(ULONG_PTR*)(Address-1);
					CellRoutineBit |= CmMatchData[VersionIndex][CmIndex].CmFlag;
					CmMatchData[VersionIndex][CmIndex].InitFlag = TRUE;
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}

NTSTATUS __stdcall NewGetCellRoutine(HHIVE Hive,HCELL Cell)
{
	NTSTATUS status;
	ULONG_PTR _Esp = 0;
	_asm
	{
		mov _Esp,esp;
	}
	InterlockedExchangeAdd(&EnterCellRoutineRefCount,1);
	if(PsGetCurrentThreadId() == GetCmRegFuncsThreadId && CmIndex < 6)
	{
		if(CmMatchData[VersionIndex][CmIndex].InitFlag && CmMatchData[VersionIndex][CmIndex].FuncAddr)
		{
			if(!(CmMatchData[VersionIndex][CmIndex].CmFlag & CellRoutineBit))
				CellRoutineBit |= CmMatchData[VersionIndex][CmIndex].CmFlag;
		}
		else
		{
			switch(CmIndex)
			{
			case ECmQueryValueKey:
				GetCmFuncsByIndex();
				break;
			case ECmSetValueKey:
				GetCmFuncsByIndex();
				break;
			case ECmDeleteValueKey:
				GetCmFuncsByIndex();
				break;
			case ECmDeleteKey:
				GetCmFuncsByIndex();
				break;
			case ECmEnumerateKey:
				GetCmFuncsByIndex();
				break;
			case ECmEnumerateValueKey:
				GetCmFuncsByIndex();
				break;
			}

		}
	}
	status = OldGetCellRoutine(Hive,Cell);
	InterlockedExchangeAdd(&EnterCellRoutineRefCount,-1);
	return status;
}

匹配结构

用于匹配cm*函数调用周围的机器码
X86的情况:

#define MaxVersion 10
enum
{
	ECmQueryValueKey=0,
	ECmSetValueKey,
	ECmDeleteValueKey,
	ECmDeleteKey,
	ECmEnumerateKey,
	ECmEnumerateValueKey,
	ECmMax,
	NCmQueryValueKey=1,
	NCmSetValueKey=0x10,
	NCmDeleteValueKey=0x100,
	NCmDeleteKey=0x1000,
	NCmEnumerateKey=0x10000,
	NCmEnumerateValueKey=0x100000,
};

#pragma pack(4)
struct CM_MATCH_DATA
{
	ULONG Version[2];//版本
	ULONG InitFlag;//是否初始化
	ULONG FuncAddr;//获取到的cm函数地址
	ULONG CmFlag;//cm函数类型,1~0x100000 对应于各个cm函数
	ULONG CodeMask;//32bit对应于BYTE ByteCode[32]的掩码,决定是否比较
	UCHAR ByteCode[32];//用于比较cm函数的机器码
};

CM_MATCH_DATA CmMatchData[MaxVersion][ECmMax]=
{
{//NON
	{
		{0, 0},
		0, NULL, NCmQueryValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 1},
		0, NULL, NCmSetValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 2},
		0, NULL, NCmDeleteValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 3},
		0, NULL, NCmDeleteKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 4},
		0, NULL, NCmEnumerateKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 5},
		0, NULL, NCmEnumerateValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
},
{//WIN2000
	{
		{1, 0},
		0, NULL, NCmQueryValueKey, 0x00176DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x57,0xFF,0x75,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x76,0x00,
		},
	},
	{
		{1, 1},
		0, NULL, NCmSetValueKey, 0x0000BB6E,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x7C,0x00,0x53,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8D,0x45,0x00,0x50,0xFF,0x77,0x00,
		},
	},
	{
		{1, 2},
		0, NULL, NCmDeleteValueKey, 0x00003DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x39,0x75,0xE4,0x7C,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
	{
		{1, 3},
		0, NULL, NCmDeleteKey, 0x0006DB6D,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8B,0x46,0x00,
			0xF6,0x40,0x00,0x80,0x75,0x00,0x8B,0x40,0x00,0xF6,0x40,0x00,0x80,0x75,0x00,0x56,
		},
	},
	{
		{1, 4},
		0, NULL, NCmEnumerateKey, 0x001AEDB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x5D,0x00,0x7C,0x00,
			0x56,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
	{
		{1, 5},
		0, NULL, NCmEnumerateValueKey, 0x001AEDB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x5D,0x00,0x7C,0x00,
			0x56,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
},
{//WINXPSP1
	{
		{2, 0},
		0, NULL, NCmQueryValueKey, 0x003B6DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0xFF,0x75,0x00,0xFF,0x75,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8B,0x7D,0x00,0xFF,0x77,0x00,
		},
	},
	{
		{2, 1},
		0, NULL, NCmSetValueKey, 0x0000BB6E,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x7C,0x00,0x53,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8D,0x45,0x00,0x50,0xFF,0x76,0x00,
		},
	},
	{
		{2, 2},
		0, NULL, NCmDeleteValueKey, 0x00001DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x85,0xF6,0x7C,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
	{
		{2, 3},
		0, NULL, NCmDeleteKey, 0x0000DB6D,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0xF6,0x40,0x00,0x80,0x75,0x00,0x8B,0x40,0x00,0xF6,0x40,0x00,0x80,0x75,0x00,0x56,
		},
	},
	{
		{2, 4},
		0, NULL, NCmEnumerateKey, 0x000EEDB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xF6,0x7C,0x00,
			0x53,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
	{
		{2, 5},
		0, NULL, NCmEnumerateValueKey, 0x000EEDB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xF6,0x7C,0x00,
			0x53,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
},
{//WINXPSP3
	{
		{3, 0},
		0, NULL, NCmQueryValueKey, 0x00176DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x56,0xFF,0x75,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
	{
		{3, 1},
		0, NULL, NCmSetValueKey, 0x0000BB6E,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x7C,0x00,0x53,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8D,0x45,0x00,0x50,0xFF,0x76,0x00,
		},
	},
	{
		{3, 2},
		0, NULL, NCmDeleteValueKey, 0x00001DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x85,0xF6,0x7C,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
	{
		{3, 3},
		0, NULL, NCmDeleteKey, 0x0000DB6D,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0xF6,0x40,0x00,0x80,0x75,0x00,0x8B,0x40,0x00,0xF6,0x40,0x00,0x80,0x75,0x00,0x56,
		},
	},
	{
		{3, 4},
		0, NULL, NCmEnumerateKey, 0x000EEDB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xF6,0x7C,0x00,
			0x53,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
	{
		{3, 5},
		0, NULL, NCmEnumerateValueKey, 0x000EEDB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xF6,0x7C,0x00,
			0x53,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x77,0x00,
		},
	},
},
{//WINVISTA
	{
		{4, 0},
		0, NULL, NCmQueryValueKey, 0x01DB6DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3B,0xC7,0x7C,0x00,0xFF,0x75,0x00,0xFF,0x75,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{4, 1},
		0, NULL, NCmSetValueKey, 0x0003BB6E,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xFF,
			0x75,0x00,0x56,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8D,0x45,0x00,0x50,0xFF,0x75,0x00,
		},
	},
	{
		{4, 2},
		0, NULL, NCmDeleteValueKey, 0x00037FF6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8B,0x45,
			0x00,0xC1,0xE8,0x02,0x25,0x01,0xFF,0xFF,0xFF,0x50,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{4, 3},
		0, NULL, NCmDeleteKey, 0x000003FD,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0xBB,0x22,0x00,0x00,0xC0,0x3B,0xDE,0x7C,0x00,0x57,
		},
	},
	{
		{4, 4},
		0, NULL, NCmEnumerateKey, 0x0016DBB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0xFF,0x75,0x00,
			0xFF,0x75,0x00,0xFF,0x75,0x00,0x57,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8B,0x4D,0x00,
		},
	},
	{
		{4, 5},
		0, NULL, NCmEnumerateValueKey, 0x0002DB76,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x75,0x00,
			0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0x57,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
},
{//WIN7
	{
		{5, 0},
		0, NULL, NCmQueryValueKey, 0x01DB6DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3B,0xC7,0x7C,0x00,0xFF,0x75,0x00,0xFF,0x75,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{5, 1},
		0, NULL, NCmSetValueKey, 0x007FBB6E,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0x01,0x0F,0xB6,0xC0,0x50,0xFF,
			0x75,0x00,0x56,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8D,0x45,0x00,0x50,0xFF,0x75,0x00,
		},
	},
	{
		{5, 2},
		0, NULL, NCmDeleteValueKey, 0x00007FF6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0xC1,0xE8,0x02,0x24,0x01,0x0F,0xB6,0xC0,0x50,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{5, 3},
		0, NULL, NCmDeleteKey, 0x00067E61,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC7,0x44,0x00,
			0x00,0x22,0x00,0x00,0xC0,0x39,0x5C,0x00,0x00,0x0F,0x8C,0x00,0x00,0x00,0x00,0x57,
		},
	},
	{
		{5, 4},
		0, NULL, NCmEnumerateKey, 0x0016DBB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0xFF,0x75,0x00,
			0xFF,0x75,0x00,0xFF,0x75,0x00,0x57,0xFF,0x75,0x00,0x8B,0x4D,0x00,0x8B,0x55,0x00,
		},
	},
	{
		{5, 5},
		0, NULL, NCmEnumerateValueKey, 0x0002DB76,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x75,0x00,
			0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0x57,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
},
{//WIN7SP1
	{
		{6, 0},
		0, NULL, NCmQueryValueKey, 0x01DB6DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3B,0xC7,0x7C,0x00,0xFF,0x75,0x00,0xFF,0x75,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{6, 1},
		0, NULL, NCmSetValueKey, 0x0003BB6E,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xFF,
			0x75,0x00,0x56,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8D,0x45,0x00,0x50,0xFF,0x75,0x00,
		},
	},
	{
		{6, 2},
		0, NULL, NCmDeleteValueKey, 0x00037FF6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8B,0x45,
			0x00,0xC1,0xE8,0x02,0x25,0x01,0xFF,0xFF,0xFF,0x50,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{6, 3},
		0, NULL, NCmDeleteKey, 0x000003FD,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0xBB,0x22,0x00,0x00,0xC0,0x3B,0xDE,0x7C,0x00,0x57,
		},
	},
	{
		{6, 4},
		0, NULL, NCmEnumerateKey, 0x0016DBB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0xFF,0x75,0x00,
			0xFF,0x75,0x00,0xFF,0x75,0x00,0x57,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8B,0x4D,0x00,
		},
	},
	{
		{6, 5},
		0, NULL, NCmEnumerateValueKey, 0x0002DB76,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x75,0x00,
			0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0x57,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
},
{//WIN8
	{
		{7, 0},
		0, NULL, NCmQueryValueKey, 0x001DA7A6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xC0,0x78,0x00,0xFF,
			0x75,0x00,0xFF,0x75,0x00,0x56,0x57,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{7, 1},
		0, NULL, NCmSetValueKey, 0x00FFFB6E,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC1,0xE8,0x02,0x24,0x01,0x0F,0xB6,0xC0,
			0x50,0x56,0x57,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8D,0x45,0x00,0x50,0xFF,0x75,0x00,
		},
	},
	{
		{7, 2},
		0, NULL, NCmDeleteValueKey, 0x001FFDB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC1,0xE8,0x02,0x24,0x01,
			0x0F,0xB6,0xC0,0x50,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{7, 3},
		0, NULL, NCmDeleteKey, 0x000003FD,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0xBB,0x22,0x00,0x00,0xC0,0x85,0xDB,0x78,0x00,0x56,
		},
	},
	{
		{7, 4},
		0, NULL, NCmEnumerateKey, 0x07DB6DB6,
		{
			0x00,0x00,0x00,0x00,0x00,0x8B,0xF0,0x85,0xF6,0x78,0x00,0xFF,0x75,0x00,0xFF,0x75,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8B,0x45,0x00,
		},
	},
	{
		{7, 5},
		0, NULL, NCmEnumerateValueKey, 0x0036DB76,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x7D,0x00,0x00,0x75,0x00,
			0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0x57,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
},
{//WIN8.1
	{
		{8, 0},
		0, NULL, NCmQueryValueKey, 0x00786DBE,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xC0,0x0F,0x85,0x00,0x00,0x00,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0x56,0x57,0x53,0xFF,0x75,0x00,
		},
	},
	{
		{8, 1},
		0, NULL, NCmSetValueKey, 0x0E1F76DD,
		{
			0x00,0x00,0x00,0x00,0x04,0x0F,0x85,0x00,0x00,0x00,0x00,0x33,0xC0,0x50,0xFF,0x75,
			0x00,0x56,0xFF,0x75,0x00,0xFF,0x75,0x00,0x8D,0x45,0x00,0x50,0x8B,0x5D,0x00,0x53,
		},
	},
	{
		{8, 2},
		0, NULL, NCmDeleteValueKey, 0x1B87FB76,
		{
			0x00,0x00,0x00,0x88,0x5D,0x00,0x0F,0xB6,0x85,0x00,0x00,0x00,0x00,0xC1,0xE8,0x02,
			0x83,0xE0,0x01,0xFF,0x75,0x00,0xFF,0x75,0x00,0x50,0xFF,0x75,0x00,0xFF,0x75,0x00,
		},
	},
	{
		{8, 3},
		0, NULL, NCmDeleteKey, 0x0F0F879C,
		{
			0x00,0x00,0x00,0x00,0x40,0x66,0x89,0x81,0x00,0x00,0x00,0x00,0x66,0x85,0xC0,0x0F,
			0x84,0x00,0x00,0x00,0x00,0x33,0xDB,0x8B,0x74,0x00,0x00,0x56,0x88,0x5C,0x00,0x00,
		},
	},
	{
		{8, 4},
		0, NULL, NCmEnumerateKey, 0x37876DBB,
		{
			0x00,0x00,0x8B,0x75,0x00,0x85,0xDB,0x0F,0x88,0x00,0x00,0x00,0x00,0x57,0xFF,0x75,
			0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0xFF,0x75,0x00,0x56,0x8B,0x7D,0x00,0x8B,0xC7,
		},
	},
	{
		{8, 5},
		0, NULL, NCmEnumerateValueKey, 0x3F0EEDDD,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0xF6,0x0F,0x85,0x00,0x00,0x00,0x00,
			0x57,0xFF,0x75,0x00,0x53,0xFF,0x75,0x00,0x8B,0x5D,0x00,0x53,0x8B,0x7D,0x00,0x57,
		},
	},
},
{//WIN10
	{
		{9, 0},
		0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
		{
			0x00,0x00,0x85,0xF6,0x0F,0x85,0x0A,0xD7,0x10,0x00,0x8B,0x7D,0xB8,0xFF,0x75,0xCC,
			0xFF,0x75,0xC8,0xFF,0x75,0xB4,0x53,0x57,0x8B,0x5D,0x10,0x8B,0xD3,0x8B,0x4D,0xBC,
		},
	},
	{
		{9, 1},
		0, NULL, NCmSetValueKey, 0xFFFFFFFF,
		{
			0x5D,0xCB,0x0F,0xB6,0x85,0x74,0xFF,0xFF,0xFF,0xC1,0xE8,0x02,0x83,0xE0,0x01,0x50,
			0xFF,0x75,0x88,0x57,0xFF,0x75,0xAC,0xFF,0x75,0x14,0x8D,0x55,0xB8,0x8B,0x4D,0xB4,
		},
	},
	{
		{9, 2},
		0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
		{
			0xC4,0x0D,0x00,0x88,0x5D,0xCB,0x0F,0xB6,0x85,0x7C,0xFF,0xFF,0xFF,0xC1,0xE8,0x02,
			0x83,0xE0,0x01,0xFF,0x75,0xBC,0xFF,0x75,0xB8,0x50,0x8B,0x55,0xA8,0x8B,0x4D,0xB4,
		},
	},
	{
		{9, 3},
		0, NULL, NCmDeleteKey, 0xFFFFFFFF,
		{
			0x01,0x00,0x00,0x40,0x66,0x89,0x81,0x3C,0x01,0x00,0x00,0x66,0x85,0xC0,0x0F,0x84,
			0x9E,0x00,0x00,0x00,0x33,0xDB,0x8B,0x74,0x24,0x10,0x8B,0xCE,0x88,0x5C,0x24,0x2C,
		},
	},
	{
		{9, 4},
		0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
		{
			0xE8,0x5A,0xB1,0xFF,0xFF,0x8B,0xF0,0x85,0xF6,0x78,0x1C,0xFF,0x75,0xB8,0xFF,0x75,
			0x18,0xFF,0x75,0xBC,0xFF,0x75,0x10,0xFF,0x75,0x0C,0x8B,0x55,0xC4,0x8B,0x4D,0xC8,
		},
	},
	{
		{9, 5},
		0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
		{
			0x8B,0xF0,0x85,0xF6,0x78,0x21,0x8B,0x4D,0xCC,0x83,0x7D,0xC8,0x00,0x0F,0x85,0x84,
			0xCA,0x0D,0x00,0xFF,0x75,0xC0,0xFF,0x75,0x18,0xFF,0x75,0xC4,0x57,0x8B,0x55,0x0C,
		},
	},
},
};

获取CmMatchData的python脚本

addr=0x22498
index1=0
index2=0
while index1 < 10:
	index2=0
	if index1 == 0:
		version="NON"
	elif index1 == 1:
		version="WIN2000"
	elif index1 == 2:
		version="WINXPSP1"
	elif index1 == 3:
		version="WINXPSP3"
	elif index1 == 4:
		version="WINVISTA"
	elif index1 == 5:
		version="WIN7"
	elif index1 == 6:
		version="WIN7SP1"
	elif index1 == 7:
		version="WIN8"
	elif index1 == 8:
		version="WIN8.1"
	elif index1 == 9:
		version="WIN10"
	print "{//%s\n" %(version)
	while index2 < 6:
		print "\t{"
		if index2 == 0:
			cm="NCmQueryValueKey"
		elif index2 == 1:
			cm="NCmSetValueKey"
		elif index2 == 2:
			cm="NCmDeleteValueKey"
		elif index2 == 3:
			cm="NCmDeleteKey"
		elif index2 == 4:
			cm="NCmEnumerateKey"
		elif index2 == 5:
			cm="NCmEnumerateValueKey"
		print "\n\t\t{%d, %d},\n\t\t0, NULL, %s, 0x%08X,\n\t\t{\n" %(Dword(addr),Dword(addr+4),cm,Dword(addr+20))
		ptr=addr+24
		print "\t\t\t0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,\n" %(Byte(ptr),Byte(ptr+1),Byte(ptr+2),Byte(ptr+3),Byte(ptr+4),Byte(ptr+5),Byte(ptr+6),Byte(ptr+7),Byte(ptr+8),Byte(ptr+9),Byte(ptr+10),Byte(ptr+11),Byte(ptr+12),Byte(ptr+13),Byte(ptr+14),Byte(ptr+15))
		ptr=ptr+16
		print "\t\t\t0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,\n" %(Byte(ptr),Byte(ptr+1),Byte(ptr+2),Byte(ptr+3),Byte(ptr+4),Byte(ptr+5),Byte(ptr+6),Byte(ptr+7),Byte(ptr+8),Byte(ptr+9),Byte(ptr+10),Byte(ptr+11),Byte(ptr+12),Byte(ptr+13),Byte(ptr+14),Byte(ptr+15))
		print "\t\t},\n"
		print "\t},"
		addr=addr+56
		index2 = index2+1
	print "},"
	index1=index1+1

X64的情况:

#pragma pack(8)
struct CM_MATCH_DATA
{
	ULONG Version[2];//版本
	ULONG InitFlag;//是否初始化
	ULONG _gap;//8字节对齐
	ULONGLONG FuncAddr;//获取到的cm函数地址
	ULONG CmFlag;//cm函数类型,1~0x100000 对应于各个cm函数
	ULONG CodeMask;//32bit对应于BYTE ByteCode[32]的掩码,决定是否比较
	UCHAR ByteCode[32];//用于比较cm函数的机器码
};

CM_MATCH_DATA CmMatchData[MaxVersion][ECmMax]=
{
{//NON
	{
		{0, 0},
		0, NULL, NCmQueryValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 1},
		0, NULL, NCmSetValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 2},
		0, NULL, NCmDeleteValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 3},
		0, NULL, NCmDeleteKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 4},
		0, NULL, NCmEnumerateKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{0, 5},
		0, NULL, NCmEnumerateValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
},
{//WIN2000
	{
		{1, 0},
		0, NULL, NCmQueryValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{1, 1},
		0, NULL, NCmSetValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{1, 2},
		0, NULL, NCmDeleteValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{1, 3},
		0, NULL, NCmDeleteKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{1, 4},
		0, NULL, NCmEnumerateKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{1, 5},
		0, NULL, NCmEnumerateValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
},
{//WINXPSP1
	{
		{2, 0},
		0, NULL, NCmQueryValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{2, 1},
		0, NULL, NCmSetValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{2, 2},
		0, NULL, NCmDeleteValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{2, 3},
		0, NULL, NCmDeleteKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{2, 4},
		0, NULL, NCmEnumerateKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{2, 5},
		0, NULL, NCmEnumerateValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
},
{//WINXPSP3
	{
		{3, 0},
		0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
		{
			0x44,0x89,0x64,0x24,0x20,0x4D,0x8B,0xCE,0x44,0x8B,0xC3,0x48,0x8D,0x94,0x24,0x30,
			0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x48,0x4C,0x89,0x64,0x24,0x40,0x49,0x8B,0xCC,
		},
	},
	{
		{3, 1},
		0, NULL, NCmSetValueKey, 0xFFFFFFFF,
		{
			0x01,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x74,0x24,0x20,0x4D,0x8B,0xCD,
			0x44,0x8B,0x84,0x24,0x58,0x01,0x00,0x00,0x48,0x8D,0x54,0x24,0x48,0x48,0x8B,0xCE,
		},
	},
	{
		{3, 2},
		0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
		{
			0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xC0,0x00,0x00,0x00,0x4C,0x8B,0x84,
			0x24,0x10,0x01,0x00,0x00,0x48,0x8D,0x94,0x24,0xC0,0x00,0x00,0x00,0x48,0x8B,0xCE,
		},
	},
	{
		{3, 3},
		0, NULL, NCmDeleteKey, 0xFFFFFFFF,
		{
			0x49,0x3B,0xCD,0x74,0x0A,0xF6,0x41,0x04,0x80,0x0F,0x85,0xE2,0x44,0x0B,0x00,0x41,
			0x3A,0xF5,0x0F,0x85,0x93,0x44,0x0B,0x00,0x41,0x3B,0xFD,0x7C,0x0F,0x48,0x8B,0xCB,
		},
	},
	{
		{3, 4},
		0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
		{
			0x4C,0x89,0x74,0x24,0x20,0x45,0x8B,0xCC,0x44,0x8B,0x84,0x24,0x58,0x01,0x00,0x00,
			0x4C,0x8B,0x64,0x24,0x50,0x49,0x8B,0xD4,0x48,0x8B,0x74,0x24,0x40,0x48,0x8B,0xCE,
		},
	},
	{
		{3, 5},
		0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
		{
			0x00,0x00,0x89,0x44,0x24,0x20,0x4C,0x8B,0x8C,0x24,0x38,0x01,0x00,0x00,0x44,0x8B,
			0xC6,0x8B,0x94,0x24,0x28,0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x50,0x49,0x8B,0xCC,
		},
	},
},
{//WINVISTA
	{
		{4, 0},
		0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
		{
			0x4C,0x89,0x6C,0x24,0x28,0x44,0x89,0x64,0x24,0x20,0x4D,0x8B,0xCE,0x44,0x8B,0xC7,
			0x48,0x8D,0x94,0x24,0x40,0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x60,0x49,0x8B,0xCC,
		},
	},
	{
		{4, 1},
		0, NULL, NCmSetValueKey, 0xFFFFFFFF,
		{
			0x48,0x8B,0x84,0x24,0x20,0x01,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x6C,
			0x24,0x20,0x4D,0x8B,0xCC,0x44,0x8B,0xC6,0x48,0x8D,0x54,0x24,0x48,0x48,0x8B,0xCF,
		},
	},
	{
		{4, 2},
		0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
		{
			0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xB0,0x00,0x00,0x00,0x4C,0x8B,0x84,
			0x24,0x00,0x01,0x00,0x00,0x48,0x8D,0x94,0x24,0xB0,0x00,0x00,0x00,0x48,0x8B,0xCF,
		},
	},
	{
		{4, 3},
		0, NULL, NCmDeleteKey, 0xFFE7F3FF,
		{
			0x49,0x3B,0xCD,0x74,0x0A,0xF6,0x41,0x04,0x80,0x0F,0x85,0x58,0x38,0x0E,0x00,0x41,
			0x3A,0xF5,0x0F,0x85,0x06,0x38,0x0E,0x00,0x41,0x3B,0xDD,0x7C,0x1D,0x48,0x8B,0xCF,
		},
	},
	{
		{4, 4},
		0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
		{
			0x30,0x89,0x74,0x24,0x28,0x4C,0x89,0x74,0x24,0x20,0x45,0x8B,0xCD,0x45,0x8B,0xC7,
			0x48,0x8B,0x7C,0x24,0x50,0x48,0x8B,0xD7,0x48,0x8B,0x74,0x24,0x40,0x48,0x8B,0xCE,
		},
	},
	{
		{4, 5},
		0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
		{
			0x24,0x28,0x44,0x89,0x64,0x24,0x20,0x4C,0x8B,0xCE,0x45,0x8B,0xC7,0x44,0x8B,0xAC,
			0x24,0x68,0x01,0x00,0x00,0x41,0x8B,0xD5,0x48,0x8B,0x74,0x24,0x50,0x48,0x8B,0xCE,
		},
	},
},
{//WIN7
	{
		{5, 0},
		0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
		{
			0x4C,0x89,0x6C,0x24,0x28,0x44,0x89,0x64,0x24,0x20,0x4D,0x8B,0xCE,0x44,0x8B,0xC7,
			0x48,0x8D,0x94,0x24,0x40,0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x60,0x49,0x8B,0xCC,
		},
	},
	{
		{5, 1},
		0, NULL, NCmSetValueKey, 0xFFFFFFFF,
		{
			0x48,0x8B,0x84,0x24,0x30,0x01,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x6C,
			0x24,0x20,0x4D,0x8B,0xCC,0x44,0x8B,0xC6,0x48,0x8D,0x54,0x24,0x48,0x48,0x8B,0xCF,
		},
	},
	{
		{5, 2},
		0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
		{
			0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xB0,0x00,0x00,0x00,0x4C,0x8B,0x84,
			0x24,0x00,0x01,0x00,0x00,0x48,0x8D,0x94,0x24,0xB0,0x00,0x00,0x00,0x48,0x8B,0xCF,
		},
	},
	{
		{5, 3},
		0, NULL, NCmDeleteKey, 0xFFE7F3FF,
		{
			0x49,0x3B,0xCD,0x74,0x0A,0xF6,0x41,0x04,0x80,0x0F,0x85,0x7A,0x55,0x0D,0x00,0x41,
			0x3A,0xF5,0x0F,0x85,0x28,0x55,0x0D,0x00,0x41,0x3B,0xDD,0x7C,0x1D,0x48,0x8B,0xCF,
		},
	},
	{
		{5, 4},
		0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
		{
			0x44,0x89,0x64,0x24,0x28,0x48,0x89,0x7C,0x24,0x20,0x45,0x8B,0xCE,0x45,0x8B,0xC7,
			0x48,0x8B,0x7C,0x24,0x50,0x48,0x8B,0xD7,0x48,0x8B,0x74,0x24,0x40,0x48,0x8B,0xCE,
		},
	},
	{
		{5, 5},
		0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
		{
			0x24,0x28,0x44,0x89,0x64,0x24,0x20,0x4C,0x8B,0xCE,0x45,0x8B,0xC7,0x44,0x8B,0xAC,
			0x24,0x68,0x01,0x00,0x00,0x41,0x8B,0xD5,0x48,0x8B,0x74,0x24,0x50,0x48,0x8B,0xCE,
		},
	},
},
{//WIN7SP1
	{
		{6, 0},
		0, NULL, NCmQueryValueKey, 0x00000000,
		{
			0x48,0x8D,0x94,0x24,0x30,0x01,0x00,0x00,0x4C,0x8B,0x64,0x24,0x48,0x4C,0x89,0x64,
			0x24,0x40,0x49,0x8B,0xCC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{6, 1},
		0, NULL, NCmSetValueKey, 0x00000000,
		{
			0x4D,0x8B,0xCD,0x44,0x8B,0x84,0x24,0x58,0x01,0x00,0x00,0x48,0x8D,0x54,0x24,0x48,
			0x48,0x8B,0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{6, 2},
		0, NULL, NCmDeleteValueKey, 0x00000000,
		{
			0x4C,0x8B,0x84,0x24,0x10,0x01,0x00,0x00,0x48,0x8D,0x94,0x24,0xC0,0x00,0x00,0x00,
			0x48,0x8B,0xCE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{6, 3},
		0, NULL, NCmDeleteKey, 0x00000000,
		{
			0x41,0x3A,0xF5,0x0F,0x85,0x4B,0x37,0x0D,0x00,0x41,0x3B,0xFD,0x7C,0x0F,0x48,0x8B,
			0xCB,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{6, 4},
		0, NULL, NCmEnumerateKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{6, 5},
		0, NULL, NCmEnumerateValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
},
{//WIN8
	{
		{7, 0},
		0, NULL, NCmQueryValueKey, 0xDFF7FFFF,
		{
			0x4C,0x89,0x7C,0x24,0x28,0x44,0x89,0x74,0x24,0x20,0x4D,0x8B,0xCC,0x44,0x8B,0xC7,
			0x48,0x8D,0x94,0x24,0x70,0x01,0x00,0x00,0x4C,0x8B,0x74,0x24,0x50,0x49,0x8B,0xCE,
		},
	},
	{
		{7, 1},
		0, NULL, NCmSetValueKey, 0xFFFFFFFF,
		{
			0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x89,0x5C,0x24,0x20,0x4C,0x8B,0x4C,0x24,0x60,
			0x45,0x8B,0xC5,0x48,0x8D,0x54,0x24,0x50,0x48,0x8B,0x7C,0x24,0x48,0x48,0x8B,0xCF,
		},
	},
	{
		{7, 2},
		0, NULL, NCmDeleteValueKey, 0xFFFF7FFE,
		{
			0xE1,0x01,0x0F,0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xE0,0x00,0x00,0x00,
			0x4C,0x8B,0xC6,0x48,0x8D,0x94,0x24,0xE0,0x00,0x00,0x00,0x48,0x8B,0x4C,0x24,0x50,
		},
	},
	{
		{7, 3},
		0, NULL, NCmDeleteKey, 0x009887FF,
		{
			0xE4,0x01,0x00,0x00,0xFF,0xC0,0x66,0x89,0x81,0xE4,0x01,0x00,0x00,0x66,0x85,0xC0,
			0x0F,0x84,0xB8,0x00,0x00,0x00,0x48,0x8B,0x7D,0xA7,0x45,0x8A,0xFD,0x48,0x8B,0xCF,
		},
	},
	{
		{7, 4},
		0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
		{
			0x30,0x89,0x74,0x24,0x28,0x48,0x89,0x7C,0x24,0x20,0x45,0x8B,0xCC,0x45,0x8B,0xC6,
			0x48,0x8B,0x7C,0x24,0x50,0x48,0x8B,0xD7,0x48,0x8B,0x74,0x24,0x48,0x48,0x8B,0xCE,
		},
	},
	{
		{7, 5},
		0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
		{
			0x00,0x4C,0x89,0x64,0x24,0x28,0x89,0x74,0x24,0x20,0x4D,0x8B,0xCE,0x45,0x8B,0xC7,
			0x44,0x8B,0x74,0x24,0x50,0x41,0x8B,0xD6,0x48,0x8B,0x74,0x24,0x58,0x48,0x8B,0xCE,
		},
	},
},
{//WIN8.1
	{
		{8, 0},
		0, NULL, NCmQueryValueKey, 0xFFFFFFFF,
		{
			0x01,0x00,0x00,0x4C,0x89,0x6C,0x24,0x28,0x44,0x89,0x7C,0x24,0x20,0x4D,0x8B,0xCC,
			0x44,0x8B,0x44,0x24,0x48,0x48,0x8D,0x94,0x24,0x60,0x01,0x00,0x00,0x49,0x8B,0xCE,
		},
	},
	{
		{8, 1},
		0, NULL, NCmSetValueKey, 0xFFFFFFFF,
		{
			0xB8,0x00,0x00,0x00,0x48,0x89,0x44,0x24,0x28,0x44,0x89,0x74,0x24,0x20,0x4C,0x8B,
			0x4C,0x24,0x68,0x44,0x8B,0xC7,0x48,0x8D,0x54,0x24,0x50,0x48,0x8B,0x4C,0x24,0x60,
		},
	},
	{
		{8, 2},
		0, NULL, NCmDeleteValueKey, 0xFFFFFFFF,
		{
			0xE1,0x01,0x0F,0x28,0x44,0x24,0x40,0x66,0x0F,0x7F,0x84,0x24,0xE0,0x00,0x00,0x00,
			0x4C,0x8B,0xC6,0x48,0x8D,0x94,0x24,0xE0,0x00,0x00,0x00,0x48,0x8B,0x4C,0x24,0x50,
		},
	},
	{
		{8, 3},
		0, NULL, NCmDeleteKey, 0xFFFFFFFF,
		{
			0xE4,0x01,0x00,0x00,0xFF,0xC0,0x66,0x89,0x81,0xE4,0x01,0x00,0x00,0x66,0x85,0xC0,
			0x0F,0x84,0xBC,0x00,0x00,0x00,0x48,0x8B,0x7D,0xB7,0x45,0x8A,0xFD,0x48,0x8B,0xCF,
		},
	},
	{
		{8, 4},
		0, NULL, NCmEnumerateKey, 0xFFFFFFFF,
		{
			0x8B,0x84,0x24,0xA0,0x01,0x00,0x00,0x89,0x44,0x24,0x28,0x4C,0x89,0x74,0x24,0x20,
			0x45,0x8B,0xCF,0x45,0x8B,0xC5,0x48,0x8B,0x54,0x24,0x58,0x48,0x8B,0x4C,0x24,0x48,
		},
	},
	{
		{8, 5},
		0, NULL, NCmEnumerateValueKey, 0xFFFFFFFF,
		{
			0x4C,0x24,0x58,0x48,0x39,0x5C,0x24,0x60,0x0F,0x85,0x7E,0xC0,0x19,0x00,0x4C,0x89,
			0x6C,0x24,0x28,0x89,0x44,0x24,0x20,0x4D,0x8B,0xCE,0x44,0x8B,0xC6,0x41,0x8B,0xD7,
		},
	},
},
{//WIN10
	{
		{9, 0},
		0, NULL, NCmQueryValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{9, 1},
		0, NULL, NCmSetValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{9, 2},
		0, NULL, NCmDeleteValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{9, 3},
		0, NULL, NCmDeleteKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{9, 4},
		0, NULL, NCmEnumerateKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
	{
		{9, 5},
		0, NULL, NCmEnumerateValueKey, 0x00000000,
		{
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
			0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		},
	},
},
},

获取DeviceObject对象类型

POBJECT_TYPE GetDeviceObjectType()
{
	UNICODE_STRING UAcpi;
	UNICODE_STRING UFilePath;
	NTSTATUS status;
	PDRIVER_OBJECT pDrvObj = NULL;
	PDEVICE_OBJECT pDevObj = NULL;
	HANDLE FileHandle = NULL;
	POBJECT_TYPE ObjectType = NULL;
	RtlInitUnicodeString(&UAcpi,L"\\Driver\\ACPI");
	status = ObReferenceObjectByName(&UAcpi,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,0,*IoDriverObjectType,KernelMode,NULL,&pDrvObj);
	if(NT_SUCCESS(status) && pDrvObj && pDrvObj->DeviceObject)
	{
		pDevObj = pDrvObj->DeviceObject;
	}
	if(pDevObj)
	{
		ObjectType = (POBJECT_TYPE)((PUCHAR)pDevObj-16);
	}
	if(pDrvObj)
	{
		ObDereferenceObject(pDrvObj);
		pDrvObj = NULL;
	}
	if(FileHandle)
	{
		ZwClose(FileHandle);
		FileHandle = NULL;
	}
	return ObjectType;
}

QQPCHW.sys分析

控制码

0x222024
	初始化线程id表
	buffer= 用Rabbit算法加密过得线程id表   sizeof=传入缓冲区大小
	
0x222004
	读取PCI数据                结构体成员含义参见HalGetBusDataByOffset参数
	buffer=                sizeof=0x18
	+00        ULONG BusNumber                <==>   ULONG ret
	+04        BYTE data1
	+08        BYTE data2   data2低3位和data1低5位组成SlotNumber
	+0C        PVOID Offset
	+10        ULONG Length
	+14        PVOID Buffer       

0x222008
	设置PCI数据   结构体成员含义参见HalSetBusDataByOffset参数
	buffer=                sizeof=0x18
	+00        ULONG BusNumber                <==>   ULONG ret
	+04        BYTE data1
	+08        BYTE data2   data2低3位和data1低5位组成SlotNumber
	+0C        PVOID Offset
	+10        ULONG Length
	+14        PVOID Buffer
	
0x22200C
	读取msr寄存器
	buffer=                sizeof=9
	+00        DWORD msrindex  存储读取序号 <==>  LONGLONG 读取到的数据
	
0x222010
	写入msr寄存器
	buffer=                sizeof=0xC
	+0        DWORD msrindex
	+4        LONGLONG value  要写入的值

0x222014
	读取端口
	buffer=         sizeof=9                        READ_PORT_UCHAR/USHORT/ULONG
	+0        BYTE readsize 0:UCHAR/1:USHORT/2:ULONG                <==>        DWORD ret
	+5        PVOID Port
	
	写入端口
	buffer=                sizeof=8                        WRITE_PORT_UCHAR
	+0        PVOID Port        端口号
	+4        UCHAR Value 数据                <==>         DWORD TAG=0x87654321  写入成功标志
	
0x222018
	读取端口
	buffer=                sizeof=8                        READ_PORT_UCHAR
	+0 PUCHAR* Port 端口号                <==>    UCHAR取出的数据
	+4 =>DWORD TAG=0x87654321  写入成功标志
	
0x22201C
	写入端口
	buffer=                sizeof=8                        WRITE_PORT_UCHAR
	+0        PVOID Port        端口号
	+4        UCHAR Value 数据                <==>         DWORD TAG=0x87654321  写入成功标志

0x222020
	写入端口
	buffer=         sizeof=9                        READ_PORT_UCHAR/USHORT/ULONG
	+0        BYTE writesize 0:UCHAR/1:USHORT/2:ULONG                <==>        DWORD ret
	+5        PVOID Port
	
0x222028
	改写PCI conf1设备空间的一个数据??实在找不到资料了!不知道在干啥
		WRITE_PORT_ULONG((PULONG)0xCF8, 0x8000F8F0);
v13 = READ_PORT_ULONG((PULONG)0xCFC);
Buffer = v13;
if ( v13 == -1
	|| (Buffer = (v13 & 0xFFFFC000) + 0x3418,
		PhysicalAddress.LowPart = Buffer,
		(v14 = (ULONG *)MmMapIoSpace((PHYSICAL_ADDRESS)Buffer, 4u, 0)) == 0)
	|| (READ_REGISTER_BUFFER_ULONG(v14, &Buffer, 1u),
		Buffer &= 0xFFFFFFF7,
		MmUnmapIoSpace(v14, 4u),
		(v15 = (ULONG *)MmMapIoSpace((PHYSICAL_ADDRESS)*(unsigned int *)&PhysicalAddress, 4u, 0)) == 0) )
{
	v2 = 0xC0000001;
	goto LABEL_4;
}
WRITE_REGISTER_BUFFER_ULONG(v15, &Buffer, 1u);
MmUnmapIoSpace(v15, 4u);

0x222040
	创建物理地址内存映射 \\Device\\PhysicalMemory
	buffer=
	+00 HANDLE hSection
	+04
	+08        PVOID BaseAddress  内存映射地址

0x222044
	取消物理地址内存映射
	buffer=
	+00 HANDLE hSection
	+04        PHYSICAL_ADDRESS BusAddress 物理地址
	+0C        PVOID BaseAddress 对齐内存映射地址

Tssk.sys分析

  该驱动主要用于防止各类已知rootkit驱动的攻击,有很多恢复系统函数的操作,具体过程不详细介绍,看idb即可。

基础库

由符号链接名获取设备名

BOOLEAN GetDeviceNameBySymbolicName(PUNICODE_STRING SymbolicName,PUNICODE_STRING DeviceName)
{
    OBJECT_ATTRIBUTES ObjectAttributes;
    UNICODE_STRING LinkTarget = {0};
    HANDLE LinkHandle = NULL;
    NTSTATUS Status;
    ULONG ReturnedLength = 0;
    BOOLEAN Ret = FALSE;
    if(!SymbolicName || !DeviceName)
        return FALSE;
    InitializeObjectAttributes(&ObjectAttributes,SymbolicName,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
    ZwOpenSymbolicLinkObject(&LinkHandle,GENERIC_READ,&ObjectAttributes);
    if(LinkHandle)
    {
        if(ZwQuerySymbolicLinkObject(LinkHandle, &LinkTarget, &ReturnedLength) == STATUS_BUFFER_TOO_SMALL)
        {
            if(ReturnedLength)
            {
                ReturnedLength += 2;
                LinkTarget.Buffer = (PWCH)ExAllocatePool(NonPagedPool,ReturnedLength);
                if(LinkTarget.Buffer)
                {
                    RtlZeroMemory(LinkTarget.Buffer,ReturnedLength);
                    LinkTarget.Length = 0;
                    LinkTarget.MaximumLength = ReturnedLength;
                    if(ZwQuerySymbolicLinkObject(LinkHandle, &LinkTarget, &ReturnedLength) == STATUS_SUCCESS)
                        Ret = TRUE;
                }
            }
        }
        if(LinkHandle)
        {
            ZwClose(LinkHandle);
            LinkHandle = NULL;
        }
        if(Ret)
            *DeviceName = LinkTarget;
    }
    if(LinkTarget.Buffer)
        ExFreePool(LinkTarget.Buffer);
}

遍历所有硬盘分区

BOOLEAN GetHarddiskPartitioNumber(PDEVICE_OBJECT DeviceObject, PULONG OutPartitionNum)
{
    KEVENT Event;
    IO_STATUS_BLOCK Ios;
    NTSTATUS Status;
    BOOLEAN Ret = FALSE;
    if(!DeviceObject || !OutPartitionNum)
        return FALSE;
    KeInitializeEvent(&Event);
    PVOID Buf = ExAllocatePool(NonPagedPool,0x2000);
    RtlZeroMemory(&Buf,0x2000);
    PIRP Irp = IoBuildDeviceIoControlRequest(0x70050,DeviceObject,NULL,0,Buf,0x2000,FALSE,&Event,&Ios);
    if(Irp)
    {
        Status = IoCallDriver(DeviceObject,Irp);
        if(Status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&Event,Suspended,KernelMode,FALSE,NULL);
            Status = Ios.Status;
        }
        if(NT_SUCCESS(Status))
        {
            *OutPartitionNum = *((ULONG*)Buf+1);
            Ret = TRUE;
        }
    }
    if(Buf)
        ExFreePool(Buf);
    return Ret;
}

void EnumPartition()
{
    if(KeGetCurrentIrql() != PASSIVE_LEVEL)
        return;
    PCONFIGURATION_INFORMATION config = IoGetConfigurationInformation();
    for(int DiskIndex=0;DiskIndex < config->DiskCount;DiskIndex++)
    {
        WCHAR Disk[260];
        UNICODE_STRING UDisk;
        PFILE_OBJECT FileObj = NULL;
        PDEVICE_OBJECT DevObj = NULL;
        vsnwprintfW(Disk,260,"\\Device\\Harddisk%d\\Partition0",DiskIndex);
        RtlInitUnicodeString(&UDisk,Disk);
        if(NT_SUCCESS(IoGetDeviceObjectPointer(&UDisk,FILE_READ_ATTRIBUTES,&FileObj,&DevObj))
        {
            if(MmIsAddressValid(FileObj->DeviceObject) && MmIsAddressValid(FileObj->DeviceObject->DriverObject))
            {
                ULONG PartitionNumber;
                if(GetHarddiskPartitionNumber(DevObj,&PartitionNumber))
                {
                    for(int PartitionIndex=0;PartitionIndex < PartitionNumber;PartitionIndex++)
                    {
                        WCHAR Partition[260];
                        UNICODE_STRING UPartition;
                        PFILE_OBJECT FileObjx = NULL;
                        PDEVICE_OBJECT DevObjx = NULL;
                        vsnwprintfW(Partition,260,"\\Device\\Harddisk%d\\Partition%d",DiskIndex,PartitionIndex);
                        RtlInitUnicodeString(&UPartition,Partition);
                        if(NT_SUCCESS(IoGetDeviceObjectPointer(&UPartition,FILE_READ_ATTRIBUTES,&FileObjx,&DevObjx))
                        {
                            if(MmIsAddressValid(FileObjx->DeviceObject) && MmIsAddressValid(FileObjx->DeviceObject->DriverObject))
                            {
                                
                            }
                        }
                    }
                }
            }
        }
    }
}

由进程对象获取文件对象

  • Xp之前
    • 由PsGetProcessSectionBaseAddress得到SectionBaseAddress在EPROCESS中的偏移,前4字节为SectionObject偏移
    • 由PEPROCESS得到_SECTION.ControlArea.FilePointer
  • Xp之后 PsReferenceProcessFilePointer得到