昨天写了一个类似SC查询驱动服务的信息的程序,发现获取到的路径ImagePath是\??\c:\xxxxx,导致我用CreateFile什么的函数,居然失败!就比较好奇windows是怎么处理驱动服务一类的路径处理。我知道windows是在注册表中记录的启动服务信息,直接用注册表打开查看如下:
注意其中的ImagePath,我发现大致有好几种情况:
1、 无ImagePath项
2、 system32\xxxxxxxx
3、 \??\c:\xxxxxx
4、 %SystemRoot%xxxxxx
我想了解的是windows驱动服务是怎么处理这玩意的,既然是驱动最终会调用NtLoadDriver函数
NTSTATUS NtLoadDriver ( __in PUNICODE_STRING DriverServiceName )
直接Windbg启动调试 bp NtLoadDriver
fa06fa2c fa06fa38 80821a99 nt!NtLoadDriver+0x143
fa06fa2c fa06fa38 80821a99 nt!KiFastCallEntry+0xf8
fa06fa2c 815d5828 815b08e8 nt!ZwLoadDriver+0x11
817c7030 815d5770 fa06fab8 NDIS!ndisPnPDispatch+0x3ad
哦,NDIS不错哦,还可以加载驱动,呵呵,相关兴趣的可以IDA研究下,下面是我发现的一些非常规驱动加载列表[2003 server]:
1 "\Registry\Machine\System\CurrentControlSet\Services\Gpc"
fa01fa20 fa01fa3c 80821a99 nt!NtLoadDriver
fa01fa20 fa01fa3c 80821a99 nt!KiFastCallEntry+0xf8
fa01fa20 8142e000 8089547a nt!ZwLoadDriver+0x11
f96454b8 8142e000 8089547a ipsec!GpcInitialize+0x7f
00000000 8081dceb 815142f0 ipsec!IPSecGpcInitialize+0x35
815142f0 e12a75dc 00000000 ipsec!IPSecGeneralInit+0x168
815142f0 81430000 e144aa30 ipsec!DriverEntry+0x104
000000ec 00000001 00000000 nt!IopLoadDriver+0x689
00000000 00043000 00000000 nt!IopInitializeSystemDrivers+0x16d
00000000 00000000 8179d740 nt!IoInitSystem+0x6ad
80087000 fa01fddc 80905b5b nt!Phase1InitializationDiscard+0x9cf
80087000 00000000 00000000 nt!Phase1Initialization+0xd
808c9f21 80087000 00000000 nt!PspSystemThreadStartup+0x2e
00000000 00000000 00000000 nt!KiThreadStartup+0x16
2 "\Registry\Machine\System\CurrentControlSet\Services\WANARP"
f9948bdc f9948bf4 80821a99 nt!NtLoadDriver
f9948bdc f9948bf4 80821a99 nt!KiFastCallEntry+0xf8
f9948bdc 00000000 81503dd0 nt!ZwLoadDriver+0x11
f9948c8c f9948c1c 8160d2dc tcpip!IPBindAdapter+0xf2
80a719b0 80a71988 f99a7534 NDIS!ndisInitializeBinding+0x189
f99a53bc 00000000 81503e60 NDIS!ndisCheckAdapterBindings+0xd9
81503dd0 00000000 81289db0 NDIS!ndisCheckProtocolBindings+0xd2
81503e50 00000000 00000000 NDIS!ndisWorkerThread+0x74
f99a8a41 81503e50 00000000 nt!PspSystemThreadStartup+0x2e
00000000 00000000 00000000 nt!KiThreadStartup+0x16
3 "\Registry\Machine\System\CurrentControlSet\Services\Cdfs"
f9948974 f994897c 80821a99 nt!NtLoadDriver
f9948974 f994897c 80821a99 nt!KiFastCallEntry+0xf8
f9948974 81751200 814861d0 nt!ZwLoadDriver+0x11
c000010e f9f0439e 814861d0 Fs_Rec!FsRecLoadFileSystem+0x4f
814861d0 81751200 8163bad8 Fs_Rec!CdfsRecFsControl+0x29
814861d0 81751200 814861d0 Fs_Rec!FsRecFsControl+0x75
81668680 808a73a0 815fa8f8 nt!IofCallDriver+0x45
814861d0 80a71908 815fa8f8 nt!IopLoadFileSystemDriver+0x62
c000019c 8163cd00 00000000 nt!IopMountVolume+0x2cc
8163cd20 815fa800 f9948b9c nt!IopCheckVpbMounted+0x54
815fa8f8 00000000 81533c60 nt!IopParseDevice+0x3d4
00000000 f9948c18 00000040 nt!ObpLookupObjectName+0x5b0
00000000 00000000 0007ff01 nt!ObOpenObjectByName+0xea
0015fe0c 00100180 0015fdd0 nt!IopCreateFile+0x447
0015fe0c 00100180 0015fdd0 nt!IoCreateFile+0xa3
0015fe0c 00100180 0015fdd0 nt!NtOpenFile+0x27
0015fe0c 00100180 0015fdd0 nt!KiFastCallEntry+0xf8
WARNING: Stack unwind information not available. Following frames may be wrong.
7c959e17 4858d650 7c958270 ntdll+0x285fe
00000000 7c94a469 00000000 0x48584401
ffffffff 4858afe8 48582f48 0x485894ec
4 "\Registry\Machine\System\CurrentControlSet\Services\tdtcp"
f7ed2b4c f7ed2b6c 80821a99 nt!NtLoadDriver
f7ed2b4c f7ed2b6c 80821a99 nt!KiFastCallEntry+0xf8
f7ed2b4c f9db12e8 8118bf78 nt!ZwLoadDriver+0x11
8127b178 f7ed2b88 81182258 termdd!_IcaLoadSdWorker+0x11b
8118225c f7ed2ba8 811c29e8 termdd!_IcaLoadSd+0x8b
811c29e8 81182258 8122cf68 termdd!_IcaPushStack+0x7b
811c29e8 8122cf68 8122cfd8 termdd!IcaDeviceControlStack+0x11f
8122cf68 8122cfd8 8122cf68 termdd!IcaDeviceControl+0x4e
81617f10 8122cf68 8151db90 termdd!IcaDispatch+0x12a
8122cfd8 ffa7ed10 8122cf68 nt!IofCallDriver+0x45
81617f10 8122cf68 ffa7ed10 nt!IopSynchronousServiceTail+0x10b
00000208 00000000 00000000 nt!IopXxxControlFile+0x60f
00000208 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
00000208 00000000 00000000 nt!KiFastCallEntry+0xf8
WARNING: Stack unwind information not available. Following frames may be wrong.
00000208 0038002b 0250fa18 ntdll+0x285fe
000a0498 0038002b 0250fa18 0x74cd166f
000a0498 0038002b 0250fa18 0x74cd16b4
000be2f0 000a0498 0038002b 0x764a0759
000a0498 0038002b 0250fa18 0x74cd16fe
00000000 00000000 808466ca 0x74cd17cf
以及"\Registry\Machine\System\CurrentControlSet\Services\rdpwd"
然后是NtLoadDriver -> IopLoadUnloadDriver -> IopLoadDriver->IopBuildFullDriverPath
NTSTATUS
IopBuildFullDriverPath(
IN PUNICODE_STRING KeyName,
IN HANDLE KeyHandle,
OUT PUNICODE_STRING FullPath
)
这里处理了下注册表路径,具体WRK代码如下
status = IopGetRegistryValue( KeyHandle, L"ImagePath", &keyValueInformation); if (NT_SUCCESS(status) && keyValueInformation->DataLength) { nameLength = keyValueInformation->DataLength - sizeof(WCHAR); name = (PWCHAR)KEY_VALUE_DATA(keyValueInformation); if (name[0] != L'\\') { path = L"\\SystemRoot\\"; pathLength = sizeof(L"\\SystemRoot\\") - sizeof(UNICODE_NULL); } else { path = NULL; } ext = NULL; } else { nameLength = KeyName->Length; name = KeyName->Buffer; pathLength = sizeof(L"\\SystemRoot\\System32\\Drivers\\") - sizeof(UNICODE_NULL); path = L"\\SystemRoot\\System32\\Drivers\\"; extLength = sizeof(L".SYS") - sizeof(UNICODE_NULL); ext = L".SYS"; }
2、如何ImagePath = 是'\'开头,=ImagePath
3、如果不是'\‘开头 path = “\SystemRoot\” + ImagePath
这里SystemRoot我比较好奇,想看看系统是怎么处理这个路径的,继续:
IopLoadDriver 会调用MmLoadSystemImage-> ZwOpenFile->NtOpenFile
bp NtOpenFile命中
kd> dt !_OBJECT_ATTRIBUTES fa06f734
nt!_OBJECT_ATTRIBUTES
+0x000 Length : 0x18
+0x004 RootDirectory : (null)
+0x008 ObjectName : 0xfa06f888 _UNICODE_STRING "\SystemRoot\System32\Drivers\NDProxy.SYS"
+0x00c Attributes : 0x240
+0x010 SecurityDescriptor : (null)
+0x014 SecurityQualityOfService : (null)
继续跟踪->IopCreateFile->ObOpenObjectByName->ObpLookupObjectName
ParseFromRoot: if (DeviceMap != NULL) { ObfDereferenceDeviceMap(DeviceMap); DeviceMap = NULL; } if (!((ULONG_PTR)(ObjectName->Buffer) & (sizeof(ULONGLONG)-1))) { // // Check if the object name is actually equal to the // global dos devices short name prefix "\??\" // if ((ObjectName->Length >= ObpDosDevicesShortName.Length) && (*(PULONGLONG)(ObjectName->Buffer) == ObpDosDevicesShortNamePrefix.Alignment.QuadPart)) { XXXXXXXXXXXXXXXXXXXX }
const ALIGNEDNAME ObpDosDevicesShortNamePrefix = { L'\\',L'?',L'?',L'\\' }; // L"\??\" const ALIGNEDNAME ObpDosDevicesShortNameRoot = { L'\\',L'?',L'?',L'\0' }; // L"\??" const UNICODE_STRING ObpDosDevicesShortName = { sizeof(ObpDosDevicesShortNamePrefix), sizeof(ObpDosDevicesShortNamePrefix), (PWSTR)&ObpDosDevicesShortNamePrefix };
大致流程是:
如果是\??\开头的直接获取RootDirectory,否则需要解析root目录,通过下面函数
PVOID
ObpLookupDirectoryEntry (
IN POBJECT_DIRECTORY Directory,
IN PUNICODE_STRING Name,
IN ULONG Attributes,
IN BOOLEAN SearchShadow,
OUT POBP_LOOKUP_CONTEXT LookupContext
)
bp ObpLookupDirectoryEntry命中:
kd> dd esp
fa06f3ec 80902d75 e1000700 fa06f410 00000240
kd> dt !_UNICODE_STRING fa06f410
nt!_UNICODE_STRING
"SystemRoot"
+0x000 Length : 0x14
+0x002 MaximumLength : 0xf8
+0x004 Buffer : 0xe12c4d62 "SystemRoot"
我们关心的SystemRoot出现了,大致看了下,居然就是计算了SystemRoot字符串的hash!!!然后估计就是查表,其hash算法为:
HashIndex = 0; while (WcharLength--) { Wchar = *Buffer++; HashIndex += (HashIndex << 1) + (HashIndex >> 1); if (Wchar < 'a') { HashIndex += Wchar; } else if (Wchar > 'z') { HashIndex += RtlUpcaseUnicodeChar( (WCHAR)Wchar ); } else { HashIndex += (Wchar - ('a'-'A')); } } HashValue = HashIndex; HashIndex %= NUMBER_HASH_BUCKETS; #define NUMBER_HASH_BUCKETS 37
在WRK中搜索"SystemRoot",发现其在Initos.c的CreateSystemRootLink函数中被初始化创建符号链接
// // Create the symbolic link to the root of the system directory. // RtlInitAnsiString( &linkString, INIT_SYSTEMROOT_LINKNAME ); status = RtlAnsiStringToUnicodeString( &linkUnicodeString, &linkString, TRUE); InitializeObjectAttributes( &objectAttributes, &linkUnicodeString, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, SePublicDefaultUnrestrictedSd ); 。。。。。。 status = NtCreateSymbolicLinkObject( &linkHandle, SYMBOLIC_LINK_ALL_ACCESS, &objectAttributes, &deviceNameUnicodeString ); #define INIT_SYSTEMROOT_LINKNAME "\\SystemRoot"