ring0 ShadowSSDTHook
SSDT:主要处理 Kernel32.dll中的系统调用,如openProcess,ReadFile等,主要在ntoskrnl.exe中实现(微软有给出 ntoskrnl源代码)
ShadowSSDT: 1.主要处理,user32.dll,GDI32.dll中调用的函数,如postMessage,SendMessage,FindWindow,主要在win32k.sys中实现.(微软未给出win32k代码)
2.需要注意的是shadowSSDT并未导出,可用ida在win32k.sys中的导出表搜索,且结构与ssdt相似,但是不能通过windbg dd命令查看值
3.ShadowSSDT表只能在GUI(即有界面的程序进程)环境下才有值,故我们需要调用KeAttachProcess来切换到GUI线程里。
4.用windbg 命令 .process 861ff020 (861ff020 是通过 命令 !process 0 0得到的)切换到GUI线程上下文
过程:1)(输入windbg命令 ) !process 0 0得到其中一个有 图形界面的程序
(数据如下)
PROCESS 861ff020 SessionId: 0 Cid: 0b58 Peb: 7ffde000 ParentCid: 05e4
DirBase: 10080380 ObjectTable: e1dd2808 HandleCount: 73.
Image: windbg.exe
2) (输入命令)
lkd> .process 861ff020
Implicit process is now 861ff020
(切换成功 )
3) 切换成功后,使用dd KeServiceDescriptorTableShadow即可得到该表数据,否则无法得到,得到数据如下
lkd> dd KeServiceDescriptorTableShadow
80553f60 80502b8c 00000000 0000011c 80503000--〉SSDT
80553f70 bf999b80 00000000 0000029b bf99a890 --〉ShadowSSDT
80553f80 00000000 00000000 00000000 00000000
80553f90 00000000 00000000 00000000 00000000
80553fa0 80502b8c 00000000 0000011c 80503000
80553fb0 00000000 00000000 00000000 00000000
80553fc0 00000000 00000000 00000000 00000000
80553fd0 00000000 00000000 00000000 00000000
其实KeServiceDescriptorTableShadow 包含4个系统服务表,但是我们只用前2个(SSDT,ShadowSSDT)
4) 总结:
1) ShadowSSDT在KeServiceDescriptorTableShadow[1]中,而KeServiceDescriptorTableShadow[0]为ssdt
2)如果要查看win32k服务,必须要切换到GUI线程上下文
5.如何得到ShadowSSDT地址:在insight source中可查询到wrk中有KeAddSystemServiceTable函数,里面有对KeServiceDescriptorTableShadow 的调用
思路:利用搜索特征码的方式搜索KeAddSystemServiceTable,取出KeServiceDescriptorTableShadow
64位
HOOK 和 UNHOOK SHADOW SSDT 跟之前的 HOOK/UNHOOK SSDT 类似,区别是查找SSSDT的特征码,以及根据索引计算函数地址的公式,还有一个就是吧跳转函数写在什么位置,SSDT的时候是写在蓝屏函数里了。
一、获得 w KeServiceDescriptorTableShadow的地址
这个跟获得 KeServiceDescriptorTable 差不多,唯一不同就是特征码:
#include "ShadowSSDTHook.h" int NtUserFindWindowExIndex = ; pfnNtUserFindWindowEx OldNtUserFindWindowEx = NULL; //ShadowSSDT
PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorShadowTable; NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegisterPath)
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status;
int i = ; PEPROCESS EProcess; UNICODE_STRING DeviceName;
UNICODE_STRING LinkName; RtlInitUnicodeString(&DeviceName,DEVICE_NAME);
RtlInitUnicodeString(&LinkName,LINK_NAME); //创建设备对象; Status = IoCreateDevice(DriverObject,,
&DeviceName,FILE_DEVICE_UNKNOWN,,FALSE,&DeviceObject);
if (!NT_SUCCESS(Status))
{
return Status;
} Status = IoCreateSymbolicLink(&LinkName,&DeviceName); for (i = ; i<IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = DefaultPassThrough;
} DriverObject->DriverUnload = UnloadDriver; KeServiceDescriptorShadowTable = GetShadowTableAddress();
if (KeServiceDescriptorShadowTable)
{
if (LookupProcessByName("explorer.exe", &EProcess) == STATUS_SUCCESS)
{
KeAttachProcess(EProcess);//附加到目标进程 HookShadowSSDTTable(&KeServiceDescriptorShadowTable[],
&NtUserFindWindowExIndex,
&(ULONG_PTR)OldNtUserFindWindowEx,
(ULONG_PTR)FakeNtUserFindWindowEx); KeDetachProcess();//解除附加
} } #ifdef WIN64
// __asm
// {
// xchg rax,rbx
// }
DbgPrint("WIN64: ShadowSSDTHook IS RUNNING!!!");
#else
// __asm
// {
// xor eax,eax
// }
DbgPrint("WIN32: ShadowSSDTHook SIS RUNNING!!!"); #endif return STATUS_SUCCESS;
} NTSTATUS
DefaultPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = ;
IoCompleteRequest(Irp,IO_NO_INCREMENT); return STATUS_SUCCESS;
} VOID
UnloadDriver(PDRIVER_OBJECT DriverObject)
{
PEPROCESS EProcess; UNICODE_STRING LinkName;
PDEVICE_OBJECT NextDeviceObject = NULL;
PDEVICE_OBJECT CurrentDeviceObject = NULL;
RtlInitUnicodeString(&LinkName,LINK_NAME); IoDeleteSymbolicLink(&LinkName);
CurrentDeviceObject = DriverObject->DeviceObject;
while (CurrentDeviceObject != NULL)
{ NextDeviceObject = CurrentDeviceObject->NextDevice;
IoDeleteDevice(CurrentDeviceObject);
CurrentDeviceObject = NextDeviceObject;
} KeServiceDescriptorShadowTable = GetShadowTableAddress();
if (KeServiceDescriptorShadowTable)
{
//获取一个gui线程的进程对象。
if (LookupProcessByName("explorer.exe", &EProcess) == STATUS_SUCCESS)
{
KeAttachProcess(EProcess);//附加到目标进程
UnHookShadowSSDTTable(&KeServiceDescriptorShadowTable[],
&NtUserFindWindowExIndex, (ULONG_PTR)OldNtUserFindWindowEx); KeDetachProcess();//解除附加
}
} DbgPrint("ShadowSSDTHook IS STOPPED!!!");
} PVOID
GetShadowTableAddress()
{
ULONG_PTR ulData = ;
ULONG_PTR i = ;
PUCHAR Temp = (PUCHAR)KeAddSystemServiceTable; //类似王艳萍的内存修改器做法
//扫描特征码
for (i = ; i<; i++, Temp++)
{
__try
{
ulData = *(ULONG_PTR*)Temp;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return FALSE;
} if (MmIsAddressValid((PVOID)ulData))
{
if (memcmp((PVOID)ulData, KeServiceDescriptorTable, ) == )
{
if ((PVOID)ulData == KeServiceDescriptorTable) //排除SSDT
{
continue;
} return (PVOID)ulData;
}
}
} return FALSE;
} NTSTATUS LookupProcessByName(
IN PCHAR ProcessName,
OUT PEPROCESS *EProcess
)
{
NTSTATUS status;
ULONG uCount = ;
ULONG uLength = ;
PLIST_ENTRY ListActiveProcess;
PEPROCESS CurrentEProcess = NULL;
ULONG ulNextProcess = ;
ULONG g_Offset_Eprocess_Flink = 0x88; //XP操作系统
char lpszProName[];
char *lpszAttackProName = NULL; uLength = strlen(ProcessName); CurrentEProcess = PsGetCurrentProcess();
ulNextProcess = (ULONG)CurrentEProcess; __try
{
memset(lpszProName, , sizeof(lpszProName));
if (uLength > )
{
strncat(lpszProName, ProcessName, );
}
while ()
{
lpszAttackProName = NULL;
lpszAttackProName = (char *)PsGetProcessImageFileName(CurrentEProcess); if (uLength > )
{
if (lpszAttackProName && strlen(lpszAttackProName) == uLength)
{
if (_strnicmp(lpszProName, lpszAttackProName, uLength) == )
{
*EProcess = CurrentEProcess;
status = STATUS_SUCCESS;
break;
}
}
}
else
{
if (lpszAttackProName && strlen(lpszAttackProName) == uLength)
{
if (_strnicmp(ProcessName, lpszAttackProName, uLength) == )
{
*EProcess = CurrentEProcess;
status = STATUS_SUCCESS;
break;
}
}
}
if ((uCount >= ) && (ulNextProcess == (ULONG)CurrentEProcess))
{
*EProcess = 0x00000000;
status = STATUS_NOT_FOUND;
break;
}
ListActiveProcess = (LIST_ENTRY *)((ULONG)CurrentEProcess + g_Offset_Eprocess_Flink);
(ULONG)CurrentEProcess = (ULONG)ListActiveProcess->Flink;
(ULONG)CurrentEProcess = (ULONG)CurrentEProcess - g_Offset_Eprocess_Flink;
uCount++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("LookupProcessByName:%08x\r\n", GetExceptionCode()));
status = STATUS_NOT_FOUND;
}
return status;
} BOOLEAN HookShadowSSDTTable(PSERVICE_DESCRIPTOR_TABLE ServiceDescriptorShadowSSDTTable,
int *Index, ULONG_PTR *OldFuctionAddress,
ULONG_PTR FakeFuctionAddress)
{
BOOLEAN bRetOK = FALSE; __try
{
//检查
if (MmIsAddressValid(ServiceDescriptorShadowSSDTTable) &&
MmIsAddressValid(ServiceDescriptorShadowSSDTTable->ServiceTable))
{
//检查*index是否在表的有效范围
if (*Index >= && *Index <(int)ServiceDescriptorShadowSSDTTable->TableSize)
{
//保存原始函数,因为我们的hook过滤函数需要用到。
*OldFuctionAddress = ServiceDescriptorShadowSSDTTable->ServiceTable[*Index]; WPOFF();
InterlockedExchange(&ServiceDescriptorShadowSSDTTable->ServiceTable[*Index],
FakeFuctionAddress);
bRetOK = TRUE;
WPON();
}
} }
__except (EXCEPTION_EXECUTE_HANDLER) { }
return bRetOK; } NTSTATUS FakeNtUserFindWindowEx(ULONG_PTR hWndParent, ULONG_PTR hWndChild, PUNICODE_STRING uniClassName,
PUNICODE_STRING uniWindowName, ULONG_PTR Type)
{
char* ProcessName = NULL;
PEPROCESS EProcess;
EProcess = IoGetCurrentProcess(); ProcessName = PsGetProcessImageFileName(EProcess);
//进行过滤
if (strstr(ProcessName, "Test.exe") != NULL)
{
DbgPrint("HookFindWindow\r\n");
return STATUS_SUCCESS;
} return OldNtUserFindWindowEx(hWndParent, hWndChild, uniClassName, uniWindowName, Type); } //去掉内存保护
void WPOFF()
{
__asm {
cli
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
}
//恢复内存保护
void WPON()
{
__asm {
mov eax, cr0
or eax, 10000h
mov cr0, eax
sti
}
} BOOLEAN UnHookShadowSSDTTable(PSERVICE_DESCRIPTOR_TABLE ServiceDescriptorShadowSSDTTable,
int *Index, ULONG_PTR OldFuctionAddress)
{
BOOLEAN bRetOK = FALSE; __try
{
//检查
if (MmIsAddressValid(ServiceDescriptorShadowSSDTTable) &&
MmIsAddressValid(ServiceDescriptorShadowSSDTTable->ServiceTable))
{
//检查*index是否在表的有效范围
if (*Index >= && *Index <(int)ServiceDescriptorShadowSSDTTable->TableSize)
{
WPOFF();
InterlockedExchange(&ServiceDescriptorShadowSSDTTable->ServiceTable[*Index],
OldFuctionAddress);
bRetOK = TRUE;
WPON();
}
} }
__except (EXCEPTION_EXECUTE_HANDLER)
{ }
return bRetOK; }
#include <ntifs.h> #ifndef CXX_ShadowSSDTHook_H
#define CXX_ShadowSSDTHook_H #define DEVICE_NAME L"\\Device\\ShadowSSDTHookDevice"
#define LINK_NAME L"\\??\\ShadowSSDTHookLink" typedef struct _SERVICE_DESCRIPTOR_TABLE {
PULONG ServiceTable;
PULONG CounterTable;
ULONG TableSize;
PUCHAR ArgumentTable;
} SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE; //SSDT表
extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable; extern
UCHAR *PsGetProcessImageFileName(PEPROCESS eprocess); typedef
NTSTATUS(*pfnNtUserFindWindowEx)(ULONG_PTR hWndParent, ULONG_PTR hWndChild, PUNICODE_STRING uniClassName,
PUNICODE_STRING uniWindowName, ULONG_PTR Type); __declspec(dllimport) _stdcall KeAddSystemServiceTable(PVOID, PVOID, PVOID, PVOID, PVOID); VOID
UnloadDriver(PDRIVER_OBJECT DriverObject); PVOID GetShadowTableAddress(); NTSTATUS LookupProcessByName(IN PCHAR ProcessName, OUT PEPROCESS * EProcess); BOOLEAN HookShadowSSDTTable(PSERVICE_DESCRIPTOR_TABLE ServiceDescriptorShadowSSDTTable, int * Index, ULONG_PTR * OldFuctionAddress, ULONG_PTR FakeFuctionAddress); NTSTATUS FakeNtUserFindWindowEx(ULONG_PTR hWndParent, ULONG_PTR hWndChild, PUNICODE_STRING uniClassName, PUNICODE_STRING uniWindowName, ULONG_PTR Type); void WPOFF(); void WPON(); BOOLEAN UnHookShadowSSDTTable(PSERVICE_DESCRIPTOR_TABLE ServiceDescriptorShadowSSDTTable, int * Index, ULONG_PTR OldFuctionAddress); NTSTATUS
DefaultPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp); #endif
ring0 ShadowSSDTHook的更多相关文章
- 函数调用关于从Ring3转到Ring0 ESP堆栈变化
在ring0堆栈获取ring3堆栈方式 第一种方式 [esp+4] == [esp+参数个数*4+4] 如果这里不相等就需要用第二种方式 [[esp+参数个数*4+8]] 这里面的值就是Ring3的堆 ...
- ring0
Intel的x86处理器是通过Ring级别来进行访问控制的,级别共分4层,RING0,RING1,RING2,RING3.Windows只使用其中的两个级别RING0和RING3. RING0层拥有最 ...
- 对付ring0 inline hook
对付ring0 inline hook的基本思路是这样的,自己写一个替换的内核函数,以NtOpenProcess为例,就是MyNtOpenProcess.然后修改SSDT表,让系统服务进入自己的函数M ...
- ring0 与 ring3 层之间的交互
在进行Windows的ring0层开发时,必不可免的要与 ring3 层进行交互.进行数据间的相互传输.可用的方法有DeviceIoCntrol,ReadFile.我平常都是用的DeviceIoCon ...
- OD: Ring0 & Kernel
开发技术讲究封装与模块化,安全技术强调底层安全性.安全技术需要打开封装.追根溯源! <0day 安全:软件漏洞分析技术(第2版)> 第21章 探索 Ring0 笔记 Intel x86 系 ...
- Ring3 和Ring0 解释
这得从CPU指令系统(用于控制CPU完成各种功能的命令)的特权级别说起.在CPU的所有指令中,有一些指令是非常危险的,如果错用,将导致整个系统崩溃.比如:清内存.设置时钟等.如果所有的程序都能使用这些 ...
- [原创]浅谈NT下Ring3无驱进入Ring0的方法
原文链接:浅谈NT下Ring3无驱进入Ring0的方法 (测试环境:Windows 2000 SP4,Windows XP SP2.Windows 2003 未测试) 在NT下无驱进入Ring0是一个 ...
- ring0和ring3的区别
现在探讨内核程序和应用程序之间的本质区别.除了能用WDK编写内核程序和阅读一部分Windows的内核代码之外,我们还需要了解它们的本质是什么,它们和我们熟悉的应用程序有什么区别. Intel的x86处 ...
- RING0,RING1,RING2,RING3
Intel的CPU将特权级别分为4个级别:RING0,RING1,RING2,RING3.Windows只使用其中的两个级别RING0和RING3,RING0只给操作系统用,RING3谁都能用.如果普 ...
随机推荐
- 1093 字符串A+B (20 分)
给定两个字符串 A 和 B,本题要求你输出 A+B,即两个字符串的并集.要求先输出 A,再输出 B,但重复的字符必须被剔除. 输入格式: 输入在两行中分别给出 A 和 B,均为长度不超过 106 ...
- HTTP时间指标
总下载时间 监测一个页面总的消耗时间,即从开始监测到监测结束的时间. 基础页面下载时间 基础页面即WEB服务器返回的纯文本HTML文件. 网络层时间 监测一个页面时,发生网络通讯的总消耗时间.IE浏览 ...
- DOC窗口之cd命令(windows)
cd的全称是Change Directory,改变文件夹,也就是切换路径.后面可以接驱动器符号.完整路径和相对路径. 通常win+R,输入cmd,便会看到以下界面, 通常,这个命令下并没有我们想要处理 ...
- PIE SDK地图范围设置
1.功能简介 地图范围设置主要就是对图层的地图浏览控制,例如地图的放大.缩小.漫游.全图显示.1:1视图.比例尺等功能,能更好的与地图有一个互动的地图浏览体验.PIE SDK对地图范围设置主要利用IC ...
- Yii2 场景scenario的应用
首先,我们在使用模型类中的验证,rules的时候,会出现以下情况: 假设有一个字段type, 当type
- rancher初级(搭建+基本操作+web应用部署)
Rancher搭建 首先rancher需要安装了docker的linux环境,我的系统版本为 在docker的基础上启动rancher服务器,Rancher 服务器是一个 Docker image,所 ...
- Linux——【rpm、yun、源码包】安装
RPM包或者安装源码包 在windows下安装一个软件很轻松,只要双击.exe的文件,安装提示连续“下一步”即可,然而linux系统下安装一个软件似乎并不那么轻松,因为我们不是在图形界面下.所以我们要 ...
- 第二十一章:deploy and live updates
通常我们开发一个app之后,需要把他们放到对应的应用商店上去以供下载.在此期间,需要经过应用商店的审核,包括初次上传和更新上传.短则需要数天,多则需要几个星期,这对于我们的快速产品迭代和hotfix来 ...
- linux文件夹权限问题
linux下 ls 某文件夹需要文件夹有 r 读权限. cd 某文件夹 需要文件夹有 x 运行权限 参考: http://www.linuxidc.com/Linux/2016-11/136959.h ...
- html 复选框checkbox
统计选中复选框的个数 <html> <head> <title> </title> <script> function static_num ...