Monday, August 8, 2011

Hook Specials 1: Pubilish project about inline hook

Anthor:shdaianita
The project is simpler and refer to master-hand's code to practise oneself.While that is simpler,Novice is be suggest practice much.

The code:

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);


  //
  // add unload's code
  //

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

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

 
Next codes realize hooking:

//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; //Keep original 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:Through known function to find us target function
//
//ARGUMENTs:
//
//FindCode:find target function(want to hook functiong),use hard code
//ExportedFnName:Known function's name
//SearchLen:at Known functions search length
//Offset:relatively jump value
//
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);    //Recover write-protect

  return STATUS_SUCCESS;
}


//
// Stop 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;
}

No comments:

Post a Comment