其實(shí)是應(yīng)用程序使用 DeviceIoControl 發(fā)送請(qǐng)求,內(nèi)核使用獨(dú)享的同步事件(KEVENT)來(lái)等待.
當(dāng)內(nèi)核想發(fā)送數(shù)據(jù)給應(yīng)用程序時(shí)就設(shè)置事件即可.
在應(yīng)用程序中因?yàn)橐却?DeviceIoControl 函數(shù)的返回,所以應(yīng)用程序應(yīng)該新開(kāi)一個(gè)線(xiàn)程來(lái)做這件事情.
內(nèi)核中的緩沖區(qū)鏈表結(jié)構(gòu)
內(nèi)核使用一個(gè) 雙向鏈表 來(lái)保存已經(jīng)輸入的字符串
應(yīng)用層取 字符串 時(shí), 每次返回一個(gè)并從鏈表中刪除 保證先入顯出的順序,就向?qū)iT(mén)原來(lái)傳遞長(zhǎng)度小于 512 字節(jié)的字符串的管道一樣,雙向鏈表使用 LIST_ENTRY
//定義一個(gè)列表原來(lái)保存字符串
#define CWK_STR_LEN_MAX 512
typedef struct {
LIST_ENTRY list_entry;
char buf[CWK_STR_LEN_MAX];
} CWK_STR_NODE;
//自旋鎖保證鏈表操作的安全
KSPIN_LOCK g_cwk_lock;
//事件標(biāo)識(shí)是否有字符串可以取
KEVENT g_cwk_event;
//必須的鏈表頭
LIST_ENTRY g_cwk_str_list;
//分配內(nèi)存并初始化一個(gè)鏈表節(jié)點(diǎn)
CWK_STR_NODE *cwkMallocStrNode(){
CWK_STR_NODE *ret = ExAllocatePoolWithTag(NonPagePool,sizeof(CWK_STR_NODE),MEM_TAG);
if(ret == NULL){
return NULL;
}
return ret;
}
//分配節(jié)點(diǎn)
str_node = cwkMallocStrNode();
if(str_node == NULL){
status = 資源不足...
break;
}
//拷貝字符串
strncpy(str_node->buf,(char *)buffer,CWK_STR_LEN_MAX);
//新的字符串插入到鏈表末尾
ExInterlockedInsertTailList(&g_cwk_str_list,(PLIST_ENTRY)str_node,&g_cwk_lock);
//設(shè)置事件
KeSetEvent(&g_cwk_event,0,TRUE);
//釋放 ExFreePool
使用 while 循環(huán)來(lái)判斷鏈表是否有數(shù)據(jù)
使用等待事件來(lái)改善CPU的占用,用睡眠也可以
注意使用過(guò)的內(nèi)存需要釋放
64位和32位內(nèi)核開(kāi)發(fā)的差異
64位系統(tǒng)新增機(jī)制 - WOW64 子系統(tǒng)
該子系統(tǒng)是為了兼容32位應(yīng)用程序的,是一個(gè)輕量級(jí)的兼容層
主要由3個(gè)DLL實(shí)現(xiàn),分配是 Wow64.dll Wow64Win.dll Wow64Cpu.dll
當(dāng)一個(gè)32位應(yīng)用程序發(fā)起系統(tǒng)調(diào)用,WoW64子系統(tǒng)攔截到系統(tǒng)調(diào)用,如果調(diào)用參數(shù)包涵指針,子系統(tǒng)就會(huì)把指針長(zhǎng)度轉(zhuǎn)換成合適的長(zhǎng)度,然后再把請(qǐng)求提交給內(nèi)核.
WOW64子系統(tǒng)有兩個(gè)只要模塊,分別是文件系統(tǒng)重定向器模塊和注冊(cè)表重定向器模塊
windows 64位系統(tǒng)有兩個(gè) system32 目錄,分別是 %windir%\System32 和 %windir%\SysWOW64
前者主要包含64位系統(tǒng)二進(jìn)制文件,后者只要包涵32位系統(tǒng)二進(jìn)制文件
不同位數(shù)的應(yīng)用程序需要調(diào)用不同的系統(tǒng)DLL,如果是32位應(yīng)用程序 WOW64子系統(tǒng)會(huì)對(duì) System32目錄做透明重定向 到 %windir%SysWOW64(絕大多數(shù)情況下)
例如:
HANDLE hFile = CreateFile(_T("C:\\windows\\system32\\testfile.txt"),
GENERIC_READ,0,NULL,CREATE_ALWAYS,0,NULL);
if(hFile != INVALID_HANDLE_VALUE){
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
這個(gè)程序如果編譯成32位程序,會(huì)在 SysWOW64 目錄下生成文件.如果是64位程序,則在 System32 下生成
可以調(diào)用系統(tǒng)API來(lái)關(guān)閉重定向
BOOL WINAPI Wow64DisableWow64FsRedirection(_Out_ PVOID *Oldvalue); //參數(shù)用來(lái)保存原來(lái)的重定向狀態(tài)
恢復(fù)重定向使用 Oldvalue 這個(gè)參數(shù)
BOOL WINAPI Wow64RevertWow64FsRedirection(_In_ PVOID Oldvalue);
并不是所有的 %windir%System32 下目錄和文件都會(huì)重定向,一些特殊目錄是不重定向的
%windir%\System32\catroot
%windir%\System32\catroot2
%windir%\System32\drivers\etc
%windir%\System32\logfiles
%windir%\System32\spool
注冊(cè)表重定向器和文件系統(tǒng)重定向器類(lèi)型,但功能更復(fù)雜,除了提供重定向功能外,還提供注冊(cè)表反射功能
HKEY_LOCAL_MACHINE\SOFTWARE --> HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node
PatchGuard 技術(shù)
對(duì)于32位系統(tǒng)來(lái)說(shuō),驅(qū)動(dòng)程序可以對(duì)內(nèi)核的數(shù)據(jù)結(jié)構(gòu)和關(guān)鍵函數(shù)進(jìn)行掛鉤和修改,但是在64位系統(tǒng)不再適用,因?yàn)槲④浽?4位系統(tǒng)中引入了 PatchGuard(安全內(nèi)核) 機(jī)制,這個(gè)機(jī)制會(huì)定時(shí)檢查系統(tǒng)關(guān)鍵位置,如 SSDT(系統(tǒng)服務(wù)描述表) GDT(全局描述表) IDT(中斷描述表) 系統(tǒng)模塊(ntoskrnl.exe hal.sys 等) 一旦發(fā)現(xiàn)這些關(guān)機(jī)位置的數(shù)據(jù)或代碼給篡改,系統(tǒng)就會(huì)觸發(fā)藍(lán)屏(BSOD),例如 SSDT HOOK INLINE HOOK IDT HOOK 等技術(shù)都不能在64位下使用(大概),然而并沒(méi)有什么軟用
注意32位應(yīng)用程序加載64位驅(qū)動(dòng)需要先關(guān)閉文件重定向
驅(qū)動(dòng)文件在64位系統(tǒng)需要簽名才能被加載,可以選擇 禁用驅(qū)動(dòng)簽名 模式進(jìn)入系統(tǒng)
64位驅(qū)動(dòng)不在允許內(nèi)嵌匯編,可以把匯編代碼寫(xiě)成函數(shù)放到一個(gè)單獨(dú)的asm文件中,然后通過(guò)函數(shù)的方式調(diào)用
Sources 文件中指定 asm 文件即可