显示标签为“驅動開發”的博文。显示所有博文
显示标签为“驅動開發”的博文。显示所有博文

2011年10月1日星期六

[轉載]Windows處理驅動Path流程


作 者: boywhp
時 間: 2011-08-31,15:50:13
鏈接: http://bbs.pediy.com/showthread.php?t=139566

昨天寫了一個類似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";
}
  1、如果沒有ImagePath項目就在”\SystemRoot\System32\Drivers\” + BaseName.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
}
其ObpXxxx定義如下:

代碼:
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
};
隨便問一下if (!((ULONG_PTR)(ObjectName->Buffer) & (sizeof(ULONGLONG)-1)))是要求64字節對齊嗎?
大致流程是:
如果是\??\開頭的直接獲取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 %= NUM​​BER_HASH_BUCKETS;
#define NUMBER_HASH_BUCKETS 37
好像大致是一個hash目錄表,首先簡單的通過hash快速查找,對應的37個鍊錶之1,然後遍歷鍊錶比較名稱是否為SystemRoot。
在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"
至此,大致了解了這個路徑的處理過程,至於我的問題應該可以很好的使用ZwOpenFile還處理,因為操作系統本身也是直接調用ZwOpenFile,或者直接把\??\過濾掉得了。

2011年9月30日星期五

[轉載]最新驅動WDK7600在VC6.0下的編譯開發配置環境


作者:wingdbg
網上找了很多資料,都不好使。相信有很多像我一樣偏好VC6.0的傢伙,最新的WDK真的用不了麼?必須可以! ! !

    開始之前要一定要明確一件事情,單獨使用WDK+記事本就可以開發驅動,和VC的編譯器耗無關係,而使用VC的唯一目的,就是把它當作超級記事本,這樣可以省去自己維護Makefile的麻煩,並且擁有IDE的其他各種便捷。


1.安裝好VC6和DWK,先後順序無關。
    從開始菜單找到WDK的程序目錄,進入“Windows XP Checked Build Environment”,輸入命令"build",此時WDK將會把自己進行編譯,大約需要1分鐘。

2.VC6設置Include/Lib/Executable目錄。
    設置為自己需要編譯的平台的各個目錄即可, Include要確保找到ntddk.h等,Lib與Include對應,Executable 要確保能找到cl.exe
例如XP平台下設置為:

include包含部分:

C:\WinDDK\7600.16385.1\inc\ddk
C:\WinDDK\7600.16385.1\inc\api
C:\WinDDK\7600.16385.1\inc\crt


lib連接庫包含部分:

C:\WINDDK\7600.16385.1\LIB\WXP\I386
C:\WINDDK\7600.16385.1\LIB\WIN7\I386


執行文件包含:

C:\WINDDK\7600.16385.1\BIN
C:\WINDDK\7600.16385.1\BIN\X86
C:\WinDDK\7600.16385.1\bin\x86\x86

對於VC原有的路徑,Include 和Lib建議都刪除掉,而Executable則將你新加的置頂,順序不能錯。其余建議保留(雖然編譯驅動不會使用VC的Bin目錄下的ml.exe、link.exe 等,但vc的代碼提示等功能是需要bin目錄下的一些程序來完成的,因此還是至少要保留VC原有的Bin目錄,但必須在DDK的之後)。

3.建立一個空工程,Exe或者Dll都可以,然後直接修改工程屬性:

要改的地方不少,描述各個選項還不如直接記錄個文本的,清空C/C++和Link下面的Option文本框,按下面的填寫。

C/C++ 選項填寫:
/nologo /Gz /MLd /W3 /WX /Z7 /Od /D WIN32=100 /D _X86_=1 /D WINVER=0x500 /D DBG=1 /Fo"MyDriver_Check/" /Fd"MyDriver_Check/" /FD /c

LINK 選項填寫:
    NT式驅動為
ntoskrnl.lib /nologo /base:"0x10000" /stack:0x400000,0x1000 /entry:"DriverEntry" /subsystem:console /incremental:no /pdb:"MyDriver_Check/HelloDDK.pdb" /map:"MyDriver_Check/HelloDDK.map " /debug /machine:I386 /nodefaultlib /out:"MyDriver_Check/HelloDDK.sys" /subsystem:native /driver /SECTION:INIT,D /RELEASE /IGNORE:4078

    WDM式驅動為

wdm.lib /nologo /base:"0x10000" /stack:0x400000,0x1000 /entry:"DriverEntry" /subsystem:console /incremental:no /pdb:"SYS_Check/HelloWDM.pdb" /debug /machine:I386 /nodefaultlib / out:"SYS_Check/HelloWDM.sys" /subsystem:native /driver /SECTION:INIT,D /RELEASE /IGNORE:4078

4.保存配置,現在給這個空工程建一個c文件,複製以下內容:

#include <ntddk.h>
NTSTATUS DriverEntry(
        IN PDRIVER_OBJECT DriverObject,
        IN PUNICODE_STRING RegistryPath
        )
{
        NTSTATUS status = STATUS_UNSUCCESSFUL;
        return status;
}

編譯通過則配置成功! ! !