写得很简单,也是看了看雪的牛们以后自己实践了一下下,虽然简单,但还是建议菜鸟们多练手(像我一样 嘿嘿),当你能自己写个出来并跑起来,才是入门~

不说废话了,上代码,还请各位指正!

代码:
NTSTATUS 
DriverEntry(
  PDRIVER_OBJECT pDriverObj, 
  PUNICODE_STRING pRegistryString
  )
{
  NTSTATUS status = STATUS_SUCCESS;
  UNICODE_STRING ustrLinkName;
  UNICODE_STRING ustrDevName;    
  PDEVICE_OBJECT pDevObj;

  //HardCode For Searching……
  ULONG Addr_KiInsertQueueApc=0;
  CHAR FindCode[1][5]={
    {0xe8,0x4b,0x2b,0x00,0x00}
  };

  KdPrint(("==>DriverEntry\n"));
  
  pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
  pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
  pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
  pDriverObj->DriverUnload = DriverUnload;


  RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
  status = IoCreateDevice(pDriverObj, 
        0,
        &ustrDevName, 
        FILE_DEVICE_UNKNOWN,
        0,
        FALSE,
        &pDevObj);

  if(!NT_SUCCESS(status))  {
    return status;
  }

  RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
  status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName);  
  if(!NT_SUCCESS(status)) {
    IoDeleteDevice(pDevObj);  
    return status;
  }
  

  //
  // 添加执行代码
  //

  KdPrint(("Search ……\n"));
    OrigfnAddr.KiInsertQueueApc=GetTargetFnAddrFromExportedFn(FindCode[0],L"KeInsertQueueApc",100,0x2b4b);
  if (OrigfnAddr.KiInsertQueueApc!=0)
  {
    KdPrint(("We find it!Address of KiInsertQueueApc: 0x%08x\n",OrigfnAddr.KiInsertQueueApc));
  }
  else
  {
    KdPrint(("Not Find~ \n"));
    return STATUS_UNSUCCESSFUL;
  }

  status=InlineHook(OrigfnAddr.KiInsertQueueApc,(ULONG)fake_KiInsertQueueApc,(ULONG)Proxy_KiInsertQueueApc,OrigHeadCode.KiInsertQueueApc); //进行inlineHook
  if (!NT_SUCCESS(status))
  {
    return status;
  }

  KdPrint(("<==DriverEntry\n"));

  return status;
}


VOID 
DriverUnload(
  PDRIVER_OBJECT pDriverObj
  )
{  
  UNICODE_STRING strLink;
  NTSTATUS status;

  RtlInitUnicodeString(&strLink, LINK_NAME);


  //
  // 添加卸载代码
  //

  status=UnHook(OrigfnAddr.KiInsertQueueApc,OrigHeadCode.KiInsertQueueApc);
  if (!NT_SUCCESS(status))
  {
    KdPrint(("DriverUnload!UnHook Failre~"));
  }

  
  IoDeleteSymbolicLink(&strLink);
  IoDeleteDevice(pDriverObj->DeviceObject);
  KdPrint(("==>DriverUnload\n"));
}


下面是实现hook的代码:

//WriteProtect OFF/ON By MDL!
PVOID WPOFFByMdl(PVOID VirtualAddr,ULONG uLen,PMDL pMDL)
{
  PVOID MVA=NULL; //system-base VA maps physical pages that MDL describes

  pMDL=IoAllocateMdl(VirtualAddr,uLen,FALSE,FALSE,NULL);
  if (pMDL==NULL)
  {
    KdPrint(("WPOFF!IoAllocateMdl FAILURE pMdl==NULL\n"));
    return NULL;
  }

  MmBuildMdlForNonPagedPool(pMDL);

  _try
  {
    MmProbeAndLockPages(pMDL,KernelMode,IoModifyAccess);
  }
  _except(EXCEPTION_EXECUTE_HANDLER)
  {
    return NULL;
  }

  pMDL->MdlFlags|=MDL_MAPPED_TO_SYSTEM_VA;

  MVA=MmGetSystemAddressForMdlSafe(pMDL,NormalPagePriority);
  if (MVA)
  {
    KdPrint(("MVA : %x",MVA));
  }

    KdPrint(("WPOFFByMdl Successful"));
  return MVA;
}

VOID WPONByMdl(PMDL pMdl)
{
  if (pMdl==NULL)
  {
    return ;
  }

  MmUnlockPages(pMdl);
  IoFreeMdl(pMdl);


}

//Write Protect OFF/ON By CR0!
VOID WPOFFByCR0()
{
   
    ULONG uAttr;
   
    _asm
    {
        push eax;
        mov eax, cr0;
        mov uAttr, eax;
        and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
        mov cr0, eax;
        pop eax;
        cli
    };
   
    g_uCr0 = uAttr; //保存原有的 CRO 性
   
}

VOID WPONByCR0()
{
   
    _asm
    {
        sti
        push eax;
        mov eax, g_uCr0; //恢原有 CR0 性
        mov cr0, eax;
        pop eax;
    };
   

}

///////////////////////////////////////////////////////////////////////
//Get the exported function's address
ULONG GetFunctionAddr(PCWSTR FunctionName)
{
  UNICODE_STRING uFnName;

  RtlInitUnicodeString(&uFnName,FunctionName);

  return (ULONG)MmGetSystemRoutineAddress(&uFnName);
}

