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;
}

宋孖健,13

Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)的更多相关文章

  1. Win64 驱动内核编程-20.UnHook SSDT

    UNHOOK SSDT 要恢复 SSDT,首先要获得 SSDT 各个函数的原始地址,而 SSDT 各个函数的原始地址,自然是存储在内核文件里的.于是,有了以下思路: 1.获得内核里 KiService ...

  2. Win64 驱动内核编程-23.Ring0 InLineHook 和UnHook

    Ring0 InLineHook 和UnHook 如果是要在R0里hook,作者的建议是InLine HOOK,毕竟SSDT HOOK 和 SHADOW SSDT HOOK比较麻烦,不好修改.目前R3 ...

  3. Win64 驱动内核编程-32.枚举与删除注册表回调

    枚举与删除注册表回调 注册表回调是一个监控注册表读写的回调,它的效果非常明显,一个回调能实现在SSDT 上 HOOK 十几个 API 的效果.部分游戏保护还会在注册表回调上做功夫,监控 service ...

  4. Win64 驱动内核编程-34.对抗与枚举MiniFilter

    对抗与枚举MiniFilter MiniFilter 是目前杀毒软件用来实现"文件系统自我保护"和"文件实时监控"的方法. 由于 MiniFilter 模型简单 ...

  5. Win64 驱动内核编程-31.枚举与删除映像回调

    枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...

  6. Win64 驱动内核编程-30.枚举与删除线程回调

    枚举与删除线程回调 进程回调可以监视进程的创建和退出,这个在前面的章节已经总结过了.某些游戏保护的驱动喜欢用这个函数来监视有没有黑名单中的程序运行,如果运行则阻止运行或者把游戏退出.而线程回调则通常用 ...

  7. Win64 驱动内核编程-29.强制解锁文件

    强制解锁文件 强制解锁因其他进程占用而无法删除的文件. 1.调用 ZwQuerySystemInformation 的 16 功能号来枚举系统里的句柄 2.打开拥有此句柄的进程并把此句柄复制到自己的进 ...

  8. Win64 驱动内核编程-18.SSDT

    SSDT 学习资料:http://blog.csdn.net/zfdyq0/article/details/26515019 学习资料:WIN64内核编程基础 胡文亮 SSDT(系统服务描述表),刚开 ...

  9. Win64 驱动内核编程-7.内核里操作进程

    在内核里操作进程 在内核里操作进程,相信是很多对 WINDOWS 内核编程感兴趣的朋友第一个学习的知识点.但在这里,我要让大家失望了,在内核里操作进程没什么特别的,就标准方法而言,还是调用那几个和进程 ...

随机推荐

  1. vue-cli脚手架安装及注意事项

    1.下载nodejs 链接:https://nodejs.org/en/直接下载电脑对应的版本即可. 13.5网上说不大稳定(一个表示①推荐用户版本,②最新版本) 2.安装nodejs 建议在D或者E ...

  2. 面试现场:说说char 和 varchar的区别你了解多少?

    Hi,大家好!我是白日梦!本文是MySQL专题的第 26 篇. 下文还是白日梦以自导自演的方式,围绕"说说char 和 varchar的区别你了解多少?"展开本话题.看看你能抗到第 ...

  3. String 类的内存 解析

    关于String类的内存解析 Person类的内存解析

  4. P1047_校门外的树(JAVA语言)

    题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米. 我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置: 数轴上的每个整数点,即0,1,2,-,L都种 ...

  5. Java例题_31 逆序输出数组的值

    1 /*31 [程序 31 数组逆序] 2 题目:将一个数组逆序输出. 3 程序分析:用第一个与最后一个交换. 4 */ 5 6 /*分析 7 * 第一种方法:找到这个数组的中间下标,然后交换两端的数 ...

  6. Codeforces1114C. Trailing Loves (or L'oeufs?)-(质因子分解)

    题目大意: 求n!转化为b进制后后导0的个数 思路: 我们首先考虑十进制转化为二进制者后,后导0的个数如何求 十进制数num y = num%2 num/=2 如果y为0则,该位为0,就是求num能连 ...

  7. 从网络请求过程看OkHttp拦截器

    前言 之前我们结合设计模式简单说了下OkHttp的大体流程,今天就继续说说它的核心部分--拦截器. 因为拦截器组成的链其实是完成了网络通信的整个流程,所以我们今天就从这个角度说说各拦截器的功能. 首先 ...

  8. 第18 章 : Kubernetes 调度和资源管理

    Kubernetes 调度和资源管理 这节课主要讲三部分的内容: Kubernetes 的调度过程: Kubernetes 的基础调度能力(资源调度.关系调度): Kubernetes 高级调度能力( ...

  9. Python基础(二十):面向对象“类”第三课——类成员

    知识点: 类属性与实例属性: 类方法与实例方法: 静态方法: 类属性与实例属性 类属性与实例属性的区别 属性的绑定不同 类属性与当前类相关(绑定的是当前类),与当前类创建的任何对象无关: 实例属性与当 ...

  10. Python简单实现杨辉三角

    n=input("请输入要打印的行数")n=int(n)for x in range(0,n+1): p=1 print(''.rjust(n-x),end="" ...