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. CMDB项目要点总结之中控机

    1.基于paramiko对远程主机执行命令操作 秘钥形式 private_key = paramiko.RSAKey.from_private_key_file('c:/Users/用户名/.ssh/ ...

  2. Java 并发工具类 CountDownLatch、CyclicBarrier、Semaphore、Exchanger

    本文部分摘自<Java 并发编程的艺术> CountDownLatch CountDownLatch 允许一个或多个线程等待其他线程完成操作.假设现有一个需求:我们需要解析一个 Excel ...

  3. .net core 和 WPF 开发升讯威在线客服系统【私有化部署免费版】发布

    希望 .net 和 WPF 技术时至今日,还能有一些存在感. 这个项目源于2015年前后,当时开发的初版,我使用了 ASP.NET MVC 做为后端,数据库使用原生 ADO.NET 进行操作.WPF ...

  4. 思维导图趋势大分析(MindMaster与百度脑图)

    思维导图现在可以说是大流行期间,涉及学习.工作.生活方方面面的内容. 一.什么是思维导图 思维导图的英文名称是The Mind Map,也叫做心智导图,脑图,心智地图,脑力激荡图等.思维导图应用图文兼 ...

  5. Android Studio 安装及配置

    安装时的那些事 •相关链接 [1]:无需翻墙的链接 [2]:Android Studio 安装教程 •从安装到放弃??? 初次接触 Android,并知道了开发 Android APP 的软件--An ...

  6. C语言之通讯录的模拟实现

    C语言之通讯录的模拟实现 在C语言学习结束之际,谨以此篇文章来对C语言的学习告一段落. 纲要: 通讯录的静态版本 通讯录的动态版本 通讯录的带文件版本 因为三种实现方法除了储存形式不同,其他都基本相同 ...

  7. 第一次OOP作业-Blog总结

    前言 第一次作业一共八道题,此次作业也是这三次作业中最接近面向过程程序设计的题目集,整体难度偏低,总耗时1.5h,主要的知识点在熟悉Java的语法上,整体题目的逻辑非常清晰简单,但最后一个判断三角形类 ...

  8. [.net] 关于Exception的几点思考和在项目中的使用(一)

    本文链接 https://www.cnblogs.com/hubaijia/p/about-exceptions-1.html 关于exception的基本语法和作用,这里不再赘述,下面记录一下我在项 ...

  9. oo第二单元——多线程魔鬼电梯

    在初步认识了面向对象思想后,立刻进入了多线程的学习,本单元的难点主要是锁的理解,需要保证线程安全的同时防止死锁的发生,也要尽可能缩小锁的范围,提高性能.这一单元以电梯为载体,让我们从生活出发,从电梯运 ...

  10. BBR拥塞算法的简单解释

    TCP BBR的ACM论文中,开篇就引入了图1,以此来说明BBR算法的切入点: 为何当前基于丢包探测的TCP拥塞控制算法还有优化空间? BBR算法的优化极限在哪儿? 图1 为了理解这张图花了我整整一个 ...