Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)
SHADOW SSDT HOOK
HOOK 和 UNHOOK SHADOW SSDT 跟之前的 HOOK/UNHOOK SSDT 类似,区别是查找SSSDT的特征码,以及根据索引计算函数地址的公式,还有一个就是吧跳转函数写在什么位置,SSDT的时候是写在蓝屏函数里了。
一、获得 w KeServiceDescriptorTableShadow的地址
这个跟获得 KeServiceDescriptorTable 差不多,唯一不同就是特征码:
ULONGLONG GetKeServiceDescriptorTableShadow64() { PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);PUCHAR EndSearchAddress = StartSearchAddress + 0x500; PUCHAR i = NULL; UCHAR b1=0,b2=0,b3=0; ULONG templong=0; ULONGLONG addr=0; for(i=StartSearchAddress;i<EndSearchAddress;i++) { if( MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2) ) { b1=*i; b2=*(i+1); b3=*(i+2); if( b1==0x4c && b2==0x8d && b3==0x1d ) //4c8d1d { memcpy(&templong,i+3,4); addr = (ULONGLONG)templong + (ULONGLONG)i + 7; return addr; } } } return 0; }
二、根据 X INDEX 获得 T SSSDT 函数在内核里的地址
原理跟获得 SSDT 函数在在内核里的地址差不多,先获得 W32pServiceTable的地址,然后再获得每个函数的偏移地址,在把偏移地址与 W32pServiceTable相加。为什么下面的计算公式是 W32pServiceTable + 4 * (index-0x1000)呢?其实这只是个理解上的问题。SSDT 函数的起始 INDEX 是 0x0,SSSDT 函数的起始 INDEX 是 0x1000,但函数地址在 W32pServiceTable 是从基址开始记录
的(假设 W32pServiceTable 的地址是 0xfffff800~80000000,第 0 个函数的地址就记录在 0xfffff800~80000000,第 1 个函数的地址就记录在0xfffff800~80000004,第 2 个函数的地址就记录在 0xfffff800~80000008,以此类推)。
ULONGLONG GetSSSDTFuncCurAddr64(ULONG64 Index) { ULONGLONG W32pServiceTable=0, qwTemp=0; LONG dwTemp=0; PSYSTEM_SERVICE_TABLE pWin32k; pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE)); W32pServiceTable=(ULONGLONG)(pWin32k->ServiceTableBase); ul64W32pServiceTable = W32pServiceTable; qwTemp = W32pServiceTable + 4 * (Index-0x1000); //这里是获得偏移地址的位置,要HOOK的话修改这里即可 dwTemp = *(PLONG)qwTemp; dwTemp = dwTemp >> 4; qwTemp = W32pServiceTable + (LONG64)dwTemp; return qwTemp; }
三、修改SSSDT里的地址
还是跟 SSDT 类似,修改 W32pServiceTable+4*index 地址的 DWORD 值(偏移地址值)。
VOID ModifySSSDT(ULONG64 Index, ULONG64 Address) {ULONGLONG W32pServiceTable=0, qwTemp=0;LONG dwTemp=0;PSYSTEM_SERVICE_TABLE pWin32k;KIRQL irql;pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE)); //4*8W32pServiceTable=(ULONGLONG)(pWin32k->ServiceTableBase);qwTemp = W32pServiceTable + 4 * (Index-0x1000);dwTemp = (LONG)(Address - W32pServiceTable);dwTemp = dwTemp << 4; irql=WPOFFx64();*(PLONG)qwTemp = dwTemp;WPONx64(irql); }
第一个代理函数用机器码写成,总共就 14 个字节,前 6 字节为 ff 25 00 00 00 00,后 8 字节为第二个代理函数的地址(JMP QWORD PTR)。
VOID ModifySSSDT(ULONG64 Index, ULONG64 Address) { ULONGLONG W32pServiceTable=0, qwTemp=0; LONG dwTemp=0; PSYSTEM_SERVICE_TABLE pWin32k; KIRQL irql; pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE)); //4*8 W32pServiceTable=(ULONGLONG)(pWin32k->ServiceTableBase); qwTemp = W32pServiceTable + 4 * (Index-0x1000); dwTemp = (LONG)(Address - W32pServiceTable); dwTemp = dwTemp << 4; irql=WPOFFx64(); *(PLONG)qwTemp = dwTemp; WPONx64(irql); }
代理函数地址:
ULONG64 ProxyNtUserPostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { if( NtUserQueryWindow(hWnd,0)==MyProcessId && PsGetCurrentProcessId()!=(HANDLE)MyProcessId ) { DbgPrint("Do not fuck with me!"); return 0; } else { DbgPrint("OriNtUserPostMessage called!"); return NtUserPostMessage(hWnd,Msg,wParam,lParam); } }
注意UnHOOK就是把真正的函数地址给填写回去
VOID UNHOOK_SSSDT() { ModifySSSDT(IndexOfNtUserPostMessage, (ULONG64)NtUserPostMessage); DbgPrint("UNHOOK_SSSDT OK!"); }
执行效果测试
以下是窗口攻击函数:
int main2() { DWORD pid, wpid, i, j; HWND hWnd; gogogo: printf("pid: "); scanf("%ld", &pid); for (i = 100; i<0xffffff; i += 2) { GetWindowThreadProcessId((HWND)i, &wpid); if (wpid == pid && IsWindowVisible((HWND)i) == 1) { hWnd = (HWND)i; for (j = 0; j<0x10000; j++) { PostMessage(hWnd, j, 0, 0); } } } printf("Ok!"); getchar(); getchar(); goto gogogo; return 0; }
通过HOOK PostMessage 来保护自己不被干掉:
至于Un SSSDT HOOK 是和SSDT思路一样的,也是自己加载相关内核模块,得到一些地址,然后在通过驱动通讯,在内核里获得一些地址,最后计算出来函数的真正地址,然后把原地址填写回去(这个地方就是继续hook一遍)就行了。直接把资料相关代码粘贴过来吧:
R3的代码:
#include <stdio.h> #include <direct.h> #include <Windows.h> #include "EnumDrv.h" #include "DrvCtrl.h"HANDLE hMyDrv;void PrintAddressByIndex() { LONG64 id=0; ULONG64 addr=0; st: printf("Input index (HEX without \"0x\" like: 1000, input -1 to exit): "); scanf("%llx",&id); if (id<0) return; IoControl(hMyDrv ,CTL_CODE_GEN(0x807), &id, 8, &addr, 8); printf("%llx\n",addr); getchar(); goto st; }DWORD FileLen(char *filename) { WIN32_FIND_DATAA fileInfo={0}; DWORD fileSize=0; HANDLE hFind; hFind = FindFirstFileA(filename ,&fileInfo); if(hFind != INVALID_HANDLE_VALUE) { fileSize = fileInfo.nFileSizeLow; FindClose(hFind); } return fileSize; }CHAR *LoadDllContext(char *filename) { DWORD dwReadWrite, LenOfFile=FileLen(filename); HANDLE hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { PCHAR buffer=(PCHAR)malloc(LenOfFile); SetFilePointer(hFile, 0, 0, FILE_BEGIN); ReadFile(hFile, buffer, LenOfFile, &dwReadWrite, 0); CloseHandle(hFile); return buffer; } return NULL; }ULONG64 GetWin32kImageBase() { PIMAGE_NT_HEADERS64 pinths64; PIMAGE_DOS_HEADER pdih; char *NtosFileData=NULL; NtosFileData=LoadDllContext("c:\\win32k.dll"); pdih=(PIMAGE_DOS_HEADER)NtosFileData; pinths64=(PIMAGE_NT_HEADERS64)(NtosFileData+pdih->e_lfanew); return pinths64->OptionalHeader.ImageBase; }void GetOriAddress() { ULONG64 W32pServiceTable, Win32kBase, Win32kImageBase, Win32kInProcess=0, retv; IoControl(hMyDrv ,CTL_CODE_GEN(0x806), NULL, 0, &W32pServiceTable, 8); Win32kBase = GetWin32kBase(); CopyFileA("c:\\windows\\system32\\win32k.sys","c:\\win32k.dll",0); Win32kImageBase = GetWin32kImageBase(); printf("W32pServiceTable: %llx\n", W32pServiceTable); printf("WIN32K.SYS base: %llx\n", Win32kBase); printf("WIN32K.SYS image base: %llx\n\n\n", Win32kImageBase); ULONG index=0; if ( Win32kInProcess==0 ) Win32kInProcess = (ULONGLONG)LoadLibraryExA("c:\\win32k.dll",0, DONT_RESOLVE_DLL_REFERENCES); for(index=0;index<825;index++) //825是WIN7X64上SSSDT的函数个数 { ULONGLONG RVA=W32pServiceTable-Win32kBase; ULONGLONG temp=*(PULONGLONG)(Win32kInProcess+RVA+8*(ULONGLONG)index); ULONGLONG RVA_index=temp-Win32kImageBase; retv = RVA_index+Win32kBase; printf("Shadow SSDT Function[%ld]: %llx\n",index,retv); if(index % 100 ==0) { printf("Press any key to continue......\n"); getchar(); } } }int main() { hMyDrv=openDriver(); GetOriAddress(); uninstallDriver(); return 0; }
宋孖健,13
总结
以上是生活随笔为你收集整理的Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: Win64 驱动内核编程-21.DKOM
- 下一篇: Win64 驱动内核编程-23.Ring