2018年2月9日星期五

查看映像回调的函数的地址

标题:查看映像回调的函数的地址。

经IDA分析:
PsSetLoadImageNotifyRoutine调用了PsSetLoadImageNotifyRoutineEx
PsSetLoadImageNotifyRoutineEx用到了PspLoadImageNotifyRoutine,PspLoadImageNotifyRoutineCount。

下面是简要的分析过程:
0: kd> ||
.  0 64-bit Full kernel dump: C:\WINDOWS\livekd.dmp
0: kd> vertarget
Windows 8 Kernel Version 9200 MP (8 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 16299.15.amd64fre.rs3_release.170928-1534
Machine Name:
Kernel base = 0xfffff800`95414000 PsLoadedModuleList = 0xfffff800`95775ff0
Debug session time: Fri Jan  5 20:23:00.320 2018 (UTC + 8:00)
System Uptime: 1 days 0:23:22.648
0: kd> dd nt!PspLoadImageNotifyRoutineCount L1
fffff800`95bfee80  00000001
0: kd> dq nt!PspLoadImageNotifyRoutine
fffff800`957ace80  ffffd489`9e93125f 00000000`00000000
fffff800`957ace90  00000000`00000000 00000000`00000000
fffff800`957acea0  00000000`00000000 00000000`00000000
fffff800`957aceb0  00000000`00000000 00000000`00000000
fffff800`957acec0  00000000`00000000 00000000`00000000
fffff800`957aced0  00000000`00000000 00000000`00000000
fffff800`957acee0  00000000`00000000 00000000`00000000
fffff800`957acef0  00000000`00000000 00000000`00000000
0: kd> dq ffffd489`9e93125f - @@(sizeof(void *)) L1
ffffd489`9e931257  fff80184`974e1000
0: kd> u fffff80184`974e10
ahcache!CitmpLoadImageCallback:
fffff801`84974e10 4885c9          test    rcx,rcx
fffff801`84974e13 0f8472010000    je      ahcache!CitmpLoadImageCallback+0x17b (fffff801`84974f8b)
fffff801`84974e19 4c8bdc          mov     r11,rsp
fffff801`84974e1c 55              push    rbp
fffff801`84974e1d 4156            push    r14
fffff801`84974e1f 4157            push    r15
fffff801`84974e21 4883ec60        sub     rsp,60h
fffff801`84974e25 4533ff          xor     r15d,r15d


最后得出重要的脚本:
0: kd> r @$t0=poi(nt!PspLoadImageNotifyRoutineCount);r @$t1=nt!PspLoadImageNotifyRoutine;.for(r @$t2=0; @$t2<@$t0; r @$t2=@$t2+1){.printf /D "ImageNotifyRoutine(%d):%y\n", (@$t2 + 1), ((poi(((poi(@$t1+@$t2*@@(sizeof(void *))))-@@(sizeof(void *))))>>8) | ff00000000000000)}
ImageNotifyRoutine(1):ahcache!CitmpLoadImageCallback (fffff801`84974e10)
ImageNotifyRoutine(2):Memory access error at ')>>8) | ff00000000000000)'


--------------------------------------------------------------------------------------------------

made by correy
made at 9:59 2018/1/7
http://correy.webs.com

查看线程回调的函数的地址

标题:查看线程回调的函数的地址。

经IDA分析:
PsSetCreateThreadNotifyRoutine调用了PspSetCreateThreadNotifyRoutine
PsSetCreateThreadNotifyRoutineEx也调用了PspSetCreateThreadNotifyRoutine

分析PspSetCreateThreadNotifyRoutine用到了PspCreateThreadNotifyRoutine,PspCreateThreadNotifyRoutineCount,PspCreateThreadNotifyRoutineNonSystemCount。

下面是简要的分析过程:
0: kd> ||
.  0 64-bit Full kernel dump: C:\WINDOWS\livekd.dmp
0: kd> vertarget
Windows 8 Kernel Version 9200 MP (8 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 16299.15.amd64fre.rs3_release.170928-1534
Machine Name:
Kernel base = 0xfffff800`95414000 PsLoadedModuleList = 0xfffff800`95775ff0
Debug session time: Fri Jan  5 20:23:00.320 2018 (UTC + 8:00)
System Uptime: 1 days 0:23:22.648
0: kd> dd nt!PspCreateThreadNotifyRoutineCount L1
fffff800`95bfee84  00000002
0: kd> dd nt!PspCreateThreadNotifyRoutineNonSystemCount l1
fffff800`95bfee88  00000000
0: kd> dq nt!PspCreateThreadNotifyRoutine
fffff800`957acc80  ffffd489`a0e2ec0f ffffd489`a6c4a1ff
fffff800`957acc90  00000000`00000000 00000000`00000000
fffff800`957acca0  00000000`00000000 00000000`00000000
fffff800`957accb0  00000000`00000000 00000000`00000000
fffff800`957accc0  00000000`00000000 00000000`00000000
fffff800`957accd0  00000000`00000000 00000000`00000000
fffff800`957acce0  00000000`00000000 00000000`00000000
fffff800`957accf0  00000000`00000000 00000000`00000000
0: kd> dq ffffd489`a0e2ec0f - @@(sizeof(void *)) L1
ffffd489`a0e2ec07  fff80187`22d16c00
0: kd> u fffff80187`22d16c
nvlddmkm+0x11d16c:
fffff801`8722d16c 48895c2408      mov     qword ptr [rsp+8],rbx
fffff801`8722d171 4889742410      mov     qword ptr [rsp+10h],rsi
fffff801`8722d176 57              push    rdi
fffff801`8722d177 4883ec20        sub     rsp,20h
fffff801`8722d17b 488bf1          mov     rsi,rcx
fffff801`8722d17e 418ad8          mov     bl,r8b
fffff801`8722d181 488b0df0b76e00  mov     rcx,qword ptr [nvlddmkm!nvDumpConfig+0x82f68 (fffff801`87918978)]
fffff801`8722d188 488bfa          mov     rdi,rdx

最后得出重要的脚本:
0: kd> r @$t0=(poi(nt!PspCreateThreadNotifyRoutineCount) + poi(nt!PspCreateThreadNotifyRoutineNonSystemCount));r @$t1=nt!PspCreateThreadNotifyRoutine;.for(r @$t2=0; @$t2<@$t0; r @$t2=@$t2+1){.printf /D "ThreadNotifyRoutine(%d):%y\n", (@$t2 + 1), ((poi(((poi(@$t1+@$t2*@@(sizeof(void *))))-@@(sizeof(void *))))>>8) | ff00000000000000)}
ThreadNotifyRoutine(1):nvlddmkm+0x11d16c (fffff801`8722d16c)
ThreadNotifyRoutine(2):mmcss!CiThreadNotification (fffff801`88081010)

--------------------------------------------------------------------------------------------------

made by correy
made at 9:59 2018/1/7
http://correy.webs.com

2017年12月26日星期二

DbgPrintEx或KdPrintEx的用法

/*
题目:
简单的说是DbgPrintEx and KdPrintEx的用法。
复杂的说是Windows驱动的(调试)打印信息子系统的设计。

参考:
Reading and Filtering Debugging Messages
https://docs.microsoft.com/zh-cn/windows-hardware/drivers/devtest/reading-and-filtering-debugging-messages

说是说有这么几种类型的设备信息:
IHVVIDEO Video driver
IHVAUDIO Audio driver
IHVNETWORK Network driver
IHVSTREAMING Kernel streaming driver
IHVBUS Bus driver
IHVDRIVER Any other type of driver

我们开发硬件驱动的不多,所以,如果要编写网络驱动就用DPFLTR_IHVNETWORK_ID,其余的非硬件的就用DPFLTR_IHVDRIVER_ID,若文件和磁盘相关的等。
其实dpfilter.h文件里定义的更多。
还可以用windbg来验证/查看:
0: kd> x nt!Kd_*_Mask
fffff802`d35bb310 nt!Kd_LDR_Mask = <no type information>
fffff802`d35bb2bc nt!Kd_WDI_Mask = <no type information>
fffff802`d35bb21c nt!Kd_POWER_Mask = <no type information>
fffff802`d35bb208 nt!Kd_CAPIMG_Mask = <no type information>
fffff802`d35bb45c nt!Kd_SETUP_Mask = <no type information>
fffff802`d35bb358 nt!Kd_DMIO_Mask = <no type information>
fffff802`d35bb2fc nt!Kd_STORMINIPORT_Mask = <no type information>
fffff802`d35bb350 nt!Kd_DMADMIN_Mask = <no type information>
fffff802`d35bb3cc nt!Kd_SCCLIENT_Mask = <no type information>
fffff802`d35bb3ec nt!Kd_TCPIP_Mask = <no type information>
fffff802`d35bb400 nt!Kd_AMLI_Mask = <no type information>
fffff802`d35bb368 nt!Kd_PREFETCHER_Mask = <no type information>
fffff802`d35bb2f0 nt!Kd_VERIFIER_Mask = <no type information>
fffff802`d35bb450 nt!Kd_CRASHDUMP_Mask = <no type information>
fffff802`d35bb3d0 nt!Kd_SCSERVER_Mask = <no type information>
fffff802`d35bb410 nt!Kd_MOUCLASS_Mask = <no type information>
fffff802`d35bb288 nt!Kd_FVEVOL_Mask = <no type information>
fffff802`d35bb384 nt!Kd_MCHGR_Mask = <no type information>
fffff802`d35bb3a4 nt!Kd_WMICORE_Mask = <no type information>
fffff802`d35bb3b0 nt!Kd_UNIMODEM_Mask = <no type information>
fffff802`d35bb380 nt!Kd_IDEP_Mask = <no type information>
fffff802`d35bb230 nt!Kd_EXFAT_Mask = <no type information>
fffff802`d35bb314 nt!Kd_RTLTHREADPOOL_Mask = <no type information>
fffff802`d35bb298 nt!Kd_THREADORDER_Mask = <no type information>
fffff802`d35bb37c nt!Kd_PCIIDE_Mask = <no type information>
fffff802`d35bb320 nt!Kd_IHVSTREAMING_Mask = <no type information>
fffff802`d35bb214 nt!Kd_GPIO_Mask = <no type information>
fffff802`d35bb2e4 nt!Kd_VDSDYN_Mask = <no type information>
fffff802`d35bb3e0 nt!Kd_FASTFAT_Mask = <no type information>
fffff802`d35bb200 nt!Kd_STORAGECLASSMEMORY_Mask = <no type information>
fffff802`d35bb34c nt!Kd_WSOCKTRANSPORT_Mask = <no type information>
fffff802`d35bb24c nt!Kd_MSDSM_Mask = <no type information>
fffff802`d35bb254 nt!Kd_FLTREGRESS_Mask = <no type information>
fffff802`d35bb378 nt!Kd_FLOPPY_Mask = <no type information>
fffff802`d35bb224 nt!Kd_SE_Mask = <no type information>
fffff802`d35bb338 nt!Kd_SR_Mask = <no type information>
fffff802`d35bb3e8 nt!Kd_DMSYNTH_Mask = <no type information>
fffff802`d35bb394 nt!Kd_FUSION_Mask = <no type information>
fffff802`d35bb43c nt!Kd_REDBOOK_Mask = <no type information>
fffff802`d35bb26c nt!Kd_COVERAGE_Mask = <no type information>
fffff802`d35bb330 nt!Kd_IHVDRIVER_Mask = <no type information>
fffff802`d35bb370 nt!Kd_TERMSRV_Mask = <no type information>
fffff802`d35bb3c4 nt!Kd_SERENUM_Mask = <no type information>
fffff802`d35bb32c nt!Kd_IHVVIDEO_Mask = <no type information>
fffff802`d35bb318 nt!Kd_HPS_Mask = <no type information>
fffff802`d35bb2d0 nt!Kd_DEFAULT_Mask = <no type information>
fffff802`d35bb3d4 nt!Kd_NETAPI_Mask = <no type information>
fffff802`d35bb434 nt!Kd_SCSIPORT_Mask = <no type information>
fffff802`d3572920 nt!Kd_WIN2000_Mask = <no type information>
fffff802`d35bb31c nt!Kd_IHVBUS_Mask = <no type information>
fffff802`d35bb3e4 nt!Kd_NTOSPNP_Mask = <no type information>
fffff802`d35bb274 nt!Kd_USBSTOR_Mask = <no type information>
fffff802`d35bb258 nt!Kd_KSECDD_Mask = <no type information>
fffff802`d35bb428 nt!Kd_I8042PRT_Mask = <no type information>
fffff802`d35bb354 nt!Kd_DMCONFIG_Mask = <no type information>
fffff802`d35bb420 nt!Kd_LSERMOUS_Mask = <no type information>
fffff802`d35bb3a0 nt!Kd_BURNENG_Mask = <no type information>
fffff802`d35bb268 nt!Kd_CACHEMGR_Mask = <no type information>
fffff802`d35bb328 nt!Kd_IHVAUDIO_Mask = <no type information>
fffff802`d35bb33c nt!Kd_DMSERVER_Mask = <no type information>
fffff802`d35bb220 nt!Kd_DRIVEEXTENDER_Mask = <no type information>
fffff802`d35bb3fc nt!Kd_HALIA64_Mask = <no type information>
fffff802`d35bb414 nt!Kd_KBDCLASS_Mask = <no type information>
fffff802`d35bb39c nt!Kd_IMAPI_Mask = <no type information>
fffff802`d35bb3b4 nt!Kd_DCOMSS_Mask = <no type information>
fffff802`d35bb458 nt!Kd_NTFS_Mask = <no type information>
fffff802`d35bb35c nt!Kd_PCI_Mask = <no type information>
fffff802`d35bb340 nt!Kd_PROCESSOR_Mask = <no type information>
fffff802`d35bb29c nt!Kd_TPM_Mask = <no type information>
fffff802`d35bb454 nt!Kd_FSTUB_Mask = <no type information>
fffff802`d35bb390 nt!Kd_IDLETASK_Mask = <no type information>
fffff802`d35bb22c nt!Kd_FILETRACE_Mask = <no type information>
fffff802`d35bb2ac nt!Kd_HEAP_Mask = <no type information>
fffff802`d35bb438 nt!Kd_STORPROP_Mask = <no type information>
fffff802`d35bb278 nt!Kd_APPCOMPAT_Mask = <no type information>
fffff802`d35bb290 nt!Kd_EMS_Mask = <no type information>
fffff802`d35bb41c nt!Kd_KBDHID_Mask = <no type information>
fffff802`d35bb2b4 nt!Kd_KTM_Mask = <no type information>
fffff802`d35bb294 nt!Kd_ENVIRON_Mask = <no type information>
fffff802`d35bb388 nt!Kd_TAPE_Mask = <no type information>
fffff802`d35bb3f8 nt!Kd_VIDEO_Mask = <no type information>
fffff802`d35bb218 nt!Kd_CRASHDUMPXHCI_Mask = <no type information>
fffff802`d35bb324 nt!Kd_IHVNETWORK_Mask = <no type information>
fffff802`d35bb448 nt!Kd_CDROM_Mask = <no type information>
fffff802`d35bb464 nt!Kd_SYSTEM_Mask = <no type information>
fffff802`d35bb38c nt!Kd_SOFTPCI_Mask = <no type information>
fffff802`d35bb424 nt!Kd_SERMOUSE_Mask = <no type information>
fffff802`d35bb204 nt!Kd_VPCI_Mask = <no type information>
fffff802`d35bb244 nt!Kd_PSHED_Mask = <no type information>
fffff802`d35bb250 nt!Kd_MPIO_Mask = <no type information>
fffff802`d35bb408 nt!Kd_WMILIB_Mask = <no type information>
fffff802`d35bb3f0 nt!Kd_VIDEOPRT_Mask = <no type information>
fffff802`d35bb3d8 nt!Kd_PNPMGR_Mask = <no type information>
fffff802`d35bb2d8 nt!Kd_VDSUTIL_Mask = <no type information>
fffff802`d35bb23c nt!Kd_LSASS_Mask = <no type information>
fffff802`d35bb2f8 nt!Kd_PRINTSPOOLER_Mask = <no type information>
fffff802`d35bb284 nt!Kd_NDIS_Mask = <no type information>
fffff802`d35bb234 nt!Kd_CNG_Mask = <no type information>
fffff802`d35bb3c0 nt!Kd_UHCD_Mask = <no type information>
fffff802`d35bb2cc nt!Kd_MM_Mask = <no type information>
fffff802`d35bb2a4 nt!Kd_USERGDI_Mask = <no type information>
fffff802`d35bb300 nt!Kd_STORPORT_Mask = <no type information>
fffff802`d35bb30c nt!Kd_TCPIP6_Mask = <no type information>
fffff802`d35bb280 nt!Kd_NVCTRACE_Mask = <no type information>
fffff802`d35bb2b8 nt!Kd_PERFLIB_Mask = <no type information>
fffff802`d35bb440 nt!Kd_DISK_Mask = <no type information>
fffff802`d35bb2d4 nt!Kd_DFRGIFC_Mask = <no type information>
fffff802`d35bb3dc nt!Kd_SAMSS_Mask = <no type information>
fffff802`d35bb364 nt!Kd_RSFILTER_Mask = <no type information>
fffff802`d35bb360 nt!Kd_FCPORT_Mask = <no type information>
fffff802`d35bb3b8 nt!Kd_AUTOCHK_Mask = <no type information>
fffff802`d35bb210 nt!Kd_REFS_Mask = <no type information>
fffff802`d35bb2a0 nt!Kd_MMCSS_Mask = <no type information>
fffff802`d35bb334 nt!Kd_INFINIBAND_Mask = <no type information>
fffff802`d35bb374 nt!Kd_FDC_Mask = <no type information>
fffff802`d35bb2ec nt!Kd_VDS_Mask = <no type information>
fffff802`d35bb20c nt!Kd_WER_Mask = <no type information>
fffff802`d35bb2c4 nt!Kd_WOW64_Mask = <no type information>
fffff802`d35bb308 nt!Kd_ISAPNP_Mask = <no type information>
fffff802`d35bb348 nt!Kd_VSS_Mask = <no type information>
fffff802`d35bb228 nt!Kd_XSAVE_Mask = <no type information>
fffff802`d35bb2e8 nt!Kd_VDSBAS_Mask = <no type information>
fffff802`d35bb344 nt!Kd_PNPMEM_Mask = <no type information>
fffff802`d35bb3a8 nt!Kd_FLTMGR_Mask = <no type information>
fffff802`d35bb42c nt!Kd_CONFIG_Mask = <no type information>
fffff802`d35bb2c8 nt!Kd_DFSC_Mask = <no type information>
fffff802`d35bb444 nt!Kd_CLASSPNP_Mask = <no type information>
fffff802`d35bb3f4 nt!Kd_SVCHOST_Mask = <no type information>
fffff802`d35bb25c nt!Kd_TXF_Mask = <no type information>
fffff802`d35bb264 nt!Kd_MOUNTMGR_Mask = <no type information>
fffff802`d35bb404 nt!Kd_ACPI_Mask = <no type information>
fffff802`d35bb1f8 nt!Kd_ENDOFTABLE_Mask = <no type information>
fffff802`d35bb1fc nt!Kd_FSLIB_Mask = <no type information>
fffff802`d35bb270 nt!Kd_SBP2PORT_Mask = <no type information>
fffff802`d35bb28c nt!Kd_WDT_Mask = <no type information>
fffff802`d35bb40c nt!Kd_TWOTRACK_Mask = <no type information>
fffff802`d35bb44c nt!Kd_CDAUDIO_Mask = <no type information>
fffff802`d35bb2f4 nt!Kd_VSSDYNDISK_Mask = <no type information>
fffff802`d35bb36c nt!Kd_W32TIME_Mask = <no type information>
fffff802`d35bb2c0 nt!Kd_ALPC_Mask = <no type information>
fffff802`d35bb248 nt!Kd_UDFS_Mask = <no type information>
fffff802`d35bb3ac nt!Kd_SIS_Mask = <no type information>
fffff802`d35bb398 nt!Kd_SXS_Mask = <no type information>
fffff802`d35bb3c8 nt!Kd_SERIAL_Mask = <no type information>
fffff802`d35bb238 nt!Kd_SSPICLI_Mask = <no type information>
fffff802`d35bb27c nt!Kd_LUAFV_Mask = <no type information>
fffff802`d35bb2e0 nt!Kd_VDSDYNDR_Mask = <no type information>
fffff802`d35bb240 nt!Kd_STORVSP_Mask = <no type information>
fffff802`d35bb2a8 nt!Kd_WHEA_Mask = <no type information>
fffff802`d35bb3bc nt!Kd_RPCPROXY_Mask = <no type information>
fffff802`d35bb460 nt!Kd_SMSS_Mask = <no type information>
fffff802`d35bb418 nt!Kd_MOUHID_Mask = <no type information>
fffff802`d35bb260 nt!Kd_CFR_Mask = <no type information>
fffff802`d35bb430 nt!Kd_SCSIMINIPORT_Mask = <no type information>
fffff802`d35bb2b0 nt!Kd_IOSTRESS_Mask = <no type information>
fffff802`d35bb2dc nt!Kd_VDSLDR_Mask = <no type information>
fffff802`d35bb304 nt!Kd_SHPC_Mask = <no type information>

这次,我们关系的是:nt!Kd_IHVDRIVER_Mask。

关于级别,在dpfilter.h里就定义了这么几种,不过,自己还可以扩充。
#define DPFLTR_ERROR_LEVEL 0
#define DPFLTR_WARNING_LEVEL 1
#define DPFLTR_TRACE_LEVEL 2
#define DPFLTR_INFO_LEVEL 3
#define DPFLTR_MASK 0x80000000
注意:这是按bit来的。

奇怪:
在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter的DEFAULT or IHVDRIVER都设置为f了,但是用
1: kd> dd nt!Kd_IHVDRIVER_Mask L1
fffff802`d35bb330  00000000
的值不是f.
过一会,去了趟厕所,才明白:
DEFAULT不和nt!Kd_IHVDRIVER_Mask对应,而和nt!Kd_DEFAULT_Mask对应
推测IHVDRIVER不和nt!Kd_DEFAULT_Mask对应,而和nt!Kd_IHVDRIVER_Mask对应。

在这种情况下测试,只有DPFLTR_ERROR_LEVEL的信息会显示。
这大概就是:
If Level is 0, the bitfield is equivalent to 0x00000001. If Level is 31, the bitfield is equivalent to 0x80000000.
这句话来解释。

执行:
ed nt!Kd_IHVDRIVER_Mask 3
然后再测试,错误和告警都显示了。

执行:
ed nt!Kd_IHVDRIVER_Mask 7
然后显示:
1: kd> g
ERROR
WARNING
TRACE

执行:
1: kd> ed nt!Kd_IHVDRIVER_Mask 8
然后显示:
0: kd> g
ERROR
INFO
为何?如此?
8是二进制的1000.
只有这样解释,信息位是第三位(从右边数第四个),而第零位是默认的,无论如何在何种情况下都认为是1(不能说显示)。

执行:
ed nt!Kd_IHVDRIVER_Mask f
然后显示:
0: kd> g
ERROR
WARNING
TRACE
INFO
这四个都显示了。

由此可见,我们可以控制nt!Kd_IHVDRIVER_Mask的值,来控制我们的输出,而不用修改代码。
相应的估计注册表也可以,那是IHVDRIVER的键值。
这是一个调试手法,谨记。

进一步的测试:
本工程和nt!Kd_DEFAULT_Mask的值无关,证明见下:
0: kd> ed nt!Kd_DEFAULT_Mask 1
0: kd> dd nt!Kd_DEFAULT_Mask L1
fffff802`d35bb2d0  00000001
0: kd> g
ERROR
WARNING
TRACE
INFO
1: kd> dd nt!Kd_IHVDRIVER_Mask L1
fffff802`d35bb330  0000000f
不过,nt!Kd_DEFAULT_Mask好像和默认的输出有关。

made by correy
made at 2017.12.22
http://correy.webs.com
*/

#pragma once

#include <fltKernel.h>
#include <ntimage.h>
#include <ntstrsafe.h>
#include <ntdef.h>
#include <ntddk.h>
#include <windef.h>

#define TAG  'tset' //test


VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
    UNREFERENCED_PARAMETER(pDriverObject);
}


extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
{
UNREFERENCED_PARAMETER(pRegistryPath);

KdBreakPoint();

pDriverObject->DriverUnload = DriverUnload;

DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "ERROR\n");
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_WARNING_LEVEL, "WARNING\n");
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "TRACE\n");
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "INFO\n");

