調試驅動程序的入口

調試驅動程序的入口(1)

這是老生常談的一個問題,先說一個一般性的方法。
將內核調試器設置成啓動時斷點(快捷鍵Ctrl+Alt+K),調試器提示:
Will breakin on first symbol load at next boot.
這句話意味着
The debugger breaks into a restarted target computer after the first kernel module is loaded.
kd> .reboot
Shutdown occurred at (Thu Mar 22 15:54:25.345 2012 (UTC + 8:00))...unloading all symbol tables.
Waiting to reconnect...
Connected to Windows XP 2600 x86 compatible target at (Thu Mar 22 15:54:36.162 2012 (UTC + 8:00)), ptr64 FALSE
Kernel Debugger connection established.
......
Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available
nt!DebugService2+0xe:
804d88ad cc              int     3

系統啓動並加載第一個模塊時會斷住,調試引擎通過內核函數nt!DbgLoadImageSymbols和調試器通信。
kd> kv
ChildEBP RetAddr  Args to Child             
0005ff80 804d88e7 000600c4 0005ff94 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
0005ffa4 80656c46 000600c4 804d4000ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
000600cc 80691ac8 00000000 80087000 80542268 nt!KdInitSystem+0x23e (FPO: [Non-Fpo])
00060100 00420e53 80087000 00467904 00438ab7 nt!KiSystemStartup+0x264
WARNING: Frame IP not in any known module. Following frames may be wrong.
00060e3c 0041ec40 00000007 00060e5c 00000000 0x420e53
00060ecc 004014fe 004678e0 0047164f 00051d68 0x41ec40
00061ff0 10101010 00000002 00000000 04e4000d 0x4014fe
00061ff4 00000000 00000000 04e4000d 003f0001 0x10101010
 
此時加載的模塊就是NT內核(the first kernel module),nt!DbgLoadImageSymbols第一個參數是模塊名稱,第二個參數是模塊的內存地址。
kd> ds 600c4
0005ffc4  "\WINDOWS\system32\ntoskrnl.exe"
事實上調試器接收到該通知事件時,內核模塊已經成功加載。
kd> lm
start end module name
804d4000 806c6980 nt(pdb symbols) d:\windbg\symbols\raymond_xp_sp1\ntoskrnl.pdb\C95EC79CFBFB4220AF2B6E9D09551A1F2\ntoskrnl.pdb
Unable to enumerate kernel-mode unloaded modules, HRESULT 0x80004005
 
理論上,系統中任何模塊的加載調試引擎都會通知調試器,包括驅動。對於驅動程序來說,映像文件雖然加載到內存中,但此時的DriverEntry還未得到機會執行。調試驅動入口就是利用這個原理。隨便找個驅動serial.sys作爲例子,
設置模塊加載斷點,然後執行,
kd> sxe -c "ds poi(@esp+4); kv" ld:serial
kd> sx

......
  ld - Load module - break
       Command: "ds poi(@esp+4); kv"
       (only break for serial)

  ud - Unload module - ignore
......
   * - Other exception - second-chance break - not handled
kd> g
816862a8  "\WINDOWS\System32\DRIVERS\serial"
816862c8  ".sys"
ChildEBP RetAddr  Args to Child             
f9e9b67c 804d88e7 f9e9b758 f9e9b690 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
f9e9b6a0 8055c9ab f9e9b758 f9b1c000ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
f9e9b844 80558b1e f9e9b904 00000000 00000000 nt!MmLoadSystemImage+0xa6b (FPO: [Non-Fpo])
f9e9b910 80555417 80000774 00000000 f9e9b900 nt!IopLoadDriver+0x311 (FPO: [4,40,3])
f9e9b954 80571f85 e1492868 00000001 80000774 nt!PipCallDriverAddDeviceQueryRoutine+0x239 (FPO: [Non-Fpo])
f9e9b9a0 80571fb3 f9e9ba2c e1492854 f9e9ba00 nt!RtlpCallQueryRegistryRoutine+0x3af (FPO: [Non-Fpo])
f9e9ba04 8055a84d 00000000 00000084 00000001 nt!RtlQueryRegistryValues+0x2a4 (FPO: [Non-Fpo])
f9e9bad8 8055a657 00000000 00000001 f9e9bd54 nt!PipCallDriverAddDevice+0x237 (FPO: [3,43,3])
f9e9bd24 805a9093 817b54c8 00000001 00000000 nt!PipProcessDevNodeTree+0x147 (FPO: [Non-Fpo])
f9e9bd4c 805071b0 00000003 80549fc0 8054eddc nt!PiProcessStartSystemDevices+0x38 (FPO: [Non-Fpo])
f9e9bd74 804ed629 00000000 00000000 817c7640 nt!PipDeviceActionWorker+0x158 (FPO: [Non-Fpo])
f9e9bdac 8057c73a 00000000 00000000 00000000 nt!ExpWorkerThread+0xfe (FPO: [Non-Fpo])
f9e9bddc 805124c1 804ed556 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
nt!DebugService2+0xe:
804d88ad cc              int     3
調試器成功捕獲到serial.sys驅動加載的事件,此時驅動已經在內存中,
kd> lm a f9b1c000
start    end        module name
f9b1c000 f9b2b400   serial     (deferred)    
分析PE文件頭,找到入口地址,(關於PE文件格式,可參考 WINDOWS內核及PE文件格式(雜燴),還有一張 史上最強的圖 )         
kd> dt _image_dos_header f9b1c000
nt!_IMAGE_DOS_HEADER
   +0x000 e_magic          : 0x5a4d
   +0x002 e_cblp           : 0x90
   +0x004 e_cp             : 3
   +0x006 e_crlc           : 0
   +0x008 e_cparhdr        : 4
   +0x00a e_minalloc       : 0
   +0x00c e_maxalloc       : 0xffff
   +0x00e e_ss             : 0
   +0x010 e_sp             : 0xb8
   +0x012 e_csum           : 0
   +0x014 e_ip             : 0
   +0x016 e_cs             : 0
   +0x018 e_lfarlc         : 0x40
   +0x01a e_ovno           : 0
   +0x01c e_res            : [4] 0
   +0x024 e_oemid          : 0
   +0x026 e_oeminfo        : 0
   +0x028 e_res2           : [10] 0
   +0x03c e_lfanew         : 0n208
kd> dt -r2 _image_nt_headers f9b1c000+0n208

