好像此论坛还没有谁发过吧,在其他论坛见过,但是有下载限制的。无奈,只好自己写,发出来供像偶这样起步较晚的朋友们参考参考,高手就略过吧,哈哈

主要功能:检测内核已加载模块的所有导出函数是否被inlinehook。

实现方法:将内存中的模块与原始磁盘文件来做比对,若不同,则此函数被inlinehook。所以各种狡诈的inlinehook伎俩(mov eax ,xxxx add eax,xxxx,call eax)是逃不过检测的,除非它修改原始磁盘文件。不过可惜,在比较之前是可以进行md5验证的。若原始磁盘文件被修改,显然是昭然若揭了。
相对其他较复杂检测技术,这个法子最简单而且同样有效。

主体函数实现如下:

代码:
void HookCheckAllModuleExportRoutine (PVOID sysInfo)
{
  int i,j,k,len,length;
  PSYSMODULELIST List = NULL;
  char image[256], Name[256],sysDir[256];
  ANSI_STRING FullPath;
  UNICODE_STRING uFullPath;
  ANSI_STRING Temp1,Temp2,Temp3,Temp4,Temp5;
  
  HANDLE hFile = NULL, hSection = NULL;
  PVOID BaseAddress = NULL;
  IO_STATUS_BLOCK IoStatusBlock;
  CLIENT_ID ClientID;
  PVOID SysInfo;


  PIMAGE_DOS_HEADER DosHead = NULL;
  PIMAGE_NT_HEADERS NtHeads = NULL;
  PIMAGE_SECTION_HEADER Section = NULL;
  PIMAGE_EXPORT_DIRECTORY ExportDir = NULL;
  PIMAGE_BASE_RELOCATION RelocDir = NULL;
  ULONG kBase = 0, mBase = 0, kNameBase = 0, kOrdinalBase = 0, kFunctionBase = 0;
  ULONG ByteEqual, Address = 0, index, NameNumbers, FixAddr = 0, FixAddrBase = 0,RelocSize;
  ULONG DataSecVA[24], DataSecSize[24], DataSec;
  
  
  USHORT Temp = 0;
  PUCHAR SystemFunName; 
  PKPROCESS Eprocess;
  KAPC_STATE ApcState;
  HANDLE ProcessHandle;
  UNICODE_STRING ProcessName;
  PSYSTEM_PROCESSES pSysinfo;
  
  PKUSER_SHARED_DATA kShareData = USER_SHARED_DATA;

  size_t size = 0;
  NTSTATUS status;
  OBJECT_ATTRIBUTES oa, ob = {sizeof (ob), NULL, NULL,NULL, NULL};  


  RtlInitAnsiString (&Temp2, "sys");
  RtlInitAnsiString (&Temp3, "dll");
  RtlInitAnsiString (&Temp4, "exe");
  RtlInitAnsiString (&Temp5, "win32k.sys");
  RtlInitUnicodeString (&ProcessName, L"winlogon.exe");
  
  w2ascll (Name, kShareData->NtSystemRoot);
  
  strcpy (sysDir, "\\??\\");
  strcat (sysDir, Name);
  
  List = (PSYSMODULELIST)sysInfo;
  
  for (j = 0; j < List->ulCount; j++)
  {
    

    
    if (StringCompare ("\\??\\", List->smi[j].ImageName, 4)) 
    {
       DbgPrint ("Skip %s\n", List->smi[j].ImageName);
       continue;
    }
    
    mBase = NULL;
    hFile = NULL;
    hSection = NULL;
    BaseAddress = NULL;
        
    memset (Name, 0, sizeof (Name));
    memset (image,0, sizeof (image));
    
    strcpy (Name, sysDir);
    strcpy(image, List->smi[j].ImageName + List->smi[j].ModuleNameOffset);
        
    len = strlen (image);  
    RtlInitAnsiString (&Temp1, image + len - 3);
    

    if (!RtlCompareString (&Temp1, &Temp2, TRUE))
    {
      if (strstr (image, "watchdog"))
      {
          strcat (Name, "\\System32\\");
      }else
      {
          strcat (Name, "\\System32\\Drivers\\");
      }
      strcat (Name, image);
    }
    else if (!RtlCompareString (&Temp1, &Temp3, TRUE) || !RtlCompareString (&Temp1, &Temp4, TRUE))
    {
      strcat (Name, "\\System32\\");
      strcat (Name, image);
    }
    else
    {
      continue;
    }
    
    RtlInitAnsiString (&Temp1, image);
    if (!RtlCompareString (&Temp5, &Temp1, TRUE))
    {    //win32.sys模块的空间必须挂靠进程才能读取
    
      status = ZwQuerySystemInformation(5,NULL,0,&length);
      if (status == STATUS_INFO_LENGTH_MISMATCH)
      {
          SysInfo = ExAllocatePool(NonPagedPool,length);
          if (NULL == SysInfo)
          {
            goto Error;
          }
      }
      pSysinfo = (PSYSTEM_PROCESSES)SysInfo;
      status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation, pSysinfo, length, &length);
      if(!NT_SUCCESS(status))
      {
        goto Error;
      }

      //找到winlogon.exe进程,挂靠空间
      do 
      {
        if (!RtlCompareString (&(pSysinfo->ProcessName), &ProcessName, TRUE))
        {
          ClientID = pSysinfo->Threads[0].ClientId; 
          ZwOpenProcess (&ProcessHandle, PROCESS_ALL_ACCESS, &ob, &ClientID);
          ObReferenceObjectByHandle (ProcessHandle, PROCESS_ALL_ACCESS, *PsProcessType, KernelMode, &Eprocess, NULL);
          KeStackAttachProcess (Eprocess, &ApcState);
          break;
        }

        if (pSysinfo->NextEntryDelta == 0) break;

        pSysinfo = (ULONG)pSysinfo + pSysinfo->NextEntryDelta;
      }while (1);
      
      ExFreePool(SysInfo);
      memset (Name, 0, sizeof(Name));
      strcpy (Name, "\\Device\\HarddiskVolume1\\Windows\\System32\\");
      strcat (Name, image);
      
    }

    RtlInitAnsiString (&FullPath, Name);
    RtlAnsiStringToUnicodeString (&uFullPath, &FullPath, TRUE);

    //获得模块在内核中的相关参数
    kBase = List->smi[j].Base;
    if (!MmIsAddressValid (kBase)) 
    {
        DbgPrint ("%s 'base is not valid!\n", image);
        goto Error;
    }

    DosHead = (PIMAGE_DOS_HEADER)kBase;
    NtHeads = (PIMAGE_NT_HEADERS)((ULONG)DosHead + DosHead->e_lfanew);
    Section = (PIMAGE_SECTION_HEADER) ((ULONG)NtHeads + sizeof(IMAGE_NT_HEADERS));
    
    if (NULL == NtHeads->OptionalHeader.DataDirectory[0].VirtualAddress) 
    {
        DbgPrint ("%s  doesnt has valid export table!\n", image);
        continue;
    }
    
    DataSec = 0;
    for (i = 0; i < NtHeads->FileHeader.NumberOfSections; i++)
    {
      if (strstr (Section->Name, "text") ||strstr (Section->Name, "PAGE")||strstr (Section->Name, "INIT"))
      {
        DataSecVA[i] = Section->Misc.VirtualSize;
        DataSecSize[i] = Section->VirtualAddress;
        DataSec++;
      }
      Section ++;
    }
    if (i ==  NtHeads->FileHeader.NumberOfSections && DataSec == 0)
    {
      DbgPrint ("%wZ  doesnt find the text section!\n", &FullPath);
    }

    
    ExportDir = (PIMAGE_EXPORT_DIRECTORY)((ULONG)kBase + NtHeads->OptionalHeader.DataDirectory[0].VirtualAddress);
    NameNumbers = ExportDir->NumberOfNames;

    kNameBase = kBase + ExportDir->AddressOfNames;
    kOrdinalBase = kBase + ExportDir->AddressOfNameOrdinals;
    kFunctionBase = kBase + ExportDir->AddressOfFunctions;



    //获得模块加载后的相关参数
    InitializeObjectAttributes (
      &oa,
      &uFullPath,
      OBJ_CASE_INSENSITIVE,
      NULL,
      NULL
      );
    status = ZwOpenFile(
      &hFile,
      FILE_READ_ACCESS,
      &oa,
      &IoStatusBlock,
      FILE_SHARE_READ,
      FILE_SYNCHRONOUS_IO_NONALERT
        );
    if (!NT_SUCCESS(status))
    {
      KdPrint (("OpenFile %wZ error\n", &uFullPath));
      goto Error;

    }
    oa.ObjectName = NULL;
    status =  ZwCreateSection(
      &hSection,
      SECTION_MAP_EXECUTE,
      &oa,
      0,
      PAGE_EXECUTE,
      SEC_IMAGE,
      hFile
      );
    if (!NT_SUCCESS(status))
    {
      
      KdPrint (("CreateSection for  %wZ error", &uFullPath));
      goto Error;

    }
    size = 0;
    status =  ZwMapViewOfSection(
      hSection,
      NtCurrentProcess(),
      &BaseAddress,
      0, 
      1000, 
      0, 
      &size, 
      (SECTION_INHERIT)1, 
      MEM_TOP_DOWN, 
      PAGE_READWRITE
      );
    if (!NT_SUCCESS(status))
    {
      KdPrint (("MapViewSection for  %wZ error", &uFullPath));
      goto Error;

    }
    
    mBase = ExAllocatePool (NonPagedPool, size);
    if (NULL == mBase)
    {  
      goto Error;
    }

    if (BaseAddress != NULL)
    {
      RtlCopyMemory (mBase, BaseAddress, size);
    }
    
    DosHead = (PIMAGE_DOS_HEADER)mBase;
    NtHeads = (PIMAGE_NT_HEADERS)((ULONG)DosHead + DosHead->e_lfanew);
    RelocDir = (PIMAGE_BASE_RELOCATION)((ULONG)mBase + NtHeads->OptionalHeader.DataDirectory[5].VirtualAddress);
    if (RelocDir != NULL)
    {
      while (RelocDir->VirtualAddress != 0 || RelocDir->SizeOfBlock !=  0)
      {
        FixAddrBase = RelocDir->VirtualAddress + (ULONG)mBase;
        RelocSize = (RelocDir->SizeOfBlock - 8)/2;
        for ( i = 0; i < RelocSize; i++)
        {
          Temp = *(PUSHORT)((ULONG)RelocDir + sizeof (IMAGE_BASE_RELOCATION) + i * 2);
          if ( (Temp & 0xF000) == 0x3000)
          {
            Temp &= 0x0FFF;
            FixAddr = FixAddrBase + (ULONG)Temp;
            *(PULONG)FixAddr = *(PULONG)FixAddr + (ULONG)kBase - (ULONG)NtHeads->OptionalHeader.ImageBase;
          }
        }
        RelocDir = (ULONG)RelocDir + RelocDir->SizeOfBlock;
      }
    }
                                /*
    if (j == 0)
    {
      KernelCheck (kBase, mBase, sysInfo);
    }
*/

    for (i = 0; i < NameNumbers; i++)
    {
      SystemFunName = (PUCHAR)(*(PULONG)(kNameBase + i * 4) + (ULONG)kBase);
      index = *((PUSHORT)(kOrdinalBase + i * 2));
      Address = *(PULONG)(kFunctionBase + index * 4);
      
      for (k = 0; k < DataSec; k++)
      {
         if ( (Address >= DataSecVA[k]) && (Address <= DataSecVA[k] + DataSecSize[k]))
         { 
              length = GetFunctionLength(kBase + Address);
              if (length)
              {
                 ByteEqual = RtlCompareMemory (kBase + Address, mBase + Address, length);
                 if (ByteEqual != length)
                 {                                             
                    KdPrint (("%s:%s:%x has been inline-hooked!\n", image, SystemFunName, kBase + Address)); 
                 }
              }
              break;
         }                
      }
        
    }



Error:
    RtlFreeUnicodeString (&uFullPath);
    if (!RtlCompareString (&Temp5, &Temp1, TRUE))
    {
      KeUnstackDetachProcess (&ApcState);
    }
    if (mBase != NULL)
    {
      ExFreePool (mBase);
      mBase = NULL;
    }
    if (hFile != NULL)
    {
      ZwClose(hFile);
      hFile = NULL;
    }
    if (hSection != NULL)
    {
      ZwClose(hSection);
      hSection = NULL;
    }
    if (BaseAddress != NULL)
    {
      ZwUnmapViewOfSection(NtCurrentProcess(),BaseAddress);
      BaseAddress = NULL;
    }

  }
  return;
}

ULONG GetFunctionLength(ULONG FAddress)
{
    ULONG i = 0, Flag = 0;
    PUCHAR Temp = NULL;
    
    Temp = FAddress;
    while (!Flag && MmIsAddressValid(Temp) && MmIsAddressValid (Temp + 1)
        && MmIsAddressValid(Temp + 2) && MmIsAddressValid (Temp + 3)&& MmIsAddressValid (Temp + 4))
    {
      
      switch (*Temp)
      { 
      case 0xc3:
      case 0xcf:
      case 0xcb:
        if ( (*(Temp+1) == 0xcc) || (*(Temp+1) == 0x8b && *(Temp+1) == 0xFF)) 
        {
            Flag = 1;
        }
        break;
        
      case 0xc2:
      case 0xca:
        if ( (*(Temp+3) == 0xcc)  || (*(Temp+3) == 0x8b && *(Temp+4) == 0xFF))
        {
            Flag = 1;
        }
        break;
        
      default:
        break;
      }
      
      if (!Flag)
      {
          if (*((PULONG)Temp) == 0 && *(Temp + 4) == 0) 
            return 0;
      }
      
      Temp ++;
      i++;
    }

    return i;
}