//Find  address of the function that we want to hook
//
//Description:通过已知函数找我们的目标函数
//
//ARGUMENTs:
//
//FindCode:寻找目标函数(即我们要HOOK的函数)的硬编码
//ExportedFnName:已知函数名
//SearchLen:在已知函数里面的搜索长度
//Offset:相对跳转值
//
ULONG GetTargetFnAddrFromExportedFn(CHAR* FindCode,PCWSTR ExportedFnName,ULONG SearchLen,ULONG Offset)
{
  ULONG i=0,j=0;
    CHAR * Addr_ExportedFn=NULL;
  ULONG TargetFnAddr=0;

  Addr_ExportedFn=(CHAR*)GetFunctionAddr(ExportedFnName);
  if (Addr_ExportedFn==NULL)
  {
    KdPrint(("GetTargetFnAddrFromExportedFn!GetFunctionAddr FAILURE\n"));
    return 0;
  }

  for (i=0;i<SearchLen;i++)                //搜索用户指定长度的函数字节
  {
    if (Addr_ExportedFn[i]==FindCode[0])
    {
      for (j=1;j<sizeof(FindCode);j++)
      {
        if (Addr_ExportedFn[i+j]==FindCode[j])
        {
          continue;
        }
        else
        {
          break;
        }
      }

      if (j==sizeof(FindCode))
      { 
      
        TargetFnAddr=(ULONG)&Addr_ExportedFn[i]+Offset+5;  //由相对jmp的dword值得到

        break;
      }
    }
  }


  return TargetFnAddr;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////
//
//Hook Function
//
NTSTATUS InlineHook(ULONG OrigFnAddr,ULONG FakeFnAddr,ULONG ProxyFnAddr,PVOID OrigHeadCode)
{
  KIRQL oldIrql;
  BYTE  HookCode[5]={0xe9,0x00,0x00,0x00,0x00};
  BYTE  jmpCode[7]={0xEA,0x00,0x00,0x00,0x00,0x08,0x00};

  PVOID MVA=NULL;

  if (!OrigFnAddr||!FakeFnAddr||!ProxyFnAddr||!OrigHeadCode)
  {
    return STATUS_UNSUCCESSFUL;
  }

  RtlCopyMemory(OrigHeadCode,(BYTE*)OrigFnAddr,5);

  *(ULONG*)(HookCode+1)=(ULONG)FakeFnAddr-(ULONG)OrigFnAddr-5;

  *(ULONG*)(jmpCode+1)=(ULONG)((BYTE*)OrigFnAddr+0x05);// 不需要相对跳转,这里是长转移

  RtlCopyMemory((BYTE*)ProxyFnAddr,(BYTE*)OrigHeadCode,5);
  RtlCopyMemory((BYTE*)ProxyFnAddr+5,(BYTE*)jmpCode,7);

  /*WPOFFByCR0();*/                                   //这里是去掉内存写保护,两种方法,我们选择MDL的方法
  MVA=WPOFFByMdl((PVOID)OrigFnAddr,10,MDLs.KiInsertQueueApc);
  if (!MVA)
  {
    KdPrint(("WPOFFByMdl FAILURE~"));
    return STATUS_UNSUCCESSFUL;
  }

  oldIrql=KeRaiseIrqlToDpcLevel();

  /*RtlCopyMemory((BYTE*)OrigFnAddr,(BYTE*)HookCode,5);*/      //将要HOOK的函数的函数头前5个字节改写 跳到我们的fake函数里面
  RtlCopyMemory((BYTE*)MVA,(BYTE*)HookCode,5);         

  KeLowerIrql(oldIrql);

  /*WPONByCR0();*/
    WPONByMdl(MDLs.KiInsertQueueApc);    //恢复写保护

  return STATUS_SUCCESS;
}


//
// 停止inline hook
//
NTSTATUS UnHook(ULONG OrigFnAddr,PVOID OrigHeadCode)
{
    KIRQL  oldIrql;
  PVOID MVA=NULL;

  if (!OrigFnAddr||!OrigHeadCode)
  {
    return STATUS_UNSUCCESSFUL;
  }

    /*WPOFFByCR0();*/
  MVA=WPOFFByMdl((PVOID)OrigFnAddr,10,MDLs.KiInsertQueueApc);
  if (!MVA)
  {
    KdPrint(("WPOFFByMdl FAILURE~"));
    return STATUS_UNSUCCESSFUL;
  }

    oldIrql = KeRaiseIrqlToDpcLevel();
    
    RtlCopyMemory ( (BYTE*)OrigFnAddr, OrigHeadCode, 5 );

    KeLowerIrql(oldIrql);
    
  /*WPONByCR0();*/
  WPONByMdl(MDLs.KiInsertQueueApc);

  return STATUS_SUCCESS;
}

嘿嘿,大家应该能看出来,在提供的工程里面,用到了sudami同学的一些框架代码,感谢!(程序的最大价值就在于复用~:3: )
上传的附件 inline_hook.rar

  • 标 题:答复
  • 作 者:morning
  • 时 间:2009-05-22 12:18:10

header inline hook 需要被拷贝的代码长度,需要一个指令长度表或者说反汇编引擎吧

  • 标 题:答复
  • 作 者:robin
  • 时 间:2009-05-22 20:00:34

楼主应该判断函数头指令长度的,如果函数头不是mov edi,edi,那就有可能不是5个字节,会有指令碎屑的。