ntdll!_IMAGE_NT_HEADERS
   +0x000 Signature        : 0x4550
   +0x004 FileHeader       : _IMAGE_FILE_HEADER
      +0x000 Machine          : 0x14c
      +0x002 NumberOfSections : 8
      +0x004 TimeDateStamp    : 0x3d6de48b
      +0x008 PointerToSymbolTable : 0
      +0x00c NumberOfSymbols  : 0
      +0x010 SizeOfOptionalHeader : 0xe0
      +0x012 Characteristics  : 0x10e
   +0x018 OptionalHeader   : _IMAGE_OPTIONAL_HEADER
      +0x000 Magic            : 0x10b
      +0x002 MajorLinkerVersion : 0x7 ''
      +0x003 MinorLinkerVersion : 0 ''
      +0x004 SizeOfCode       : 0xc200
      +0x008 SizeOfInitializedData : 0x2e80
      +0x00c SizeOfUninitializedData : 0
      +0x010 AddressOfEntryPoint : 0xa793
      +0x014 BaseOfCode       : 0x380
      +0x018 BaseOfData       : 0x2d80
      +0x01c ImageBase        : 0x10000
      +0x020 SectionAlignment : 0x80
      +0x024 FileAlignment    : 0x80
      +0x028 MajorOperatingSystemVersion : 5
      +0x02a MinorOperatingSystemVersion : 1
      +0x02c MajorImageVersion : 5
      +0x02e MinorImageVersion : 1
      +0x030 MajorSubsystemVersion : 5
      +0x032 MinorSubsystemVersion : 1
      +0x034 Win32VersionValue : 0
      +0x038 SizeOfImage      : 0xf400
      +0x03c SizeOfHeaders    : 0x380
      +0x040 CheckSum         : 0x1ddb8
      +0x044 Subsystem        : 1
      +0x046 DllCharacteristics : 0
      +0x048 SizeOfStackReserve : 0x40000
      +0x04c SizeOfStackCommit : 0x1000
      +0x050 SizeOfHeapReserve : 0x100000
      +0x054 SizeOfHeapCommit : 0x1000
      +0x058 LoaderFlags      : 0
      +0x05c NumberOfRvaAndSizes : 0x10
      +0x060 DataDirectory    : [16] _IMAGE_DATA_DIRECTORY
         +0x000 VirtualAddress   : 0
         +0x004 Size             : 0
因爲有符號,可以測試一下這個值,
kd> ln f9b1c000+a793
(f9b26793)   serial!DriverEntry   |  (f9b268d7)   serial!SerialEnumerateLegacy
Exact matches:
    serial!DriverEntry = <no type information>

相對於分析PE文件頭,還有一個簡單的做法是使用調試器腳本中的operator,如下:
kd> ? $iment(f9b1c000)
Evaluate expression: -105748589 = f9b26793
kd> bp $iment(f9b1c000)
kd> bl

 0 e f9b26793     0001 (0001) serial!DriverEntry
kd> g
Breakpoint 0 hit
serial!DriverEntry:
f9b26793 53              push    ebx

斷點命中,察看堆棧,正是驅動入口處。
kd> kv
ChildEBP RetAddr  Args to Child             
f9e9b854 80558d13 816862e0 81683000 00000000 serial!DriverEntry(FPO: [2,0,3])
f9e9b910 80555417 80000774 81683000 816862e0 nt!IopLoadDriver+0x5e0 (FPO: [4,40,3])
f9e9b954 80571f85 e1492868 00000001 80000774 nt!PipCallDriverAddDeviceQueryRoutine+0x239 (FPO: [Non-Fpo])
f9e9b9a0 80571fb3 f9e9ba2c e1492854 f9e9ba00 nt!RtlpCallQueryRegistryRoutine+0x3af (FPO: [Non-Fpo])
f9e9ba04 8055a84d 00000000 00000084 00000001 nt!RtlQueryRegistryValues+0x2a4 (FPO: [Non-Fpo])
f9e9bad8 8055a657 00000000 00000001 f9e9bd54 nt!PipCallDriverAddDevice+0x237 (FPO: [3,43,3])
f9e9bd24 805a9093 817b54c8 00000001 00000000 nt!PipProcessDevNodeTree+0x147 (FPO: [Non-Fpo])
f9e9bd4c 805071b0 00000003 80549fc0 8054eddc nt!PiProcessStartSystemDevices+0x38 (FPO: [Non-Fpo])
f9e9bd74 804ed629 00000000 00000000 817c7640 nt!PipDeviceActionWorker+0x158 (FPO: [Non-Fpo])
f9e9bdac 8057c73a 00000000 00000000 00000000 nt!ExpWorkerThread+0xfe (FPO: [Non-Fpo])
f9e9bddc 805124c1 804ed556 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16 
 
最後歸納一下驅動程序的加載過程,幾個函數的的調用關係如下,首先加載映象,通知調試器,然後調用入口函數。
IopLoadDriver
    MmLoadSystemImage
        DbgLoadImageSymbols
    DriverEntry



==============================================================================================

調試驅動程序的入口 (2) 強大的條件斷點

調試驅動程序的入口(1) 文中的方法大多數情況下是有效的,請注意是大多數。但例外總是有的,拿最近分析的一個曾經很流行的rootkit TDSS作爲例子,
 
下面的命令相當於系統啓動時斷點,會在加載第一個模塊(NT內核)時斷住,同時顯示模塊名稱和調用棧。
kd> sxe -c "ds poi(@esp+4); kv" ld:nt
kd> .reboot

Shutdown occurred at (Thu Mar 22 17:02:36.023 2012 (UTC + 8:00))...unloading all symbol tables.
Waiting to reconnect...
......
Machine Name:
Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available
0005ffc4  "\WINDOWS\system32\ntoskrnl.exe"
ChildEBP RetAddr  Args to Child             
0005ff80 804d88e7 000600c4 0005ff94 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
0005ffa4 80656c46 000600c4 804d4000 ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
000600cc 80691ac8 00000000 80087000 80542268 nt!KdInitSystem+0x23e (FPO: [Non-Fpo])
00060100 00420e53 80087000 00467904 00438ab7 nt!KiSystemStartup+0x264
WARNING: Frame IP not in any known module. Following frames may be wrong.
00060e3c 0041ec40 00000007 00060e5c 00000000 0x420e53
00060ecc 004014fe 004678e0 0047164f 00051d68 0x41ec40
00061ff0 10101010 00000002 00000000 04e4000d 0x4014fe
00061ff4 00000000 00000000 04e4000d 003f0001 0x10101010
nt!DebugService2+0xe:
804d88ad cc              int     3
 
