今晚又这么无聊,听着《那些花儿》有点想哭,放假这几天真是无聊ing,正好前几天学习了内核的 inline hook,不如现在写点东西来总结一下吧。
本人对内核的认识也不多,对内核的认识是在 2007 年离别的泪花中开始的,到现在一眨眼就两年啦,真快吖哈!不过认识的也不多,想那年还以为在内核中就是实模式,嘿嘿、你看我有多么的傻!嘿嘿、2 年过去了,梁老师现在还好吧,我很记得 2 年前的那个散学礼,当梁老师说不做我们的班主任了的时候,我还静静的哭了几分钟呢,有没有人看见我就不知到了,不过也正是这离别的泪花让我开始了内核的“不归路”,这儿说的内核是指 Windows 的内核,众周所知 Windows 也就 ring0 和 ring3 组成的吧,ring0 就是内核了,因为 Windows 的内核运行在 ring0级别的哈....
上面又扯了这么多的废话,那么下面就进入正题哈
        inline hook & NtQuerySystemInformation & ring0
本文呢,是介绍一种保护进程不被结束的方法,这个方法不算新了,好旧好旧的了,其实呢,也是 hook 了某个函数来实现的,不过没有 hook NtOpenProcess 、NtTerminateProcess、KiInsertQueuApc 等函数,而是 hook 了 NtQuerySystemInformation 来保护我们的进程,NtQuerySystemInformation 是用来查询系统信息的,可以查询的系统信息有 54 种这么多,其中 ID 是 5 的话呢,就会返回一个链表,这个链表中包括了当前系统中的所以的进程名、进程ID,也就是说这个函数可以获取系统的进程列表,我们可以 hook 这个函数来隐藏进程,不过这次是保护进程,不是隐藏哦
在 ring3 中,列举进程的方法是调用 Tool32 或者 psapi 中的 EnumProcess,可是这些函数都调用了ZwQuerySystemInformation 然后在NtQuerySystemInformation,也就是我们hook NtQuerySystemInformation 就可以保护&隐藏进程了哇
hookNtQuerySystemInformation 的方法有好的,可以修改 SSDT,也可以修改函数前 5 个字节,也就是inline hook了,本文采用后者哦
在函数开始的5个字节中,改为一个 Jmp 指令,让她在调用这个函数的时候跳转到我们的函数中,我们在经过一些处理后再调用原来的****
流程如下:
cli
mov eax,cr0
and eax,0fffeffffh
mov cr0,eax
修改前5个字节
mov eax,cr0
or eax,not 0fffeffffh
mov cr0,eax
sti
这儿说下怎么样保护进程,在NtQuerySystemInformation返回的链表中包含了进程的ID,想一下如果我们把某个进程的ID改了后再返回给别人,那么别人就不会得到某个进程的正确的ID了,这样她再怎么NtOpenProcess 也没有了吧,因为她得到是一个错误的ID了哇,(听起来好像好衰,但有什么办法呢,现实就是这样)
下面代码奉上

代码:
///////////////////////////////////////////////////////////////////////////////
///
/// Copyright (c) 2009 - <company name here>
///
/// Original filename: zhenzhen_feifei_inlinehook_kernel.cpp
/// Project          : zhenzhen_feifei_inlinehook_kernel
/// Date of creation : 2009-07-08
/// Author(s)        : 
///
/// Purpose          : <description>
///
/// Revisions:
///  0000 [2009-07-08] Initial revision.
///
///////////////////////////////////////////////////////////////////////////////

// $Id$

#ifdef __cplusplus
extern "C" {
#endif
#include <ntddk.h>
#include <ntifs.h>
#include <string.h>
#ifdef __cplusplus
}; // extern "C"
#endif

#include ".h"

