Win64 驱动内核编程-30.枚举与删除线程回调
枚舉與刪除線程回調
? ? 進程回調可以監視進程的創建和退出,這個在前面的章節已經總結過了。某些游戲保護的驅動喜歡用這個函數來監視有沒有黑名單中的程序運行,如果運行則阻止運行或者把游戲退出。而線程回調則通常用來監控遠程線程的建立,如果發現有遠程線程注入到了游戲進程里,則馬上把游戲退出。現在來詳細講解如何繞過這個兩個監控。
????我們注冊的進程回調,會存儲在一個名為?PspCreateProcessNotifyRoutine?的數組里。
PspCreateProcessNotifyRoutine?可以理解成一個?PVOID?數組,它記錄了系統里所有進程回調的地址。這個數組最大長度是?64*sizeof(PVOID)。所以枚舉進程回調的思路如下:找到這個數組的地址,然后解密數組的數據,得到所有回調的地址(這個數組記錄的數據并不是回調的?地?址?,?而?是?經?過?加?密?地?址?,?需?要?解?密?才?行?)。?枚?舉?線?程?回?調?同?理?,?要?找?到PspCreateThreadNotifyRoutine?的地址(這個數組最大長度也是?64*sizeof(PVOID)),然后解密數據,并把解密后的地址打印出來。
? ? 至于怎么處理這些回調就簡單了。可以使用標準函數(PsSetCreateProcessNotifyRoutine、PsRemoveCreateThreadNotifyRoutine)將其摘掉,也可以直接在回調函數首地址寫入?RET?把回調函數廢掉。
????首先要獲得?PspCreateProcessNotifyRoutine?的地址。PspCreateProcessNotifyRoutine?在PspSetCreateProcessNotifyRoutine?函數里出現了。而?PspSetCreateProcessNotifyRoutine?則在PsSetCreateProcessNotifyRoutine?中被調用(注意前一個是?PspXXX,后一個是?PsXXX)。找到PspSetCreateProcessNotifyRoutine?之后,再匹配特征碼:
?
?
? ? 于是我們根據特征碼寫出了以下代碼(僅在?WIN7X64?上有效,WIN8、8.1?需要自己重新
定義特征碼):
?
ULONG64 FindPspCreateProcessNotifyRoutine() { LONG OffsetAddr=0; ULONG64 i=0,pCheckArea=0; UNICODE_STRING unstrFunc; //獲得PsSetCreateProcessNotifyRoutine的地址 RtlInitUnicodeString(&unstrFunc, L"PsSetCreateProcessNotifyRoutine"); pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc); //獲得PspSetCreateProcessNotifyRoutine的地址 memcpy(&OffsetAddr,(PUCHAR)pCheckArea+4,4); pCheckArea=(pCheckArea+3)+5+OffsetAddr; DbgPrint("PspSetCreateProcessNotifyRoutine: %llx",pCheckArea); //獲得PspCreateProcessNotifyRoutine的地址 for(i=pCheckArea;i<pCheckArea+0xff;i++) { if(*(PUCHAR)i==0x4c && *(PUCHAR)(i+1)==0x8d && *(PUCHAR)(i+2)==0x35) //lea r14,xxxx { LONG OffsetAddr=0; memcpy(&OffsetAddr,(PUCHAR)(i+3),4); return OffsetAddr+7+i; } } return 0; }? ? 找到了?PspCreateProcessNotifyRoutine,枚舉操作就好辦了。需要說明的是,在PspCreateProcessNotifyRoutine?里的數據竟然被加密了,需要把數組的值和?0xfffffffffffffff8進行“與”位運算才行:
?
?
?
找線程的同理:
PspCreateThreadNotifyRoutine?->?
PsSetCreateThreadNotifyRoutine?->
PspCreateThreadNotifyRoutine
?
執行結果如下(干凈win7系統沒有線程回調,特意注冊了兩個):
?
void EnumCreateProcessNotify() { int i=0; BOOLEAN b; ULONG64 NotifyAddr=0,MagicPtr=0; ULONG64 PspCreateProcessNotifyRoutine=FindPspCreateProcessNotifyRoutine(); DbgPrint("PspCreateProcessNotifyRoutine: %llx",PspCreateProcessNotifyRoutine); if(!PspCreateProcessNotifyRoutine) return; for(i=0;i<64;i++) { MagicPtr=PspCreateProcessNotifyRoutine+i*8; NotifyAddr=*(PULONG64)(MagicPtr); if(MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr!=0) { NotifyAddr=*(PULONG64)(NotifyAddr & 0xfffffffffffffff8); DbgPrint("[CreateProcess]%llx",NotifyAddr); } } }
代碼整理:?進程
?
?
ULONG64 FindPspCreateProcessNotifyRoutine() { LONG OffsetAddr=0; ULONG64 i=0,pCheckArea=0; UNICODE_STRING unstrFunc; //獲得PsSetCreateProcessNotifyRoutine的地址 RtlInitUnicodeString(&unstrFunc, L"PsSetCreateProcessNotifyRoutine"); pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc); //獲得PspSetCreateProcessNotifyRoutine的地址 memcpy(&OffsetAddr,(PUCHAR)pCheckArea+4,4); pCheckArea=(pCheckArea+3)+5+OffsetAddr; DbgPrint("PspSetCreateProcessNotifyRoutine: %llx",pCheckArea); //獲得PspCreateProcessNotifyRoutine的地址 for(i=pCheckArea;i<pCheckArea+0xff;i++) { if(*(PUCHAR)i==0x4c && *(PUCHAR)(i+1)==0x8d && *(PUCHAR)(i+2)==0x35) //lea r14,xxxx { LONG OffsetAddr=0; memcpy(&OffsetAddr,(PUCHAR)(i+3),4); return OffsetAddr+7+i; } } return 0; }void EnumCreateProcessNotify() { int i=0; BOOLEAN b; ULONG64 NotifyAddr=0,MagicPtr=0; ULONG64 PspCreateProcessNotifyRoutine=FindPspCreateProcessNotifyRoutine(); DbgPrint("PspCreateProcessNotifyRoutine: %llx",PspCreateProcessNotifyRoutine); if(!PspCreateProcessNotifyRoutine) return; for(i=0;i<64;i++) { MagicPtr=PspCreateProcessNotifyRoutine+i*8; NotifyAddr=*(PULONG64)(MagicPtr); if(MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr!=0) { NotifyAddr=*(PULONG64)(NotifyAddr & 0xfffffffffffffff8); DbgPrint("[CreateProcess]%llx",NotifyAddr); } } }
線程(包括創建線程回調測試代碼):
?
?
void CreateThreadNotify1 (IN HANDLE ProcessId,IN HANDLE ThreadId,IN BOOLEAN Create ) { DbgPrint("CreateThreadNotify1\n"); }void CreateThreadNotify2 (IN HANDLE ProcessId,IN HANDLE ThreadId,IN BOOLEAN Create ) { DbgPrint("CreateThreadNotify2\n"); }void CreateThreadNotifyTest(BOOLEAN Remove) { if(!Remove) { PsSetCreateThreadNotifyRoutine(CreateThreadNotify1); PsSetCreateThreadNotifyRoutine(CreateThreadNotify2); } else { PsRemoveCreateThreadNotifyRoutine(CreateThreadNotify1); PsRemoveCreateThreadNotifyRoutine(CreateThreadNotify2); } }ULONG64 FindPspCreateThreadNotifyRoutine() { ULONG64 i=0,pCheckArea=0; UNICODE_STRING unstrFunc; RtlInitUnicodeString(&unstrFunc, L"PsSetCreateThreadNotifyRoutine"); pCheckArea = (ULONG64)MmGetSystemRoutineAddress (&unstrFunc); DbgPrint("PsSetCreateThreadNotifyRoutine: %llx",pCheckArea); for(i=pCheckArea;i<pCheckArea+0xff;i++) { if(*(PUCHAR)i==0x48 && *(PUCHAR)(i+1)==0x8d && *(PUCHAR)(i+2)==0x0d) //lea rcx,xxxx { LONG OffsetAddr=0; memcpy(&OffsetAddr,(PUCHAR)(i+3),4); return OffsetAddr+7+i; } } return 0; }void EnumCreateThreadNotify() { int i=0; BOOLEAN b; ULONG64 NotifyAddr=0,MagicPtr=0; ULONG64 PspCreateThreadNotifyRoutine=FindPspCreateThreadNotifyRoutine(); DbgPrint("PspCreateThreadNotifyRoutine: %llx",PspCreateThreadNotifyRoutine); if(!PspCreateThreadNotifyRoutine) return; for(i=0;i<64;i++) { MagicPtr=PspCreateThreadNotifyRoutine+i*8; NotifyAddr=*(PULONG64)(MagicPtr); if(MmIsAddressValid((PVOID)NotifyAddr) && NotifyAddr!=0) { NotifyAddr=*(PULONG64)(NotifyAddr & 0xfffffffffffffff8); DbgPrint("[CreateThread]%llx",NotifyAddr);PsRemoveCreateThreadNotifyRoutine(NotifyAddr); } } }宋孖健,13
?
?
?
?
總結
以上是生活随笔為你收集整理的Win64 驱动内核编程-30.枚举与删除线程回调的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win64 驱动内核编程-29.强制解锁
- 下一篇: Win64 驱动内核编程-31.枚举与删