設置模塊的加載斷點,
kd> sxe ld:*tdss*
kd> g
OS啓動完成了都沒斷下來。可見,常規的方法不起作用。不過沒關係,既然知道加載驅動的函數是MmLoadSystemImage,就可以使用威力無與倫比的條件斷點。 ,Try it again!
kd> sxe -c "ds poi(@esp+4); kv" ld:ntos
kd> .reboot

Shutdown occurred at (Thu Mar 22 17:08:52.694 2012 (UTC + 8:00))...unloading all symbol tables.
Waiting to reconnect...
......
Machine Name:
Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available
0005ffc4  "\WINDOWS\system32\ntoskrnl.exe"
ChildEBP RetAddr  Args to Child             
0005ff80 804d88e7 000600c4 0005ff94 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
0005ffa4 80656c46 000600c4 804d4000 ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
000600cc 80691ac8 00000000 80087000 80542268 nt!KdInitSystem+0x23e (FPO: [Non-Fpo])
00060100 00420e53 80087000 00467904 00438ab7 nt!KiSystemStartup+0x264
WARNING: Frame IP not in any known module. Following frames may be wrong.
00060e3c 0041ec40 00000007 00060e5c 00000000 0x420e53
00060ecc 004014fe 004678e0 0047164f 00051d68 0x41ec40
00061ff0 10101010 00000002 00000000 04e4000d 0x4014fe
00061ff4 00000000 00000000 04e4000d 003f0001 0x10101010
nt!DebugService2+0xe:
804d88ad cc              int     3
 
MmLoadSystemImage這個函數的原型如下,
NTSTATUS MmLoadSystemImage (
IN PUNICODE_STRING ImageFileName,
IN PUNICODE_STRING NamePrefix OPTIONAL,
IN PUNICODE_STRING LoadedBaseName OPTIONAL,
IN ULONG LoadFlags,
OUT PVOID *ImageHandle,
OUT PVOID *ImageBaseAddress
)
因此,可以通過觀察第一個參數得知模塊名稱,最後一個參數來得到模塊的加載地址。
設置條件斷點,打印模塊名稱,並且加載名稱爲"*tdss*"的模塊時斷住,顯示函數棧。
kd> bp MmLoadSystemImage "aS /msu ${ModuleName} poi(@esp+4); .block {.echo ${ModuleName}; r @$t1 = $spat(@\"${ModuleName}\", \"*tdss*\"); }; ad /q ${ModuleName}; .if(@$t1<=0) {gc} .else { kv }"
kd> g
......
\SystemRoot\System32\Drivers\Npfs.SYS
\systemroot\system32\drivers\TDSSmqxt.sys
ChildEBP RetAddr  Args to Child             
f9e63584 80558b1e f9e63644 00000000 00000000 nt!MmLoadSystemImage(FPO: [Non-Fpo])
f9e63650 8068b8b4 000002ec 00000001 00000000 nt!IopLoadDriver+0x311 (FPO: [4,40,3])
f9e636ac 8068a5f7 00034000 00000000 00000000 nt!IopInitializeSystemDrivers+0x16d (FPO: [Non-Fpo])
f9e63844 8068b3a1 00820000 00000000 817cb928 nt!IoInitSystem+0x697 (FPO: [1,97,3])
f9e63dac 8057c73a 80087000 00000000 00000000 nt!Phase1Initialization+0x83b (FPO: [1,340,3])
f9e63ddc 805124c1 8068ad55 80087000 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
nt!MmLoadSystemImage:
8055cacf 6874010000      push    174h
 
條件斷點成功命中,
kd> gu
nt!IopLoadDriver+0x311:
80558b1e 3bc3            cmp     eax,ebx
看下返回值來判斷函數是否成功。
kd> r eax
eax=c0000034
TDSS rootkit 使用不同的名字備份了自己,確保多個模塊的加載總有一個能夠成功,這次的加載失敗了,返回值STATUS_OBJECT_NAME_NOT_FOUND,也就是沒找到這個文件。(NTStatus 值參考:http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx),
讓程序繼續,看看下一次的加載,
kd> g
\SystemRoot\System32\DRIVERS\rasacd.sys
\SystemRoot\System32\DRIVERS\ipsec.sys
......
\SystemRoot\System32\Drivers\ParVdm.SYS
\SystemRoot\System32\DRIVERS\srv.sys
\??\C:\WINDOWS\system32\drivers\TDSSpaxt.sys
ChildEBP RetAddr  Args to Child             
f9e9fc80 80558b1e f9e9fd40 00000000 00000000 nt!MmLoadSystemImage (FPO: [Non-Fpo])
f9e9fd4c 80550cfb 000004e4 00000001 00000000 nt!IopLoadDriver+0x311 (FPO: [4,40,3])
f9e9fd74 804ed629 000004e4 00000000 817c73c8 nt!IopLoadUnloadDriver+0x43 (FPO: [Non-Fpo])
f9e9fdac 8057c73a f9afbcf4 00000000 00000000 nt!ExpWorkerThread+0xfe (FPO: [Non-Fpo])
f9e9fddc 805124c1 804ed556 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
nt!MmLoadSystemImage:
8055cacf 6874010000      push    174h
 
再次命中,看看函數MmLoadSystemImage 的參數,關鍵是第6個參數,
kd> dd f9e9fc80 l8
f9e9fc80  00000246 80558b1e f9e9fd40 00000000
f9e9fc90  00000000 00000000 f9e9fd24 f9e9fd30
kd> gu

nt!IopLoadDriver+0x311:
80558b1e 3bc3            cmp     eax,ebx
kd> r eax
eax=00000000
kd> dd f9e9fd30 l1
f9e9fd30  f9072000
這次的加載成功,模塊的地址爲f9072000,嘗試使用 $iment 得到驅動的入口,
kd> ? $iment(f9072000)
     ^ Unknown image error in '? $iment(f9072000)'
失敗了。可見系統提供的不是每次都好用的,一旦發生了例外,例外就會接踵而至。 
還是老老實實的嘗試解析PE文件頭信息。
kd> dt _image_dos_header f9072000
nt!_IMAGE_DOS_HEADER
   +0x000 e_magic          : 0x5a4d
   +0x002 e_cblp           : 0x90
   +0x004 e_cp             : 3
   +0x006 e_crlc           : 0
   +0x008 e_cparhdr        : 4
   +0x00a e_minalloc       : 0
   +0x00c e_maxalloc       : 0xffff
   +0x00e e_ss             : 0
   +0x010 e_sp             : 0xb8
   +0x012 e_csum           : 0
   +0x014 e_ip             : 0
   +0x016 e_cs             : 0
   +0x018 e_lfarlc         : 0x40
   +0x01a e_ovno           : 0
   +0x01c e_res            : [4] 0
   +0x024 e_oemid          : 0
   +0x026 e_oeminfo        : 0
   +0x028 e_res2           : [10] 0
   +0x03c e_lfanew         : 0n224
