久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

《Undocumented Windows 2000 Secrets》翻譯 --- 3

瀏覽:93日期:2023-08-27 13:21:01

第一章 Windows 2000對調(diào)試技術(shù)的支持

翻譯:Kendiv

更新:Monday, January 17, 2005

枚舉系統(tǒng)模塊和驅(qū)動(dòng)(Drivers)

psapi.dll可以返回當(dāng)前內(nèi)存中的內(nèi)核模塊。這本是非常簡單的工作。psapi.dll的EnumDeviceDrivers()函數(shù)接受一個(gè)PVOID類型的數(shù)組,它將用當(dāng)前活動(dòng)的內(nèi)核驅(qū)動(dòng)模塊(active kernel-mode driver)的映像基址(image base address)來填充這個(gè)數(shù)組,這包括基本的內(nèi)核模塊ntdll.dll、ntoskrnl.exe、Win32K.sys、hal.dll和bootvid.dll。返回值是這些可執(zhí)行文件映射到的虛擬內(nèi)存地址(譯注,也稱作線性地址)。如果你使用內(nèi)核調(diào)試器或其他調(diào)試工具檢查這些地址的最初幾個(gè)字節(jié),你將清楚地認(rèn)出那個(gè)有名的Dos stub程序,它以著名的Mark Zbikowski的首字母大寫“MZ”開始,內(nèi)含一個(gè)文本消息--“This program cannot be run in DOS mode”或類似的東西。列表1-3展示了一個(gè)使用EnumDeviceDrivers()的簡單函數(shù),以及EnumDeviceDrivers函數(shù)的原型。

BOOL WINAPI EnumDeviceDrivers ( PVOID* lpImageBase,

DWord; cb,

PDWORD lpcbNeeded);

PPVOID WINAPI dbgDriverAddresses( PDWORD pdCount )

{

DWORD dSize;

DWORD dCount = 0;

PPVOID ppList = NULL;

dSize = SIZE_MINIMUM * sizeof( PVOID );

while ( (ppList = dbgMemoryCreate(dSize)) != NULL )

{

if ( EnumDeviceDrivers( ppList, dSize, &dCount) && (dCount < dSize) )

{

dCount /= sizeof( PVOID );

break;

}

dCount = 0;

ppList = dbgMemoryDestroy( ppList );

if ( (dSize <<= 1) > (SIZE_MAXIMUM * sizeof( PVOID )))

{

break;

}

}

if ( pdCount != NULL )

{

*pdCount = dCount;

}

return ppList;

}

列表1-3枚舉系統(tǒng)模塊地址

EnumDeviceDrivers()期望三個(gè)參數(shù):一個(gè)數(shù)組指針,一個(gè)表示輸入大小的值以及一個(gè)用于輸出的類型為DWORD的變量。第二個(gè)參數(shù)指定了傳入的數(shù)組的字節(jié)數(shù),第三個(gè)參數(shù)表示復(fù)制到該數(shù)組中的字節(jié)數(shù)。因此,你必須將返回值除以sizeof(PVOID)來確定有多少個(gè)地址數(shù)據(jù)復(fù)制到了數(shù)組中。不幸的是,該函數(shù)不能幫助你確定該提供多大的數(shù)組,盡管它實(shí)際上知道有多少個(gè)Driver在運(yùn)行。但它僅僅告訴你返回了多少字節(jié),而且,如果數(shù)組太小,它會(huì)隱藏多出的字節(jié)。因此,你必須使用無聊的trial-and-error循環(huán)來確定適當(dāng)?shù)臄?shù)組大小,就如同列表1-3所示的那樣,只要返回值與數(shù)組大小相同就假定還有數(shù)據(jù)未復(fù)制到數(shù)組中。在剛開始時(shí),代碼中使用了一個(gè)合理的最小值--256(由SIZE_MINIMUM表示),這通常都足夠大了,但是如果不夠的話,在開始新的循環(huán)時(shí),數(shù)組大小會(huì)增加為原來的2倍,直到獲取了所有的指針或者數(shù)組大小超過了65,536。數(shù)組使用的內(nèi)存緩沖區(qū)由兩個(gè)幫助函數(shù)dbgMemoryCreate()和dbgMemoryDestroy()提供,這兩個(gè)函數(shù)只是Win32函數(shù)LocalAlloc和LocalFree的外包而已,這兒就不列出了。