return STATUS_UNSUCCESSFUL;
}

2017年10月1日星期日

!vtop命令的X64分析

标题:X64的虚拟地址到物理地址的手工分析。

前言:虚拟地址到物理地址的转换这大部分是CPU的事,偶尔OS也做下,程序员一般不接触这,最多是了解下。

这里的实验环境是Windows 10 + windbg + vmware.

这里说下注意事项:
1.确保进程的上下文,就是CR3的值和进程对象的DirBase值一样。
2.加载符号文件,这是基本的也是重要的。
3.选取虚拟地址,如果实在不知道就用lm vm 看看某个模块的基地址。

--------------------------------------------------------------------------------------------------

0: kd> vertarget
Windows 10 Kernel Version 14393 MP (6 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 14393.1593.amd64fre.rs1_release.170731-1934
Machine Name:
Kernel base = 0xfffff800`8f091000 PsLoadedModuleList = 0xfffff800`8f38f040
Debug session time: Sun Oct  1 13:57:58.216 2017 (UTC + 8:00)
System Uptime: 0 days 0:01:27.925

选定一个虚拟内存,这个内存的信息如下:
0: kd> db 0x00007ff7`ceb8df10 L5
00007ff7`ceb8df10  74 65 73 74 00                                   test.

看看系统命令对这个地址的转换:
0: kd> !vtop 0 00007ff7ceb8df10
Amd64VtoP: Virt 00007ff7`ceb8df10, pagedir 3a4d8000
Amd64VtoP: PML4E 3a4d87f8
Amd64VtoP: PDPE 303b5ef8
Amd64VtoP: PDE 34e363a8
Amd64VtoP: PTE 354b7c68
Amd64VtoP: Mapped phys 371def10
Virtual address 7ff7ceb8df10 translates to physical address 371def10.
可以以这个命令的信息为参考进行分析。

查看CR3的值:
0: kd> r cr3 
cr3=000000003a4d8000

自己手动分析虚拟地址的格式:
0: kd> .formats 00007ff7ceb8df10
Evaluate expression:
  Hex:     00007ff7`ceb8df10
  Decimal: 140702301871888
  Octal:   0000003777371656157420
  Binary:  0000000000000000 011111111 111011111 001110101 110001101 111100010000    这里自己格式化下。
                                   ff       1df        75       18d          f10    这个是自己的手工分析,具体的见intel的资料。
  Chars:   .......
  Time:    Wed Jun 13 04:23:50.187 1601 (UTC + 8:00)
  Float:   low -1.55081e+009 high 4.59051e-041
  Double:  6.95162e-310

最终的物理地址的内容是:
0: kd> !db 371def10 L5
#371def10 74 65 73 74 00 test.....E......

!vtop命令已经实现了,但是它是如何实现的呢?
这个命令显示的信息太简单了,下面就是自己的分析。

--------------------------------------------------------------------------------------------------

PML4E 3a4d87f8,这个数是怎么来的呢?
0: kd> ? cr3 + ff * 8
Evaluate expression: 978159608 = 00000000`3a4d87f8

PDPE 303b5ef8,这个数是怎么来的呢?
0: kd> !dq 3a4d87f8 L1
#3a4d87f8 01000000`303b5867
0: kd> ? 303b5000 + 8 * 1df
Evaluate expression: 809197304 = 00000000`303b5ef8

PDE 34e363a8,这个数是怎么来的呢?
0: kd> !dq 303b5ef8 L1
#303b5ef8 01100000`34e36867
0: kd> ? 34e36000 + 8 * 75
Evaluate expression: 887317416 = 00000000`34e363a8

PTE 354b7c68,这个数是怎么来的呢?
0: kd> !dq 34e363a8 L1
#34e363a8 01200000`354b7867
0: kd> ? 354b7000 + 8 * 18d
Evaluate expression: 894139496 = 00000000`354b7c68

最后就是那个物理地址了。
0: kd> !dq 354b7c68 L1
#354b7c68 a0600000`371de025
0: kd> ? 371de000 + f10
Evaluate expression: 924708624 = 00000000`371def10

--------------------------------------------------------------------------------------------------

made by correy
made at 2017/10/1
http://correy.webs.com

2017年9月7日星期四

SeRegisterImageVerificationCallback

/*
如何在驱动中获取SYS或者DLL,EXE等的签名信息?
自己编写代码也可以,就是难定位到文件的签名文件,如:用CAT的。

高版本的WDK下有个Early Launch Anti-Malware Driver或者叫elam工程。
这个工程IoRegisterBootDriverCallback的使用有限制,测试了没有成功:平常返回失败,BOOT启动也失败。
不过,在这里看到一个数据结构:PBDCB_IMAGE_INFORMATION。

偶尔你会看到这两个函数:
SeRegisterImageVerificationCallback,SeUnregisterImageVerificationCallback
在网上一搜,果然看到:
http://www.codemachine.com/article_kernel_callback_functions.html
http://eretik.omegahg.com/art/1E.html
其实这两个函数定义在WDK8.1及以上的版本的WDM.H中,且也导出了,所以可直接使用。
本文就是关于这的测试代码。

made by correy
made at 2017.09.07
http://correy.webs.com
*/

#include <fltKernel.h>

PVOID g_CallbackHandle;


VOID PrintHex(_In_reads_bytes_(DataSize) PVOID Data, _In_ ULONG DataSize)
/*++
Routine Description:
This routine prints out the supplied data in hexadecimal form.
Arguments:
Data - Supplies a pointer to the data to be printed.
DataSize - Supplies the length in bytes of the data to be printed.
--*/
{
    PCUCHAR Bytes;
    ULONG Index;

    for (Bytes = (PCUCHAR)Data, Index = 0; Index < DataSize; Index++)
    {
        if ((Index & 15) == 0)
        {
            KdPrint(("\r\n:    "));
        }

        KdPrint(("%02x ", Bytes[Index]));
    }

    KdPrint(("\r\n"));
}


VOID MY_SE_IMAGE_VERIFICATION_CALLBACK_FUNCTION(_In_opt_ PVOID CallbackContext, _In_ SE_IMAGE_TYPE ImageType, _Inout_ PBDCB_IMAGE_INFORMATION ImageInformation)
/*
加载没有签名的驱动这里拦截不到。

估计这里的ImageType的值和传递给SeRegisterImageVerificationCallback的第一个参数的值一样。
*/
{
    UNREFERENCED_PARAMETER(CallbackContext);

    KdPrint(("    ImageType = 0x%08x.\r\n", ImageType));

    // Display the image name and any associated registry path.
    KdPrint(("    Image name \"%wZ\"\r\n", &ImageInformation->ImageName));
    if (ImageInformation->RegistryPath.Buffer != NULL)
    {
        KdPrint(("    Registry path \"%wZ\"\r\n", &ImageInformation->RegistryPath));
    }

    // Did this image fail Code Integrity checks?
    if ((ImageInformation->ImageFlags & BDCB_IMAGEFLAGS_FAILED_CODE_INTEGRITY) != 0)
    {
        KdPrint(("    FAILED Code Integrity checks but boot policy allowed it to be loaded.\r\n"));
    }

    // Display the image's hash.
    if (ImageInformation->ImageHash != NULL && ImageInformation->ImageHashLength != 0)
    {
        KdPrint(("    Image hash algorithm = 0x%08x.\r\n", ImageInformation->ImageHashAlgorithm));
        KdPrint(("    Image hash:"));
        PrintHex(ImageInformation->ImageHash, ImageInformation->ImageHashLength);
    }

    // Display who signed the image (if at all).
    if (ImageInformation->CertificatePublisher.Buffer != NULL)
    {
        KdPrint(("    Image is signed by \"%wZ\".\r\n", &ImageInformation->CertificatePublisher));//重点是获取这个。
        if (ImageInformation->CertificateIssuer.Buffer != NULL)
        {
            KdPrint(("    Certificate issued by \"%wZ\".\r\n", &ImageInformation->CertificateIssuer));
        }

        if (ImageInformation->CertificateThumbprint != NULL && ImageInformation->CertificateThumbprintLength != 0)
        {
            KdPrint(("    Certificate thumb print algorithm = 0x%08x.\r\n", ImageInformation->ThumbprintHashAlgorithm));
            KdPrint(("    Certificate thumb print:"));
            PrintHex(ImageInformation->CertificateThumbprint, ImageInformation->CertificateThumbprintLength);
        }
    }
    else
    {
        KdPrint(("    Not signed.\r\n"));
    }

    KdPrint(("\r\n"));
}


extern "C" void DriverUnload(PDRIVER_OBJECT driver_object)
{
    UNREFERENCED_PARAMETER(driver_object);

    SeUnregisterImageVerificationCallback(g_CallbackHandle);
}


extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)
{
    UNREFERENCED_PARAMETER(registry_path);
    PAGED_CODE();

    __debugbreak();

    driver_object->DriverUnload = DriverUnload;

    NTSTATUS status = STATUS_SUCCESS;

#if (NTDDI_VERSION < NTDDI_WINBLUE)
    return STATUS_UNSUCCESSFUL;
#endif

    status = SeRegisterImageVerificationCallback(SeImageTypeDriver, SeImageVerificationCallbackInformational, MY_SE_IMAGE_VERIFICATION_CALLBACK_FUNCTION, NULL, NULL, &g_CallbackHandle);

    return status;
}

2017年6月2日星期五

驱动中获取哈希

/*
功能:驱动中获取哈希。

注意事项:
1.要链接到cng.lib,而不是应用层的Bcrypt.lib,
  否则驱动启动因为找不到以来的文件,而显示错误码:2,及找不到文件。
  具体的做法是:
  SOURCE文件的TARGETLIBS加上$(DDK_LIB_PATH)\cng.lib
  或者:
  sources.props或类似的文件里的TARGETLIBS加上$(DDK_LIB_PATH)\cng.lib。
  再说下是DDK_LIB_PATH,而不是SDK_LIB_PATH。

made by correy
made at 2017.06.02
http://correy.webs.com
*/


#include <ntifs.h>
#include <windef.h>
#include <Bcrypt.h>
#include <Ntstrsafe.h>


#pragma warning(disable:4201) // nameless struct/union
#pragma warning(disable:4214) // bit field types other than int
#pragma warning(disable:4100) // 未引用的形参
#pragma warning(disable:4101) // 未引用的局部变量
#pragma warning(disable:4189) // 局部变量已初始化但不引用


#define TAG 'test' //test


BOOL HASH(IN PBYTE rgbMsg, IN ULONG cbInput, LPWSTR algorithm, OUT PBYTE * Hash, DWORD * HashLen)
    /*
    注意:
    1.多字节和单字节。
    2.算法名区分大小写,否者出现异常。
    3.pbHash由调用者释放。

    参考:https://msdn.microsoft.com/en-us/library/windows/desktop/aa376217(v=vs.85).aspx
    */
{
    BOOL B = FALSE;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    BCRYPT_ALG_HANDLE hAlg = NULL;
    DWORD cbData = 0;//calculate the size of the buffer to hold the hash object
    DWORD cbHashObject    = 0;
    PBYTE pbHashObject = NULL;
    DWORD cbHash = 0;//calculate the length of the hash
    PBYTE pbHash = NULL;
    BCRYPT_HASH_HANDLE hHash = NULL;

    if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAlg, algorithm, NULL, 0)))//open an algorithm handle
    {
        goto Cleanup;
    }
    
    if(!NT_SUCCESS(status = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0)))
    {
        goto Cleanup;
    }
    pbHashObject = (PBYTE)ExAllocatePoolWithTag(NonPagedPoolNx, cbHashObject, TAG);
    if(NULL == pbHashObject)
    {
        goto Cleanup;
    }
    RtlZeroMemory(pbHashObject, cbHashObject);
    
    if(!NT_SUCCESS(status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0)))
    {
        goto Cleanup;
    }
    pbHash = (PBYTE)ExAllocatePoolWithTag(NonPagedPoolNx, cbHash, TAG);
    if(NULL == pbHash)
    {
        goto Cleanup;
    }
    RtlZeroMemory(pbHash, cbHash);

    if(!NT_SUCCESS(status = BCryptCreateHash(hAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0)))//create a hash
    {
        goto Cleanup;
    }
    
    if(!NT_SUCCESS(status = BCryptHashData(hHash, rgbMsg, cbInput, 0)))//hash some data
    {
        goto Cleanup;
    }

    //pbHash是哈希内容,cbHash是哈希的长度。
    
    if(!NT_SUCCESS(status = BCryptFinishHash(hHash, pbHash, cbHash, 0)))//close the hash
    {
        goto Cleanup;
    }

    //wprintf(L"Success!\n");

    * Hash = pbHash;
    * HashLen = cbHash;
    B = TRUE;

Cleanup:

    if(hAlg)
    {
        BCryptCloseAlgorithmProvider(hAlg,0);
    }

    if (hHash)    
    {
        BCryptDestroyHash(hHash);
    }

    if(pbHashObject)
    {
        ExFreePoolWithTag(pbHashObject, TAG);
    }

    //if(pbHash)
    //{
    //    HeapFree(GetProcessHeap(), 0, pbHash);
    //}

    return B;
}


BOOL HASHFILE(LPCTSTR lpFileName, LPWSTR algorithm, LPWSTR lpFileHash)
    /*
    注意:lpFileName支持DOS格式,包括流,
         但是不支持:
         1.NT式的,\Device\XXX 
         2.带环境扩展的,%systemroot%
         3.网络的也不行,如:\Device\Mup\vmware-host\Shared Folders\XXX
         4.还有\SystemRoot\system32\drivers\spsys.sys。
    注意:lpFileHash提供的空间要足够大,足够容纳想要的数据。
    */
{
    unsigned int status = STATUS_SUCCESS;
    BOOL B = FALSE;
    HANDLE hFile = NULL; 
    PBYTE buffer = NULL;
    DWORD NumberOfBytesRead = 0;
    PBYTE Hash;
    DWORD HashLen;
    unsigned int i;
    OBJECT_ATTRIBUTES ob;
    IO_STATUS_BLOCK  IoStatusBlock = {0};
    LARGE_INTEGER AllocationSize = {0};
    UNICODE_STRING FileName;
    PFILE_OBJECT FileObject = 0;
    LARGE_INTEGER file_size = {0};
    LARGE_INTEGER ByteOffset = {0};

    RtlInitUnicodeString(&FileName, lpFileName);
    InitializeObjectAttributes(&ob, &FileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
    status = ZwCreateFile(
        &hFile, 
        FILE_ALL_ACCESS | SYNCHRONIZE, 
        &ob,
        &IoStatusBlock,
        &AllocationSize, 
        FILE_ATTRIBUTE_NORMAL,
        FILE_SHARE_VALID_FLAGS, 
        FILE_OPEN, 
        FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 
        NULL,
        0
        );
    if (!NT_SUCCESS (status)) 
    {
        return FALSE;
    }

    status = ObReferenceObjectByHandle(hFile, FILE_LIST_DIRECTORY | SYNCHRONIZE, *IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL );
    ASSERT (NT_SUCCESS( status ));
    status = FsRtlGetFileSize(FileObject, &file_size);
    ASSERT (NT_SUCCESS( status ));
    ASSERT(file_size.QuadPart);
    ASSERT(0 == file_size.HighPart);

    buffer = (PBYTE)ExAllocatePoolWithTag(NonPagedPoolNx, file_size.LowPart, TAG);//文件过大,这里会失败。
    ASSERT(NULL != buffer);
    
    status = ZwReadFile(hFile, NULL, NULL, NULL, &IoStatusBlock, buffer, file_size.LowPart, &ByteOffset, NULL);
    ASSERT (NT_SUCCESS( status ));

    B = HASH(buffer, file_size.LowPart, algorithm, &Hash, &HashLen);
    if (B)
    {
        //确保lpFileHash的大小大于HashLen
        for (i = 0; i < HashLen; i++)
        {
            RtlStringCchPrintfW(&lpFileHash[i * 2], 4, L"%02X", Hash[i]);
        }
    }

    ExFreePoolWithTag(Hash, TAG);
    ExFreePoolWithTag(buffer, TAG);
    ObDereferenceObject(FileObject);
    ZwClose( hFile );
    return B;
}


VOID Unload(_In_ PDRIVER_OBJECT DriverObject)
{  
    UNREFERENCED_PARAMETER(DriverObject);

    PAGED_CODE();

}


NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS Status = STATUS_SUCCESS;
    wchar_t buffer[MAX_PATH] = {0};
    BOOL B = FALSE;
    
    UNREFERENCED_PARAMETER(RegistryPath);

    PAGED_CODE();

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;
    
    B = HASHFILE(L"\\Device\\HarddiskVolume1\\test.txt", BCRYPT_SHA256_ALGORITHM, buffer);

    return Status;
}

驱动中获取域名的IP地址

/*
功能:获取域名的IP地址。

made by correy
made at 2017.06.01
http://correy.webs.com
*/


#include <ntddk.h>
#include <wsk.h>
#include <ws2def.h>


#pragma warning(disable:4201) // nameless struct/union
#pragma warning(disable:4214) // bit field types other than int
#pragma warning(disable:4100) // 未引用的形参
#pragma warning(disable:4101) // 未引用的局部变量
#pragma warning(disable:4189) // 局部变量已初始化但不引用


const WSK_CLIENT_DISPATCH WskAppDispatch = {
  MAKE_WSK_VERSION(1,0), // Use WSK version 1.0
  0,    // Reserved
  NULL  // WskClientEvent callback not required for WSK version 1.0
};


WSK_REGISTRATION WskRegistration;


NTSTATUS
SyncIrpCompletionRoutine(
    __in PDEVICE_OBJECT Reserved,
    __in PIRP Irp,
    __in PVOID Context
    )
{    
    PKEVENT compEvent = (PKEVENT)Context;
    UNREFERENCED_PARAMETER(Reserved);
    UNREFERENCED_PARAMETER(Irp);
    KeSetEvent(compEvent, 2, FALSE);    
    return STATUS_MORE_PROCESSING_REQUIRED;
}


NTSTATUS
KernelNameResolutionSample(
    __in PCWSTR NodeName,
    __in_opt PCWSTR ServiceName,
    __in_opt PADDRINFOEXW Hints,
    __in PWSK_PROVIDER_NPI WskProviderNpi
    )
    //https://docs.microsoft.com/en-us/windows-hardware/drivers/network/resolving-host-names-and-ip-addresses
{
    NTSTATUS status;
    PIRP irp;
    KEVENT completionEvent;
    UNICODE_STRING uniNodeName, uniServiceName, *uniServiceNamePtr;
    PADDRINFOEXW results;
    SOCKADDR_IN * psi = NULL;
    wchar_t buffer[64] = {0};
    PWSTR p = NULL;
    UNICODE_STRING ip = {0};
    const struct in_addr * temp = NULL;

    PAGED_CODE();
    
    RtlInitUnicodeString(&uniNodeName, NodeName);// Initialize UNICODE_STRING structures for NodeName and ServiceName 

    if(ServiceName == NULL) {
        uniServiceNamePtr = NULL;
    }
    else {
        RtlInitUnicodeString(&uniServiceName, ServiceName);
        uniServiceNamePtr = &uniServiceName;
    }
    
    KeInitializeEvent(&completionEvent, SynchronizationEvent, FALSE);// Use an event object to synchronously wait for the WskGetAddressInfo request to be completed. 

    // Allocate an IRP for the WskGetAddressInfo request, and set the IRP completion routine, which will signal the completionEvent when the request is completed.
    irp = IoAllocateIrp(1, FALSE);
    if(irp == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }        

    IoSetCompletionRoutine(irp, SyncIrpCompletionRoutine, &completionEvent, TRUE, TRUE, TRUE);

    // Make the WskGetAddressInfo request.
    WskProviderNpi->Dispatch->WskGetAddressInfo (
        WskProviderNpi->Client,
        &uniNodeName,
        uniServiceNamePtr,
        NS_ALL,
        NULL, // Provider
        Hints,
        &results, 
        NULL, // OwningProcess
        NULL, // OwningThread
        irp);

    // Wait for completion.
    // Note that processing of name resolution results can also be handled directly within the IRP completion routine,
    // but for simplicity, this example shows how to wait synchronously for completion.
    KeWaitForSingleObject(&completionEvent, Executive, KernelMode, FALSE, NULL);
    status = irp->IoStatus.Status;
    IoFreeIrp(irp);
    if(!NT_SUCCESS(status)) {
        return status;
    }

    // Process the name resolution results by iterating through the addresses within the returned ADDRINFOEXW structure.
    //results; // your code here
    psi = (SOCKADDR_IN *)results->ai_addr;//注意:这一行很重要。有时要该为IPV6版本的。
    temp = (const struct in_addr *)&psi->sin_addr;
    p = RtlIpv4AddressToString(temp, buffer);
    ASSERT(p);
    RtlInitUnicodeString(&ip, buffer);
    KdPrint(("ipv4:%wZ.\r\n", &ip));
    
    WskProviderNpi->Dispatch->WskFreeAddressInfo(WskProviderNpi->Client, results);// Release the returned ADDRINFOEXW structure when no longer needed.

    return status;
} 


VOID Unload(_In_ PDRIVER_OBJECT DriverObject)
{  
    UNREFERENCED_PARAMETER(DriverObject);

    PAGED_CODE();

    WskDeregister(&WskRegistration);
}


NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS Status = STATUS_SUCCESS;
    WSK_CLIENT_NPI wskClientNpi;
    WSK_PROVIDER_NPI wskProviderNpi;
    //UNICODE_STRING test  = RTL_CONSTANT_STRING(L"DESKTOP-SQRJ1QU");
    
    UNREFERENCED_PARAMETER(RegistryPath);

    PAGED_CODE();

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;
    
    wskClientNpi.ClientContext = NULL;
    wskClientNpi.Dispatch = &WskAppDispatch;
    Status = WskRegister(&wskClientNpi, &WskRegistration);
    ASSERT(NT_SUCCESS(Status));

    Status = WskCaptureProviderNPI(&WskRegistration, WSK_INFINITE_WAIT, &wskProviderNpi);
    ASSERT(NT_SUCCESS(Status));

    /*
    做一些事情。
    */
    Status = KernelNameResolutionSample(L"www.baidu.com", NULL, NULL, &wskProviderNpi);
    ASSERT(NT_SUCCESS(Status));

    WskReleaseProviderNPI(&WskRegistration);

    return Status;
}

snwscanf

/*
文件名snwscanf.C

缘故:
系统中格式化字符串的函数不少,如:
2: kd> x nt!*Printf*
fffff800`04dd1fa4 nt!vsnwprintf (<no parameter info>)
fffff800`04dbe0e8 nt!RtlStringCbPrintfA (<no parameter info>)
fffff800`04c96890 nt!RtlStringCbVPrintfA (<no parameter info>)
fffff800`04dd746c nt!snwprintf_s (<no parameter info>)
fffff800`04dd20b0 nt!vsnprintf_l (<no parameter info>)
fffff800`04ec3e04 nt!StringCchPrintfExW (<no parameter info>)
fffff800`04dd36f4 nt!sprintf (<no parameter info>)
fffff800`04dd4164 nt!vsprintf_l (<no parameter info>)
fffff800`04dd7ddc nt!sprintf_s (<no parameter info>)
fffff800`04dd2098 nt!vsnprintf (<no parameter info>)
fffff800`04dd7380 nt!snprintf_s (<no parameter info>)
fffff800`04dd6c70 nt!vswprintf_s (<no parameter info>)
fffff800`04dd1fbc nt!vsnwprintf_l (<no parameter info>)
fffff800`04dd748c nt!vsnwprintf_s (<no parameter info>)
fffff800`04c9cf54 nt!RtlStringCbPrintfW (<no parameter info>)
fffff800`04d83d80 nt!StringCchPrintfW (<no parameter info>)
fffff800`04f867e8 nt!g_AslLogPfnVPrintf = <no type information>
fffff800`04d7e268 nt!RtlStringCbPrintfExW (<no parameter info>)
fffff800`04dd29e0 nt!swprintf (<no parameter info>)
fffff800`04dd29e0 nt!swprintf (<no parameter info>)
fffff800`04dd6750 nt!get_printf_count_output (<no parameter info>)
fffff800`04dd24d0 nt!snprintf (<no parameter info>)
fffff800`05352008 nt!AslLogCallPrintf (<no parameter info>)
fffff800`04dd2578 nt!snwprintf (<no parameter info>)
fffff800`04dd6c50 nt!swprintf_s (<no parameter info>)
fffff800`04dd2aa0 nt!vswprintf_l (<no parameter info>)
fffff800`04dd2a94 nt!vswprintf (<no parameter info>)
fffff800`04dbfdcc nt!RtlUnicodeStringPrintf (<no parameter info>)
fffff800`04dd41dc nt!vsprintf (<no parameter info>)
fffff800`04dd73a0 nt!vsnprintf_s (<no parameter info>)
fffff800`04e5eba0 nt!RtlUnicodeStringPrintfEx (<no parameter info>)
fffff800`04dd7dfc nt!vsprintf_s (<no parameter info>)
fffff800`04d331b0 nt!RtlStringCchPrintfExW (<no parameter info>)
fffff800`04e41a80 nt!RtlStringCbPrintfExA (<no parameter info>)
fffff800`04dbfc5c nt!RtlStringCchPrintfA (<no parameter info>)
fffff800`04d8ca18 nt!RtlStringCchPrintfW (<no parameter info>)
WRK中也有不少,不信,你看代码。

凡是反过来,就没有,如:WRK中没有,XP和2003中没有。

还好vista开始有了,不信,你看:
2: kd> x nt!*scanf*
fffff800`04dd7434 nt!snscanf_s (<no parameter info>)
fffff800`04dd7e44 nt!sscanf_s (<no parameter info>)
fffff800`04dd8298 nt!swscanf_s (<no parameter info>)
fffff800`04dd752c nt!snwscanf_s (<no parameter info>)
有此足矣!

stdio.h中尽管有_snwscanf_s的定义/声明,但是没有实现,不信,你编译下:
error LNK2019: 无法解析的外部符号 _snwscanf_s,该符号在函数 XXX 中被引用。
但是,这不是难事,不信,你看本文的实现办法。

参考:
https://msdn.microsoft.com/zh-cn/library/dktz45bk.aspx

made by correy
made at 2017.03.31
homepage:http://correy.webs.com 
*/

#include <ntifs.h>
//#include <ntddk.h> //这两个次序不能乱(乱会出错的),有上面的,这个可以注释掉。
#include <windef.h>
#include <stdio.h>

#define tag  'tset' //test

#pragma warning(disable:4100) //未引用的形参
#pragma warning(disable:4214) //整形以外的位域类型
#pragma warning(disable:4121) //封装要区分成员对齐方式
#pragma warning(disable:4189) //局部变量已初始化但不引用
#pragma warning(disable:4101) //未引用的局部变量
#pragma warning(disable:4201) //使用了非标准扩展 : 无名称的结构/联合
#pragma warning(disable:4055) //

//typedef OBJECT_TYPE * (*ObGetObjectType)(IN PVOID pObject);
typedef  int (__cdecl * SNWSCANF_S)(//snwscanf_s
   const wchar_t * input,
   size_t length,
   const wchar_t * format,
   ...
);

SNWSCANF_S g_snwscanf_s;


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    UNICODE_STRING test;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;

    RtlInitUnicodeString( &test, L"_snwscanf_s" );
    g_snwscanf_s = (SNWSCANF_S)MmGetSystemRoutineAddress(&test);//注意:赋值的类型转换。
    if (g_snwscanf_s)
    {
        wchar_t input[] = L"999999999"; 
        int number = 0;
        int i = g_snwscanf_s(input, wcslen(input) * sizeof(wchar_t),  L"%d", &number);
        ASSERT(i);
    }

    return status;
}

2017年1月13日星期五

IPv6EnableFirewallHook.C

/*
文件名:IPv6EnableFirewallHook.C

这是一项过时的技术:Available on Microsoft Windows XP with Service Pack 2 (SP2) and Windows Server 2003 with Service Pack 1 (SP1).
而且编译平台只有:XP和2003,因为:只有这个有Tcpip6.lib。
运行平台,那你就测试吧!

不过,有时还是必不可少的技术。

前提条件:安装IPV6协议,
非正式的办法是加载并运行Tcpip6.SYS。
其中的一个检测办法是查看:sc query tcpip6是否运行。
否则本驱动启动失败,返回错误值2,找不到文件,这个文件肯定是Tcpip6.SYS,不信看这两个文件的导出依赖信息。
也就是说Tcpip6.SYS本身是存在的,但是默认没有安装,更不用说启动了。

made by correy
made at 2017.01.13.
homepage:http://correy.webs.com
*/

#include <ntifs.h>
#include <windef.h>
#include <ntddk.h>
#include <ntstrsafe.h>
#include <assert.h>
#include <ipexport.h>
#include <Ip6firewall.h> //编译版本不能超过:NTDDI_LONGHORN。

#pragma warning(disable:4100) //未引用的形参
#pragma warning(disable:4214) //整形以外的位域类型
#pragma warning(disable:4121) //封装要区分成员对齐方式
#pragma warning(disable:4189) //局部变量已初始化但不引用

KEVENT DisableCompleteEvent;// Event to indicate when the disable is complete

#define DATA_ALIGNMENT  4// Alignment for packet data


// Driver's FirewallHook function
IPv6Action
FirewallHook(
const IPv6Addr  *SourceAddress,
const IPv6Addr  *DestinationAddress,
uint  PayloadLength,
uchar  HeaderType,
const uchar  *HeaderData,
const void  *PacketContext,
uint  DataLength,
uint  InterfaceIndex,
IPv6Direction  Direction,
BOOLEAN  IsLoopBack
)
{
    const uchar *PacketData;
    IP6RouteEntry SourceRoute;
    IP6RouteEntry DestinationRoute;
    IP_STATUS Status;

    // Obtain a pointer to the packet data
    PacketData = IPv6ObtainPacketData(PacketContext, DataLength, DATA_ALIGNMENT);
    if (!PacketData)// Check result
    {
        return ActionDrop;// Drop the packet to be safe
    }

    // Get the source route information
    Status = IPv6GetBestRouteInfo(
        SourceAddress,
        0, // Global scope
        0, // No interface constraint
        &SourceRoute
        );
    if (Status != IP_SUCCESS)// Check result
    {
        return ActionDrop;// Drop the packet to be safe
    }

    // Get the destination route information
    Status = IPv6GetBestRouteInfo(
        DestinationAddress,
        0, // Global scope
        0, // No interface constraint
        &DestinationRoute
        );
    if (Status != IP_SUCCESS)// Check result
    {
        return ActionDrop;// Drop the packet to be safe
    }

    // Inspect the various data sources to determine
    // the action to be taken on the packet
    //...

        // If there is a reason why the packet should be dropped...
        //if (...)
        {
            // Drop the packet
            //return ActionDrop;
        }

    return ActionAccept;// Accept the packet
}


// Disable completion routine
VOID DisableComplete(VOID)
{
    KeSetEvent(&DisableCompleteEvent, 0, FALSE);// Set the disable complete event
}


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    KeInitializeEvent(&DisableCompleteEvent, NotificationEvent, FALSE);// Initialize the disable complete event
    IPv6DisableFirewallHook(DisableComplete);// Disable the firewall hook
    KeWaitForSingleObject(&DisableCompleteEvent, Executive, KernelMode, FALSE, NULL);// Wait for the disable complete event to be signaled
}


NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;

    //KdBreakPoint();
    __debugbreak();

    DriverObject->DriverUnload = Unload;

    status = IPv6EnableFirewallHook(FirewallHook);// Enable the FirewallHook callback function

    return status;
}

PacketFilterExtensionPtr.C

/*
文件名:PacketFilterExtensionPtr.C

说明:经常看到WDK的Hook Drivers,Filter-Hook Drivers,一直没有深入研究,直到今天。

参考:
1.WDK
2.http://newbiecoder.0ginr.com/blog/?p=550#comment-122368
3.开源防火墙NetDefender的IP过滤驱动模块
4.http://myblog-maurice.blogspot.jp/2012/02/sniffer.html

注意:
1.IpFilterDriver模块默认安装,但是没有运行。
2.或许是上面的原因,这个模块/功能会被删除/禁用掉。

made by correy
made at 2017.01.09.
homepage:http://correy.webs.com
*/

#include <ntifs.h>
#include <windef.h>
#include <ntddk.h>
#include <ntstrsafe.h>
#include <assert.h>
#include <Ntdddisk.h>

#include <ndis.h>
#include <Pfhook.h>

#include <intrin.h> //VS2012编译。
#include <immintrin.h>//VS2012编译。
//#include <mmintrin.h> //WDK 编译。
//#include <emmintrin.h>//WDK 编译。
//#include <xmmintrin.h>//WDK 编译。

#pragma warning(disable:4100) //未引用的形参
#pragma warning(disable:4214) //整形以外的位域类型
#pragma warning(disable:4121) //封装要区分成员对齐方式
#pragma warning(disable:4189) //局部变量已初始化但不引用


#define TAG 'test' test


PF_FORWARD_ACTION PacketFilterExtension(
    IN unsigned char  *PacketHeader,
    IN unsigned char  *Packet,
    IN unsigned int  PacketLength,
    IN unsigned int  RecvInterfaceIndex,
    IN unsigned int  SendInterfaceIndex,
    IN IPAddr  RecvLinkNextHop,
    IN IPAddr  SendLinkNextHop
    )
{
    return PF_FORWARD;
}


NTSTATUS StopIpFilter()
{
    NTSTATUS status = STATUS_SUCCESS;
    UNICODE_STRING IpFilterDriver = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\IpFilterDriver");//默认情况下,注册表已经存在,但是没有启动。
    UNICODE_STRING IpFilterDevice = RTL_CONSTANT_STRING(DD_IPFLTRDRVR_DEVICE_NAME);
    PDEVICE_OBJECT deviceObject;
    PFILE_OBJECT fileObject;
    PF_SET_EXTENSION_HOOK_INFO psehi = {0};
    KEVENT event;
    IO_STATUS_BLOCK ioStatusBlock;
    PIRP irp;

    status = IoGetDeviceObjectPointer(&IpFilterDevice, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
    ASSERT(NT_SUCCESS(status));

    psehi.ExtensionPointer = NULL;

    KeInitializeEvent(&event, NotificationEvent, FALSE);

    irp = IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER, deviceObject, &psehi, sizeof(PF_SET_EXTENSION_HOOK_INFO), NULL, 0, FALSE, &event, &ioStatusBlock);
    if (!irp)
    {
        ObDereferenceObject(fileObject);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    status = IoCallDriver(deviceObject, irp);
    if (status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
        status = ioStatusBlock.Status;
    }
    ASSERT(NT_SUCCESS(status));

    ObDereferenceObject(fileObject);

    status = ZwUnloadDriver(&IpFilterDriver);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwLoadDriver fail with 0x%x.\r\n", status));
        return status;
    }

    return status;
}


NTSTATUS StartIpFilter(PacketFilterExtensionPtr PacketFilter)
{
    NTSTATUS status = STATUS_SUCCESS;
    UNICODE_STRING IpFilterDriver = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\IpFilterDriver");//默认情况下,注册表已经存在,但是没有启动。
    UNICODE_STRING IpFilterDevice = RTL_CONSTANT_STRING(DD_IPFLTRDRVR_DEVICE_NAME);
    PDEVICE_OBJECT deviceObject;
    PFILE_OBJECT fileObject;
    PF_SET_EXTENSION_HOOK_INFO psehi = {0};
    KEVENT event;
    IO_STATUS_BLOCK ioStatusBlock;
    PIRP irp;

    status = ZwLoadDriver(&IpFilterDriver);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwLoadDriver fail with 0x%x.\r\n", status));
        return status;
    }

    status = IoGetDeviceObjectPointer(&IpFilterDevice, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
    ASSERT(NT_SUCCESS(status));

    psehi.ExtensionPointer = PacketFilter;

    KeInitializeEvent(&event, NotificationEvent, FALSE);

    irp = IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER, deviceObject, &psehi, sizeof(PF_SET_EXTENSION_HOOK_INFO), NULL, 0, FALSE, &event, &ioStatusBlock);
    if (!irp)
    {
        ObDereferenceObject(fileObject);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    status = IoCallDriver(deviceObject, irp);
    if (status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
        status = ioStatusBlock.Status;
    }
    ASSERT(NT_SUCCESS(status));

    ObDereferenceObject(fileObject);

    return status;
}


//DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    StopIpFilter();
}


NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;

    //KdBreakPoint();
    __debugbreak();

    DriverObject->DriverUnload = Unload;

    status = StartIpFilter(PacketFilterExtension);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("StartIpFilter fail with 0x%x.\r\n", status));
        return status;
    }

    return status;
}

2016年8月31日星期三

枚举ALE的endpoints

/*
目的:演示FwpsAleEndpointEnum的用法。
注意:编译的平台和运行的平台。
说明:Ale的Endpoint,这是什么呢?
      类似TCPView.exe不停的显示和更新,
      当然这个函数每次获取的值/数量也是不同的。

made by correy
made at 2016.08.31.
homepage:http://correy.webs.com
*/

#include <ntifs.h>
#include <windef.h>
#include <ntddk.h>
#include <ntstrsafe.h>
#include <Fwpsk.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。
#include <Fwpmk.h>
#include <ndis.h>
#include <Wsk.h>
#include <ipmib.h>
#include <netpnp.h>
#include <ntintsafe.h>

#include <intrin.h> //VS2012编译。
#include <immintrin.h>//VS2012编译。
//#include <mmintrin.h> //WDK 编译。
//#include <emmintrin.h>//WDK 编译。
//#include <xmmintrin.h>//WDK 编译。

#pragma warning(disable:4100) //未引用的形参
#pragma warning(disable:4214) //整形以外的位域类型
#pragma warning(disable:4121) //封装要区分成员对齐方式

#define TAG 'test' //test

//https://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
//其实:IPV4的只需This buffer should be large enough to hold at least 16 characters.
#define MAX_ADDRESS_STRING_LENGTH   64


wchar_t * get_protocol_name(UINT8 protocol)
{
    wchar_t * protocol_name = 0;

    switch(protocol)
    {
    case IPPROTO_TCP:
        protocol_name = L"TCP";
        break;
    case IPPROTO_UDP:
        protocol_name = L"UDP";
        break;
    case IPPROTO_IPV4:
        protocol_name = L"IPV4";
        break;
    case IPPROTO_IPV6:
        protocol_name = L"IPV6";
        break;
    case IPPROTO_ICMP:
        protocol_name = L"ICMP";
        break;
    case IPPROTO_IGMP:
        protocol_name = L"IGMP";
        break;
    case IPPROTO_ICMPV6:
        protocol_name = L"ICMPV6";
        break;
    default:
        protocol_name = L"未知";//也可打印一个数值。
        break;
    }

    return protocol_name;
}


//DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{

}


//DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    HANDLE gEngineHandle;
    NTSTATUS Status = STATUS_SUCCESS;
    FWPM_SESSION0 session = {0};
    FWPS_ALE_ENDPOINT_ENUM_TEMPLATE0 enumTemplate;//编译为WIN 7版本,VISTA是没有这个变量的。
    HANDLE enumHandle;
    FWPS_ALE_ENDPOINT_PROPERTIES0 **entries;
    UINT32                        numEntriesReturned;
    UINT32 calloutIndex = 0;
    UNICODE_STRING appId = {0};

    //KdBreakPoint();
    __debugbreak();

    DriverObject->DriverUnload = Unload;

    session.flags = FWPM_SESSION_FLAG_DYNAMIC;
    Status = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &gEngineHandle);
    ASSERT (NT_SUCCESS(Status));

    RtlZeroMemory(&enumTemplate, sizeof(FWPS_ALE_ENDPOINT_ENUM_TEMPLATE0));
    Status = FwpsAleEndpointCreateEnumHandle0(gEngineHandle, &enumTemplate, &enumHandle);//Available starting with Windows 7
    ASSERT (NT_SUCCESS(Status));

    Status = FwpsAleEndpointEnum0(gEngineHandle, enumHandle, 0xFFFFFFFF, &entries, &numEntriesReturned);//Available starting with Windows 7
    ASSERT (NT_SUCCESS(Status));

    KdPrint(("numEntriesReturned:0x%x.\n\n\n", numEntriesReturned));

    for( ; calloutIndex < numEntriesReturned; calloutIndex++)
    {
        KdPrint(("calloutIndex:0x%x.\n",(calloutIndex + 1)));

        if (entries[calloutIndex]->ipVersion == FWP_IP_VERSION_V4)
        {
            UINT32 l4a = RtlUlongByteSwap((ULONG)entries[calloutIndex]->localV4Address);
            UINT32 r4a = RtlUlongByteSwap((ULONG)entries[calloutIndex]->remoteV4Address);
            wchar_t localV4Address[MAX_ADDRESS_STRING_LENGTH] = {0};
            wchar_t remoteV4Address[MAX_ADDRESS_STRING_LENGTH] = {0};

            RtlIpv4AddressToString((const struct in_addr *)&l4a, localV4Address);
            RtlIpv4AddressToString((const struct in_addr *)&r4a, remoteV4Address);

            KdPrint(("ipVersion:FWP_IP_VERSION_V4.\n"));
            KdPrint(("localV4Address:%ws.\n", localV4Address));
            KdPrint(("remoteV4Address:%ws.\n", remoteV4Address));
        }
        else if (entries[calloutIndex]->ipVersion == FWP_IP_VERSION_V6)
        {
            /*
            这个IPV6的地址的字节序需要转换不?
            最大是RtlUlonglongByteSwap,64-bit,但是IPv6 is 128 bits。
            难道要用这个函数两次,两次的也不符合,自己写个函数?自己可以验证下。
            */
            wchar_t localV6Address[MAX_ADDRESS_STRING_LENGTH] = {0};
            wchar_t remoteV6Address[MAX_ADDRESS_STRING_LENGTH] = {0};

            RtlIpv6AddressToString((const struct in6_addr *)&entries[calloutIndex]->localV6Address, localV6Address);
            RtlIpv6AddressToString((const struct in6_addr *)&entries[calloutIndex]->remoteV6Address, remoteV6Address);

            KdPrint(("ipVersion:FWP_IP_VERSION_V6.\n"));
            KdPrint(("localV6Address:%ws.\n", localV6Address));
            KdPrint(("remoteV6Address:%ws.\n", remoteV6Address));
        }
        else
        {
            KdBreakPoint();
        }

        KdPrint(("ipProtocol:%ws.\n", get_protocol_name(entries[calloutIndex]->ipProtocol)));
        KdPrint(("localPort:%d.\n", entries[calloutIndex]->localPort));
        KdPrint(("remotePort:%d.\n", entries[calloutIndex]->remotePort));
        KdPrint(("localTokenModifiedId:0x%x.\n", entries[calloutIndex]->localTokenModifiedId));
        KdPrint(("mmSaId:0x%x.\n", entries[calloutIndex]->mmSaId));
        KdPrint(("qmSaId:0x%x.\n", entries[calloutIndex]->qmSaId));
        KdPrint(("ipsecStatus:0x%x.\n", entries[calloutIndex]->ipsecStatus));
        KdPrint(("flags:0x%x.\n", entries[calloutIndex]->flags));

        appId.Buffer = (PWCH)&entries[calloutIndex]->appId.data[0];
        appId.Length = (USHORT)entries[calloutIndex]->appId.size;
        appId.MaximumLength = appId.Length;
        KdPrint(("appId:%wZ.\n", &appId));//进程的完整路径(NT式的设备路径)。一个特殊是:System。

        KdPrint(("\n"));
    }

    FwpmFreeMemory((VOID**)&entries);
    Status = FwpsAleEndpointDestroyEnumHandle0(gEngineHandle, enumHandle);//Available starting with Windows 7
    ASSERT (NT_SUCCESS(Status));

    FwpmEngineClose0(gEngineHandle);

    return Status;
}

2016年8月23日星期二

获取WFP的Bfe的State及相关

/*
起因:系统启动的时候FwpmEngineOpen0返回c0020035即EPT_NT_CANT_PERFORM_OP ,意思是:The operation cannot be performed.(服务器终结点无法运行操作)。
所以:有此文。

文件名:BfeState.C

测试要点和心得:
1.FwpmBfeStateGet0在系统启动的时候返回值是FWPM_SERVICE_STOPPED。
2.FwpmBfeStateGet0在正常驱动加载的时候返回值是FWPM_SERVICE_RUNNING。
3.只有在系统启动的时候会调用FwpmBfeStateSubscribeChanges的回调函数。两次,第一次是FWPM_SERVICE_START_PENDING,后来FWPM_SERVICE_RUNNING。
4.在正常的驱动加载时,不会调用FwpmBfeStateSubscribeChanges的回调函数。
5.所以FwpmBfeStateGet可判断驱动是否在系统启动的时候运行/加载。
...,更多的你想吧,如:启动的时候如何完美的获取EngineHandle。
6.驱动卸载和关机时是没有反应的,可以注册电源事件的监控看看。
7.在系统启动时,从加载驱动到FwpmBfeStateSubscribeChanges的回调函数被调用,这一段时间是很长的:前者很早,后者已经有启动画面了。

WDK说明:
A callout driver calls the FwpmBfeStateSubscribeChanges0 function to register a callback function that is called whenever there is a change to the state of the filter engine.
A callout driver cannot open a session to the filter engine unless the filter engine is currently running.
A callout driver can use the FWPM_SERVICE_RUNNING notification to open a session to the filter engine so that it can make calls to the other Windows Filtering Platform management functions.
Similarly, a callout driver can use the FWPM_SERVICE_STOP_PENDING notification to perform any cleanup before the filter engine is stopped.

A callout driver can retrieve the current state of the filter engine at any time by calling the FwpmBfeStateGet0 function.

A callout driver must deregister the callback function by calling the FwpmBfeStateUnsubscribeChanges0 function before the callout driver can be unloaded.

made by correy
made at 2016.08.23
http://correy.webs.com
*/

#pragma once

#include <ntifs.h>
#include <Fwpsk.h>
#include <windef.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。
#include <Fwpmk.h>
#include <Ntstrsafe.h>
#include <ndis.h>
#include <Wsk.h>
#include <ipmib.h>
#include <netpnp.h>
#include <ntintsafe.h>

#pragma warning(disable:4047)
#pragma warning(disable:4028)

#define TAG 'test' //test

PDEVICE_OBJECT gDeviceObject;

HANDLE gEngineHandle;
HANDLE gChangeHandle;


VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status;
    UNICODE_STRING uniWin32NameString;
 
    FwpmBfeStateUnsubscribeChanges0(gChangeHandle);

    if (gEngineHandle)
    {
        FwpmEngineClose0(gEngineHandle);
    }

    RtlInitUnicodeString( &uniWin32NameString, L"\\DosDevices\\hpm" );
    IoDeleteSymbolicLink( &uniWin32NameString );

    IoDeleteDevice(gDeviceObject);// Delete the device object
}


VOID NTAPI SubscriptionBFEStateChangeCallback(IN OUT void  *context, IN FWPM_SERVICE_STATE  newState)
//VOID SubscriptionBFEStateChangeCallback(_Inout_ VOID* pContext, _In_ FWPM_SERVICE_STATE bfeState)
/**
   Purpose:  Callback, invoked on BFE service state change, which will get or release a handle to the engine.
   MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF550062.aspx
   测试心得:
   1.操作系统启动的时候先来FWPM_SERVICE_START_PENDING,后来FWPM_SERVICE_RUNNING。
   2.正常的启动是不会走这里的。
*/
{
    NTSTATUS status;
    FWPM_SESSION0 session = {0};

    switch(newState)
    {
    case FWPM_SERVICE_RUNNING:
        //调用FwpmEngineOpen获取EngineHandle。
        KdPrint(("FWPM_SERVICE_RUNNING.\n",__LINE__));

        session.flags = FWPM_SESSION_FLAG_DYNAMIC;
        status = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &gEngineHandle);
        ASSERT(NT_SUCCESS(status));

        break;
    case FWPM_SERVICE_STOP_PENDING://要走这里,还得做一些小动作。
        //调用FwpmEngineClose释放EngineHandle。
        KdPrint(("FWPM_SERVICE_RUNNING.\n",__LINE__));
        break;
    case FWPM_SERVICE_STOPPED:
        KdPrint(("FWPM_SERVICE_STOPPED.\n",__LINE__));//系统启动的时候会是这个。
        break;
    case FWPM_SERVICE_START_PENDING :
        KdPrint(("FWPM_SERVICE_START_PENDING.\n",__LINE__));//操作系统启动的时候会有这个。
        break;
    }
}


NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS NtStatus = STATUS_SUCCESS;
    UNICODE_STRING  ntUnicodeString;
    UNICODE_STRING  ntWin32NameString;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;

    RtlInitUnicodeString( &ntUnicodeString, L"\\Device\\hpm");
    NtStatus = IoCreateDevice(DriverObject, 0, &ntUnicodeString, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &gDeviceObject);
    if (!NT_SUCCESS(NtStatus))
    {
        return NtStatus;
    }

    RtlInitUnicodeString( &ntWin32NameString, L"\\DosDevices\\hpm" );
    NtStatus = IoCreateSymbolicLink(&ntWin32NameString, &ntUnicodeString );
    if (!NT_SUCCESS(NtStatus))
    {
        IoDeleteDevice( gDeviceObject );
        return NtStatus;
    }

    SubscriptionBFEStateChangeCallback(NULL, FwpmBfeStateGet0());//这个可判断驱动是否在系统的启动状态。

    NtStatus = FwpmBfeStateSubscribeChanges0(gDeviceObject, SubscriptionBFEStateChangeCallback, NULL, &gChangeHandle);
    if (!NT_SUCCESS(NtStatus))
    {
        IoDeleteSymbolicLink( &ntWin32NameString );
        IoDeleteDevice(gDeviceObject);
        return NtStatus;
    }

    return NtStatus;
}

演示ObCreateObjectType的用法

/*
目的:演示ObCreateObjectType的用法(XP到WIN10)。
注意:编译的平台和运行的平台。

made by correy
made at 2016.05.30.
homepage:http://correy.webs.com
*/

#include <ntifs.h>
#include <windef.h>
#include <ntddk.h>
#include <ntstrsafe.h>

#include <intrin.h> //VS2012编译。
#include <immintrin.h>//VS2012编译。
//#include <mmintrin.h> //WDK 编译。
//#include <emmintrin.h>//WDK 编译。
//#include <xmmintrin.h>//WDK 编译。

#pragma warning(disable:4100) //未引用的形参
#pragma warning(disable:4214) //整形以外的位域类型
#pragma warning(disable:4121) //封装要区分成员对齐方式

typedef struct _OBJECT_DUMP_CONTROL {
    PVOID Stream;
    ULONG Detail;
} OB_DUMP_CONTROL, *POB_DUMP_CONTROL;

typedef VOID(*OB_DUMP_METHOD)(
    IN PVOID Object,
    IN POB_DUMP_CONTROL Control OPTIONAL
    );

typedef enum _OB_OPEN_REASON {
    ObCreateHandle,
    ObOpenHandle,
    ObDuplicateHandle,
    ObInheritHandle,
    ObMaxOpenReason
} OB_OPEN_REASON;


typedef NTSTATUS(*OB_OPEN_METHOD)(
    IN OB_OPEN_REASON OpenReason,
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN ACCESS_MASK GrantedAccess,
    IN ULONG HandleCount
    );

typedef BOOLEAN(*OB_OKAYTOCLOSE_METHOD)(
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN HANDLE Handle,
    IN KPROCESSOR_MODE PreviousMode
    );

typedef VOID(*OB_CLOSE_METHOD)(
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN ACCESS_MASK GrantedAccess,
    IN ULONG_PTR ProcessHandleCount,
    IN ULONG_PTR SystemHandleCount
    );

typedef VOID(*OB_DELETE_METHOD)(
    IN  PVOID   Object
    );

typedef NTSTATUS(*OB_PARSE_METHOD)(
    IN PVOID ParseObject,
    IN PVOID ObjectType,
    IN OUT PACCESS_STATE AccessState,
    IN KPROCESSOR_MODE AccessMode,
    IN ULONG Attributes,
    IN OUT PUNICODE_STRING CompleteName,
    IN OUT PUNICODE_STRING RemainingName,
    IN OUT PVOID Context OPTIONAL,
    IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
    OUT PVOID *Object
    );

typedef NTSTATUS(*OB_SECURITY_METHOD)(
    IN PVOID Object,
    IN SECURITY_OPERATION_CODE OperationCode,
    IN PSECURITY_INFORMATION SecurityInformation,
    IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN OUT PULONG CapturedLength,
    IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
    IN POOL_TYPE PoolType,
    IN PGENERIC_MAPPING GenericMapping
    );

typedef NTSTATUS(*OB_QUERYNAME_METHOD)(
    IN PVOID Object,
    IN BOOLEAN HasObjectName,
    OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
    IN ULONG Length,
    OUT PULONG ReturnLength,
    IN KPROCESSOR_MODE Mode
    );

#if (NTDDI_VERSION < NTDDI_VISTA)
typedef struct _OBJECT_TYPE_INITIALIZER {
    USHORT Length;
    BOOLEAN UseDefaultObject;
    BOOLEAN CaseInsensitive;
    ULONG InvalidAttributes;
    GENERIC_MAPPING GenericMapping;
    ULONG ValidAccessMask;
    BOOLEAN SecurityRequired;
    BOOLEAN MaintainHandleCount;
    BOOLEAN MaintainTypeList;
    POOL_TYPE PoolType;
    ULONG DefaultPagedPoolCharge;
    ULONG DefaultNonPagedPoolCharge;
    OB_DUMP_METHOD DumpProcedure;
    OB_OPEN_METHOD OpenProcedure;
    OB_CLOSE_METHOD CloseProcedure;
    OB_DELETE_METHOD DeleteProcedure;
    OB_PARSE_METHOD ParseProcedure;
    OB_SECURITY_METHOD SecurityProcedure;
    OB_QUERYNAME_METHOD QueryNameProcedure;
    OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure;
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
#else
__declspec(align(2))
//#pragma pack(2)
#pragma warning(push)
#pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION
typedef struct _OBJECT_TYPE_INITIALIZER {
    USHORT Length;

    union //这里是不是一个联合还有待考察。可怀疑ObjectTypeFlags和下面的一个位结构构成两个字节。
    {
        UCHAR   ObjectTypeFlags;//ObjectTypeFlags就是下面的位结构,总共占用2字节,但是只用一字节。

        struct
        {
            unsigned char  CaseInsensitive : 1;
            unsigned char  UnnamedObjectsOnly : 1;
            unsigned char  UseDefaultObject : 1;
            unsigned char  SecurityRequired : 1;
            unsigned char  MaintainHandleCount : 1;
            unsigned char  MaintainTypeList : 1;
            unsigned char  SupportsObjectCallbacks : 1;
            unsigned char  CacheAligned : 1;
        };
    }ObjectTypeFlags;

    ULONG ObjectTypeCode;
    ULONG InvalidAttributes;
    GENERIC_MAPPING GenericMapping;
    ULONG ValidAccessMask;
    ULONG RetainAccess;
    POOL_TYPE PoolType;
    ULONG DefaultPagedPoolCharge;
    ULONG DefaultNonPagedPoolCharge;
    OB_DUMP_METHOD DumpProcedure;
    OB_OPEN_METHOD OpenProcedure;
    OB_CLOSE_METHOD CloseProcedure;
    OB_DELETE_METHOD DeleteProcedure;
    OB_PARSE_METHOD ParseProcedure;
    OB_SECURITY_METHOD SecurityProcedure;
    OB_QUERYNAME_METHOD QueryNameProcedure;
    OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure;
#if 0 //WIN 10 特有的。因为编译环境是VS2012,所以就不再做特别的处理了。
    ULONG  WaitObjectFlagMask;
    USHORT WaitObjectFlagOffset;
    USHORT WaitObjectPointerOffset;
#endif
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
#pragma warning(pop)
#endif


/*
WIN10 64
1: kd> dt _OBJECT_TYPE_INITIALIZER
ntdll!_OBJECT_TYPE_INITIALIZER
+0x000 Length           : Uint2B
+0x002 ObjectTypeFlags  : UChar
+0x002 CaseInsensitive  : Pos 0, 1 Bit
+0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
+0x002 UseDefaultObject : Pos 2, 1 Bit
+0x002 SecurityRequired : Pos 3, 1 Bit
+0x002 MaintainHandleCount : Pos 4, 1 Bit
+0x002 MaintainTypeList : Pos 5, 1 Bit
+0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
+0x002 CacheAligned     : Pos 7, 1 Bit
+0x004 ObjectTypeCode   : Uint4B
+0x008 InvalidAttributes : Uint4B
+0x00c GenericMapping   : _GENERIC_MAPPING
+0x01c ValidAccessMask  : Uint4B
+0x020 RetainAccess     : Uint4B
+0x024 PoolType         : _POOL_TYPE
+0x028 DefaultPagedPoolCharge : Uint4B
+0x02c DefaultNonPagedPoolCharge : Uint4B
+0x030 DumpProcedure    : Ptr64     void
+0x038 OpenProcedure    : Ptr64     long
+0x040 CloseProcedure   : Ptr64     void
+0x048 DeleteProcedure  : Ptr64     void
+0x050 ParseProcedure   : Ptr64     long
+0x058 SecurityProcedure : Ptr64     long
+0x060 QueryNameProcedure : Ptr64     long
+0x068 OkayToCloseProcedure : Ptr64     unsigned char
+0x070 WaitObjectFlagMask : Uint4B
+0x074 WaitObjectFlagOffset : Uint2B
+0x076 WaitObjectPointerOffset : Uint2B


ObCreateObjectTypeEx中有如下的代码:
if ( !TypeName
|| (Length = TypeName->Length) == 0
|| Length & 1
|| !ObjectTypeInitializer
|| ObjectTypeInitializer->InvalidAttributes & 0xFFFEE00D
|| ObjectTypeInitializer->Length != 120
|| (ObjectTypeFlags = ObjectTypeInitializer->ObjectTypeFlags, ObjectTypeFlags & 0x10) && !ObjectTypeInitializer->OpenProcedure && !ObjectTypeInitializer->CloseProcedure
|| !(ObjectTypeFlags & 4) && ObjectTypeInitializer->PoolType & 0xFFFFFDFF && !((unsigned __int8)ObjectType & 1) )
{
DbgPrintEx(0i64, 0i64, "Error creating object type\n");
__debugbreak();
JUMPOUT(loc_1405CF068);
}
而WRK中是这样的:
PoolType = ObjectTypeInitializer->PoolType;
if ((!TypeName) || (!TypeName->Length) || (TypeName->Length % sizeof( WCHAR )) ||
(ObjectTypeInitializer == NULL) ||
(ObjectTypeInitializer->InvalidAttributes & ~OBJ_ALL_VALID_ATTRIBUTES) ||
(ObjectTypeInitializer->Length != sizeof( *ObjectTypeInitializer )) ||
(ObjectTypeInitializer->MaintainHandleCount && (ObjectTypeInitializer->OpenProcedure == NULL && ObjectTypeInitializer->CloseProcedure == NULL )) ||
((!ObjectTypeInitializer->UseDefaultObject) && (PoolType != NonPagedPool)))
{
return( STATUS_INVALID_PARAMETER );
}


而XP32上是这样的:
0: kd> dt _OBJECT_TYPE_INITIALIZER
ntdll!_OBJECT_TYPE_INITIALIZER
+0x000 Length           : Uint2B
+0x002 UseDefaultObject : UChar
+0x003 CaseInsensitive  : UChar
+0x004 InvalidAttributes : Uint4B
+0x008 GenericMapping   : _GENERIC_MAPPING
+0x018 ValidAccessMask  : Uint4B
+0x01c SecurityRequired : UChar
+0x01d MaintainHandleCount : UChar
+0x01e MaintainTypeList : UChar
+0x020 PoolType         : _POOL_TYPE
+0x024 DefaultPagedPoolCharge : Uint4B
+0x028 DefaultNonPagedPoolCharge : Uint4B
+0x02c DumpProcedure    : Ptr32     void
+0x030 OpenProcedure    : Ptr32     long
+0x034 CloseProcedure   : Ptr32     void
+0x038 DeleteProcedure  : Ptr32     void
+0x03c ParseProcedure   : Ptr32     long
+0x040 SecurityProcedure : Ptr32     long
+0x044 QueryNameProcedure : Ptr32     long
+0x048 OkayToCloseProcedure : Ptr32     unsigned char

自己定义的结构如下:
1: kd> dt test!_OBJECT_TYPE_INITIALIZER  ffffd001`310a68c0
+0x000 Length           : 0x78
+0x002 ObjectTypeFlags  : <unnamed-tag>
+0x004 ObjectTypeCode   : 0
+0x008 InvalidAttributes : 0x100
+0x00c GenericMapping   : _GENERIC_MAPPING
+0x01c ValidAccessMask  : 0xf0001
+0x020 RetainAccess     : 0
+0x024 PoolType         : 0 ( NonPagedPool )
+0x028 DefaultPagedPoolCharge : 0
+0x02c DefaultNonPagedPoolCharge : 0
+0x030 DumpProcedure    : (null)
+0x038 OpenProcedure    : (null)
+0x040 CloseProcedure   : (null)
+0x048 DeleteProcedure  : (null)
+0x050 ParseProcedure   : (null)
+0x058 SecurityProcedure : (null)
+0x060 QueryNameProcedure : (null)
+0x068 OkayToCloseProcedure : (null)
+0x070 WaitObjectFlagMask : 0
+0x074 WaitObjectFlagOffset : 0
+0x076 WaitObjectPointerOffset : 0
不过要定义和系统的结构(显示)一样的结构也是可以,重在内在的一样。

经验证:ObjectTypeFlags就是下面的位结构,总共占用2字节,但是只用一字节。
而且偏移的第二字节和第三字节的内容是不一样的,大多偏移的第三自己的内容是0.
kd> dt _OBJECT_TYPE_INITIALIZER fffff800`ff4b5220 -b
nt!_OBJECT_TYPE_INITIALIZER
+0x000 Length           : 0x78
+0x002 ObjectTypeFlags  : 0x24 '$'
+0x002 CaseInsensitive  : 0y0
+0x002 UnnamedObjectsOnly : 0y0
+0x002 UseDefaultObject : 0y1
+0x002 SecurityRequired : 0y0
+0x002 MaintainHandleCount : 0y0
+0x002 MaintainTypeList : 0y1
+0x002 SupportsObjectCallbacks : 0y0
+0x002 CacheAligned     : 0y0
+0x004 ObjectTypeCode   : 0
+0x008 InvalidAttributes : 0x100
+0x00c GenericMapping   : _GENERIC_MAPPING
+0x000 GenericRead      : 0x20000
+0x004 GenericWrite     : 0x20000
+0x008 GenericExecute   : 0x20000
+0x00c GenericAll       : 0xf0001
+0x01c ValidAccessMask  : 0xf0001
+0x020 RetainAccess     : 0
+0x024 PoolType         : 200 ( NonPagedPoolNx )
+0x028 DefaultPagedPoolCharge : 0
+0x02c DefaultNonPagedPoolCharge : 0xd8
+0x030 DumpProcedure    : (null)
+0x038 OpenProcedure    : (null)
+0x040 CloseProcedure   : (null)
+0x048 DeleteProcedure  : (null)
+0x050 ParseProcedure   : (null)
+0x058 SecurityProcedure : (null)
+0x060 QueryNameProcedure : (null)
+0x068 OkayToCloseProcedure : (null)
+0x070 WaitObjectFlagMask : 0
+0x074 WaitObjectFlagOffset : 0
+0x076 WaitObjectPointerOffset : 0
kd> .formats 24
Evaluate expression:
Hex:     00000000`00000024
Decimal: 36
Octal:   0000000000000000000044
Binary:  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00100100
Chars:   .......$
Time:    Thu Jan 01 08:00:36 1970
Float:   low 5.04467e-044 high 0
Double:  1.77864e-322

2008 X64的测试效果:
0: kd> dt nt!_OBJECT_TYPE_INITIALIZER -b
   +0x000 Length           : Uint2B
   +0x002 ObjectTypeFlags  : UChar
   +0x002 CaseInsensitive  : Pos 0, 1 Bit
   +0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
   +0x002 UseDefaultObject : Pos 2, 1 Bit
   +0x002 SecurityRequired : Pos 3, 1 Bit
   +0x002 MaintainHandleCount : Pos 4, 1 Bit
   +0x002 MaintainTypeList : Pos 5, 1 Bit
   +0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
   +0x002 CacheAligned     : Pos 7, 1 Bit
   +0x004 ObjectTypeCode   : Uint4B
   +0x008 InvalidAttributes : Uint4B
   +0x00c GenericMapping   : _GENERIC_MAPPING
      +0x000 GenericRead      : Uint4B
      +0x004 GenericWrite     : Uint4B
      +0x008 GenericExecute   : Uint4B
      +0x00c GenericAll       : Uint4B
   +0x01c ValidAccessMask  : Uint4B
   +0x020 RetainAccess     : Uint4B
   +0x024 PoolType         :
      NonPagedPool = 0n0
      PagedPool = 0n1
      NonPagedPoolMustSucceed = 0n2
      DontUseThisType = 0n3
      NonPagedPoolCacheAligned = 0n4
      PagedPoolCacheAligned = 0n5
      NonPagedPoolCacheAlignedMustS = 0n6
      MaxPoolType = 0n7
      NonPagedPoolSession = 0n32
      PagedPoolSession = 0n33
      NonPagedPoolMustSucceedSession = 0n34
      DontUseThisTypeSession = 0n35
      NonPagedPoolCacheAlignedSession = 0n36
      PagedPoolCacheAlignedSession = 0n37
      NonPagedPoolCacheAlignedMustSSession = 0n38
   +0x028 DefaultPagedPoolCharge : Uint4B
   +0x02c DefaultNonPagedPoolCharge : Uint4B
   +0x030 DumpProcedure    : Ptr64
   +0x038 OpenProcedure    : Ptr64
   +0x040 CloseProcedure   : Ptr64
   +0x048 DeleteProcedure  : Ptr64
   +0x050 ParseProcedure   : Ptr64
   +0x058 SecurityProcedure : Ptr64
   +0x060 QueryNameProcedure : Ptr64
   +0x068 OkayToCloseProcedure : Ptr64
0: kd> dt test!_OBJECT_TYPE_INITIALIZER -b
   +0x000 Length           : Uint2B
   +0x002 ObjectTypeFlags  : <unnamed-tag>
      +0x000 ObjectTypeFlags  : UChar
      +0x000 CaseInsensitive  : Pos 0, 1 Bit
      +0x000 UnnamedObjectsOnly : Pos 1, 1 Bit
      +0x000 UseDefaultObject : Pos 2, 1 Bit
      +0x000 SecurityRequired : Pos 3, 1 Bit
      +0x000 MaintainHandleCount : Pos 4, 1 Bit
      +0x000 MaintainTypeList : Pos 5, 1 Bit
      +0x000 SupportsObjectCallbacks : Pos 6, 1 Bit
      +0x000 CacheAligned     : Pos 7, 1 Bit
   +0x004 ObjectTypeCode   : Uint4B
   +0x008 InvalidAttributes : Uint4B
   +0x00c GenericMapping   : _GENERIC_MAPPING
      +0x000 GenericRead      : Uint4B
      +0x004 GenericWrite     : Uint4B
      +0x008 GenericExecute   : Uint4B
      +0x00c GenericAll       : Uint4B
   +0x01c ValidAccessMask  : Uint4B
   +0x020 RetainAccess     : Uint4B
   +0x024 PoolType         :
      NonPagedPool = 0n0
      NonPagedPoolExecute = 0n0
      PagedPool = 0n1
      NonPagedPoolMustSucceed = 0n2
      DontUseThisType = 0n3
      NonPagedPoolCacheAligned = 0n4
      PagedPoolCacheAligned = 0n5
      NonPagedPoolCacheAlignedMustS = 0n6
      MaxPoolType = 0n7
      NonPagedPoolBase = 0n0
      NonPagedPoolBaseMustSucceed = 0n2
      NonPagedPoolBaseCacheAligned = 0n4
      NonPagedPoolBaseCacheAlignedMustS = 0n6
      NonPagedPoolSession = 0n32
      PagedPoolSession = 0n33
      NonPagedPoolMustSucceedSession = 0n34
      DontUseThisTypeSession = 0n35
      NonPagedPoolCacheAlignedSession = 0n36
      PagedPoolCacheAlignedSession = 0n37
      NonPagedPoolCacheAlignedMustSSession = 0n38
      NonPagedPoolNx = 0n512
      NonPagedPoolNxCacheAligned = 0n516
      NonPagedPoolSessionNx = 0n544
   +0x028 DefaultPagedPoolCharge : Uint4B
   +0x02c DefaultNonPagedPoolCharge : Uint4B
   +0x030 DumpProcedure    : Ptr64
   +0x038 OpenProcedure    : Ptr64
   +0x040 CloseProcedure   : Ptr64
   +0x048 DeleteProcedure  : Ptr64
   +0x050 ParseProcedure   : Ptr64
   +0x058 SecurityProcedure : Ptr64
   +0x060 QueryNameProcedure : Ptr64
   +0x068 OkayToCloseProcedure : Ptr64
*/


NTSTATUS ObCreateObjectType(__in PUNICODE_STRING TypeName, __in POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, __in_opt PSECURITY_DESCRIPTOR SecurityDescriptor, __out POBJECT_TYPE *ObjectType);


POBJECT_TYPE MyObjectType;


//DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    //MyObjectType创建了,如何删除呢?
    ObDereferenceObject(MyObjectType);//不行,依然存在。
}


//DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
    NTSTATUS Status = STATUS_SUCCESS;
    UNICODE_STRING TypeName;
    const GENERIC_MAPPING ExpEventMapping = {
        STANDARD_RIGHTS_READ,
        STANDARD_RIGHTS_WRITE,
        STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
        GENERIC_ALL
    };

    //KdBreakPoint();
    __debugbreak();

    DriverObject->DriverUnload = Unload;

    RtlInitUnicodeString(&TypeName, L"Correy");// Initialize string descriptor.
    RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
    ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
    ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
    ObjectTypeInitializer.GenericMapping = ExpEventMapping;
    ObjectTypeInitializer.PoolType = NonPagedPool;
    ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
    //这里还可以定义八个方法/函数。
    Status = ObCreateObjectType(&TypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR) NULL, &MyObjectType);//XP成功,Win10 64返回参数错误。

#if (NTDDI_VERSION > NTDDI_VISTA)
    //XXX
#endif

    return Status;//在XP上的另一个验证办法:!object \ObjectTypes\Correy
}

2016年8月17日星期三

Windows Filtering Platform 的例子

//////////////////////////////////////////////////////////////////////////////////////////////////



/*
因WFP的资料极度匮乏,特公示。
注释:这是初级的,入门的,更深的等待你挖掘。

这里有两个例子:
1.一个是纯内核驱动的。
2.一个是R0和R3紧密配合使用的。

made by correy
made at 2016.08.17
homepage:http://correy.webs.com
*/