kd> dt -r2 _image_nt_headers f9072000+0n224

ntdll!_IMAGE_NT_HEADERS
   +0x000 Signature        : 0x4550
   +0x004 FileHeader       : _IMAGE_FILE_HEADER
      +0x000 Machine          : 0x14c
      +0x002 NumberOfSections : 5
      +0x004 TimeDateStamp    : 0x490f76f9
      +0x008 PointerToSymbolTable : 0
      +0x00c NumberOfSymbols  : 0
      +0x010 SizeOfOptionalHeader : 0xe0
      +0x012 Characteristics  : 0x2102
   +0x018 OptionalHeader   : _IMAGE_OPTIONAL_HEADER
      +0x000 Magic            : 0x10b
      +0x002 MajorLinkerVersion : 0x8 ''
      +0x003 MinorLinkerVersion : 0 ''
      +0x004 SizeOfCode       : 0x2400
      +0x008 SizeOfInitializedData : 0xa800
      +0x00c SizeOfUninitializedData : 0
      +0x010 AddressOfEntryPoint : 0x2c13
      +0x014 BaseOfCode       : 0x1000
      +0x018 BaseOfData       : 0x4000
      +0x01c ImageBase        : 0x10000000
      +0x020 SectionAlignment : 0x1000
      +0x024 FileAlignment    : 0x200
      +0x028 MajorOperatingSystemVersion : 4
      +0x02a MinorOperatingSystemVersion : 0
      +0x02c MajorImageVersion : 0
      +0x02e MinorImageVersion : 0
      +0x030 MajorSubsystemVersion : 4
      +0x032 MinorSubsystemVersion : 0
      +0x034 Win32VersionValue : 0
      +0x038 SizeOfImage      : 0x12000
      +0x03c SizeOfHeaders    : 0x400
      +0x040 CheckSum         : 0xf4d3
      +0x044 Subsystem        : 1
      +0x046 DllCharacteristics : 0
      +0x048 SizeOfStackReserve : 0x100000
      +0x04c SizeOfStackCommit : 0x1000
      +0x050 SizeOfHeapReserve : 0x100000
      +0x054 SizeOfHeapCommit : 0x1000
      +0x058 LoaderFlags      : 0
      +0x05c NumberOfRvaAndSizes : 0x10
      +0x060 DataDirectory    : [16] _IMAGE_DATA_DIRECTORY
         +0x000 VirtualAddress   : 0
         +0x004 Size             : 0
還好這個能夠工作,在入口處設置斷點
kd> bp f9072000+2c13
kd> bl

 0 e 8055cacf     0001 (0001) nt!MmLoadSystemImage "aS /msu ${ModuleName} poi(@esp+4); .block {.echo ${ModuleName}; r @$t1 = $spat(@\"${ModuleName}\", \"*tdss*\"); }; ad /q ${ModuleName}; .if(@$t1<=0) {g} .else { kv }"
 1 e f9074c13     0001 (0001)
kd> g
Breakpoint 1 hit
f9074c13 eb2a            jmp     f9074c3f
斷點命中,接下來就可以開始調試之旅了。但爲什麼TDSS驅動的模塊加載斷點不起作用呢?



==============================================================================================

調試驅動程序的入口 (3) 探索與發現
 
前面2篇文章中介紹的方法已經達到了調試驅動程序的目的,這裏是一些過程中的總結與摸索。
 
1. 如果是有符號的驅動程序,還有一個更加直接簡單的方法。
先設置初始斷點,確保在要調試的驅動程序入口運行之前。
kd> sxe -c "ds poi(@esp+4); kv" ld:*oskr*
kd> .reboot
Shutdown occurred at (Fri Mar 23 15:16:11.518 2012 (UTC + 8:00))...unloading all symbol tables.
Waiting to reconnect...
......
Machine Name:
Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available
0005ffc4  "\WINDOWS\system32\ntoskrnl.exe"
ChildEBP RetAddr  Args to Child             
0005ff80 804d88e7 000600c4 0005ff94 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
0005ffa4 80656c46 000600c4 804d4000 ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
000600cc 80691ac8 00000000 80087000 80542268 nt!KdInitSystem+0x23e (FPO: [Non-Fpo])
00060100 00420e53 80087000 00467904 00438ab7 nt!KiSystemStartup+0x264
WARNING: Frame IP not in any known module. Following frames may be wrong.
00060e3c 0041ec40 00000007 00060e5c 00000000 0x420e53
00060ecc 004014fe 004678e0 0047164f 00051d68 0x41ec40
00061ff0 10101010 00000002 00000000 04e4000d 0x4014fe
00061ff4 00000000 00000000 04e4000d 003f0001 0x10101010
nt!DebugService2+0xe:
804d88ad cc              int     3
 
設置目標斷點,還是使用serial.sys爲例,直接使用bu命令。
kd> bu serial!driverentry
kd> bl

 0 eu             0001 (0001) (serial!driverentry)
kd> g
Breakpoint 0 hit
serial!DriverEntry:
f9b26793 53              push    ebx
系統執行,斷點命中。
kd> kv
ChildEBP RetAddr  Args to Child             
f9e9b854 80558d13 81686480 81684000 00000000 serial!DriverEntry(FPO: [2,0,3])
f9e9b910 80555417 80000370 81684000 81686480 nt!IopLoadDriver+0x5e0 (FPO: [4,40,3])
f9e9b954 80571f85 e1492f20 00000001 80000370 nt!PipCallDriverAddDeviceQueryRoutine+0x239 (FPO: [Non-Fpo])
f9e9b9a0 80571fb3 f9e9ba2c e1492f0c f9e9ba00 nt!RtlpCallQueryRegistryRoutine+0x3af (FPO: [Non-Fpo])
f9e9ba04 8055a84d 00000000 00000084 00000001 nt!RtlQueryRegistryValues+0x2a4 (FPO: [Non-Fpo])
f9e9bad8 8055a657 00000000 00000001 f9e9bd54 nt!PipCallDriverAddDevice+0x237 (FPO: [3,43,3])
f9e9bd24 805a9093 817b54c8 00000001 00000000 nt!PipProcessDevNodeTree+0x147 (FPO: [Non-Fpo])
f9e9bd4c 805071b0 00000003 80549fc0 8054eddc nt!PiProcessStartSystemDevices+0x38 (FPO: [Non-Fpo])
f9e9bd74 804ed629 00000000 00000000 817c7640 nt!PipDeviceActionWorker+0x158 (FPO: [Non-Fpo])
f9e9bdac 8057c73a 00000000 00000000 00000000 nt!ExpWorkerThread+0xfe (FPO: [Non-Fpo])
f9e9bddc 805124c1 804ed556 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
bu設置的斷點很強大的,這個方法方便,但前提是需要符號文件。
 