BOOL WINAPI EnumDeviceDrivers( PVOID* lpImageBase,

DWORD; cb,

DWORD* lpcbNeeded)

{

SYSTEM_MODULE_INFORMATION; smi;

PSYSTEM_MODULE_INFORMATION psmi;

DWORD;;;dSize, i;

NTSTATUSns;

BOOL;;;;fOk = FALSE;

ns = NtQuerySystemInformation( SystemModuleInformation,

&smi, sizeof(smi),NULL);

if ( (STATUS_SUCCESS == ns) | (STATUS_INFO_LENGTH_MISMATCH == ns) )

{

dSize = sizeof(SYSTEM_MODULE_INFORMATION)

+ ;(smi.dCount*sizeof(SYSTEM_MODULE));

if ( (psmi = LocalAlloc(LEME_FIXED,dSize)) != NULL )

{

ns = NtQuerySystemInformation( SystemModuleInformation,psmi,dSize,NULL );

if ( ns == STATUS_SUCCESS )

{

for( i = 0; (i < psmi->dCount) && (i < cb/sizeof(DWORD))i++)

lpImageBase[i] = psmi->aModules[i].pImageBase;

*lpcbNeeded = i*sizeof(DWORD);

fOk = TRUE;

}

LocalFree(psmi);

if ( !fOk ); SetLastError( RtlNtStatusToDosError(ns) );

}

}

else

SetLastError( RtlNtStatusToDosError(ns) );

return fOk;

}

列表1-4; EnumDeviceDrivers函數(shù)的示列

列表1-4列出了EnumDeviceDrivers()一種可能的實(shí)現(xiàn)方式。注意這并不是來自psapi.dll的原始代碼。但通過C編譯器它可以變成等效的二進(jìn)制代碼。為了保持簡單干凈,我省略了源代碼中易分散注意力的細(xì)節(jié),比如結(jié)構(gòu)化異常等。在列表1-4的中間,你會(huì)看到NtQuerySystemInformation()函數(shù)作了很多工作。這是我非常喜歡的Windows 2000函數(shù)之一,因?yàn)樵摵瘮?shù)可以訪問多種重要的數(shù)據(jù)結(jié)構(gòu),如驅(qū)動(dòng)、進(jìn)程、線程、句柄(handle)和LPC端口列表等等。我的文章“Inside Windows NT Sytem Data”(出版于1999年11月的Dr.Dobb’s Journal)在第一時(shí)間提供了有關(guān)該函數(shù)的內(nèi)部信息及其搭檔函數(shù)NtSetSystemInformation()的文檔化資料。另外的全面講述這兩個(gè)函數(shù)的文檔可以在Gary Nebbett的《Indispendsable Windows NT/2000 Native API Reference》中找到。

不要過于擔(dān)心列表1-4列出的EnumDeviceDrivers()函數(shù)的實(shí)現(xiàn)細(xì)節(jié)。我增加這些代碼片斷只是為了例舉該函數(shù)有趣的一面,這像一根紅線貫穿于psapi.dll。在使用SystemModuleInformation標(biāo)志第二次調(diào)用NtQuerySystemInformation()獲取了完整的驅(qū)動(dòng)列表后,代碼遍歷驅(qū)動(dòng)模塊數(shù)組并將其pImageBase成員復(fù)制到調(diào)用者提供的指針數(shù)組(名為lpImageBase[])中。這似乎很正確,但除非你不知道NtQuerySystemInformation提供的模塊數(shù)組所包含的其他信息。這些數(shù)據(jù)結(jié)構(gòu)都是沒有文檔化的,但是我現(xiàn)在可以告訴你,這些信息同樣是有關(guān)模塊在內(nèi)存中的大小、它們的路徑和名稱、引用計(jì)數(shù)(load counts)和其他一些標(biāo)志信息的。甚至文件名在路徑中的偏移量也是很容易就能得到的!,EnumDeviceDrivers()殘忍的丟掉了所有這些有用的信息,僅僅保留了映像基址(Image Base address)。

