这几天研究这个SsdtHook,总的来说遇到了很多意想不到的问题,都在意料之外,在网上找了很多有关的资料和代码,最后搭建起了SsdtHook框架,在学习SsdtHook的同时也学到了很多其他方面的知识,由于白天要上班,只有晚上有点时间,在这里就先不去单步去调试了,先贴上代码,通过编译,通过验证,代码没问题,在此也贴上测试功能的应用程序,并说说可能会碰到的问题;
SsdtHook.h文件:
typedef struct ServiceDescriptorEntry {
unsigned int*ServiceTableBase; //指向系统服务程序的地址(SSDT)
unsigned int*ServiceCounterTableBase; //指向另一个索引表,该表包含了每个服务表项被调用的次数;不过这个值只在Checkd Build的内核中有效,在FreeBuild的内核中,这个值总为NULL
unsigned intNumberOfServices; //表示当前系统所支持的服务个数
unsigned char*ParamTableBase; //指向SSPT中的参数地址,它们都包含了NumberOfService这么多个数组单元
} ServiceDescriptorTableEntry ,*PServiceDescriptorTableEntry;
extern PServiceDescriptorTableEntryKeServiceDescriptorTable;//KeServiceDescriptorTable为导出函数
typedef NTSTATUS(*NTTERNIMATEPROCESS)(
IN HANDLE ProcessHandle,
IN NTSTATUS ExitStatus
); //定义一个函数指针
NTTERNIMATEPROCESSpRealNtTerminateAddr;
UCHAR *PsGetProcessImageFileName( IN PEPROCESS Process);
BOOLEAN IsProtect(CHAR *temp) ;
NTSTATUS MyNtTerminateProcess(IN HANDLE ProcessHandle, INNTSTATUS ExitStatus);
VOID Hook() ;
VOID Unhook() ;
VOID OnUnload(IN PDRIVER_OBJECTDriverObject) ;
SsdtHook.cpp文件:
#include<ntddk.h>
#include "SsdtHook.h"
ULONGRealServiceAddress; //接受被hook的函数地址
CHAR *TerminateName ="notepad.exe"; //这里就是我们的进程名
BOOLEAN IsProtect(CHAR*temp) //判断正在结束的进程是否是我们要保护的进程
{
ULONG len = strcmp(TerminateName,temp);
if(!len)
returnTRUE;
return FALSE;
}
NTSTATUS MyNtTerminateProcess(IN HANDLE ProcessHandle, INNTSTATUSExitStatus)//我们自己的NtTerminateProcess
{
PEPROCESS process; //接受通过ProcessHandle返回的进程
NTSTATUSstatus;
CHAR*pName; //接受进程的进程名
status =ObReferenceObjectByHandle(ProcessHandle,
FILE_READ_DATA,0,KernelMode,&process,NULL); //获取进程 ..也就是要正在要被操作的进程;
if(!NT_SUCCESS(status))
return(NTSTATUS)(NTTERNIMATEPROCESS)pRealNtTerminateAddr(ProcessHandle,ExitStatus);
pName =(CHAR*)PsGetProcessImageFileName(process);//获取进程名
if(IsProtect(pName))//判断是否是我们要保护的进程,是则返回权限不足,否则调用原函数结束进程
{
if(process !=PsGetCurrentProcess())
{
returnSTATUS_ACCESS_DENIED;
}
}
return(NTSTATUS)(NTTERNIMATEPROCESS)pRealNtTerminateAddr(ProcessHandle,ExitStatus);
}
VOID Hook()
{
ULONG Address;
Address =(ULONG)KeServiceDescriptorTable->ServiceTableBase +0x101 * 4; // 2003 0x10A
RealServiceAddress =*(ULONG*)Address;
pRealNtTerminateAddr =(NTTERNIMATEPROCESS)RealServiceAddress;
__asm{//去掉内存保护
cli
moveax,cr0
and eax,not10000h
movcr0,eax
}
*((ULONG*)Address) = (ULONG)MyNtTerminateProcess;//替换为我们自己的NtTerminateProcess函数
__asm{//恢复内存保护
moveax,cr0
oreax,10000h
movcr0,eax
sti
}
}
VOID Unhook()
{
ULONG Address;
Address =(ULONG)KeServiceDescriptorTable->ServiceTableBase +0x101 * 4; // 2003 0x10A
__asm{
cli
moveax,cr0
and eax,not10000h
movcr0,eax
}
*((ULONG*)Address) =(ULONG)RealServiceAddress;
__asm{
moveax,cr0
oreax,10000h
movcr0,eax
sti
}
}
VOID OnUnload(IN PDRIVER_OBJECTDriverObject)
{
DbgPrint("Unhookerunload!");
Unhook();
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECTDriverObject,PUNICODE_STRING RegistryPath)
{
DriverObject->DriverUnload =OnUnload;
DbgPrint("Unhookerload");
Hook();
return STATUS_SUCCESS;
}
这个SsdtHook代码是最简单的代码,是根据进程名实现进程保护的,写的很简单,同时功能也不强大,只能对特定的进程进行保护。
我现在正在研究根据在应用层输入任何一个用户进程ID号就可以保护相应的进程,这样的效果功能就稍稍强大一点了,不过代码还在调试过程中,由于才学驱动不久,对驱动和应用层的通信还不太了解,故碰到了点点小困难,不过这二天可以应该搞定,呵呵。下面贴下应用层代码,进程对进程的打开的关闭工作。其实我们也可以直接对进程管理器操作也行,也可以验证驱动的功能,看进程是否删不掉就行了。我创建的是MFC工程;
打开进程
PROCESS_INFORMATION pi;
void CMFCDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
STARTUPINFO si = {sizeof(si)};
BOOL bStat = CreateProcess(NULL, "notepad.exe ",NULL,NULL,
TRUE,0,NULL,NULL,&si,&pi );
}
关闭进程:
void CMFCDlg::OnBnClickedButton2()
{
BOOL bStat =TerminateProcess(pi.hProcess,0);
}
在用VS2005编译器可能会碰到下面二个问题,都是工程设置问题。
第一就是生成的可执行文件放到虚拟机中却运行不了,提示工程配制出错,在这里我们要这么设置一下就行了,
属性-》常规-》MFC的使用。。。。把这项设置成“在静态库中使用MFC”
第二个问题就是编译这个应用程序的时候会出现 error C2664:'CreateProcessW' : cannot convert parameter 2 from 'const char[15]' to 'LPWSTR';。。。。。这时我会同样打开 属性-》常规-》字符集设置成“未设置”就行了。