2. 第一個模塊是相對的
這條命令會在系統加載第一個模塊(即NT內核)時斷住,
kd> sxe -c "!str poi(@esp+4); kv" ld:ntoskr
kd> .reboot

Shutdown occurred at (Fri Mar 23 22:07:42.387 2012 (UTC + 8:00))...unloading all symbol tables.
Waiting to reconnect...
......
Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available
String(30,31) at 000600c4: \WINDOWS\system32\ntoskrnl.exe
ChildEBP RetAddr  Args to Child             
0005ff80 804d88e7 000600c4 0005ff94 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
0005ffa4 80656c46 000600c4 804d4000 ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
000600cc 80691ac8 00000000 80087000 80542268 nt!KdInitSystem+0x23e (FPO: [Non-Fpo])
00060100 00420e53 80087000 00467904 00438ab7 nt!KiSystemStartup+0x264
WARNING: Frame IP not in any known module. Following frames may be wrong.
00060e3c 0041ec40 00000007 00060e5c 00000000 0x420e53
00060ecc 004014fe 004678e0 0047164f 00051d68 0x41ec40
00061ff0 10101010 00000002 00000000 04e4000d 0x4014fe
00061ff4 00000000 00000000 04e4000d 003f0001 0x10101010
nt!DebugService2+0xe:
804d88ad cc              int     3
 
這真的是OS加載的第一個模塊嘛? 
啓動安全模式就能知到答案,下面的圖顯示了斷點的時刻OS已經加載的若干模塊,或許有點驚訝但仔細一想,卻是必然的結果。

圖片

 

3. 前面文章中提到了個問題,爲什麼有的模塊的加載,調試器的模塊加載斷點機制失效?
由於調試引擎通過函數DbgLoadImageSymbols和調試器通信,內核中的調試引擎如果不調用這個函數,調試器是無法知道模塊的加載的,這時模塊加載斷點會失效。
利用這點,可以觀察一下有多少模塊的加載沒有通知調試器。要做到這點不容易,但並非絕不可能,還是要使用powerful 的條件斷點。
kd> .reboot
Shutdown occurred at (Fri Mar 23 16:34:59.709 2012 (UTC + 8:00))...unloading all symbol tables.
Waiting to reconnect...
......
Machine Name:
Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available
0005ffc4  "\WINDOWS\system32\ntoskrnl.exe"
ChildEBP RetAddr  Args to Child             
0005ff80 804d88e7 000600c4 0005ff94 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
0005ffa4 80656c46 000600c4 804d4000 ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
000600cc 80691ac8 00000000 80087000 80542268 nt!KdInitSystem+0x23e (FPO: [Non-Fpo])
00060100 00420e53 80087000 00467904 00438ab7 nt!KiSystemStartup+0x264
WARNING: Frame IP not in any known module. Following frames may be wrong.
00060e3c 0041ec40 00000007 00060e5c 00000000 0x420e53
00060ecc 004014fe 004678e0 0047164f 00051d68 0x41ec40
00061ff0 10101010 00000002 00000000 04e4000d 0x4014fe
00061ff4 00000000 00000000 04e4000d 003f0001 0x10101010
nt!DebugService2+0xe:
804d88ad cc              int     3
kd> bp MmLoadSystemImage "aS /msu ${ModuleName} poi(@esp+4); r @$t3 = poi(@esp+18);.block {.echo ${ModuleName}; r @$t1 = $spat(@\"${ModuleName}\", \"*tdss*\"); }; ad /q ${ModuleName}; r @$t2 = 0; bp /1 /C @$csp /t $thread DbgLoadImageSymbols \"r @$t2 = 1; gc;\" ; dd @$t3 l1; gu; reax; dd @$t3 l1; .if(@$t2 < 1) {kv } ; gc;"
MmLoadSystemImage函數中下斷點,這個斷點命中的時候再給DbgLoadImageSymbols下個一次性的斷點,如果第2個斷點也命中,表示工作正常,模塊加載的時候調試器得到了通知,反之則是異常情況,打印函數MmLoadSystemImage的返回值,模塊的地址(函數執行的前後)及棧。
執行後的輸出很長,歸納成下面幾種情況。
1. eax=c000010e,STATUS_IMAGE_ALREADY_LOADED,表示該模塊已經加載過。(NTSTATUS值可參考:http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx)。
2. eax=c0000034,STATUS_OBJECT_NAME_NOT_FOUND,表示找不到該對象,也就是說驅動程序的文件找不到。在我的XP系統上,有如下的模塊返回這個錯誤。
\SystemRoot\System32\Drivers\lbrtfdc.SYS
f9e63634  80690e14
eax=c0000034
f9e63634  80690e14
\SystemRoot\System32\Drivers\i2omgmt.SYS
f9e63634  80690e14
eax=c0000034
f9e63634  80690e14
\SystemRoot\System32\Drivers\Changer.SYS
f9e63634  80690e14
eax=c0000034
f9e63634  80690e14
\systemroot\system32\drivers\TDSSmqxt.sys
f9e63634  80690e14
eax=c0000034
f9e63634  80690e14
\SystemRoot\System32\Drivers\PCIDump.SYS
f9e63634  80690e14
eax=c0000034
f9e63634  80690e14
從這些輸出可以看到,如果模塊的加載失敗,模塊的加載地址不會被改變,是一個棧中的無具體意義的隨機值。
 
\??\C:\WINDOWS\system32\drivers\TDSSpaxt.sys
f9e9bd30  00000018
eax=00000000
f9e9bd30  f8f2a000 
另外,TDSS 表現的很奇怪,eax是0,表示模塊加載成功,但是同樣沒有調用DbgLoadImageSymbols,這又是爲什麼呢? 
 
