SHADOW表地址的获取。
CSRSS进程。system进程并没有载入win32k.sys,所以,要访问shadowssdt表,必须KeStackAttackProces到一个有GUI线程的进程中,而csrss.exe就是这样的一个合适的进程(管理Windows图形相关任务)
Index?硬编码
挂钩NtGdiBitBlt、NtGdiStretchBlt用于截屏保护
挂钩NtUserSetWindowsHookEx 保护键盘钩子
http://blog.csdn.net/evi10r/article/details/6932607
CSRSS进程。system进程并没有载入win32k.sys,所以,要访问shadowssdt表,必须KeStackAttackProces到一个有GUI线程的进程中,而csrss.exe就是这样的一个合适的进程(管理Windows图形相关任务)
Index?硬编码
挂钩NtGdiBitBlt、NtGdiStretchBlt用于截屏保护
挂钩NtUserSetWindowsHookEx 保护键盘钩子
http://blog.csdn.net/evi10r/article/details/6932607
http://blog.csdn.net/lionzl/article/details/7735483
代码:
#include "ShadowSsdt.h"
#pragma pack(1)
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only in checked build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t;
#pragma pack()
__declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
REAL_NtGdiStretchBlt real_NtGdiStretchBlt;
REAL_NtGdiBitBlt real_NtGdiBitBlt;
ULONG GetAddressOfShadowTable()
{
ULONG i;
UCHAR* p;
ULONG dwordatbyte;
UNICODE_STRING usKeAddSystemServiceTable;
RtlInitUnicodeString(&usKeAddSystemServiceTable, L"KeAddSystemServiceTable");
p = (UCHAR*)MmGetSystemRoutineAddress(&usKeAddSystemServiceTable);
for (i = 0; i < 4096; i++,p++)
{
__try
{
dwordatbyte = *(ULONG*)p;
}__except(EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}
if(MmIsAddressValid((PVOID)dwordatbyte))
{
if(memcmp((PVOID)dwordatbyte, &KeServiceDescriptorTable, 16) == 0) //比较的是地址指向的内容
{
if((PVOID)dwordatbyte == &KeServiceDescriptorTable)
{
continue;
}
return dwordatbyte;
}
}
}
return 0;
}
PDWORD NtGdiStretchBltAddr;
PDWORD NtGdiBitBltAddr;
BOOL flag = FALSE;
void StartHookShadow (void)
{
DWORD SSDTShadowBaseAddr=GetAddressOfShadowTable()+0x10;//表基址所在地址
DWORD TableCount=SSDTShadowBaseAddr+0x8;//函数数量所在地址
DWORD dwCount=*((PDWORD)TableCount);
PDWORD Fun_Addr=(PDWORD)(*((PDWORD)SSDTShadowBaseAddr));
KdPrint(("ssdt shadow addr:0x%X = 0x%X= 0x%X",SSDTShadowBaseAddr,
*(PDWORD)SSDTShadowBaseAddr,Fun_Addr));
KdPrint(("数量是:%d",dwCount));
if (!MmIsAddressValid(Fun_Addr))
{
KdPrint(("Fun_Addr地址不可访问%X!",Fun_Addr));
return;
}
NtGdiStretchBltAddr=Fun_Addr+292;
NtGdiBitBltAddr=Fun_Addr+13;
KdPrint(("NtGdiStretchBltAddr:%X",NtGdiStretchBltAddr));
KdPrint(("NtGdiBitBltAddr:%X",NtGdiBitBltAddr));
//Fun_Addr是KeServiceDescriptorTable表的首地址,但是一用*Fun_Addr就出现0x50的蓝屏代码
//0x50 PAGE_FAULT_IN_NONPAGED_AREA Parameters 分页内存读取错误,但是这里没分配分页内存呢。
KdPrint(("*Fun_Addr:%X",*Fun_Addr));
//保存原函数地址,SSDT HOOK是根据ZW函数地址硬编码得出的索引得到的函数地址
real_NtGdiStretchBlt&