所以如果你試圖通過返回的指針來獲取有關(guān)模塊的更多信息,則肯定會(huì)失敗。當(dāng)你調(diào)用GetDeviceDriverFileName()來獲取指定映像基址對應(yīng)的文件路徑時(shí),猜猜psapi.dll會(huì)怎樣做?它會(huì)運(yùn)行與列表1-4類似的代碼來獲取完整的驅(qū)動(dòng)列表,并遍歷該列表來尋找指定的映像基址。如果它找到一個(gè)匹配項(xiàng),就將其路徑復(fù)制到調(diào)用者的緩沖區(qū)中。這難道很高效嗎?為什么EnumDeviceDrivers不在它首次遍歷驅(qū)動(dòng)列表時(shí)就復(fù)制路徑呢?按這樣的方式實(shí)現(xiàn)此函數(shù)并沒有多么困難。除去性能問題,這種設(shè)計(jì)還有另一個(gè)潛在的問題:如果在GetDeviceDriverFileName()執(zhí)行之前指定的模塊就已經(jīng)被卸載了會(huì)怎么樣呢?該模塊的地址將不會(huì)出現(xiàn)在第二次獲取的驅(qū)動(dòng)列表中,GetDeviceDriverFileName()將會(huì)失敗。我真不明白微軟為什么會(huì)發(fā)布這樣的DLL。

枚舉活動(dòng)進(jìn)程

psapi.dll的另一個(gè)典型工作就是枚舉當(dāng)前系統(tǒng)中運(yùn)行的進(jìn)程。為此目的,該DLL提供了EnumProcesses()函數(shù)。該函數(shù)的工作與EnumDeviceDrivers()十分類似,不過返回的是進(jìn)程ID而不是虛擬地址了。再次提示,該函數(shù)并不會(huì)提示緩沖區(qū)大小不足,因此我們還需再次使用trial-and-error循環(huán),如列表1-5所示,這些代碼和列表1-3很相似,除了有些不同的符號(hào)和類型名稱。

一個(gè)進(jìn)程ID是一個(gè)全局?jǐn)?shù)字標(biāo)簽可在整個(gè)系統(tǒng)中唯一標(biāo)識(shí)一個(gè)進(jìn)程。進(jìn)程和線程ID都取自同一個(gè)數(shù)字池(pool of numbers),從以0開始的Idle進(jìn)程,在同一時(shí)間,所有運(yùn)行的進(jìn)程和線程都不會(huì)有相同的ID。但是,當(dāng)一個(gè)進(jìn)程結(jié)束后,另一個(gè)進(jìn)程可能會(huì)再次使用該結(jié)束進(jìn)程或線程的ID。因此,在X時(shí)間獲取的一個(gè)進(jìn)程ID在Y時(shí)間可能會(huì)代表另一個(gè)完全不同的進(jìn)程。也有可能在其使用的那一刻還沒有定義或者指定給了某個(gè)線程。所以,EnumProcesses()返回一個(gè)簡單的進(jìn)程ID列表并不能可靠的代表當(dāng)前系統(tǒng)活動(dòng)進(jìn)程的快照。如果考慮該函數(shù)的實(shí)現(xiàn)方式,這個(gè)設(shè)計(jì)缺陷真是無法原諒。列表1-6是psapi.dll另一個(gè)函數(shù)的克隆,大致勾勒出了EnumProcessees()的基本動(dòng)作。和EnumDeviceDrivers()類似,它也依賴NtQuerySystemInformation()函數(shù),不過在調(diào)用時(shí),用SystemProcessInformation代替了SystemModuleInformation。注意列表1-6中間的循環(huán),在哪兒lpidProcess[]數(shù)組被來自SYSTEM_PROCESS_INFORMATION結(jié)構(gòu)中的數(shù)據(jù)填充。沒什么好驚奇的,該結(jié)構(gòu)也沒有文檔化。

BOOL WINAPI EnumProcesses( DWORD* lpidProcess,

DWORD; cb,

DWORD* lpcbNeeded);

PDWORD WINAPI dbgProcessIds( PDWORD pdCount )

{

DWORD dSize;

DWORD dCount = 0;

PDWORD pdList = NULL;

dSize = SIZE_MINIMUM * sizeof( DWORD );

while ( (pdList = dbgMemoryCreate(dSize)) != NULL )

{

if ( EnumProcesses( pdList, dSize, &dCount) && (dCount < dSize) )

{

dCount /= sizeof( DWORD );

break;

}

dCount = 0;

pdList = dbgMemoryDestroy(pdList);

if ( (dSize <<= 1) > (SIZE_MXAIMUM*sizeof(DWORD)) ); break;

}

if ( pdCount != NULL ) *pdCount = dCount;

return pdList;

}