這個問題需要從操作系統的代碼中得到答案。
kd> uf mmloadsystemimage
......
nt!MmLoadSystemImage+0x9ca:
8055c919 ff37            push    dword ptr [edi]
8055c91b e887050000      call    nt!CacheImageSymbols(8055cea7)
8055c920 85c0            test    eax,eax
8055c922 0f8487000000    je      nt!MmLoadSystemImage+0xa6f (8055c9af)
nt!MmLoadSystemImage+0x9d9:
8055c928 66837da416      cmp     word ptr [ebp-5Ch],16h
8055c92d 0f867bd70700    jbe     nt!MmLoadSystemImage+0xa38 (805da0ae)
nt!MmLoadSystemImage+0x9e0:
8055c933 6a0b            push    0Bh
8055c935 68ee915980      push    offset nt!MmGetSystemRoutineAddress+0x124 (805991ee)
8055c93a ff75a8          push    dword ptr [ebp-58h]
8055c93d e8a986f8ff      call    nt!_wcsnicmp (804e4feb)
8055c942 83c40c          add     esp,0Ch
8055c945 85c0            test    eax,eax
8055c947 0f8561d70700    jne     nt!MmLoadSystemImage+0xa38 (805da0ae)
nt!MmLoadSystemImage+0x9f6:
8055c94d 8b45a4          mov     eax,dword ptr [ebp-5Ch]
8055c950 89851cffffff    mov     dword ptr [ebp-0E4h],eax
8055c956 8b45a8          mov     eax,dword ptr [ebp-58h]
8055c959 898520ffffff    mov     dword ptr [ebp-0E0h],eax
8055c95f 83c016          add     eax,16h
8055c962 898520ffffff    mov     dword ptr [ebp-0E0h],eax
8055c968 6683851cffffffea add     word ptr [ebp-0E4h],0FFEAh
8055c970 8d851cffffff    lea     eax,[ebp-0E4h]
8055c976 50              push    eax
8055c977 683400dfff      push    0FFDF0034h
8055c97c 6806925980      push    offset nt!MmGetSystemRoutineAddress+0x13c (80599206)
8055c981 ff75cc          push    dword ptr [ebp-34h]
8055c984 e8c9bef7ff      call    nt!sprintf (804d8852)
8055c989 83c410          add     esp,10h
nt!MmLoadSystemImage+0xa4c:
8055c98c ff75cc          push    dword ptr [ebp-34h]
8055c98f 8d8514ffffff    lea     eax,[ebp-0ECh]
8055c995 50              push    eax
8055c996 e8f23bfbff      call    nt!RtlInitString (8051058d)
8055c99b 6aff            push    0FFFFFFFFh
8055c99d ff37            push    dword ptr [edi]
8055c99f 8d8514ffffff    lea     eax,[ebp-0ECh]
8055c9a5 50              push    eax
8055c9a6 e806bff7ff      call    nt!DbgLoadImageSymbols(804d88b1)
8055c9ab 804b3610        or      byte ptr [ebx+36h],10h
......
函數MmLoadSystemImage非常複雜,這麼複雜的邏輯估計就算是看源代碼也會一頭霧水,因此儘可能的縮小範圍,只關注調用DbgLoadImageSymbols周圍的一小段代碼,花點時間分析,  可以發現CacheImageSymbols就是根源所在。
kd> uf CacheImageSymbols
nt!CacheImageSymbols:
8055cea7 6a10            push    10h
8055cea9 6820f44f80      push    offset nt!MMDB+0x18 (804ff420)
8055ceae e86e4efbff      call    nt!_SEH_prolog (80511d21)
8055ceb3 8365fc00        and     dword ptr [ebp-4],0
8055ceb7 8d45e4          lea     eax,[ebp-1Ch]
8055ceba 50              push    eax
8055cebb 6a06            push    6
8055cebd 6a01            push    1
8055cebf ff7508          push    dword ptr [ebp+8]

8055cec2 e8c2abf9ff      call    nt!RtlImageDirectoryEntryToData(804f7a89)
8055cec7 8945e0          mov     dword ptr [ebp-20h],eax
8055ceca 85c0            test    eax,eax
8055cecc 740f            je      nt!CacheImageSymbols+0x37 (8055cedd)
nt!CacheImageSymbols+0x27:
8055cece 834dfcff        or      dword ptr [ebp-4],0FFFFFFFFh
8055ced2 33c0            xor     eax,eax
8055ced4 40              inc     eax
nt!CacheImageSymbols+0x3d:
8055ced5 e8804efbff      call    nt!_SEH_epilog (80511d5a)
8055ceda c20400          ret     4
nt!CacheImageSymbols+0x37:
8055cedd 834dfcff        or      dword ptr [ebp-4],0FFFFFFFFh
8055cee1 33c0            xor     eax,eax
8055cee3 ebf0            jmp     nt!CacheImageSymbols+0x3d (8055ced5)
 
這個函數就簡單的多,檢測PE文件有沒有包含調試目錄(IMAGE_DIRECTORY_ENTRY_DEBUG:6),有就返回1,沒有就返回0。
綜合上面2個函數,結論就是如果PE文件中沒有調試目錄信息,就不會調用DbgLoadImageSymbols,調試器也就不會得到通知。
使用PE工具觀察TDSS文件,確實沒有調試目錄。


 

還可以做個簡單的實驗,用工具把serial.sys的調試信息去掉,測試一下。


重啓系統,再設置一下上面那個高級的條件斷點,輸出結果裏多了一條

\SystemRoot\System32\DRIVERS\serial.sys
f9e9b8f4  f9e9ba80
eax=00000000
f9e9b8f4  f9afc000

象TDSS一樣,serial.sys也加載成功,但沒有調用DbgLoadImageSymbols。 

這時再試試模塊的加載斷點,

kd> sxe ld:serial
kd> .reboot

Shutdown occurred at (Sun Mar 25 11:52:08.382 2012 (UTC + 8:00))...unloading all symbol tables.
Waiting to reconnect...
......

Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available 

如預期的那樣,OS已經啓動完成,但模塊加載斷點沒有起作用。下面的調試記錄從另一個角度證明了這點。