#ifdef __cplusplus
namespace { // anonymous namespace to limit the scope of this global variable!
#endif
PDRIVER_OBJECT pdoGlobalDrvObj = 0;
#ifdef __cplusplus
}; // anonymous namespace
#endif
PVOID inlinehook(UNICODE_STRING *hookfunction,ULONG NewFunction,UCHAR oldCode[5]);
void uninlinehook(PVOID oldfunaddr,UCHAR oldcode[5]);
PVOID lpNtQuerySystemInformation;
UCHAR boldCode[5];
ULONG a;
NTSTATUS MyNtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
    OUT PVOID                   SystemInformation,
    IN ULONG                    Length,
    OUT PULONG                  ReturnLength);
NTSTATUS ZHENZHENFEIFEI_INLINEHOOK_KERNEL_DispatchCreateClose(
  IN PDEVICE_OBJECT    DeviceObject,
  IN PIRP          Irp
  )
{
  NTSTATUS status = STATUS_SUCCESS;
  Irp->IoStatus.Status = status;
  Irp->IoStatus.Information = 0;
  IoCompleteRequest(Irp, IO_NO_INCREMENT);
  return status;
}

NTSTATUS ZHENZHENFEIFEI_INLINEHOOK_KERNEL_DispatchDeviceControl(
  IN PDEVICE_OBJECT    DeviceObject,
  IN PIRP          Irp
  )
{
  NTSTATUS status = STATUS_SUCCESS;
  PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);

  switch(irpSp->Parameters.DeviceIoControl.IoControlCode)
  {
  case IOCTL_ZHENZHENFEIFEI_INLINEHOOK_KERNEL_OPERATION:
    // status = SomeHandlerFunction(irpSp);
    break;
  default:
    Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
    Irp->IoStatus.Information = 0;
    break;
  }

  status = Irp->IoStatus.Status;
  IoCompleteRequest(Irp, IO_NO_INCREMENT);
  return status;
}

VOID ZHENZHENFEIFEI_INLINEHOOK_KERNEL_DriverUnload(
  IN PDRIVER_OBJECT    DriverObject
  )
{
  PDEVICE_OBJECT pdoNextDeviceObj = pdoGlobalDrvObj->DeviceObject;
  IoDeleteSymbolicLink(&usSymlinkName);

  // Delete all the device objects
  while(pdoNextDeviceObj)
  {
    PDEVICE_OBJECT pdoThisDeviceObj = pdoNextDeviceObj;
    pdoNextDeviceObj = pdoThisDeviceObj->NextDevice;
    IoDeleteDevice(pdoThisDeviceObj);
  }
  uninlinehook(lpNtQuerySystemInformation,boldCode);
}