列表1-5; 枚舉進(jìn)程ID

在看過EnumDeviceDrivers()是如何浪費(fèi)從NtQuerySystemInformation()返回的數(shù)據(jù)后,不幸的是,EnumProcesses也是和其類似的函數(shù),但,事實(shí)上,這個(gè)函數(shù)更糟糕!因?yàn)榭捎玫倪M(jìn)程信息要遠(yuǎn)多于驅(qū)動(dòng)模塊的信息,因?yàn)檫M(jìn)程數(shù)據(jù)之后還包含很多有關(guān)系統(tǒng)中每個(gè)線程的詳細(xì)信息。在我寫下這段文字時(shí),我的系統(tǒng)正運(yùn)行著37個(gè)進(jìn)程,調(diào)用NtQuerySystemInformation()產(chǎn)了一個(gè)24,488字節(jié)的數(shù)據(jù)塊!而當(dāng)EnumProcesses()處理完這些數(shù)據(jù)后,僅剩下了148字節(jié),這些剛好夠存放37個(gè)進(jìn)程ID。

盡管EnumDeviceDirvers()讓我有些難過,但EnumProcesses()卻真正傷害了我的心。如果你需要使用未文檔化API函數(shù)的理由,那這兩個(gè)函數(shù)就是最好的證據(jù)。如果實(shí)際的工作只需一步既可完成,那為什么還要使用如此低效的函數(shù)呢?為什么不自己調(diào)用NtQuerySystemInformation()函數(shù)自由的獲取感興趣的系統(tǒng)信息?微軟提供的許多系統(tǒng)管理工具都依賴于NtQuerySystemInformation()而不是psapi.dll,so why settle for less?

BOOL WINAPI EnumProcesses( PDWORD lpidProcess,

DWORD; cb,

;PDWORD lpcbNeeded)

{

PSYSTEM_PROCESS_INFORMATION pspi, pSpiNext;

DWORD;;;;dSize, i;

NTSTATUS;ns;

BOOL;;;;;fOk = FALSE;

// 0x8000 = 32KB

for (dSize=0x8000; ((pspi = LocalAlloc(LMEM_FIXED,dSize)) != NULL);

;;dSize += 0x8000)

{

ns = NtQuerySystemInformation( SystemProcessInformation,pspi,

dSize, NULL);

if ( STATUS_SUCCESS == ns )

{

pSpiNext = pspi;

for ( i=0; i < cb/sizeof(DWORD); i++ )

{

lpidProcess[i] = pspiNext->dUniqueProcessId;

pSpiNext = (PSYSTEM_PROCESS_INFORMATION)

;;;;((BYTE)pSpiNext+pSpiNext->dNext);

}

*lpcbNeeded = i * sizeof(DWORD);

fOk = TRUE;

}

LocalFree(pspi);

if ( fOk || (ns != STATUS_INFO_LENGTH_MISMATCH) )

{

if ( !fOk) SetLastError(RtlNtStatusToDosError(ns));

break;

}

return fOk;

}

列表1-6; EnumProcesses()函數(shù)的示例實(shí)現(xiàn)

枚舉進(jìn)程模塊

一但你從EnumProcess()返回的進(jìn)程列表中發(fā)現(xiàn)了你感興趣的進(jìn)程ID,你可能會(huì)想知道在此進(jìn)程的虛擬地址空間中加載了哪些模塊。psapi.dll提供了另一個(gè)API函數(shù)來完成此功能,叫做EnumProcessModules()。與EnumDeviceDrivers()和EnumProcesses()不同,這個(gè)函數(shù)需要四個(gè)參數(shù)(參見列表1-7)。不同于前兩個(gè)返回系統(tǒng)全局列表的函數(shù),EnumProcessModules()只取回指定進(jìn)程的列表,因此,增加的那個(gè)參數(shù)唯一表示一個(gè)進(jìn)程。然而,該函數(shù)需要一個(gè)進(jìn)程句柄(HANDLE)來代替進(jìn)程ID。為了通過進(jìn)程ID獲取其句柄(HANDLE),必須調(diào)用OpenProcess()函數(shù)。

BOOL WINAPI EnumProcessModule( HNADLEhProcess,

HMODULE* lphModule,

DWORD;cb,

DWORD*lpcbNeeded);

PHMODULE WINAPI dbgProcessModules( HANDLE hProcess, PDWORD pdCount)

{

DWORD;dSize;

DWORD;dCount = 0;

PHMODULE phList = NULL;

if ( hProcess != NULL )

{

dSize = SIZE_MINIMUM * sizeof( HMODULE );

while ( (phList = dbgMemoryCreate(dSize)) != NULL )

{

if ( EnumProcessModules(hProcess,phList,dSize,&dCount))

{

if (dCount <= dSize)

{

dCount /= sizeof( HMODULE );

break;

}

}

else

{

dCount = 0;

}

phList = dbgMemoryDestroy(phList);

if ( !(dSize = dCount) ) break;

}

}

if ( pdCount != NULL) *pdCount = dCount;

return phList;

}

列表1-7; 枚舉進(jìn)程模塊

EnumProcessModules()返回指定進(jìn)程所有模塊的句柄的引用。在Windows 2000中,一個(gè)HMODULE只是簡單的模塊映像基址。在SDK頭文件windef.h中,HMODULE被定義為HINSTANCE的別名,二者都是HANDLE類型。嚴(yán)格的來講HMODULE并不是一個(gè)句柄。通常,句柄是系統(tǒng)管理的一個(gè)表的索引,可通過此表來查找對象屬性。系統(tǒng)返回的所有句柄都有一個(gè)與特定對象相關(guān)的計(jì)數(shù)器,在一個(gè)對象的所有句柄沒有返回系統(tǒng)時(shí),該對象不能從內(nèi)存中被移除。Win32 API提供了CloseHandle()函數(shù)用于關(guān)閉句柄。該函數(shù)與Native API NtClose()等價(jià)。有關(guān)HMODULEs最重要的事情是,這些“handles”不需要關(guān)閉。

另一件讓人困惑的事是,事實(shí)上,模塊句柄通常并不被保證是一直有效的。SDK的GetModuleHandle()函數(shù)文檔提示到,在多線程程序中必須更加注意模塊句柄,因?yàn)橐粋€(gè)線程可以通過卸載HMODULE引用的模塊而讓另一個(gè)線程擁有的HMODULE無效。在多任務(wù)環(huán)境下,一個(gè)程序(如調(diào)試器)使用另一程序的模塊句柄時(shí)也許注意這一點(diǎn)。這似乎使HMODULEs沒有多大用處了,但是,在下面兩種情況中,HMODULE的有效性會(huì)保持足夠長的時(shí)間:

