《Undocumented Windows 2000 Secrets》翻譯 --- 第五章(1)
第五章 監(jiān)控Native API調(diào)用
翻譯:Kendiv( fcczj@263.net )
更新:Tuesday, February 22, 2005
聲明:轉(zhuǎn)載請(qǐng)注明出處,并保證文章的完整性,本人保留譯文的所有權(quán)利。
攔截系統(tǒng)調(diào)用在任何時(shí)候都是程序員們的最?lèi)?ài)。這種大眾化愛(ài)好的動(dòng)機(jī)也是多種多樣的:代碼性能測(cè)試(Code Profiling)和優(yōu)化,逆向工程,用戶活動(dòng)記錄等等。所有這些都有一個(gè)共同的目的:將控制傳遞給一塊特殊的代碼,這樣無(wú)論一個(gè)應(yīng)用程序何時(shí)調(diào)用系統(tǒng)服務(wù),都可以發(fā)現(xiàn)哪個(gè)服務(wù)被調(diào)用了,接收了什么參數(shù),返回的結(jié)果是什么以及執(zhí)行它花費(fèi)了多少時(shí)間。根據(jù)最初由Mark Russinovich和Bryce Cogswell提出的技巧,本章將介紹一個(gè)可以hook任意Native API函數(shù)的通用框架。這里使用的方法完全是數(shù)據(jù)驅(qū)動(dòng)(data-driven)的,因此,它可以很容易被擴(kuò)展,并能適應(yīng)其他Windows NT/2000版本。所有進(jìn)程的API調(diào)用產(chǎn)生的數(shù)據(jù)都被寫(xiě)入一個(gè)環(huán)狀緩沖區(qū)中,客戶端程序可以通過(guò)設(shè)備I/O控制來(lái)讀取該緩沖區(qū)。采用的數(shù)據(jù)協(xié)議(protocol data)的格式是以行為導(dǎo)向的ANSI文本流,它符合嚴(yán)格的格式化規(guī)則,應(yīng)用程序可以很容易的再次處理它們(postprocessing)。為了示范此種客戶端程序的基本框架,本章還提供了一個(gè)示例性的數(shù)據(jù)協(xié)議察看器,該程序運(yùn)行于控制臺(tái)窗口中。
譯注:
profiling 一般是指對(duì)程序做性能方面的測(cè)試, 主要是速度上的。 在翻譯時(shí),可譯為:剖析,最好是根據(jù)上文環(huán)境進(jìn)行翻譯。
修改服務(wù)描述符表
對(duì)比“原始”的操作系統(tǒng),如Dos或Windows 3.x,它們對(duì)程序員在API中加入hook的限制很少,而Win32系統(tǒng),如Windows 2000/NT和Windows 9.x則很難駕馭,因?yàn)樗鼈兪褂昧饲擅畹谋Wo(hù)機(jī)制把不相關(guān)的代碼分離出來(lái)。在Win32 API上設(shè)置一個(gè)系統(tǒng)范圍的hook絕不是一個(gè)小任務(wù)。幸運(yùn)的是,我們有像Matt PIEtrek和Jeffery Richter這樣的Win32向?qū)?,他們做了大量的工作?lái)向我們展示如何完成這一任務(wù),盡管事實(shí)上,并沒(méi)有簡(jiǎn)單和優(yōu)雅的解決方案。在1997年,Russinovich和Cogswell介紹了一種可在Windows NT上實(shí)現(xiàn)系統(tǒng)范圍hook的完全不同的方法,可在更低一層上攔截系統(tǒng)調(diào)用(Russinovich和Cogswell 1997)。他們提議向Native API Dispatcher中注入日志機(jī)制,這僅比用戶模式和內(nèi)核模式之間的邊界低一些,在這個(gè)位置上Windows NT暴露出一個(gè)“瓶頸”:所有用戶模式的線程必須通過(guò)此處,才能使用操作系統(tǒng)內(nèi)核提供的服務(wù)。
服務(wù)和參數(shù)表
就像在第二章討論過(guò)的,發(fā)生在用戶模式下的Native API調(diào)用必須通過(guò)INT 2eh接口,該接口提供一個(gè)i386的中斷門(mén)來(lái)改變特權(quán)級(jí)別。你可能還記得所有INT 2eh調(diào)用都是由內(nèi)部函數(shù)KiSystemService()在內(nèi)核模式下處理的,該函數(shù)使用系統(tǒng)服務(wù)描述符表(SDT)來(lái)查找Native API處理例程的入口地址。圖5-1給出了這種分派機(jī)制的基本組件之間的相互關(guān)系。列表5-1再次給出了SERVICE_DESCRIPTOR_TABLE結(jié)構(gòu)及其子結(jié)構(gòu)的正式定義,在第二章中,已經(jīng)給出過(guò)它們的定義(列表2-1)。
調(diào)用KiSystemService()時(shí),需提供兩個(gè)參數(shù),由INT 2eh的調(diào)用者通過(guò)EAX和EDX寄存器傳入。EAX包含從0開(kāi)始的索引,該索引可用于一個(gè)API函數(shù)指針的數(shù)組,EDX指向調(diào)用者的參數(shù)堆棧。KiSystemService()通過(guò)讀取ServiceTable的一個(gè)成員的值(該成員是ntoskrnl.exe的一個(gè)公開(kāi)數(shù)據(jù)結(jié)構(gòu):KeServiceDescriptorTable,圖5-1的左面列出了該結(jié)構(gòu))來(lái)獲取函數(shù)數(shù)組的基地址。實(shí)際上,KeServiceDescriptorTable指向一個(gè)包含四個(gè)服務(wù)表的結(jié)構(gòu),但默認(rèn)情況下,僅有第一個(gè)服務(wù)表是有效的。KiSystemService()通過(guò)EAX中的索引值進(jìn)入內(nèi)部結(jié)構(gòu)KiServiceTable,以查找可處理此API調(diào)用的函數(shù)的入口地址。在調(diào)用目標(biāo)函數(shù)之前,KiSystemServie()以相同的方式查詢KiArgumentTable結(jié)構(gòu),以找出調(diào)用者在參數(shù)堆棧中傳入了多少字節(jié),然后使用這個(gè)值將參數(shù)復(fù)制到當(dāng)前內(nèi)核堆棧中。此后,就只需要一個(gè)簡(jiǎn)單的匯編指令:CALL來(lái)執(zhí)行API處理例程了。這里涉及的所有函數(shù)都符合__stdcall標(biāo)準(zhǔn)。
圖5-1. KeServiceDescriptorTable的結(jié)構(gòu)圖
typedef NTSTATUS (NTAPI*NTPROC)();
typedef NTPROC* PNTPROC;
#define NTPROC_ sizeof(NTPROC)
typedef struct _SYSTEM_SERVICE_TABLE
{
PNTPROC ;ServiceTable;// array of entry points
PDOWRD; CounterTable;// array of usage counters
DWordServiceLimit;;// number of table entries
PBYTE; ;;ArgumentTable; ;// array of byte counts
}
SYSTEM_SERVICE_TABLE,
*PSYSTEM_SERVICE_TABLE,
**PPSYSTEM_SERVICE_TABLE;
//-----------------------------------------------------------------------------------------------------------
typedef struct _SERVICE_DESCRIPTOR_TABLE
{
SYSTEM_SERVICE_TABLE ntoskrnl// ntoskrnl.exe ( native api )
SYSTEM_SERVICE_TABLE win32k;;// win32k.sys (gdi/user support)
SYSTEM_SERVICE_TABLE Table3;;// not used
SYSTEM_SERVICE_TABLE Table4;;// not used
}
SYSTEM_DESCRIPTOR_TABLE,
*PSYSTEM_DESCRIPTOR_TABLE,
**PPSYSTEM_DESCRIPTOR_TABLE;
列表5-1. SERVICE_DESCRIPTOR_TABLE結(jié)構(gòu)的定義
Windows 2000還提供了另一個(gè)服務(wù)描述符表參數(shù)塊----KeServiceDescriptorTableShadow。不過(guò),KeServiceDescriptorTable已經(jīng)由ntoskrnl.exe公開(kāi)的導(dǎo)出了,因此,內(nèi)核模式的驅(qū)動(dòng)程序可以很容易的訪問(wèn)它,而KeServiceDescriptorTableShadow則不行。在Windows 2000下,KeServiceDescriptorTableShadow緊隨KeServiceDescriptorTable之后,但是你不能在Windows NT中以這樣的方法找到它,因?yàn)?,這一規(guī)則并不使用于Windows NT。可能在Windows 2000的后續(xù)版本的中,這種方法也不行。這兩個(gè)參數(shù)塊的不同之處在于:KeServiceDescriptorTableShadow中的第二個(gè)項(xiàng)被系統(tǒng)使用了,用來(lái)指向內(nèi)部的W32pServiceTable和w32pArgumentTable結(jié)構(gòu),Win32的內(nèi)核模式組件Win32K.sys使用這兩個(gè)結(jié)構(gòu)來(lái)分派自己的API調(diào)用,如圖5-2所示。KiSystemService()通過(guò)檢查EAX中索引值的第12和13位來(lái)確認(rèn)是不是應(yīng)該由Win32K.sys處理API調(diào)用。如果這兩個(gè)位都是0,則是由ntoskrnl.exe處理的Native API調(diào)用,因此KiSystemService()使用第一個(gè)SDT。如果第12位為1并且第13位為0,KiSystemService()使用第二個(gè)SDT,這個(gè)SDT并沒(méi)有被當(dāng)前系統(tǒng)使用。這意味著Native API調(diào)用的索引值的潛在范圍是:0x0000 --- 0x0FFFF,Win32K.sys調(diào)用使用的索引范圍是:0x1000 --- 0x1FFF。因此,0x2000 --- 0x2FFF和0x3000 --- 0x3FFF保留給剩下的兩個(gè)SDT。在Windows 2000中,Native API服務(wù)表包含248個(gè)項(xiàng),Win32K.sys表包含639個(gè)項(xiàng)。
圖5-2. KeServiceDescriptorTableShadow的結(jié)構(gòu)圖
Russinovich和Cogswell的獨(dú)具特色的方法是:通過(guò)簡(jiǎn)單的向KiServiceTable數(shù)組中放入一個(gè)不同的處理例程來(lái)hook所有API調(diào)用。這個(gè)處理例程最終會(huì)調(diào)用位于ntoskrnl.exe中的原始處理例程,但它有機(jī)會(huì)察看一下被調(diào)用函數(shù)的輸入/輸出參數(shù)。這個(gè)方法非常強(qiáng)大卻又如此簡(jiǎn)單。因?yàn)樗杏脩裟J降木€程必須經(jīng)過(guò)這個(gè)“針眼”才能獲得Native API的服務(wù),安裝一個(gè)全局hook來(lái)簡(jiǎn)單的替換一個(gè)函數(shù)指針的方法,在啟動(dòng)一個(gè)新的進(jìn)程和線程的情況下,也能很穩(wěn)定的工作。這并不需要一種通訊機(jī)制來(lái)通知新加入或?qū)⒁瞥倪M(jìn)程/線程。
不幸的是,系統(tǒng)服務(wù)表在不同Windows NT版本上不相同。表5-1比較了Windows NT/2000的KiServiceTable。很顯然,不僅是處理例程的號(hào)碼從211增加到了248,而且新的處理例程并不是直接添加到列表的末尾,而是被插入到了各個(gè)地方!因此,一個(gè)服務(wù)函數(shù)索引,如0x20在Windows 2000中指向NtCreateFile(),而在Windows NT中卻指向NtCreateProfile()。所以,通過(guò)操作服務(wù)函數(shù)表進(jìn)行hook的API調(diào)用監(jiān)控器必須小心的檢查它所在的Windows NT的版本。這可以通過(guò)如下幾個(gè)方式來(lái)完成:
l 一種可能性是,檢查由ntoskrnl.exe導(dǎo)出的公開(kāi)變量:NtBuildNumber,就像Russinovich和Cogswell在他們的原文中所作的那樣。Windows NT 4.0為所有Service Pack提供的Build Number是:1381。Windows 2000的當(dāng)前Build Number是:2195。看來(lái)有希望,這個(gè)版本號(hào)在Windows NT的早期版本中很穩(wěn)定。
l 另一個(gè)可能性是,檢查SharedUserData結(jié)構(gòu)中的NtMajorVersion和NtMinorVersion成員,該結(jié)構(gòu)定義與Windows 2000頭文件ntddk.h中。Windows NT 4.0的所有Service Pack都將SharedUserData->NtMajorVersion設(shè)為4,將SharedUserData->NtMinorVersion設(shè)為0。Windows 2000的當(dāng)前版本為Windows NT Version 5.0。
l 本章給出的代碼采用了另一中替代方法:它測(cè)試SDT的ServiceLimit成員是否和它的預(yù)期值相匹配,該預(yù)期值是211(0xD3)針對(duì)Windows NT 4.0和248(0xF8)針對(duì)Windows 2000。
表5-1. Windows 2000/NT 服務(wù)表對(duì)比
Windows 2000
索引
Windows NT 4.0
NtAcceptConnectPort
0x00
NtAcceptConnectPort
NtAccessCheck
0x01
NtAccessCheck
NtAccessCheckAndAuditAlarm
0x02
NtAccessCheckAndAuditAlarm
NtAccessCheckByType
0x03
NtAddAtom
NtAccessCheckByTypeAndAuditAlarm
0x04
NtAdjustGroupsToken
NtAccessCheckByTypeResultList
0x05
NtAdjustPrivilegesToken
NtAccessCheckByTypeResultListAndAuditAlarm
0x06
NtAlertResumeThread
NtAccessCheckByTypeResultListAndAuditAlarmByHandle
0x07
NtAlertThread
NtAddAtom
0x08
NtAllocateLocallyUniqueld
NtAdjustGroupsToken
0x09
NtAllocateUuids
NtAdjustPrivilegesToken
0x0A
NtAllocateVirtualMemory
NtAlertResumeThread
0x0B
NtCallbackReturn
NtAlertThread
0x0C
NtCancelloFile
NtAllocateLocallyUniqueld
0x0D
NtCancelTimer
NtAllocateUserPhysicalPages
0x0E
NtClearEvent
NtAllocateUuids
0x0F
NtClose
NtAllocateVirtualMemory
0x10
NtCloseObjectAuditAlarm
NtAreMappedFilesTheSame
0x11
NtCompleteConnectPort
NtAssignProcessToJobObject
0x12
NtConnectPort
NtCallbackReturn
0x13
NtContinue
NtCancelloFile
0x14
NtCreateDirectoryObject
NtCancelTi mer
0x15
NtCreateEvent
NtCancelDeviceWakeupRequest
0x16
NtCreateEventPair
NtClearEvent
0x17
NtCreateFile
NtClose
0x18
NtCreateloCompletion
NtCloseObjectAuditAlarm
0x19
NtCreateKey
NtCompleteConnectPort
0x1A
NtCreateMailslotFile
NtConnectPort
0x1B
NtCreateMutant
NtContinue
0x1C
NtCreateNamedPipeFile
NtCreateDirectoryObject
0x1D
NtCreatePagingFile
NtCreateEvent
0x1E
NtCreatePort
NtCreateEventPair
0x1F
NtCreateProcess
NtCreateFile
0x20
NtCreateProfile
NtCreateloCompletion
0x21
NtCreateSection
NtCreateJobObject
0x22
NtCreateSemaphore
NtCreateKey
0x23
NtCreateSymbolicLinkObject
NtCreateMailslotFile
0x24
NtCreateThread
NtCreateMutant
0x25
NtCreateTimer
NtCreateNamedPipeFile
0x26
NtCreateToken
NtCreatePagingFile
0x27
NtDelayExecution
NtCreatePort
0x28
NtDeleteAtom
NtCreateProcess
0x29
NtDeleteFile
NtCreateProfile
0x2A
NtDeleteKey
NtCreateSection
0x2B
NtDeleteObjectAuditAlarm
NtCreateSemaphore
0x2C
NtDeleteValueKey
NtCreateSymbolicLinkObject
0x2D
NtDeviceloControlFile
NtCreateThread
0x2E
NtDisplayString
NtCreateTimer
0x2F
NtDuplicateObject
NtCreateToken
0x30
NtDuplicateToken
NtCreateWaitablePort
0x31
NtEnumerateKey
NtDelayExecution
0x32
NtEnumerateValueKey
NtDeleteAtom
0x33
NtExtendSection
NtDeleteFile
0x34
NtFindAtom
NtDeleteKey
0x35
NtFlushBuffersFile
NtDeleteObj ectAuditAlarm
0x36
NtFlushlnstructionCache
NtDeleteValueKey
0x37
NtFlushKey
NtDeviceloControlFile
0x38
NtFlushVirtualMemory
NtDisplayString
0x39
NtFlushWriteBuffer
NtDuplicateObject
0x3A
NtFreeVirtualMemory
NtDuplicateToken
0x3B
NtFsControlFile
NtEnumerateKey
0x3C
NtGetContextThread
NtEnumerateValueKey
0x3D
NtGetPlugPlayEvent
NtExtendSection
0x3E
NtGetTickCount
NtFilterToken
0x3F
NtlmpersonateClientOfPort
NtFindAtom
0x40
NtlmpersonateThread
NtFlushBuffersFile
0x41
NtlnitializeRegistry
NtFlushlnstructionCache
0x42
NtListenPort
NtFlushKey
0x43
NtLoadDriver
NtFlushVirtualMemory
0x44
NtLoadKey
NtFlushWriteBuffer
0x45
NtLoadKey2
NtFreeUserPhysicalPages
0x46
NtLockFile
NtFreeVirtualMemory
0x47
NtLockVirtualMemory
NtFsControlFile
0x48
NtMakeTemporaryObject
NtGetContextThread
0x49
NtMapViewOfSection
NtGetDevicePowerState
0x4A
NtNotifyChangeDirectoryFile
NtGetPlugPlayEvent
0x4B
NtNotifyChangeKey
NtGetTickCount
0x4C
NtOpenDirectoryObject
NtGetWriteWatch
0x4D
NtOpenEvent
NtlmpersonateAnonymousToken
0x4E
NtOpenEventPair
NtlmpersonateClientOfPort
0x4F
NtOpenFile
NtlmpersonateThread
0x50
NtOpenloCompletion
NtlnitializeRegistry
0x51
NtOpenKey
NtlnitiatePowerAction
0x52
NtOpenMutant
NtlsSystemResumeAutomatic
0x53
NtOpenObjectAuditAlarm
NtListenPort
0x54
NtOpenProcess
NtLoadDriver
0x55
NtOpenProcessToken
NtLoadKey
0x56
NtOpenSection
NtLoadKey2
0x57
NtOpenSemaphore
NtLockFile
0x58
NtOpenSymbolicLinkObject
NtLockVirtualMemory
0x59
NtOpenThread
NtMakeTemporaryObject
0x5A
NtOpenThreadToken
NtMapUserPhysicalPages
0x5B
NtOpenTimer
NtMapUserPhysicalPagesScatter
0x5C
NtPlugPlayControl
NtMapViewOfSection
0x5D
NtPrivilegeCheck
NtNotifyChangeDirectoryFile
0x5E
NtPrivilegedServiceAuditAlarm
NtNotifyChangeKey
0x5F
NtPrivilegeObjectAuditAlarm
NtNotifyChangeMultipleKeys
0x60
NtProtectVirtualMemory
NtOpenDirectoryObject
0x61
NtPulseEvent
NtOpenEvent
0x62
NtQuerylnformationAtom
NtOpenEventPair
0x63
NtQueryAttributesFile
NtOpenFile
0x64
NtQueryDefaultLocale
NtOpenloCompletion
0x65
NtQueryDirectoryFile
NtOpenJobObject
0x66
NtQueryDirectoryObject
NtOpenKey
0x67
NtQueryEaFile
NtOpenMutant
0x68
NtQueryEvent
NtOpenObjectAuditAlarm
0x69
NtQueryFullAttributesFile
NtOpenProcess
0x6A
NtQuerylnformationFile
NtOpenProcessToken
0x6B
NtQueryloCompletion
NtOpenSection
0x6C
NtQuerylnformationPort
NtOpenSemaphore
0x6D
NtQuerylnformationProcess
NtOpenSymbolicLinkObject
0x6E
NtQuerylnformationThread
NtOpenThread
0x6F
NtQuerylnformationToken
NtOpenThreadToken
0x70
NtQuerylntervalProfile
NtOpenTimer
0x71
NtQueryKey
NtPlugPlayControl
0x72
NtQueryMultipleValueKey
NtPowerlnformation
0x73
NtQueryMutant
NtPrivilegeCheck
0x74
NtQueryObject
NtPrivilegedServiceAuditAlarm
0x75
NtQueryOleDirectoryFile
NtPrivilegeObjectAuditAlarm
0x76
NtQueryPerformanceCounter
NtProtectVirtualMemory
0x77
NtQuerySection
NtPulseEvent
0x78
NtQuerySecurityObject
NtQuerylnformationAtom
0x79
NtQuery Semaphore
NtQueryAttributesFile
0x7A
NtQuerySymbolicLinkObject
NtQueryDefaultLocale
0x7B
NtQuerySystemEnvironmentValue
NtQueryDefaultUILanguage
0x7C
NtQuerySystemlnformation
NtQueryDirectoryFile
0x7D
NtQuerySystemTime
NtQueryDirectoryObject
0x7E
NtQuery Timer
NtQueryEaFile
0x7F
NtQueryTimerResolution
NtQueryEvent
0x80
NtQuery ValueKey
NtQueryFullAttributesFile
0x81
NtQuery VirtualMemory
NtQuerylnformationFile
0x82
NtQuery VolumelnformationFile
NtQuerylnformationJobObject
0x83
NtQueueApcThread
NtQueryloCompletion
0x84
NtRaiseException
NtQuerylnformationPort
0x85
NtRaiseHardError
NtQuerylnformationProcess
0x86
NtReadFile
NtQuerylnformationThread
0x87
NtReadFileScatter
NtQuerylnformationToken
0x88
NtReadRequestData
NtQuerylnstallUILanguage
0x89
NtReadVirtualMemory
NtQuerylntervalProfile
0x8A
NtRegisterThreadTerminatePort
NtQueryKey
0x8B
NtReleaseMutant
NtQueryMultiple ValueKey
0x8C
NtReleaseSemaphore
NtQueryMutant
0x8D
NtRemoveloCompletion
NtQueryObject
0x8E
NtReplaceKey
NtQueryOpenSubKeys
0x8F
NtReplyPort
NtQueryPerformanceCounter
0x90
NtReplyWaitReceivePort
NtQueryQuotalnformationFile
0x91
NtReplyWaitReplyPort
NtQuerySection
0x92
NtRequestPort
NtQuerySecurityObject
0x93
NtRequestWaitReplyPort
NtQuerySemaphore
0x94
NtResetEvent
NtQuerySymbolicLinkObject
0x95
NtRestoreKey
NtQuerySystemEnvironmentValue
0x96
NtResumeThread
NtQuerySystemlnformation
0x97
NtSaveKey
NtQuerySystemTime
0x98
NtSetloCompletion
NtQueryTimer
0x99
NtSetContextThread
NtQueryTimerResolution
0x9A
NtSetDefaultHardErrorPort
NtQueryValueKey
0x9B
NtSetDefaultLocale
NtQueryVirtualMemory
0x9C
NtSetEaFile
NtQueryVolumelnformationFile
0x9D
NtSetEvent
NtQueueApcThread
0x9E
NtSetHighEventPair
NtRaiseException
0x9F
NtSetHighWaitLowEventPair
NtRaiseHardError
0xA0
NtSetHighWaitLowThread
NtReadFile
0xA1
NtSetlnformationFile
NtReadFileScatter
0xA2
NtSetlnformationKey
NtReadRequestData
0xA3
NtSetlnformationObject
NtReadVirtualMemory
0xA4
NtSetlnformationProcess
NtRegisterThreadTerminatePort
0xA5
NtSetlnformationThread
NtReleaseMutant
0xA6
NtSetlnformationToken
NtReleaseSemaphore
0xA7
NtSetlntervalProfile
NtRemoveloCompletion
0xA8
NtSetLdtEntries
NtReplaceKey
0xA9
NtSetLowEventPair
NtReplyPort
0xAA
NtSetLowWaitHighEventPair
NtReplyWaitReceivePort
0xAB
NtSetLowWaitHighThread
NtReplyWaitReceivePortEx
0xAC
NtSetSecurity Object
NtReplyWaitRepiyPort
0xAD
NtSetSystemEnvironmentValue
NtRequestDeviceWakeup
0xAE
NtSetSystemlnformation
NtRequestPort
0xAF
NtSetSystemPowerState
NtRequestWaitReplyPort
0xB0
NtSetSystemTime
NtRequestWakeupLatency
0xB1
NtSetTimer
NtResetEvent
0xB2
NtSetTimerResolution
NtResetWriteWatch
0xB3
NtSetValueKey
NtRestoreKey
0xB4
NtSetVolumelnformationFile
NtResumeThread
0xB5
NtShutdownSystem
NtSaveKey
0xB6
NtSignalAndWaitForSingleObject
NtSaveMergedKeys
0xB7
NtStartProfile
NtSecureConnectPort
0xB8
NtStopProfile
NtSetloCompletion
0xB9
NtSuspendThread
NtSetContextThread
0xBA
NtSystemDebugControl
NtSetDefaultHardErrorPort
0xBB
NtTerminateProcess
NtSetDefaultLocale
0xBC
NtTerminateThread
NtSetDefaultUILanguage
0xBD
NtTestAlert
NtSetEaFile
0xBE
NtUnloadDriver
NtSetEvent
0xBF
NtUnloadKey
NtSetHighEventPair
0xC0
NtUnlockFile
NtSetHighWaitLowEventPair
0xC1
NtUnlockVirtualMemory
NtSetlnformationFile
0xC2
NtUnmapViewOfSection
NtSetlnformationJobObject
0xC3
NtVdmControl
NtSetlnformationKey
0xC4
NtWaitForMultipleObjects
NtSetlnformationObject
0xC5
NtWaitForSingleObject
NtSetlnformationProcess
0xC6
NtWaitHighEventPair
NtSetlnformationThread
0xC7
NtWaitLowEventPair
NtSetlnformationToken
0xC8
NtWriteFile
NtSetlntervalProfile
0xC9
NtWriteFileGather
NtSetLdtEntries
0xCA
NtWriteRequestData
NtSetLowEventPair
0xCB
NtWriteVirtualMemory
NtSetLowWaitHighEventPair
0xCC
NtCreateChannel
NtSetQuotalnformationFile
0xCD
NtListenChannel
NtSetSecurity O b j ect
0xCE
NtOpenChannel
NtSetSystemEnvironment Value
0xCF
NtReplyWaitSendChannel
NtSetSystemlnformation
0xD0
NtSendWaitReplyChannel
NtSetSystemPowerSrate
0xD1
NtSetContextChannel
NtSetSystemTime
0xD2
NtYieldExecution
NtSetThreadExecutionState
0xD3
N/A
NtSetTimer
0xD4
N/A
NtSetTimerResolution
0xD5
N/A
NtSetUuidSeed
0xD6
N/A
NtSetValueKey
0xD7
N/A
NtSetVolumelnformationFile
0xD8
N/A
NtShutdownSystem
0xD9
N/A
NtSignalAndWaitForSingleObject
0xDA
N/A
NtStartProfile
0xDB
N/A
NtStopProfile
0xDC
N/A
NtSuspendThread
0xDD
N/A
NtSystemDebugControl
0xDE
N/A
NtTerminateJobObject
0xDF
N/A
NtTerminateProcess
0xE0
N/A
NtTerminateThread
0xE1
N/A
NtTestAlert
0xE2
N/A
NtUnloadDriver
0xE3
N/A
NtUnloadKey
0xE4
N/A
NtUnlockFile
0xE5
N/A
NtUnlockVirtualMemory
0xE6
N/A
NtUnmapViewOfSection
0xE7
N/A
NtVdmControl
0xE8
N/A
NtWaitForMultipleObjects
0xE9
N/A
NtWaitForSingleObject
0xEA
N/A
NtWaitHighEventPair
0xEB
N/A
NtWaitLowEventPair
0xEC
N/A
NtWriteFile
0xED
N/A
NtWriteFileGather
0xEE
N/A
NtWriteRequestData
0xEF
N/A
NtWriteVirtualMemory
0xF0
N/A
NtCreateChannel
0xF1
N/A
NtListenChannel
0xF2
N/A
NtOpenChannel
0xF3
N/A
NtReplyWaitSendChannel
0xF4
N/A
NtSendWaitReplyChannel
0xF5
N/A
NtSetContextChannel
0xF6
N/A
NtYieldExecution
0xF7
N/A
Russinoich和Cogewell采用的最重要的一步是:編寫(xiě)一個(gè)內(nèi)核模式的設(shè)備驅(qū)動(dòng)程序來(lái)安裝和維護(hù)Native API Hook。因?yàn)?,用戶模式下的模塊沒(méi)有修改系統(tǒng)服務(wù)描述符表的權(quán)限。就像第四章中的Spy驅(qū)動(dòng)程序,這是一種多少有些特殊的驅(qū)動(dòng)程序,因?yàn)樗惶幚硗ǔ5腎/O請(qǐng)求。它只是導(dǎo)出一個(gè)簡(jiǎn)單的設(shè)備I/O控制(IOCTL)接口,以讓用戶模式下的代碼訪問(wèn)它收集到的數(shù)據(jù)。該驅(qū)動(dòng)程序的主要任務(wù)是修改KiServiceTable、攔截并記錄所選的Windows 2000 Native API調(diào)用。盡管這種方法很簡(jiǎn)單而且優(yōu)雅,它還是有些讓人擔(dān)心。它的簡(jiǎn)單使我想起了在DOS時(shí)代,hook一個(gè)系統(tǒng)服務(wù)只需要簡(jiǎn)單的修改處理器的中斷向量表中的指針。任何知道如何編寫(xiě)基本的Windows 2000內(nèi)核驅(qū)動(dòng)程序的人都可以hook任意的NT系統(tǒng)服務(wù)而不需要而外的努力。
Russinovich和Cogswell使用他們的技術(shù)開(kāi)發(fā)了一個(gè)非常有用的Windows NT注冊(cè)表監(jiān)視器。當(dāng)使用他們的技術(shù)來(lái)完成其他“間諜”任務(wù)時(shí),我很快就變得煩躁起來(lái),這是因?yàn)槲倚枰獮槲乙O(jiān)控的每個(gè)API函數(shù)都編寫(xiě)一個(gè)獨(dú)立的hook API函數(shù)。為了避免編寫(xiě)大量的代碼,我打算找出一種方法來(lái)強(qiáng)迫所有我感興趣的API函數(shù)進(jìn)入同一個(gè)hook函數(shù)中。這個(gè)任務(wù)花費(fèi)了我大量的時(shí)間,并給我展示了多種多樣的藍(lán)屏。不過(guò),最終的結(jié)果是我得到了一個(gè)通用的解決方案,只需花費(fèi)很少的努力,我就能hook不同的API函數(shù)集合。