//////////////////////////////////////////////////////////////////////////////////////////////////



//驱动代码如下:

#pragma once

#include <ntifs.h>
#include <Fwpsk.h>
#include <windef.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。
#include <Fwpmk.h>
#include <Ntstrsafe.h>
#include <ndis.h>
#include <Wsk.h>
#include <ipmib.h>
#include <netpnp.h>
#include <ntintsafe.h>
#include <intrin.h>

#pragma warning(disable:4047)
#pragma warning(disable:4028)

#define TAG 'test' //test

PDEVICE_OBJECT deviceObject;

DEFINE_GUID(CALLOUTKEY, 0x99999999, 0x9999, 0x9999, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99);


VOID NTAPI ClassifyFn(
    IN const FWPS_INCOMING_VALUES0  *inFixedValues,
    IN const FWPS_INCOMING_METADATA_VALUES0  *inMetaValues,
    IN OUT VOID  *layerData,
    IN const FWPS_FILTER0  *filter,
    IN UINT64  flowContext,
    OUT FWPS_CLASSIFY_OUT0  *classifyOut
    )
{
    KdPrint(("ClassifyFn.\r\n"));
}


NTSTATUS NTAPI NotifyFn(IN FWPS_CALLOUT_NOTIFY_TYPE  notifyType, IN const GUID  *filterKey, IN const FWPS_FILTER0  *filter)
{
    return STATUS_SUCCESS;
}


VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status;
    UNICODE_STRING uniWin32NameString;
   
    status = FwpsCalloutUnregisterByKey(&CALLOUTKEY); ASSERT(NT_SUCCESS(status));

    //RtlInitUnicodeString( &uniWin32NameString, L"\\DosDevices\\hpm" );
    //IoDeleteSymbolicLink( &uniWin32NameString );
    IoDeleteDevice(deviceObject);// Delete the device object
}


NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS NtStatus = STATUS_SUCCESS;
    UNICODE_STRING  ntUnicodeString;
    UNICODE_STRING  ntWin32NameString;
    FWPS_CALLOUT0 sCallout ={0};
    UINT32 CalloutId;// Variable for the run-time callout identifier

    KdBreakPoint();
    __debugbreak();

    DriverObject->DriverUnload = Unload;

    RtlInitUnicodeString( &ntUnicodeString, L"\\Device\\hpm");
    NtStatus = IoCreateDevice(DriverObject, 0, &ntUnicodeString, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject);
    ASSERT (NT_SUCCESS( NtStatus ));

    //RtlInitUnicodeString( &ntWin32NameString, L"\\DosDevices\\hpm" );
    //NtStatus = IoCreateSymbolicLink(&ntWin32NameString, &ntUnicodeString );
    //ASSERT (NT_SUCCESS( NtStatus ));

    sCallout.calloutKey = CALLOUTKEY;
    sCallout.classifyFn = ClassifyFn;
    sCallout.notifyFn = NotifyFn;
    NtStatus = FwpsCalloutRegister0(deviceObject, &sCallout, &CalloutId);
    ASSERT (NT_SUCCESS( NtStatus ));

    return NtStatus;
}