1.由LoadLibrary()或LoadLibraryEx()返回的HMODULE在進(jìn)程調(diào)用FreeLibrary()之前都會(huì)一直有效,由于這些函數(shù)包含了模塊引用計(jì)數(shù),所以即使在多線程程序中,這也會(huì)阻止模塊被意外卸載。

2.如果HMODULE指向的模塊會(huì)永久的存在,那么它也會(huì)一直有效。例如,所有Windows 2000內(nèi)核組件(不包括內(nèi)核模式的驅(qū)動(dòng)程序)總是被映射到每個(gè)進(jìn)程的相同固定地址上,并且在進(jìn)程生命期里一直在那里。

不幸地是,這些情況并不適用于EnumProcessModules()函數(shù)返回的模塊句柄,至少通常不行。復(fù)制到調(diào)用者提供的緩沖區(qū)中的HMODULE,在獲取進(jìn)程快照那一刻其所表示映像基址是有效的。稍后,進(jìn)程可能調(diào)用FreeLibrary()來釋放一個(gè)或多個(gè)模塊,并將其從內(nèi)存中移除,此時(shí)它們的句柄將無效,隨后進(jìn)程很有可能立即調(diào)用LoadLibrary()加載了另一個(gè)DLL,而此新模塊恰好映射到了前面釋放的地址上。這看上去是不是很熟悉?是的,同樣的問題也存在于EnumDeviceDrivers()的指針數(shù)組和EnumProcesses()函數(shù)的ID數(shù)組。不過,這些問題是可以避免的。psapid.dll通過調(diào)用未文檔化的API函數(shù)來完成數(shù)據(jù)收集工作后,考慮這些數(shù)據(jù)的完整性,可返回一個(gè)完整的請求對象的快照,其中應(yīng)包括所有感興趣的屬性信息。這樣就沒有必要在稍后調(diào)用另一個(gè)函數(shù)來獲取附加的信息了。我的觀點(diǎn)是,psapi.dll的設(shè)計(jì)過于簡單,因?yàn)樗雎粤藬?shù)據(jù)的完整性,這也是我不會(huì)將此DLL作為一個(gè)專業(yè)調(diào)試工具的基礎(chǔ)的原因。

