以前的看雪,老Y发表了一篇《从内核层保护文件不被删除》,他由于部分原因,只提供了部分代码碎片,但是还是要感谢老Y的无私,有兴趣的朋友可以去看看此文,我在此基础上通过自己的编写和调试,终于完整实现,与老Y的给的代码还是有不少地方不同,不敢私藏,特贡献给大家,方便有需要的朋友,本文已发表在黑客防线2010年2期上。

完整的代码如下:
#include <ntddk.h>
#include <stdio.h>
       
NTSTATUS DriverUnload(IN PDRIVER_OBJECT DriverObject);
int IsNeedProtect(DEVICE_OBJECT *DeviceObject, PIRP Irp);
ULONG GetFunctionAddr(IN PCWSTR FunctionName);
VOID InlineHook();


typedef NTSTATUS (FASTCALL *pIofCallDriver)(
                                           IN PDEVICE_OBJECT DeviceObject,
                                           IN OUT PIRP Irp);
pIofCallDriver OldAddress;


NTSTATUS FASTCALL MyIofCallDriver(IN PDEVICE_OBJECT DeviceObject,
                                  IN OUT PIRP Irp)
{
  NTSTATUS stat;
//先保存所有寄存器的原来状态,到时好恢复现场环境,跟加壳软件开始的指令也是一样
  __asm
  {
    pushad
  pushfd  
  }

   if(IsNeedProtect(DeviceObject,Irp))
  {
  //返回删除失败的提示
    __asm
  {
      popfd
      popad
    mov eax,0xC000000D
      mov stat,eax 
  }
    return stat;  
  }
  
   //先恢复现场环境,跳转回原地址
  __asm
  {
   popfd
   popad 
   mov ecx,DeviceObject
   mov edx,Irp
   call OldAddress;
   mov stat,eax
  }
return stat;

}





int IsNeedProtect(DEVICE_OBJECT *DeviceObject, PIRP Irp)
{
  NTSTATUS status;
  int nResult=FALSE;
  DRIVER_OBJECT *DriverObject=DeviceObject->DriverObject;
  WCHAR *pwsz=NULL;
  IO_STACK_LOCATION *sp;
  FILE_OBJECT *FileObject=NULL;
  
  status=STATUS_INVALID_PARAMETER;
  sp=IoGetNextIrpStackLocation(Irp);;
  

  switch(sp->MajorFunction)
  { 
  case IRP_MJ_SET_INFORMATION:
  goto Continue11;
  
  case IRP_MJ_WRITE:
  goto Continue11;
  
  default:
  goto Exit00;
  }
  
  Continue11:
  FileObject=sp->FileObject;
  _try
  {
    pwsz=wcsrchr(DriverObject->DriverName.Buffer,L'\\');
  pwsz++;
  
  //判断Irp是不是发往ntfs和fastfat驱动的,不是则跳出
  if (_wcsnicmp(pwsz,L"ntfs",4)&&_wcsnicmp(pwsz,L"fastfat",7))
  {
  goto Exit00;
  }
  
   DbgPrint("IofCallDriver:Delete File:%ws\n",FileObject->FileName.Buffer);

   pwsz=wcsrchr(FileObject->FileName.Buffer,L'\\'); 
   if (pwsz!=NULL)
   {
   pwsz++;
   }
  

   if (!_wcsnicmp(pwsz,L"IceSword122cn.exe",34))  //保护的文件名xxxxx
   {
    Irp->IoStatus.Information=0;
  Irp->IoStatus.Status=STATUS_ACCESS_DENIED;
  IoCompleteRequest(Irp,IO_NO_INCREMENT);
  nResult=TRUE; 
  goto Exit00; 
   }

  }

  except(1)
  {
  goto Exit00;
  }

Exit00:
  return nResult;
}



ULONG GetFunctionAddr(IN PCWSTR FunctionName)
{
UNICODE_STRING HookFunctionName;
RtlInitUnicodeString(&HookFunctionName,FunctionName);
return (ULONG)MmGetSystemRoutineAddress(&HookFunctionName);
}



//inlineHook IofCallDriver函数
VOID InlineHook()
{
KIRQL oldIrql;
ULONG Address;

Address=(ULONG)GetFunctionAddr(L"IofCallDriver");
  __asm
  {
   mov eax,Address
   mov esi,[eax+2]
   mov eax,[esi]
   mov OldAddress,eax 
  }

//提升中断层次
  oldIrql=KeRaiseIrqlToDpcLevel();
  __asm
  {
   cli
   mov eax,cr0
   and eax,not 10000h
   mov cr0,eax
  }
  //进行地址替换  
  _asm
  {
  mov eax,Address
  mov esi,[eax+2]
  mov dword ptr [esi],offset MyIofCallDriver
  }
  _asm
  {
  mov eax,cr0
  or eax,10000h
  mov cr0,eax 
  sti
  } 

//恢复中断层次
KeLowerIrql(oldIrql);
return ;
}



VOID UninlineHook()
{
KIRQL oldIrql;
ULONG Address;

Address=(ULONG)GetFunctionAddr(L"IofCallDriver");
//提升中断层次
  oldIrql=KeRaiseIrqlToDpcLevel();
  __asm
  {
   cli
   mov eax,cr0
   and eax,not 10000h
   mov cr0,eax
  }
  //进行地址替换  
  _asm
  {
  mov eax,Address
  mov esi,[eax+2]
  mov eax,OldAddress
  mov dword ptr [esi],eax
  }
  
  _asm
  {
  mov eax,cr0
  or eax,10000h
  mov cr0,eax 
  sti
  } 

//恢复中断层次
KeLowerIrql(oldIrql);
return ;
}




NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
           IN PUNICODE_STRING theRegistryPath)
{
              
  DbgPrint("Hook Called!\n");
  theDriverObject->DriverUnload=DriverUnload; 
  InlineHook();
  return STATUS_SUCCESS ;
}


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