kd> .reboot
Shutdown occurred at (Sun Mar 25 12:27:35.747 2012 (UTC + 8:00))...unloading all symbol tables.
Waiting to reconnect...
......
Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available
String(30,31) at 000600c4: \WINDOWS\system32\ntoskrnl.exe
ChildEBP RetAddr  Args to Child             
0005ff80 804d88e7 000600c4 0005ff94 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
0005ffa4 80656c46 000600c4 804d4000 ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
000600cc 80691ac8 00000000 80087000 80542268 nt!KdInitSystem+0x23e (FPO: [Non-Fpo])
00060100 00420e53 80087000 00467904 00438ab7 nt!KiSystemStartup+0x264
WARNING: Frame IP not in any known module. Following frames may be wrong.
00060e3c 0041ec40 00000007 00060e5c 00000000 0x420e53
00060ecc 004014fe 004678e0 0047164f 00051d68 0x41ec40
00061ff0 10101010 00000002 00000000 04e4000d 0x4014fe
00061ff4 00000000 00000000 04e4000d 003f0001 0x10101010
nt!DebugService2+0xe:
804d88ad cc              int     3

設置條件斷點,如果CacheImageSymbols函數返回0,打印參數和棧。
kd> bp CacheImageSymbols "r @$t1 = poi(@esp+4); gu; .if( eax > 0 ) { gc } .else { ? @$t1; kv }"
kd> g

Evaluate expression: -105988096 = f9aec000
ChildEBP RetAddr  Args to Child             
f9e9b844 80558b1e f9e9b904 00000000 00000000 nt!MmLoadSystemImage+0x9d1 (FPO: [Non-Fpo])
f9e9b910 80555417 8000054c 00000000 f9e9b900 nt!IopLoadDriver+0x311 (FPO: [4,40,3])
f9e9b954 80571f85 e1445b18 00000001 8000054c nt!PipCallDriverAddDeviceQueryRoutine+0x239 (FPO: [Non-Fpo])
f9e9b9a0 80571fb3 f9e9ba2c e1445b04 f9e9ba00 nt!RtlpCallQueryRegistryRoutine+0x3af (FPO: [Non-Fpo])
f9e9ba04 8055a84d 00000000 00000084 00000001 nt!RtlQueryRegistryValues+0x2a4 (FPO: [Non-Fpo])
f9e9bad8 8055a657 00000000 00000001 f9e9bd54 nt!PipCallDriverAddDevice+0x237 (FPO: [3,43,3])
f9e9bd24 805a9093 817b54c8 00000001 00000000 nt!PipProcessDevNodeTree+0x147 (FPO: [Non-Fpo])
f9e9bd4c 805071b0 00000003 80549fc0 8054eddc nt!PiProcessStartSystemDevices+0x38 (FPO: [Non-Fpo])
f9e9bd74 804ed629 00000000 00000000 817c7640 nt!PipDeviceActionWorker+0x158 (FPO: [Non-Fpo])
f9e9bdac 8057c73a 00000000 00000000 00000000 nt!ExpWorkerThread+0xfe (FPO: [Non-Fpo])
f9e9bddc 805124c1 804ed556 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
nt!MmLoadSystemImage+0x9d1:
8055c920 85c0            test    eax,eax
kd> !ustr poi(@ebp+8); r @$t1=poi(@ebp+1c); dd @$t1 l1; gu ; reax;
String(78,80) at f9e9b904: \SystemRoot\System32\DRIVERS\serial.sys
f9e9b8f4  f9aec000
eax=00000000

kd> ? $iment(f9aec000)
     ^ Unknown image error in '? $iment(f9aec000)'
kd> g
Evaluate expression: -118317056 = f8f2a000
ChildEBP RetAddr  Args to Child             
f9e9bc80 80558b1e f9e9bd40 00000000 00000000 nt!MmLoadSystemImage+0x9d1 (FPO: [Non-Fpo])
f9e9bd4c 80550cfb 000003e4 00000001 00000000 nt!IopLoadDriver+0x311 (FPO: [4,40,3])
f9e9bd74 804ed629 000003e4 00000000 817c7640 nt!IopLoadUnloadDriver+0x43 (FPO: [Non-Fpo])
f9e9bdac 8057c73a f9ccbcf4 00000000 00000000 nt!ExpWorkerThread+0xfe (FPO: [Non-Fpo])
f9e9bddc 805124c1 804ed556 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
nt!MmLoadSystemImage+0x9d1:
8055c920 85c0            test    eax,eax
kd> !ustr poi(@ebp+8); r @$t1=poi(@ebp+1c); dd @$t1 l1; gu ; reax;
String(88,90) at f9e9bd40: \??\C:\WINDOWS\system32\drivers\TDSSpaxt.sys
f9e9bd30  f8f2a000
eax=00000000

kd> ? $iment(f8f2a000)
     ^ Unknown image error in '? $iment(f8f2a000)'
kd> g

系統啓動過程中,總共2個模塊發現了問題,一個是剛剛去掉調試目錄信息的serial.sys,另一個是TDSS。$iment 信賴於調試符號,對於沒有調試目錄的模塊,失效了。

 

4. 驅動程序的入口是如何被調用的?

還是要從代碼下手,重啓系統,

Waiting to reconnect...
Connected to Windows XP 2600 x86 compatible target at (Sun Mar 25 13:29:15.138 2012 (UTC + 8:00)), ptr64 FALSE
Kernel Debugger connection established.
......
Kernel base = 0x804d4000 PsLoadedModuleList = 0x8054be30
System Uptime: not available
String(30,31) at 000600c4: \WINDOWS\system32\ntoskrnl.exe
ChildEBP RetAddr  Args to Child             
0005ff80 804d88e7 000600c4 0005ff94 00000003 nt!DebugService2+0xe (FPO: [3,0,0])
0005ffa4 80656c46 000600c4 804d4000 ffffffff nt!DbgLoadImageSymbols+0x40 (FPO: [Non-Fpo])
000600cc 80691ac8 00000000 80087000 80542268 nt!KdInitSystem+0x23e (FPO: [Non-Fpo])
00060100 00420e53 80087000 00467904 00438ab7 nt!KiSystemStartup+0x264
WARNING: Frame IP not in any known module. Following frames may be wrong.
00060e3c 0041ec40 00000007 00060e5c 00000000 0x420e53
00060ecc 004014fe 004678e0 0047164f 00051d68 0x41ec40
00061ff0 10101010 00000002 00000000 04e4000d 0x4014fe
00061ff4 00000000 00000000 04e4000d 003f0001 0x10101010
nt!DebugService2+0xe:
804d88ad cc              int     3

設置斷點,重複上面的實驗,第一個斷點會在serial.sys處,用這個作例子,
kd> bp CacheImageSymbols "r @$t1 = poi(@esp+4); gu; .if( eax > 0 ) { gc } .else { ? @$t1; kv }"
kd> g