與EnumDeviceDrivers()和EnunProcesses()函數(shù)相比EnumProcessModules()函數(shù)算是個(gè)好公民了,因?yàn)槿绻{(diào)用者提供的緩沖區(qū)不能放下全部的輸出數(shù)據(jù),它會(huì)準(zhǔn)確地提示有多少字節(jié)沒有復(fù)制。注意列表1-7沒有包括一個(gè)循環(huán),在那里緩沖區(qū)會(huì)不斷增大直到足夠的大。然而,仍然需要trial-and-error循環(huán),因?yàn)樵谙乱淮握{(diào)用時(shí),EnumProcessModules報(bào)告的所需大小可能已經(jīng)無效了(如果指定進(jìn)程在兩次調(diào)用之間又加載了新的模塊)。因此,列表1-7中的代碼將不斷枚舉模塊直到EnumProcessModules()報(bào)告需要的緩沖區(qū)等于或小于實(shí)際可用大小,或者出現(xiàn)了錯(cuò)誤。

我不想描述EnumProcessModules()的等價(jià)函數(shù),因?yàn)樵摵瘮?shù)要比EnumDeviceDrivers和EnumProcesses稍微復(fù)雜些,它涉及幾個(gè)未文檔化的數(shù)據(jù)結(jié)構(gòu)?;旧?,它還是通過調(diào)用NtQuerySystemInformation()函數(shù)(當(dāng)然,該函數(shù)也沒有文檔化)來獲取目標(biāo)進(jìn)程環(huán)境塊(PEB)的地址,通過該地址可獲取一個(gè)模塊信息鏈表。因?yàn)椴还苁荘EB還是這個(gè)鏈表在調(diào)用進(jìn)程的地址空間都是無法直接使用的,EnumProcessModules調(diào)用Win32 API ReadProcessMemory()(該函數(shù)有文檔記載)來遍歷目標(biāo)進(jìn)程的地址空間。順便說一下,PEB結(jié)構(gòu)的布局將在第7章討論,在附錄C中,可以找到該結(jié)構(gòu)的定義。

調(diào)整進(jìn)程特權(quán)

回憶一下稍早討論過的有關(guān)EnumProcessModules所需的進(jìn)程句柄。通常,你首先得到的是進(jìn)程ID---可能是EnumProcesses返回的進(jìn)程ID集中的一個(gè)。Win32 API OpenProcess()可通過進(jìn)程ID來獲取其句柄。這個(gè)函數(shù)期望一個(gè)訪問標(biāo)志符作為其第一個(gè)參數(shù)。假定進(jìn)程ID存放在一個(gè)DWORD類型的變量dId中,你以最大訪問權(quán)限來調(diào)用OpenProcess,如下:

OpenProcess(PROCESS_ALL_ACCESS,F(xiàn)ALSE,dId)

以獲取該進(jìn)程的句柄,此時(shí)你會(huì)收到一個(gè)針對幾個(gè)低ID進(jìn)程的錯(cuò)誤代碼。這并不是bug---這是安全特性!這些進(jìn)程都是保持系統(tǒng)活動(dòng)的系統(tǒng)服務(wù)。一個(gè)普通用戶進(jìn)程不允許執(zhí)行針對系統(tǒng)服務(wù)的所有操作。例如,允許所有進(jìn)程都可以殺死系統(tǒng)中其余進(jìn)程并不是個(gè)好主意。如果一個(gè)程序意外終止了一個(gè)系統(tǒng)服務(wù),那么整個(gè)系統(tǒng)都將崩潰。因此,一個(gè)進(jìn)程只有擁有確切的訪問權(quán)限才會(huì)有適當(dāng)?shù)奶貦?quán)。

由于多種原因,調(diào)試器必須擁有大量的權(quán)限來完成他的工作。改變進(jìn)程的特權(quán)可通過以下三個(gè)簡單的基本步驟:

1.首先,必須打開進(jìn)程的訪問令牌(access token),使用advapi32.dll中的函數(shù)OpenProcessToken()。