//////////////////////////////////////////////////////////////////////////////////////////////////
//应用层的代码如下:



#include <windows.h>
#include <fwpmu.h>
#include <stdio.h>
#include <assert.h>
#include <intrin.h>
#include <conio.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。

#pragma comment(lib, "fwpuclnt.lib")

const GUID PROVIDER_KEY = {0x5fb216a8, 0xe2e8, 0x4024, { 0xb8, 0x53, 0x39, 0x1a, 0x41, 0x68, 0x64, 0x1e }};
DEFINE_GUID(CALLOUTKEY, 0x99999999, 0x9999, 0x9999, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99);


DWORD Install()
    /*
    功能:开启内核的WFP的Callout。

    参考:
    1.https://msdn.microsoft.com/en-us/library/windows/desktop/bb427376(v=vs.85).aspx
    2.Windows-driver-samples-master\network\trans\msnmntr
    */
{
   HANDLE engine = NULL;
   FWPM_SESSION0 session;
   memset(&session, 0, sizeof(session));  
   session.displayData.name = L"SDK Examples";// The session name isn't required but may be useful for diagnostics.  
   session.txnWaitTimeoutInMSec = INFINITE;// Set an infinite wait timeout, so we don't have to handle FWP_E_TIMEOUT errors while waiting to acquire the transaction lock.  
   session.flags = FWPM_SESSION_FLAG_DYNAMIC;// Let the Base Filtering Engine cleanup after us.
   DWORD result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &session, &engine);// The authentication service should always be RPC_C_AUTHN_DEFAULT.
   assert(ERROR_SUCCESS == result);
 
   result = FwpmTransactionBegin0(engine, 0);// We add the provider and sublayer from within a single transaction to make it easy to clean up partial results in error paths.
   assert(ERROR_SUCCESS == result);

   /*
   此处不是必要的调用:
   1.FwpmProviderAdd0
   2.FwpmSubLayerAdd0
   3.如果加上更好。
   */

   //不添加过滤条件,WFP的内核Callout汗函数也不会调用。
   FWPM_FILTER filter;
   RtlZeroMemory(&filter, sizeof(FWPM_FILTER));
   filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
   filter.displayData.name = L"name";
   filter.displayData.description = L"description";
   filter.action.type = FWP_ACTION_CALLOUT_INSPECTION; // We're only doing inspection.
   filter.action.calloutKey = CALLOUTKEY;
   filter.weight.type = FWP_EMPTY; // auto-weight.    
   filter.numFilterConditions = 0;
   result = FwpmFilterAdd(engine, &filter, NULL, NULL);
   assert(ERROR_SUCCESS == result);

   // Once all the adds have succeeded, we commit the transaction to persist the new objects.
   result = FwpmTransactionCommit0(engine);
   assert(ERROR_SUCCESS == result);

   _getch();//一调用FwpmEngineClose0效果就没有了,就是内核的ClassifyFn就不运行了。

   // FwpmEngineClose0 accepts null engine handles, so we needn't precheck for null.
   // Also, when closing an engine handle, any transactions still in progress are automatically aborted, so we needn't explicitly abort the transaction in error paths.
   FwpmEngineClose0(engine);
   return result;
}