Evaluate expression: -105988096 = f9aec000
ChildEBP RetAddr  Args to Child             
f9e9f844 80558b1e f9e9f904 00000000 00000000 nt!MmLoadSystemImage+0x9d1 (FPO: [Non-Fpo])
f9e9f910 80555417 80000548 00000000 f9e9f900 nt!IopLoadDriver+0x311 (FPO: [4,40,3])
f9e9f954 80571f85 e1444fb0 00000001 80000548 nt!PipCallDriverAddDeviceQueryRoutine+0x239 (FPO: [Non-Fpo])
f9e9f9a0 80571fb3 f9e9fa2c e1444f9c f9e9fa00 nt!RtlpCallQueryRegistryRoutine+0x3af (FPO: [Non-Fpo])
f9e9fa04 8055a84d 00000000 00000084 00000001 nt!RtlQueryRegistryValues+0x2a4 (FPO: [Non-Fpo])
f9e9fad8 8055a657 00000000 00000001 f9e9fd54 nt!PipCallDriverAddDevice+0x237 (FPO: [3,43,3])
f9e9fd24 805a9093 817b54c8 00000001 00000000 nt!PipProcessDevNodeTree+0x147 (FPO: [Non-Fpo])
f9e9fd4c 805071b0 00000003 80549fc0 8054eddc nt!PiProcessStartSystemDevices+0x38 (FPO: [Non-Fpo])
f9e9fd74 804ed629 00000000 00000000 817c73c8 nt!PipDeviceActionWorker+0x158 (FPO: [Non-Fpo])
f9e9fdac 8057c73a 00000000 00000000 00000000 nt!ExpWorkerThread+0xfe (FPO: [Non-Fpo])
f9e9fddc 805124c1 804ed556 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
nt!MmLoadSystemImage+0x9d1:
8055c920 85c0            test    eax,eax

kd> !dh -f f9aec000

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
     14C machine (i386)
       8 number of sections
3D6DE48B time date stamp Thu Aug 29 17:08:27 2002

       0 file pointer to symbol table
       0 number of symbols
      E0 size of optional header
     10E characteristics
            Executable
            Line numbers stripped
            Symbols stripped
            32 bit word machine

OPTIONAL HEADER VALUES
     10B magic #
    7.00 linker version
    C200 size of code
    2E80 size of initialized data
       0 size of uninitialized data
    A793 address of entry point
     380 base of code

......

kd> bp f9aec000+A793
kd> g

Breakpoint 1 hit
f9af6793 53              push    ebx

 

這是斷在了serial.sys!DriverEntry,也就是驅動的入口處。
kd> kv
ChildEBP RetAddr  Args to Child             
WARNING: Frame IP not in any known module. Following frames may be wrong.
f9e9f854 80558d13 816bc2c8 816ae000 00000000 0xf9af6793
f9e9f910 80555417 80000548 816ae000 816bc2c8 nt!IopLoadDriver+0x5e0 (FPO: [4,40,3])
f9e9f954 80571f85 e1444fb0 00000001 80000548 nt!PipCallDriverAddDeviceQueryRoutine+0x239 (FPO: [Non-Fpo])
f9e9f9a0 80571fb3 f9e9fa2c e1444f9c f9e9fa00 nt!RtlpCallQueryRegistryRoutine+0x3af (FPO: [Non-Fpo])
f9e9fa04 8055a84d 00000000 00000084 00000001 nt!RtlQueryRegistryValues+0x2a4 (FPO: [Non-Fpo])
f9e9fad8 8055a657 00000000 00000001 f9e9fd54 nt!PipCallDriverAddDevice+0x237 (FPO: [3,43,3])
f9e9fd24 805a9093 817b54c8 00000001 00000000 nt!PipProcessDevNodeTree+0x147 (FPO: [Non-Fpo])
f9e9fd4c 805071b0 00000003 80549fc0 8054eddc nt!PiProcessStartSystemDevices+0x38 (FPO: [Non-Fpo])
f9e9fd74 804ed629 00000000 00000000 817c73c8 nt!PipDeviceActionWorker+0x158 (FPO: [Non-Fpo])
f9e9fdac 8057c73a 00000000 00000000 00000000 nt!ExpWorkerThread+0xfe (FPO: [Non-Fpo])
f9e9fddc 805124c1 804ed556 00000001 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo])
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

看下代碼,驅動入口是如何被調用的,

kd> ub 80558d13
nt!IopLoadDriver+0x5cd:
80558d00 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
80558d02 8bc8            mov     ecx,eax
80558d04 83e103          and     ecx,3
80558d07 f3a4            rep movs byte ptr es:[edi],byte ptr [esi]
80558d09 8b7d78          mov     edi,dword ptr [ebp+78h]
80558d0c ff7574          push    dword ptr [ebp+74h]
80558d0f 57              push    edi
80558d10 ff572c          call    dword ptr [edi+2Ch]
kd> dd ebp+74 l1

f9e9f91c  816ae000
kd> dS 816ae000

816ae008  "\REGISTRY\MACHINE\SYSTEM\Control"
816ae048  "Set001\Services\Serial"

 

驅動入口的原型如下,

NTSTATUS DriverEntry(
  __in  struct _DRIVER_OBJECT *DriverObject,
  __in  PUNICODE_STRING RegistryPath
);

2 個參數,第一個是對象,第二個是串。
kd> dt _driver_object 816bc2c8
ntdll!_DRIVER_OBJECT
   +0x000 Type             : 0n4
   +0x002 Size             : 0n168
   +0x004 DeviceObject     : (null)
   +0x008 Flags            : 2
   +0x00c DriverStart      : 0xf9aec000 Void
   +0x010 DriverSize       : 0xf400
   +0x014 DriverSection    : 0x816bb868 Void
   +0x018 DriverExtension  : 0x816bc370 _DRIVER_EXTENSION
   +0x01c DriverName       : _UNICODE_STRING "\Driver\Serial"
   +0x024 HardwareDatabase : 0x806680c8 _UNICODE_STRING "\REGISTRY\MACHINE\HARDWARE\DESCRIPTION\SYSTEM"
   +0x028 FastIoDispatch   : (null)
   +0x02c DriverInit       : 0xf9af6793     long  +fffffffff9af6793
   +0x030 DriverStartIo    : (null)
   +0x034 DriverUnload     : (null)
   +0x038 MajorFunction    : [28] 0x804f886f     long  nt!IopInvalidDeviceRequest+0

 

也就是說函數IopLoadDriver初始化了數據結構_DRIVER_OBJECT,然後調用了驅動的入口(+0x02c DriverInit)。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章