Win64 驱动内核编程-32.枚举与删除注册表回调
枚舉與刪除注冊(cè)表回調(diào)
????注冊(cè)表回調(diào)是一個(gè)監(jiān)控注冊(cè)表讀寫的回調(diào),它的效果非常明顯,一個(gè)回調(diào)能實(shí)現(xiàn)在SSDT?上?HOOK?十幾個(gè)?API?的效果。部分游戲保護(hù)還會(huì)在注冊(cè)表回調(diào)上做功夫,監(jiān)控?service
鍵的子鍵,實(shí)現(xiàn)雙層攔截驅(qū)動(dòng)加載(在映像回調(diào)那里還有一層)。而在卡巴斯基等?HIPS?類軟件里,則用來(lái)監(jiān)控自啟動(dòng)等鍵值。
? ? 注冊(cè)表回調(diào)在?XP?系統(tǒng)上貌似是一個(gè)數(shù)組,但是從?WINDOWS?2003?開始,就變成了一個(gè)鏈表。這個(gè)鏈表的頭稱為?CallbackListHead,可在?CmUnRegisterCallback?中找到:
? ? 搜索的過程跟尋找進(jìn)程、線程、映像的數(shù)組類似,根據(jù)?lea?REG,XXX?來(lái)定位。不過為了更加精準(zhǔn),這次資料中是采用兩次?lea?REG,XXX?來(lái)定位:
?
ULONG64 FindCmpCallbackAfterXP() { ULONG64 uiAddress=0; PUCHAR pCheckArea=NULL, i=0, j=0, StartAddress=0, EndAddress=0; ULONG64 dwCheckAddr=0; UNICODE_STRING unstrFunc; UCHAR b1=0,b2=0,b3=0; ULONG templong=0,QuadPart=0xfffff800; RtlInitUnicodeString(&unstrFunc, L"CmUnRegisterCallback"); pCheckArea = (UCHAR*)MmGetSystemRoutineAddress (&unstrFunc) ; if (!pCheckArea) { KdPrint(("MmGetSystemRoutineAddress failed.")); return 0; } StartAddress = (PUCHAR)pCheckArea; EndAddress = (PUCHAR)pCheckArea + PAGE_SIZE; for(i=StartAddress;i<EndAddress;i++) { if( MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2) ) { b1=*i; b2=*(i+1); b3=*(i+2); if( b1==0x48 && b2==0x8d && b3==0x0d ) //488d0d(lea rcx,) { j=i-5; b1=*j; b2=*(j+1); b3=*(j+2); if( b1==0x48 && b2==0x8d && b3==0x54 ) //488d54(lea rdx,) { memcpy(&templong,i+3,4); uiAddress = MakeLong64ByLong32(templong) + (ULONGLONG)i + 7; return uiAddress; } } } } return 0; }?
?
?
????定位完畢之后,就是枚舉鏈表了。注冊(cè)表回調(diào)是一個(gè)“結(jié)構(gòu)體鏈表”,類似于?EPROCESS,它的定義如下:
?
typedef struct _CM_NOTIFY_ENTRY { LIST_ENTRY ListEntryHead; ULONG UnKnown1; ULONG UnKnown2; LARGE_INTEGER Cookie; ULONG64 Context; ULONG64 Function; }CM_NOTIFY_ENTRY, *PCM_NOTIFY_ENTRY;
? ? 我們只關(guān)心兩個(gè)值,一個(gè)是?Cookie,一個(gè)是?Function。前者可以理解成注冊(cè)表回調(diào)的“句柄”(用?CmUnRegisterCallback?注銷回調(diào)傳入的就是這個(gè)?Cookie),后者是回調(diào)函數(shù)的地址。代碼如下:
?
?
ULONG CountCmpCallbackAfterXP(ULONG64* pPspLINotifyRoutine) { ULONG sum = 0; ULONG64 dwNotifyItemAddr; ULONG64* pNotifyFun; ULONG64* baseNotifyAddr; ULONG64 dwNotifyFun; LARGE_INTEGER cmpCookie; PLIST_ENTRY notifyList; PCM_NOTIFY_ENTRY notify; dwNotifyItemAddr = *pPspLINotifyRoutine; notifyList = (LIST_ENTRY *)dwNotifyItemAddr; do { notify = (CM_NOTIFY_ENTRY *)notifyList; if (MmIsAddressValid(notify)) { if (MmIsAddressValid((PVOID)(notify->Function)) && notify->Function > 0x8000000000000000) { DbgPrint("[CmCallback]Function=%p\tCookie=%p", (PVOID)(notify->Function),(PVOID)(notify->Cookie.QuadPart)); //notify->Function=(ULONG64)MyRegistryCallback; sum ++; } } notifyList = notifyList->Flink; }while ( notifyList != ((LIST_ENTRY*)(*pPspLINotifyRoutine)) ); return sum; }
執(zhí)行效果(在有360的機(jī)器上執(zhí)行的):
?
????
對(duì)付注冊(cè)表回調(diào)有三種方法:
1.直接使用CmUnRegisterCallback?把回調(diào)注銷;
2.把鏈表中記錄的回調(diào)地址修改為自定義的空函數(shù)的回調(diào)地址;
3.直接在目標(biāo)回調(diào)地址上寫一個(gè)?RET,使其不執(zhí)行任何代碼就返回。?第三種?方法?沒有針對(duì)性,可以用于對(duì)付?任何?回調(diào)函數(shù)。DisableFunctionWithReturnValue?用來(lái)對(duì)付有返回值的回調(diào)函數(shù),DisableFunctionWithoutReturnValue?用于對(duì)付無(wú)返回值的回調(diào)函數(shù)。
?
/* 給函數(shù)頭寫RET廢除函數(shù)功能,這份代碼可以用于對(duì)抗任意回調(diào)函數(shù),但僅限于WIN64系統(tǒng)。 DisableFunctionWithReturnValue用于有返回值的回調(diào) DisableFunctionWithoutReturnValue用于無(wú)返回值的回調(diào) */KIRQL WPOFFx64() { KIRQL irql=KeRaiseIrqlToDpcLevel(); UINT64 cr0=__readcr0(); cr0 &= 0xfffffffffffeffff; __writecr0(cr0); _disable(); return irql; }void WPONx64(KIRQL irql) { UINT64 cr0=__readcr0(); cr0 |= 0x10000; _enable(); __writecr0(cr0); KeLowerIrql(irql); }VOID DisableFunctionWithReturnValue(PVOID Address) { KIRQL irql; CHAR patchCode[] = "\x33\xC0\xC3"; //xor eax,eax + ret if(MmIsAddressValid(Address)) { irql=WPOFFx64(); memcpy(Address,patchCode,3); WPONx64(irql); } }VOID DisableFunctionWithoutReturnValue(PVOID Address) { KIRQL irql; if(MmIsAddressValid(Address)) { irql=WPOFFx64(); RtlFillMemory(Address,1,0xC3); WPONx64(irql); } }?
?
?
?
?
代碼備份:win7?X64
?
typedef struct _CM_NOTIFY_ENTRY { LIST_ENTRY ListEntryHead; ULONG UnKnown1; ULONG UnKnown2; LARGE_INTEGER Cookie; ULONG64 Context; ULONG64 Function; }CM_NOTIFY_ENTRY, *PCM_NOTIFY_ENTRY;LARGE_INTEGER Cookie; ULONG64 CmCallbackListHead=0;NTSTATUS MyRegistryCallback(IN PVOID CallbackContext,IN PVOID Argument1,IN PVOID Argument2) { return STATUS_SUCCESS; }ULONG CountCmpCallbackAfterXP(ULONG64* pPspLINotifyRoutine) { ULONG sum = 0; ULONG64 dwNotifyItemAddr; ULONG64* pNotifyFun; ULONG64* baseNotifyAddr; ULONG64 dwNotifyFun; LARGE_INTEGER cmpCookie; PLIST_ENTRY notifyList; PCM_NOTIFY_ENTRY notify; dwNotifyItemAddr = *pPspLINotifyRoutine; notifyList = (LIST_ENTRY *)dwNotifyItemAddr; do { notify = (CM_NOTIFY_ENTRY *)notifyList; if (MmIsAddressValid(notify)) { if (MmIsAddressValid((PVOID)(notify->Function)) && notify->Function > 0x8000000000000000) { DbgPrint("[CmCallback]Function=%p\tCookie=%p", (PVOID)(notify->Function),(PVOID)(notify->Cookie.QuadPart)); //notify->Function=(ULONG64)MyRegistryCallback; sum ++; } } notifyList = notifyList->Flink; }while ( notifyList != ((LIST_ENTRY*)(*pPspLINotifyRoutine)) ); return sum; }LONG64 MakeLong64ByLong32(LONG lng32) { LONG64 lng64=0; if(lng32>0) { lng64=(LONG64)lng32; } else { lng64=0xffffffffffffffff; memcpy(&lng64,&lng32,4); } return lng64; }ULONG64 FindCmpCallbackAfterXP() { ULONG64 uiAddress=0; PUCHAR pCheckArea=NULL, i=0, j=0, StartAddress=0, EndAddress=0; ULONG64 dwCheckAddr=0; UNICODE_STRING unstrFunc; UCHAR b1=0,b2=0,b3=0; ULONG templong=0,QuadPart=0xfffff800; RtlInitUnicodeString(&unstrFunc, L"CmUnRegisterCallback"); pCheckArea = (UCHAR*)MmGetSystemRoutineAddress (&unstrFunc) ; if (!pCheckArea) { KdPrint(("MmGetSystemRoutineAddress failed.")); return 0; } StartAddress = (PUCHAR)pCheckArea; EndAddress = (PUCHAR)pCheckArea + PAGE_SIZE; for(i=StartAddress;i<EndAddress;i++) { if( MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2) ) { b1=*i; b2=*(i+1); b3=*(i+2); if( b1==0x48 && b2==0x8d && b3==0x0d ) //488d0d(lea rcx,) { j=i-5; b1=*j; b2=*(j+1); b3=*(j+2); if( b1==0x48 && b2==0x8d && b3==0x54 ) //488d54(lea rdx,) { memcpy(&templong,i+3,4); uiAddress = MakeLong64ByLong32(templong) + (ULONGLONG)i + 7; return uiAddress; } } } } return 0; }void EnumCmCallback64() { //test to add my reg callback CmRegisterCallback(MyRegistryCallback, NULL, &Cookie); DbgPrint("[MY FUNCTION]: %p",(PVOID)MyRegistryCallback); DbgPrint("[MY COOKIE]: %p",(PVOID)Cookie.QuadPart); //get CmCallbackListHead address CmCallbackListHead=FindCmpCallbackAfterXP(); DbgPrint("CmCallbackListHead: %p",(PVOID)CmCallbackListHead); //enum callback address CountCmpCallbackAfterXP((ULONG64*)CmCallbackListHead); //unregister my callback CmUnRegisterCallback(Cookie); }/* 給函數(shù)頭寫RET廢除函數(shù)功能,這份代碼可以用于對(duì)抗任意回調(diào)函數(shù),但僅限于WIN64系統(tǒng)。 DisableFunctionWithReturnValue用于有返回值的回調(diào) DisableFunctionWithoutReturnValue用于無(wú)返回值的回調(diào) */KIRQL WPOFFx64() { KIRQL irql=KeRaiseIrqlToDpcLevel(); UINT64 cr0=__readcr0(); cr0 &= 0xfffffffffffeffff; __writecr0(cr0); _disable(); return irql; }void WPONx64(KIRQL irql) { UINT64 cr0=__readcr0(); cr0 |= 0x10000; _enable(); __writecr0(cr0); KeLowerIrql(irql); }VOID DisableFunctionWithReturnValue(PVOID Address) { KIRQL irql; CHAR patchCode[] = "\x33\xC0\xC3"; //xor eax,eax + ret if(MmIsAddressValid(Address)) { irql=WPOFFx64(); memcpy(Address,patchCode,3); WPONx64(irql); } }VOID DisableFunctionWithoutReturnValue(PVOID Address) { KIRQL irql; if(MmIsAddressValid(Address)) { irql=WPOFFx64(); RtlFillMemory(Address,1,0xC3); WPONx64(irql); } }宋孖健,13
?
?
?
?
?
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Win64 驱动内核编程-32.枚举与删除注册表回调的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win64 驱动内核编程-31.枚举与删
- 下一篇: Win64 驱动内核编程-33.枚举与删