SSDT HOOK

打造自己的HOOK引擎 之一 --- SSDT HOOK引擎

SSDT HOOK已经是老生常谈的话题了,这里我就不对其进行介绍了,其实HOOK技术已经被大牛们分析的淋漓尽致,无以复加了,我也只是个初学者,失误之处,还望大牛们多多指教

读者可以通过后面的参考连接得到更多的关于SSDT HOOK的信息
我就相当于在这里对论坛的关于SSDT的精华贴做个总结了 呵呵

【原创】扫盲贴,HOOK SSDT 短文一篇。 
【原创】分享比较完整的ROOTKIT DEMO! 原来Shadow Hook和SSDT Hook一样容易!
【原创】SSDT Hook的妙用-对抗ring0 inline hook 
【原创】寻找原始表,恢复 ssdt 表 
【原创】RootKit hook之[二] SSDT hook 
【原创】用DDDK编写驱动,修改SSDT表HOOK NTDebugActiveProcess函数
【转帖】城里城外看SSDT 

关于HOOK的文章实在是太多了,但是不同的文章由于作者的不同,导致文章的写作风格不同,代码的风格也各不相同,这样就导致了同样的技术,不同的作者用代码表现出来的形式却大相径庭,这样对我们初学者来讲实在是很不方便,于是便有了打造自己的HOOK引擎的想法,将技术细节封装起来,因为这个本来就不用去修改,需要修改的仅仅是用户自定义的HOOK例程

这个也就是我的HOOK引擎的基本思想,将HOOK的具体实现封装在引擎中,用户想HOOK某个函数时,不用去想HOOK的技术细节了,直接编写自己的HOOK函数然后调用引擎提供的某个接口即可

因为是第一次写,就写个最简单的,SSDT的HOOK
譬如如果用户想把NtOpenProcess HOOK成自己的MyNtOpenProcess
用户只需要在DriverEntry中调用HookService((ULONG)ZwOpenProcess, (ULONG)MyNtOpenProcess)
然后编写自己的钩子函数即可 接口很简单也易于实现

这里是个调用的例子

代码:
// Unload例程 卸载钩子
VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
  KdPrint(("Unload Routine.\n"));
  UnHookService((ULONG)ZwSetInformationFile);
  UnHookService((ULONG)ZwOpenProcess);
}

// DriverEntry例程 初始化并安装钩子
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
           IN PUNICODE_STRING RegistryPath)
{
  DriverObject->DriverUnload = Unload;
  InitServicesTable();
  HookService((ULONG)ZwSetInformationFile, (ULONG)MyZwSetInformationFile);
  HookService((ULONG)ZwOpenProcess, (ULONG)MyNtOpenProcess);

  return STATUS_SUCCESS;
}
然后只需要关注自己的函数了,如下编写了两个示例,第一个例子HOOK了ZwSetInformationFile保护test.txt文件不被删除,第二个例子HOOK了NtOpenProcess保护PID大于1000的进程不被结束,代码都是参考前人的,我只是在这里做个总结罢了

代码:
// 定义HOOK的函数原型
typedef
NTSTATUS
(__stdcall *ZWSETINFORMATIONFILE)(IN HANDLE FileHandle,
          OUT PIO_STATUS_BLOCK IoStatusBlock,
          IN PVOID FileInformation,
          IN ULONG Length,
          IN FILE_INFORMATION_CLASS FileInformationClass);
typedef
NTSTATUS
(__stdcall *NTOPENPROCESS)( OUT PHANDLE ProcessHandle,
          IN ACCESS_MASK AccessMask,                                           
          IN POBJECT_ATTRIBUTES ObjectAttributes,                                           
          IN PCLIENT_ID ClientId);

// 对于ntddk.h中未定义的函数
// 可以根据<<Undocument>>一书在这里给出定义
NTSYSAPI
NTSTATUS
NTAPI 
ZwOpenProcess( OUT PHANDLE ProcessHandle,
         IN ACCESS_MASK AccessMask,                                           
         IN POBJECT_ATTRIBUTES ObjectAttributes,
               IN PCLIENT_ID ClientId);

// ==============================================================
// 用户自定义HOOK例程
NTSTATUS MyZwSetInformationFile(IN HANDLE FileHandle,
        OUT PIO_STATUS_BLOCK IoStatusBlock,
        IN PVOID FileInformation,
        IN ULONG Length,
        IN FILE_INFORMATION_CLASS FileInformationClass)
{
  PFILE_OBJECT pFileObject;

  // 在OldServiceAddressTable中取出原服务函数地址
  ZWSETINFORMATIONFILE OldZwSetInformationFile = 
    (ZWSETINFORMATIONFILE)OldServiceAddressTable[SERVICE_ID(ZwSetInformationFile)];
  
  NTSTATUS ret = ObReferenceObjectByHandle(FileHandle, 
             GENERIC_READ,
             *IoFileObjectType, 
             KernelMode, 
             (PVOID*)&pFileObject, 
             0); 
  if(NT_SUCCESS(ret))
  {
    KdPrint(("%S opened.\n", pFileObject->FileName.Buffer));
    if (wcsstr(pFileObject->FileName.Buffer, L"test.txt"))
    {
      KdPrint(("test.txt opened. Deny it.\n"));
      return STATUS_ACCESS_DENIED;
    }
  }
      ObDereferenceObject(pFileObject);  
  // 调用原服务函数
  return OldZwSetInformationFile( FileHandle, IoStatusBlock, FileInformation, 
          Length, FileInformationClass);
}

NTSTATUS MyNtOpenProcess(OUT PHANDLE ProcessHandle,
       IN ACCESS_MASK DesiredAccess,
       IN POBJECT_ATTRIBUTES ObjectAttributes,
       IN PCLIENT_ID ClientId )
{
  NTSTATUS rc;
  ULONG PID;

  KPROCESSOR_MODE PreMode;

  
  NTOPENPROCESS OldNtOpenProcess = 
    (NTOPENPROCESS)OldServiceAddressTable[SERVICE_ID(ZwOpenProcess)];

  PreMode = ExGetPreviousMode();
  if(PreMode != KernelMode)
  {
    __try
    {
      ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
      return GetExceptionCode();
    }
  }

  if(ClientId != NULL)
  {
    PID = (ULONG)ClientId->UniqueProcess;
        if(PID > 1000)
        {
      return STATUS_ACCESS_DENIED;
        }
  }
  return OldNtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}
上面的代码都是对前人的代码进行了一些整合而得到的,仅仅是对引擎做个测试而已
然后说明一点,就是HookService()的第一个参数都应该是以Zw开头的函数,因为代码是根据这个函数来计算服务ID的
还有就是在调用HookService()之前应该先调用InitServicesTalbe()来对SSDT进行一次性的保存,避免后面多次HOOK就要保存多次

你可能感兴趣的:(SSDT HOOK)