Win64 驱动内核编程-22.SHADOW SSDT HOOK
2017-03-26 11:51
441 查看
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*8 W32pServiceTable=(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;
}
R0的代码:
#pragma intrinsic(__readmsr)
typedef struct _SYSTEM_SERVICE_TABLE{
PVOID ServiceTableBase;
PVOID ServiceCounterTableBase;
ULONGLONG NumberOfServices;
PVOID ParamTableBase;
} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;
typedef struct _SERVICE_DESCRIPTOR_TABLE{
SYSTEM_SERVICE_TABLE ntoskrnl; // ntoskrnl.exe (native api)
SYSTEM_SERVICE_TABLE win32k; // win32k.sys (gdi/user)
SYSTEM_SERVICE_TABLE Table3; // not used
SYSTEM_SERVICE_TABLE Table4; // not used
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE;
PSYSTEM_SERVICE_TABLE KeServiceDescriptorTableShadow = 0;
ULONG64 ul64W32pServiceTable = 0;
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; }
//在WINDBG里查看:
//ln win32k!W32pServiceTable+((poi(win32k!W32pServiceTable+4*(<syscall nbr>-1000))&0x00000000`ffffffff)>>4)-10000000
//u win32k!W32pServiceTable+((poi(win32k!W32pServiceTable+4*(Index-0x1000))&0x00000000`ffffffff)>>4)-0x10000000
//u poi(win32k!W32pServiceTable+4*(1-0x1000))
//u poi(win32k!W32pServiceTable+4*(1-0x1000))&0x00000000`ffffffff
//u (poi(win32k!W32pServiceTable+4*(1-0x1000))&0x00000000`ffffffff)>>4
//u win32k!W32pServiceTable+((poi(win32k!W32pServiceTable+4*(1-0x1000))&0x00000000`ffffffff)>>4)-0x10000000
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)); //sizeof(SYSTEM_SERVICE_TABLE)
W32pServiceTable=(ULONGLONG)(pWin32k->ServiceTableBase);
ul64W32pServiceTable = W32pServiceTable;
//DbgPrint("W32pServiceTable: %llx",W32pServiceTable);
//DbgPrint("Service Count: %lld",pWin32k->NumberOfServices);
qwTemp = W32pServiceTable + 4 * (Index-0x1000); //这里是获得偏移地址的位置,要HOOK的话修改这里即可
dwTemp = *(PLONG)qwTemp;
dwTemp = dwTemp >> 4;
qwTemp = W32pServiceTable + (LONG64)dwTemp;
return qwTemp;
}
VOID ListAllShadowFunctionAddress()
{
ULONGLONG W32pServiceTable=0, FunctionCount=0, i=0, Index=0;
ULONGLONG qwTemp=0;
LONG dwTemp;
PSYSTEM_SERVICE_TABLE pWin32k;
pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow+4*8);
W32pServiceTable=(ULONGLONG)(pWin32k->ServiceTableBase);
FunctionCount=pWin32k->NumberOfServices;
for(i=0;i<FunctionCount;i++)
{
Index = 0x1000 + i;
qwTemp = W32pServiceTable + 4 * (Index-0x1000); //DbgPrint("qwTemp: %llx",qwTemp);
dwTemp = *(PLONG)qwTemp;
dwTemp = dwTemp >> 4;
qwTemp = W32pServiceTable + (LONG64)dwTemp;
DbgPrint("Address: %llx",qwTemp);
}
}
相关文章推荐
- Win64 驱动内核编程-18.SSDT
- Win64 驱动内核编程-24.64位驱动里内嵌汇编
- Win64 驱动内核编程-31.枚举与删除映像回调
- Win64 驱动内核编程-9.系统调用、WOW64与兼容模式
- Win64 驱动内核编程-14.回调监控文件
- Win64 驱动内核编程-21.DKOM隐藏和保护进程
- Win64 驱动内核编程-27.强制读写受保护的内存
- Win64 驱动内核编程-2.基本框架(安装.通讯.HelloWorld)
- Win64 驱动内核编程-5.内核里操作文件
- Win64 驱动内核编程-7.内核里操作进程
- Win64 驱动内核编程-10.突破WIN7的PatchGuard
- Win64 驱动内核编程-19.HOOK-SSDT
- Win64 驱动内核编程-20.UnHook SSDT
- Win64 驱动内核编程-34.对抗与枚举MiniFilter
- Win64 驱动内核编程-6.内核里操作注册表
- Win64 驱动内核编程-8.内核里的其他常用
- Win64 驱动内核编程-11.回调监控进线程句柄操作
- Win64 驱动内核编程-16.WFP网络监控驱动(防火墙)
- Win64 驱动内核编程-32.枚举与删除注册表回调
- Win64 驱动内核编程-12.回调监控进线程创建和退出