#ifdef __cplusplus
extern "C" {
#endif
NTSTATUS DriverEntry(
  IN OUT PDRIVER_OBJECT   DriverObject,
  IN PUNICODE_STRING      RegistryPath
  )
{
  PDEVICE_OBJECT pdoDeviceObj = 0;
  NTSTATUS status = STATUS_UNSUCCESSFUL;
  pdoGlobalDrvObj = DriverObject;

  // Create the device object.
  if(!NT_SUCCESS(status = IoCreateDevice(
    DriverObject,
    0,
    &usDeviceName,
    FILE_DEVICE_UNKNOWN,
    FILE_DEVICE_SECURE_OPEN,
    FALSE,
    &pdoDeviceObj
    )))
  {
    // Bail out (implicitly forces the driver to unload).;
    return status;
  };

  // Now create the respective symbolic link object
  if(!NT_SUCCESS(status = IoCreateSymbolicLink(
    &usSymlinkName,
    &usDeviceName
    )))
  {
    IoDeleteDevice(pdoDeviceObj);
    return status;
  }

  // NOTE: You need not provide your own implementation for any major function that
  //       you do not want to handle. I have seen code using DDKWizard that left the
  //       *empty* dispatch routines intact. This is not necessary at all!
  DriverObject->MajorFunction[IRP_MJ_CREATE] =
  DriverObject->MajorFunction[IRP_MJ_CLOSE] = ZHENZHENFEIFEI_INLINEHOOK_KERNEL_DispatchCreateClose;
  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ZHENZHENFEIFEI_INLINEHOOK_KERNEL_DispatchDeviceControl;
  DriverObject->DriverUnload = ZHENZHENFEIFEI_INLINEHOOK_KERNEL_DriverUnload;
  UNICODE_STRING usNtOpenProcess;
  RtlInitUnicodeString(&usNtOpenProcess,L"NtQuerySystemInformation");
  lpNtQuerySystemInformation= inlinehook(&usNtOpenProcess,(ULONG)MyNtQuerySystemInformation,boldCode);
  return STATUS_SUCCESS;
}
#ifdef __cplusplus
}; // extern "C"
#endif
PVOID inlinehook(UNICODE_STRING *hookfunction,ULONG NewFunction,UCHAR oldCode[5])
{
  PVOID lpfunname = MmGetSystemRoutineAddress(hookfunction);
  DbgPrint("\nyuan dizhi shi :%x,",oldCode);
  int ijmpaddr;
  UCHAR uchjmpcode[5] = {0xE9,0,0,0,0};
  ijmpaddr = (UCHAR*)NewFunction - (UCHAR*)lpfunname - 5;
  RtlCopyMemory(uchjmpcode+1,&ijmpaddr,4);
  DbgPrint("\n%x",uchjmpcode);          
  __asm cli;
  __asm mov eax,cr0;
  __asm and eax,0fffeffffh;
  __asm mov cr0,eax;
  RtlCopyMemory(oldCode,lpfunname,5);
  RtlCopyMemory(lpfunname,uchjmpcode,5);
  __asm mov eax,cr0;
  __asm or eax,not 0fffeffffh;
  __asm mov cr0,eax;
  __asm sti;
  return lpfunname;
}
void uninlinehook(PVOID oldfunaddr,UCHAR oldcode[5])
{
  __asm cli;
  __asm mov eax,cr0;
  __asm and eax,0fffeffffh;
  __asm mov cr0,eax;
  //DbgPrint("%x\n",oldCode);
  RtlCopyMemory(oldfunaddr,oldcode,5);
  __asm mov eax,cr0;
  __asm or eax,not 0fffeffffh;
  __asm mov eax,cr0;
  __asm sti;
}
NTSTATUS
MyNtQuerySystemInformation(
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
    OUT PVOID                   SystemInformation,
    IN ULONG                    Length,
    OUT PULONG                  ReturnLength)
{
  SYSTEM_PROCESSES_INFORMATION *lpspi = 0,*lpspia = 0;
  lpspi = (SYSTEM_PROCESSES_INFORMATION*)SystemInformation;
  //lpspia = lpspi;
  UNICODE_STRING aProcessName;
  RtlInitUnicodeString(&aProcessName,L"Explorer.exe");
                uninlinehook(lpNtQuerySystemInformation,boldCode);
  NTSTATUS a = Zwq(SystemInformationClass,SystemInformation,Length,ReturnLength);
                UNICODE_STRING usNtOpenProcess;
  RtlInitUnicodeString(&usNtOpenProcess,L"NtQuerySystemInformation");
  lpNtQuerySystemInformation= inlinehook(&usNtOpenProcess,(ULONG)MyNtQuerySystemInformation,boldCode);

  if(SystemInformationClass != 5 || !NT_SUCCESS(a)) {
    return a;
  }
  while(lpspi->NextEntryDelta != 0) {
    if(RtlEqualUnicodeString(&aProcessName,&lpspi->ProcessName,1)) {
      //lpspia->NextEntryDelta += lpspi->NextEntryDelta;
      lpspi->ProcessId = 123;
    }
    //lpspia = lpspi;
    lpspi = (SYSTEM_PROCESSES_INFORMATION*)((PUCHAR)lpspi+lpspi->NextEntryDelta);
  }
  return a;
}