int _tmain(int argc, _TCHAR* argv[])
{
    DebugBreak();
    __debugbreak();

    //运行/测试前确保驱动加载。
    DWORD D = Install();

    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////////
//如果需要SOURCES文件,SOURCES文件内容如下:



TARGETNAME=wfp
TARGETTYPE=DRIVER

LINKER_FLAGS = $(LINKER_FLAGS)/INTEGRITYCHECK

INCLUDES=\
   $(DDK_INC_PATH);

TARGETLIBS=\
    $(DDK_LIB_PATH)\ntoskrnl.lib \
    $(DDK_LIB_PATH)\ndis.lib \
    $(DDK_LIB_PATH)\fwpkclnt.lib \
    $(SDK_LIB_PATH)\uuid.lib
   
TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\Ntstrsafe.lib

C_DEFINES=$(C_DEFINES) -DBINARY_COMPATIBLE=0 -DNT -DUNICODE -D_UNICODE -DNDIS60 -DNDIS_SUPPORT_NDIS6

SOURCES= wfp.c



//////////////////////////////////////////////////////////////////////////////////////////////////
/*
纯驱动版的。

注释:可以没有用FwpmSubLayerAdd添加自己的SubLayer,而是用FWPM_SUBLAYER_UNIVERSAL设置subLayerKey
*/


#pragma once

#include <ntifs.h>
#include <Fwpsk.h>
#include <windef.h>
#include <initguid.h> //静态定义UUID用的,否则:error LNK2001。
#include <Fwpmk.h>


// Context structure to be associated with the filters
typedef struct FILTER_CONTEXT_ {
    //.
    //.  // Driver-specific content
    //.
    int test;
} FILTER_CONTEXT, *PFILTER_CONTEXT;

#define FILTER_CONTEXT_POOL_TAG 'fcpt'// Memory pool tag for filter context structures


// Context structure to be associated with data flows
typedef struct FLOW_CONTEXT_ {
    //...
    int test;
} FLOW_CONTEXT, *PFLOW_CONTEXT;

#define FLOW_CONTEXT_POOL_TAG 'fcpt'

PDEVICE_OBJECT deviceObject;
UINT32 CalloutId;// Variable for the run-time callout identifier
FWPS_CALLOUT0 Callout ={0};
HANDLE injectionHandle;// Injection handle
HANDLE gEngineHandle;

DEFINE_GUID(WFP_TEST_GUID, 0x99999999, 0x9999, 0x9999, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99);
DEFINE_GUID(WFP_TEST_LAYER, 0x88888888, 0x8888, 0x8888, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88);


// Prototypes for the callout's callout functions
VOID NTAPI ClassifyFn(
    IN const FWPS_INCOMING_VALUES0  *inFixedValues,
    IN const FWPS_INCOMING_METADATA_VALUES0  *inMetaValues,
    IN OUT VOID  *layerData,
    IN const FWPS_FILTER0  *filter,
    IN UINT64  flowContext,
    OUT FWPS_CLASSIFY_OUT0  *classifyOut
    )
{

}


NTSTATUS NTAPI NotifyFn(
    IN FWPS_CALLOUT_NOTIFY_TYPE  notifyType,
    IN const GUID  *filterKey,
    IN const FWPS_FILTER0  *filter
    )
{
    NTSTATUS NtStatus = STATUS_SUCCESS;
    PFILTER_CONTEXT context;

    ASSERT(filter != NULL);
   
    switch(notifyType)// Switch on the type of notification
    {        
    case FWPS_CALLOUT_NOTIFY_ADD_FILTER:// A filter is being added to the filter engine      
        //context = (PFILTER_CONTEXT)ExAllocatePoolWithTag(NonPagedPool, sizeof(FILTER_CONTEXT), FILTER_CONTEXT_POOL_TAG);// Allocate the filter context structure      
        //if (context == NULL) {// Check the result of the memory allocation          
        //    return STATUS_INSUFFICIENT_RESOURCES;// Return error
        //}

        // Initialize the filter context structure
        //...
       
        //filter->context = (UINT64)context;// Associate the filter context structure with the filter
        break;      
    case FWPS_CALLOUT_NOTIFY_DELETE_FILTER:// A filter is being removed from the filter engine      
        context = (PFILTER_CONTEXT)filter->context;// Get the filter context structure from the filter      
        if (context) {// Check whether the filter has a context

            // Cleanup the filter context structure
            //...

            //ExFreePoolWithTag(context, FILTER_CONTEXT_POOL_TAG);// Free the memory for the filter context structure
        }
        break;  
    case FWPS_CALLOUT_NOTIFY_ADD_FILTER_POST_COMMIT:

        break;
    default:// Unknown notification
        // Do nothing
        break;
    }

    return STATUS_SUCCESS;
    return NtStatus;
}


VOID NTAPI FlowDeleteFn(
    IN UINT16  layerId,
    IN UINT32  calloutId,
    IN UINT64  flowContext
    )
{
    PFLOW_CONTEXT context;

    context = (PFLOW_CONTEXT)flowContext;// Get the flow context structure

    // Cleanup the flow context structure
    //...

    //ExFreePoolWithTag(context, FLOW_CONTEXT_POOL_TAG);// Free the memory for the flow context structure
}


VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status;
 
    FwpmEngineClose0(gEngineHandle);

    status = FwpsCalloutUnregisterById0(CalloutId);// Unregister the callout
    if (status == STATUS_DEVICE_BUSY)// Check result
    {
        // For each data flow that is being processed by the callout that has an associated context,
        // clean up the context and then call FwpsFlowRemoveContext0 to remove the context from the data flow.
        //...

        status = FwpsCalloutUnregisterById0(CalloutId);// Finish unregistering the callout
    }

    if (status != STATUS_SUCCESS)// Check status
    {
        // Handle error
        //...
    }

    IoDeleteDevice(deviceObject);// Delete the device object

    status = FwpsInjectionHandleDestroy0(injectionHandle);// Destroy the injection handle
    if (status != STATUS_SUCCESS)// Check status
    {
        // Handle error
        //...
    }
}


NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS NtStatus = STATUS_SUCCESS;
    FWPM_SUBLAYER0 SubLayer;
    FWPM_SESSION0 session = {0};
    FWPM_FILTER0 filter = {0};
    FWPM_FILTER_CONDITION0 filterConditions[3] = {0};
    FWPM_CALLOUT0 mCallout = {0};
    FWPM_DISPLAY_DATA0 displayData = {0};

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;// Specify the callout driver's Unload function

    NtStatus = IoCreateDevice(DriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject);// Create a device object
    if (!NT_SUCCESS( NtStatus )) {
        return NtStatus;
    }

    //WDK文档的Registering Callouts with the Filter Engine章节没有这个函数,可是卸载里有用这个变量。DDPROXY有。
    NtStatus = FwpsInjectionHandleCreate0(AF_INET, FWPS_INJECTION_TYPE_TRANSPORT, &injectionHandle);
    if (!NT_SUCCESS(NtStatus)) {
        IoDeleteDevice(deviceObject);
        return NtStatus;
    }

    session.flags = FWPM_SESSION_FLAG_DYNAMIC;
    NtStatus = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &gEngineHandle);
    if (!NT_SUCCESS(NtStatus)) {      
        FwpsInjectionHandleDestroy0(injectionHandle);
        IoDeleteDevice(deviceObject);
        return NtStatus;
    }

    NtStatus = FwpmTransactionBegin0(gEngineHandle, 0);
    if (!NT_SUCCESS(NtStatus)) {      
        FwpmEngineClose0(gEngineHandle);
        FwpsInjectionHandleDestroy0(injectionHandle);
        IoDeleteDevice(deviceObject);
        return NtStatus;
    }

   RtlZeroMemory(&SubLayer, sizeof(FWPM_SUBLAYER0));
   SubLayer.subLayerKey = WFP_TEST_LAYER;
   SubLayer.displayData.name = L"WFP TEST NAME";
   SubLayer.displayData.description = L"WFP TEST DESCRIPTION";
   SubLayer.flags = 0;
   SubLayer.weight = FWP_EMPTY; // auto-weight.;
   NtStatus = FwpmSubLayerAdd0(gEngineHandle, &SubLayer, NULL);
   if (!NT_SUCCESS(NtStatus)) {
       FwpmEngineClose0(gEngineHandle);
       FwpsInjectionHandleDestroy0(injectionHandle);
       IoDeleteDevice(deviceObject);
       return NtStatus;
   }

    Callout.calloutKey = WFP_TEST_GUID;
    Callout.flags = 0;
    Callout.classifyFn = ClassifyFn;
    Callout.notifyFn = NotifyFn;
    Callout.flowDeleteFn = FlowDeleteFn;
    NtStatus = FwpsCalloutRegister0(deviceObject, &Callout, &CalloutId);
    if (!NT_SUCCESS( NtStatus )) {
        FwpmEngineClose0(gEngineHandle);
        FwpsInjectionHandleDestroy0(injectionHandle);
        IoDeleteDevice(deviceObject);
        return NtStatus;
    }

    displayData.name = L"XXX name";
    displayData.description = L"XXX description";
    mCallout.calloutKey = WFP_TEST_GUID;
    mCallout.displayData = displayData;
    mCallout.applicableLayer = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
    NtStatus = FwpmCalloutAdd0(gEngineHandle, &mCallout, NULL, NULL);
    if (!NT_SUCCESS(NtStatus)) {
        FwpsCalloutUnregisterById0(CalloutId);
        FwpmEngineClose0(gEngineHandle);
        FwpsInjectionHandleDestroy0(injectionHandle);
        IoDeleteDevice(deviceObject);
        return NtStatus;
    }

    filterConditions[0].fieldKey = FWPM_CONDITION_DIRECTION;
    filterConditions[0].matchType = FWP_MATCH_EQUAL;
    filterConditions[0].conditionValue.type = FWP_UINT32;
    filterConditions[0].conditionValue.uint32 = FWP_DIRECTION_OUTBOUND;

    filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
    filter.displayData.name = L"WFP TEST NAME";
    filter.displayData.description = L"WFP TEST DESCRIPTION";
    filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
    filter.action.calloutKey = WFP_TEST_GUID;
    filter.filterCondition = filterConditions;
    filter.subLayerKey = WFP_TEST_LAYER;
    filter.weight.type = FWP_EMPTY; // auto-weight.
    filter.rawContext = 0;
    filter.numFilterConditions = 1;
    NtStatus = FwpmFilterAdd0(gEngineHandle, &filter, NULL, NULL);
    if (!NT_SUCCESS(NtStatus)) {
        FwpsCalloutUnregisterById0(CalloutId);
        FwpmEngineClose0(gEngineHandle);
        FwpsInjectionHandleDestroy0(injectionHandle);
        IoDeleteDevice(deviceObject);
        return NtStatus;
    }

    NtStatus = FwpmTransactionCommit0(gEngineHandle);
    if (!NT_SUCCESS(NtStatus)) {
        FwpsCalloutUnregisterById0(CalloutId);
        FwpmEngineClose0(gEngineHandle);
        FwpsInjectionHandleDestroy0(injectionHandle);
        IoDeleteDevice(deviceObject);
        return NtStatus;
    }

    return NtStatus;
}


//////////////////////////////////////////////////////////////////////////////////////////////////