2.如果上一步正確完成,接下來就是準(zhǔn)備TOKEN_PRIVILEGES結(jié)構(gòu),該結(jié)構(gòu)包含有關(guān)要請求的特權(quán)的信息。這個(gè)工作需要advapi32.dll中的另一個(gè)函數(shù)LookupPrivilegeValue()的幫助。特權(quán)通過名稱來指定。SDK文檔winnt.h定義了27中特權(quán)名稱和其對應(yīng)的符號(hào)名稱。例如,調(diào)試權(quán)限的符號(hào)名稱為:SE_DEBUG_NAME,該名稱和字符串“SeDebugPrivilege”等效。

3.如果上一步正確完成,就可以使用進(jìn)程的令牌句柄(Token Handle)來調(diào)用AdjustTokenPrivileges()函數(shù)以初始化TOKEN_PRIVILEGES結(jié)構(gòu)。該函數(shù)也是advapi32.dll導(dǎo)出的。

如果OpenProcessToken()調(diào)用成功,要記得關(guān)閉其返回的令牌句柄(Token Handle)。w2k_dbg.dll包含一個(gè)dbgPrivilegeSet()函數(shù),該函數(shù)合并了這幾個(gè)步驟,下面的列表1-8列出了該函數(shù)和w2k_dbg.dll中的另一個(gè)函數(shù):dbgPrivilegeDebug()。此函數(shù)是dbgPrivilegeSet()的一個(gè)外包函數(shù),為了便于設(shè)定調(diào)試特權(quán)。順便說一下,Windows NT Server資源工具集中的kill.exe也使用了同樣的技巧。Kill.exe需要調(diào)試特權(quán)來剔除內(nèi)存中餓死的服務(wù)(starved services)。這是NT Server管理員不可缺少的一個(gè)工具,這對于重起一個(gè)掛掉的系統(tǒng)服務(wù)十分有用,而且可以避免不必要的系統(tǒng)重啟。對于使用IIS(Internet Information Server)的人,在他們的緊急工具箱中可能都有這個(gè)工具,以便重起偶爾掛掉的inerinfo.exe。

BOOL WINAPI dbgPrivilegeSet(PWORD pwName)

{

HANDLEhToken;

TOKEN_PRIVILEGES tp;

BOOL;;fOk = FALSE;

if ( (pwName != NULL) &&

OpenProcessToken(GetCurrentProcess(),

TOKEN_ADJUST_PRIVILEGES,

&hToken) )

{

if ( LookupPrivilegeValue(NULL,pwName,&tp,Privileges->Luid) )

{

;;;;tp.Privileges->Attributes = SE_PRIVILEGE_ENABLED;

tp.PrivilegeCount = 1;

fOk = AdjustTokenPrivileges(hToken,FALSE,&tp,0,NULL,NULL)

; && (GetLastError() == ERROR_SUCCESS);

}

CloseHandle(hToken);

}

return fOk;

}

//------------------------------------------------------------------------------------

BOOL WINAPI dbgPrivilegeDebug(void)

{

return dbgPrivilegeSet(SE_DEBGU_NAME);

}

列表1-8; Requesting a Privilege for a Process

標(biāo)簽: Windows系統(tǒng)
主站蜘蛛池模板: 日韩一| 亚洲视频自拍 | 国产aaa大片 | 亚洲精品成人悠悠色影视 | 久久免费精品 | 婷婷丁香综合 | 久久四色 | 国产区视频在线 | 2020国产在线 | 欧洲精品乱码久久久久蜜桃 | 三级色网站 | 91视频免费播放 | 黄色一级网址 | 久久国产精品一区二区 | 欧美激情精品久久久久久 | 欧美日一区 | 三级视频在线 | 日韩精品在线免费观看 | 91不卡| 欧美日韩视频在线观看一区 | 精品一区二区三区免费毛片爱 | 国产精品成人一区二区三区夜夜夜 | 午夜精品一区二区三区在线观看 | 日韩av高清在线 | 国产精品二区三区 | 国产精品久久久久久久竹霞 | 日韩毛片免费看 | 综合久久综合 | 欧美亚洲二区 | av电影一区二区 | 国产91麻豆视频 | 欧美一级精品片在线看 | 电影91久久久| 精品欧美一区二区三区久久久 | 午夜精品影院 | 久久福利 | 国产免费黄色 | 国产美女视频网站 | 日韩有码一区 | 北条麻妃一区二区三区在线 | 狠狠操狠狠操 |