发新话题
打印

[原创]ring3 下挂钩Native API 简单实现文件防删除

[原创]ring3 下挂钩Native API 简单实现文件防删除

[文章作者]zhouzhen[E.S.T]
[信息来源]邪恶八进制信息安全团队 & 安全代码 http://www.securitycode.cn/bbs

简单实现文件防删除,说简单是因为没有用很底层的技术,例如文件驱动之类。我只用最简单的方法实现了, 使用 ring3 的API hook 技术。随着技术的发展这种技术已经过不了很多的主动防御技术了。主要是思路和方法和分析过程。(高手飘过)

ring3 下挂钩 API 基本上也就是修改导入表,和Inline hook 修改前5个字节这几种方法。挂钩Native API 没有什么区别,也就是多声明几个结构和变量类型。

关于挂钩API 请参见:www.xfocus.net/articles/200403/681.html

文件删除的ring3 API 是DeleteFile, 此API 存在于kernel32.dll 中,用OD分析一下。(哪个都可以,IDA更不用说)

DeleteFileA 的反汇编代码:

7C80D2FB >/$ 8BFF     mov   edi, edi
7C80D2FD |. 55      push  ebp
7C80D2FE |. 8BEC     mov   ebp, esp
7C80D300 |. FF75 08    push  dword ptr [ebp+8]
7C80D303 |. E8 17790100  call  7C824C1F
7C80D308 |. 85C0     test  eax, eax
7C80D30A |. 74 08     je   short 7C80D314
7C80D30C |. FF70 04    push  dword ptr [eax+4]        ; /FileName
7C80D30F |. E8 3D170000  call  DeleteFileW           ; \DeleteFileW
7C80D314 |> 5D      pop   ebp
7C80D315 \. C2 0400    retn  4

可以得到一个流程 DeleteFileA --> DeleteFileW

DeleteFileW 的反汇编代码:

7C80EA51 > $ 8BFF     mov   edi, edi
7C80EA53  . 55      push  ebp
7C80EA54  . 8BEC     mov   ebp, esp
7C80EA56  . 83EC 50    sub   esp, 50
7C80EA59  . 56      push  esi
7C80EA5A  . 8D45 C8    lea   eax, dword ptr [ebp-38]
7C80EA5D  . 50      push  eax
7C80EA5E  . 33F6     xor   esi, esi
7C80EA60  . 56      push  esi
7C80EA61  . 8D45 E0    lea   eax, dword ptr [ebp-20]
7C80EA64  . 50      push  eax
7C80EA65  . FF75 08    push  dword ptr [ebp+8]
7C80EA68  . C645 FF 00  mov   byte ptr [ebp-1], 0
7C80EA6C  . FF15 5411807C call  dword ptr [<&ntdll.RtlDosPathNam>; ntdll.RtlDosPathNameToRelativeNtPathName_U
7C80EA72  . 84C0     test  al, al
7C80EA74  . 0F84 FBCC0200 je   7C83B775
7C80EA7A  . 8B45 E4    mov   eax, dword ptr [ebp-1C]
7C80EA7D  . 8945 F4    mov   dword ptr [ebp-C], eax
7C80EA80  . 8B45 C8    mov   eax, dword ptr [ebp-38]
7C80EA83  . 66:3BC6    cmp   ax, si
7C80EA86  . 0F85 E9660200 jnz   7C835175
7C80EA8C  . 8975 D0    mov   dword ptr [ebp-30], esi
7C80EA8F  > 8B45 D0    mov   eax, dword ptr [ebp-30]
7C80EA92  . 53      push  ebx
7C80EA93  . 57      push  edi
7C80EA94  . 8945 B4    mov   dword ptr [ebp-4C], eax
7C80EA97  . 8D45 E0    lea   eax, dword ptr [ebp-20]
7C80EA9A  . 8945 B8    mov   dword ptr [ebp-48], eax
7C80EA9D  . BF 40402000  mov   edi, 204040
7C80EAA2  . 57      push  edi
7C80EAA3  . 6A 07     push  7
7C80EAA5  . 8D45 E8    lea   eax, dword ptr [ebp-18]
7C80EAA8  . 50      push  eax
7C80EAA9  . 8D45 B0    lea   eax, dword ptr [ebp-50]
7C80EAAC  . 50      push  eax
7C80EAAD  . 68 80000100  push  10080              ; UNICODE "ocuments and
7C80EAB2  . 8D45 F8    lea   eax, dword ptr [ebp-8]
7C80EAB5  . 8975 C0    mov   dword ptr [ebp-40], esi
7C80EAB8  . 8975 C4    mov   dword ptr [ebp-3C], esi
7C80EABB  . 8B35 1410807C mov   esi, dword ptr [<&ntdll.NtOpenFi>; ntdll.ZwOpenFile
7C80EAC1  . 50      push  eax
7C80EAC2  . C745 B0 18000>mov   dword ptr [ebp-50], 18
7C80EAC9  . C745 BC 40000>mov   dword ptr [ebp-44], 40
7C80EAD0  . FFD6     call  esi               ; <&ntdll.NtOpenFile>
7C80EAD2  . 8BD8     mov   ebx, eax
7C80EAD4  . 85DB     test  ebx, ebx
7C80EAD6  .^ 0F8C F5F4FFFF jl   7C80DFD1
7C80EADC  . 6A 23     push  23                ; /InfoClass = FileAttributeTagInformation
7C80EADE  . 6A 08     push  8                ; |Bufsize = 8
7C80EAE0  . 8D45 D8    lea   eax, dword ptr [ebp-28]     ; |
7C80EAE3  . 50      push  eax               ; |Buffer
7C80EAE4  . 8D45 E8    lea   eax, dword ptr [ebp-18]     ; |
7C80EAE7  . 50      push  eax               ; |pStatusBlock
7C80EAE8  . FF75 F8    push  dword ptr [ebp-8]        ; |hFile
7C80EAEB  . FF15 1810807C call  dword ptr [<&ntdll.NtQueryInform>; \ZwQueryInformationFile
7C80EAF1  . 8BD8     mov   ebx, eax
7C80EAF3  . 85DB     test  ebx, ebx
7C80EAF5  . 0F8C D5CC0200 jl   7C83B7D0
7C80EAFB  . 8B45 D8    mov   eax, dword ptr [ebp-28]
7C80EAFE  . 25 00040000  and   eax, 400
7C80EB03  . 0F85 0ECD0200 jnz   7C83B817
7C80EB09  > 85C0     test  eax, eax
7C80EB0B  . 0F85 1CCD0200 jnz   7C83B82D
7C80EB11  > 8D45 C8    lea   eax, dword ptr [ebp-38]
7C80EB14  . 50      push  eax
7C80EB15  . FF15 5011807C call  dword ptr [<&ntdll.RtlReleaseRel>; ntdll.RtlReleaseRelativeName
7C80EB1B  . FF75 F4    push  dword ptr [ebp-C]
7C80EB1E  . 64:A1 1800000>mov   eax, dword ptr fs:[18]
7C80EB24  . 8B40 30    mov   eax, dword ptr [eax+30]
7C80EB27  . 6A 00     push  0
7C80EB29  . FF70 18    push  dword ptr [eax+18]
7C80EB2C  . FF15 1010807C call  dword ptr [<&ntdll.RtlFreeHeap>] ; ntdll.RtlFreeHeap
7C80EB32  . 6A 0D     push  0D                ; /InfoClass = FileDispositionInformation
7C80EB34  . 6A 01     push  1                ; |Bufsize = 1
7C80EB36  . 8D45 0B    lea   eax, dword ptr [ebp+B]      ; |
7C80EB39  . 50      push  eax               ; |Buffer
7C80EB3A  . 8D45 E8    lea   eax, dword ptr [ebp-18]     ; |
7C80EB3D  . 50      push  eax               ; |pStatusBlock
7C80EB3E  . FF75 F8    push  dword ptr [ebp-8]        ; |hFile
7C80EB41  . C645 0B 01  mov   byte ptr [ebp+B], 1       ; |
7C80EB45  . FF15 3010807C call  dword ptr [<&ntdll.NtSetInformat>; \ntdll.ZwSetInformationFile
7C80EB4B  . FF75 F8    push  dword ptr [ebp-8]        ; /Handle
7C80EB4E  . 8BF0     mov   esi, eax             ; |
7C80EB50  . FF15 3810807C call  dword ptr [<&ntdll.NtClose>]   ; \ZwClose
7C80EB56  . 85F6     test  esi, esi
7C80EB58  .^ 0F8C 1F91FFFF jl   7C807C7D
7C80EB5E  . 33C0     xor   eax, eax
7C80EB60  . 40      inc   eax
7C80EB61  > 5F      pop   edi
7C80EB62  . 5B      pop   ebx
7C80EB63  > 5E      pop   esi
7C80EB64  . C9      leave
7C80EB65  . C2 0400    retn  4

得到一个流程 DeleteFileA --> DeleteFileW --> ntdll.ZwSetInformationFile,因此我们只要挂钩了ZwSetInformationFile 就可以简单实现目标了。这里写出了新的 ZwSetInformationFile 函数。

typedef LONG NTSTATUS;
#define STATUS_SUCCESS        ((NTSTATUS)0x00000000L)
#define STATUS_ACCESS_DENIED     ((NTSTATUS)0xC0000022L)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)

typedef struct _IO_STATUS_BLOCK {
DWORD Status;
ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef enum _FILE_INFORMATION_CLASS {
// end_wdm
  FileDirectoryInformation    = 1,
  FileFullDirectoryInformation, // 2
  FileBothDirectoryInformation, // 3
  FileBasicInformation,     // 4 wdm
  FileStandardInformation,   // 5 wdm
  FileInternalInformation,   // 6
  FileEaInformation,      // 7
  FileAccessInformation,    // 8
  FileNameInformation,     // 9
  FileRenameInformation,    // 10
  FileLinkInformation,     // 11
  FileNamesInformation,     // 12
  FileDispositionInformation,  // 13
  FilePositionInformation,   // 14 wdm
  FileFullEaInformation,    // 15
  FileModeInformation,     // 16
  FileAlignmentInformation,   // 17
  FileAllInformation,      // 18
  FileAllocationInformation,  // 19
  FileEndOfFileInformation,   // 20 wdm
  FileAlternateNameInformation, // 21
  FileStreamInformation,    // 22
  FilePipeInformation,     // 23
  FilePipeLocalInformation,   // 24
  FilePipeRemoteInformation,  // 25
  FileMailslotQueryInformation, // 26
  FileMailslotSetInformation,  // 27
  FileCompressionInformation,  // 28
  FileObjectIdInformation,   // 29
  FileCompletionInformation,  // 30
  FileMoveClusterInformation,  // 31
  FileQuotaInformation,     // 32
  FileReparsePointInformation, // 33
  FileNetworkOpenInformation,  // 34
  FileAttributeTagInformation, // 35
  FileTrackingInformation,   // 36
  FileMaximumInformation
// begin_wdm
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

typedef struct _FILE_NAME_INFORMATION {
  ULONG FileNameLength;
  WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;



typedef NTSTATUS (__stdcall *ZWQUERYINFORMATIONFILE)(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG FileInformationLength,
IN FILE_INFORMATION_CLASS FileInformationClass
);

ZWQUERYINFORMATIONFILE ZwQueryInformationFile;

NTSTATUS __stdcall Hook_ZwSetInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
IN ULONG FileInformationLength,
IN FILE_INFORMATION_CLASS FileInformationClass)
{
  NTSTATUS ntstatus = STATUS_ACCESS_DENIED;

  HMODULE hNtdll = GetModuleHandle("ntdll.dll");
  ZwQueryInformationFile = (ZWQUERYINFORMATIONFILE)GetProcAddress(hNtdll, "ZwQueryInformationFile");

   IO_STATUS_BLOCK ioStatus;
   FILE_NAME_INFORMATION * psi = {0};

  psi = (FILE_NAME_INFORMATION*)new WCHAR[sizeof(FILE_NAME_INFORMATION) + 1024];
  memset(psi, 0, (sizeof(FILE_NAME_INFORMATION) + 1024)*2);
  psi->FileNameLength = 1024;

  ntstatus = ZwQueryInformationFile(FileHandle, &ioStatus, psi, sizeof(FILE_NAME_INFORMATION) + 1024 * sizeof(WCHAR),

FileNameInformation);

  if (ntstatus != STATUS_SUCCESS)
    PrintZwError("ZwQueryInformationFile", ntstatus);

  ntstatus = STATUS_ACCESS_DENIED;
  
  if( wcsstr(psi->FileName, L"b.txt") == NULL)
   ntstatus = ((PFZWSETINFORMATIONFILE)(PROC)g_ZwSetInformationFile)

(FileHandle,IoStatusBlock,FileInformation,FileInformationLength,FileInformationClass);

  delete psi;
  return ntstatus;

}


这只是一个证明性代码,要实战的兄弟自己动点手吧。
安全就象毒品一样,上瘾了就戒不掉了 http://www.6code.net

TOP

不错,Ring3下的稳定,这点很重要

TOP

删除是不行,但是可以重命名,重命名之后,就可以删除了。。。
游戏吧  http://www.game8.cc/MyBlog    http://www.asm32.cn

TOP

想问下zhouzhen大哥,怎样才能获得FileHandle的句柄?

TOP

TO : asm

这里我留了一个玄机。。。你认真看看下面的结构就知道了

ypedef enum _FILE_INFORMATION_CLASS {
// end_wdm
FileDirectoryInformation   = 1,
FileFullDirectoryInformation, // 2
FileBothDirectoryInformation, // 3
FileBasicInformation,    // 4 wdm
FileStandardInformation,   // 5 wdm
FileInternalInformation,   // 6
FileEaInformation,      // 7
FileAccessInformation,    // 8
FileNameInformation,     // 9
FileRenameInformation,    // 10
FileLinkInformation,     // 11
FileNamesInformation,    // 12
FileDispositionInformation, // 13
FilePositionInformation,   // 14 wdm
FileFullEaInformation,    // 15
FileModeInformation,     // 16
FileAlignmentInformation,  // 17
FileAllInformation,     // 18
FileAllocationInformation,  // 19
FileEndOfFileInformation,  // 20 wdm
FileAlternateNameInformation, // 21
FileStreamInformation,    // 22
FilePipeInformation,     // 23
FilePipeLocalInformation,  // 24
FilePipeRemoteInformation,  // 25
FileMailslotQueryInformation, // 26
FileMailslotSetInformation, // 27
FileCompressionInformation, // 28
FileObjectIdInformation,   // 29
FileCompletionInformation,  // 30
FileMoveClusterInformation, // 31
FileQuotaInformation,    // 32
FileReparsePointInformation, // 33
FileNetworkOpenInformation, // 34
FileAttributeTagInformation, // 35
FileTrackingInformation,   // 36
FileMaximumInformation
// begin_wdm
} FILE_INFORMATION_CLASS


To eros412:

FileHandle 是其它地方传到我们的函数里的,这里不关心它具体的值
安全就象毒品一样,上瘾了就戒不掉了 http://www.6code.net

TOP

NtQueryDirectoryFile 好了...

TOP

引用:
引用第2楼asm于2007-09-20 21:52发表的 :
删除是不行,但是可以重命名,重命名之后,就可以删除了。。。
呵呵,CreateFile独占之~

其实弄个DLL注入所有进程,然后每一个都CreateFile独占文件,能够对付大多数用户

FSD钩子好是好,就是容易blue掉

TOP

为什么这里 psi = (FILE_NAME_INFORMATION*)new WCHAR[sizeof(FILE_NAME_INFORMATION) + 1024];还要加个1024?这个值怎样确定的?
众人都在假装正经,我唯有假装不正经了。

TOP

好象没什么意义.
就是欲留点空间吧.

TOP

sunwear 说的没有错,就是分配一点空间了

typedef struct _FILE_NAME_INFORMATION {
  ULONG FileNameLength;
  WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;

看这个结构,如果不多分配一些,文件名一长就崩溃了。
安全就象毒品一样,上瘾了就戒不掉了 http://www.6code.net

TOP

哦,原来这样,明白了,谢谢楼上两位
众人都在假装正经,我唯有假装不正经了。

TOP

请问一下ring3 和ring0 下的挂钩怎么区分的,徘徊hook ring3 还是hook ring0,我也想按楼主的思路模仿一下!

刚刚入门的菜鸟呀

TOP

呵呵。不用挂钩也可以。直接文件占亢也行。

DebugMan上一大牛给了个很猥亵的方法。打开要保护的文件句柄。NtDuplicateObject复制System的句柄权限给它。然后就可以很XX啦~~~

360的文件粉碎机只能看重启后才能删除它,其他的直接无视。。。
WINDOWS内核疯狂爱好者

TOP

引用:
引用第12楼sudami于2008-01-17 21:39发表的 :
呵呵。不用挂钩也可以。直接文件占亢也行。

DebugMan上一大牛给了个很猥亵的方法。打开要保护的文件句柄。NtDuplicateObject复制System的句柄权限给它。然后就可以很XX啦~~~

360的文件粉碎机只能看重启后才能删除它,其他的直接无视。。。
汗.......NtDuplicateObject,够委琐.....
just try ,good life !

TOP

很久以前就看到这个帖子了,那时候一窍不通呀,那时候就想当成填空题做了,现在我终于拼出来了,
注意用这个工具加载
http://bbs.pediy.com/showthread.php?t=60689    在7楼
其实这些代码早就满天飞了,就被传烂了!
希望能给后来的朋友们多一种选择,因为系统最终是通过发irp来删除的,所以无法过那些发irp的工具,
如果你看过2000的源码,你就会知道也不能重命名!
因为是从ntdll中导出函数,应该通用,(仅测试过xp)

源码如下:
复制内容到剪贴板
代码:
#include "ntddk.h"
#include "ntimage.h"
#include "windef.h"

#define DWORD unsigned long
#define WORD unsigned short
#define BOOL unsigned long
#define BYTE unsigned char

typedef struct ServiceDescriptorEntry {
    unsigned int *ServiceTableBase;
    unsigned int *ServiceCounterTableBase;
    unsigned int NumberOfServices;
    unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;

extern PServiceDescriptorTableEntry KeServiceDescriptorTable;

typedef NTSTATUS (*NTSETINFORMATIONFILE)(
IN HANDLE  FileHandle,
OUT PIO_STATUS_BLOCK  IoStatusBlock,
IN PVOID  FileInformation,
IN ULONG  Length,
IN FILE_INFORMATION_CLASS  FileInformationClass
);

NTSETINFORMATIONFILE RealZwSetInformationFile;

NTSTATUS HookZwSetInformationFile(
IN HANDLE  FileHandle,
OUT PIO_STATUS_BLOCK  IoStatusBlock,
IN PVOID  FileInformation,
IN ULONG  Length,
IN FILE_INFORMATION_CLASS  FileInformationClass
);

//becuse zecreatesection,so we export it
typedef
NTSTATUS
NTCREATESECTION(
  OUT PHANDLE             SectionHandle,
  IN ULONG                DesiredAccess,
  IN POBJECT_ATTRIBUTES   ObjectAttributes OPTIONAL,
  IN PLARGE_INTEGER       MaximumSize OPTIONAL,
  IN ULONG                PageAttributess,
  IN ULONG                SectionAttributes,
  IN HANDLE               FileHandle OPTIONAL );

NTCREATESECTION       ZwCreateSection;

NTKERNELAPI
NTSTATUS
ObQueryNameString (
    IN PVOID                        Object,
    OUT POBJECT_NAME_INFORMATION    ObjectNameInfo,
    IN ULONG                        Length,
    OUT PULONG                      ReturnLength
);
//-----------------------------------------------------------------------------
#define MAXPATHLEN 1024
#define MaxBuf 1024

NTSTATUS
HookZwSetInformationFile(
  IN HANDLE                                        FileHandle,
  OUT PIO_STATUS_BLOCK                IoStatusBlock,
  IN PVOID                                        FileInformation,
  IN ULONG                                        Length,
  IN FILE_INFORMATION_CLASS FileInformationClass)
{
PFILE_OBJECT        pFileObject;
NTSTATUS                rc;
ULONG                        ActualLength;


PUNICODE_STRING puniFileName_Del;

ANSI_STRING
          ansiFileName_Del,
    m_ansiFileName_Del,
      ansiGetFileName_Del,
    m_ansiGetFileName_Del;

IO_STATUS_BLOCK MyIoStatusBlock;
PFILE_NAME_INFORMATION pFileInfo;

char DeleteFileDir[MaxBuf];

UNICODE_STRING                                pHideFileDir;
PUNICODE_STRING                        pFullPath=NULL;

pFileInfo = (PFILE_NAME_INFORMATION)ExAllocatePool( NonPagedPool, sizeof(FILE_NAME_INFORMATION)*255);

//调用ZwQueryInformationFile函数将操作文件的信息放如pFileInfo。
rc = ZwQueryInformationFile( FileHandle,&MyIoStatusBlock,pFileInfo,sizeof(FILE_NAME_INFORMATION)*255,FileNameInformation );
if(NT_SUCCESS(rc))
{
  //定义变量
  PWSTR pTemp = (PWSTR)ExAllocatePool( NonPagedPool, sizeof(PWSTR)*pFileInfo->FileNameLength);
  puniFileName_Del = (PUNICODE_STRING)ExAllocatePool( NonPagedPool, sizeof( UNICODE_STRING));
  puniFileName_Del->Buffer = pTemp;

  //将文件名成拷贝到puniFileName_Del变量中
  RtlCopyMemory( puniFileName_Del->Buffer, pFileInfo->FileName, pFileInfo->FileNameLength);
  puniFileName_Del->Length = (USHORT)pFileInfo->FileNameLength;
  puniFileName_Del->MaximumLength = (USHORT)pFileInfo->FileNameLength;
  
  //对文件名称转换大小写
  RtlUnicodeStringToAnsiString( &ansiFileName_Del, puniFileName_Del, TRUE);
  RtlUnicodeStringToAnsiString( &m_ansiFileName_Del, puniFileName_Del, TRUE);
  RtlUpperString(&ansiFileName_Del,&m_ansiFileName_Del);
  //将文件名称保存在变量ansiFileName_Del中
  RtlFreeAnsiString(&m_ansiFileName_Del);
  //比较我们要保护的文件名称是否和正在操作的文件名称相同
DbgPrint("FILE will be dele ***");
DbgPrint("file name: %s \n", ansiFileName_Del.Buffer);
  if (RtlCompareMemory(ansiFileName_Del.Buffer,"\\UNCLEDO.TXT",strlen("\\UNCLEDO.TXT") ) == strlen("\\UNCLEDO.TXT"))
  {
    rc = ObReferenceObjectByHandle(FileHandle,0,NULL,KernelMode,(PVOID*)&pFileObject,NULL);
   
        if(!NT_SUCCESS(rc))   
    {
     //如果调用ObReferenceObjectByHandle函数不正常,则调用原来的操作
     rc=RealZwSetInformationFile(FileHandle,IoStatusBlock,FileInformation,Length,FileInformationClass);
     RtlFreeAnsiString(&ansiFileName_Del);
     ExFreePool(puniFileName_Del);
     ExFreePool(pTemp);
     ExFreePool(pFileInfo);
     return rc;
    }

     pFullPath = (PUNICODE_STRING )ExAllocatePool(NonPagedPool,MaxBuf);
     RtlZeroMemory(pFullPath,MaxBuf);
     pFullPath->MaximumLength = MaxBuf ;

     //得到文件的全路径
     rc = ObQueryNameString(pFileObject,(POBJECT_NAME_INFORMATION)pFullPath,MaxBuf,&ActualLength);
    if(rc != STATUS_SUCCESS)
         {
     {
       

      //如果失败 则调用正常处理
      rc=RealZwSetInformationFile(FileHandle,IoStatusBlock,FileInformation,Length,FileInformationClass);
      RtlFreeAnsiString(&ansiFileName_Del);
      ExFreePool(puniFileName_Del);
      ExFreePool(pTemp);
      ExFreePool(pFileInfo);
      ExFreePool(pFullPath);
      ObDereferenceObject(pFileObject);
      return rc;
     }
     ObDereferenceObject(pFileObject);
         }

         else
         {      
     //将文件的全路径转换成大写
     RtlUnicodeStringToAnsiString(&ansiGetFileName_Del,pFullPath,TRUE);
     RtlUnicodeStringToAnsiString(&m_ansiGetFileName_Del,pFullPath,TRUE);
     RtlUpperString(&ansiGetFileName_Del,&m_ansiGetFileName_Del);
     RtlFreeAnsiString(&m_ansiGetFileName_Del);
     memset(DeleteFileDir,0,MaxBuf);
     memcpy(DeleteFileDir,ansiGetFileName_Del.Buffer,ansiGetFileName_Del.Length);
     RtlFreeAnsiString(&ansiGetFileName_Del);
     ExFreePool(pFullPath);

         //判断文件的全路径是否和我们需要保护的文件全路径匹配
         DbgPrint("FILE NAME: %s \n", DeleteFileDir);

         if(RtlCompareMemory(DeleteFileDir,"\\DEVICE\\HARDDISKVOLUME1\\UNCLEDO.TXT",strlen("\\DEVICE\\HARDDISKVOLUME1\\UNCLEDO.TXT") ) == strlen("\\DEVICE\\HARDDISKVOLUME1\\UNCLEDO.TXT"))
     {

          //如果匹配,直接返回,不调用删除功能
      RtlFreeAnsiString(&ansiFileName_Del);
      ExFreePool(puniFileName_Del);
      ExFreePool(pTemp);
      ExFreePool(pFileInfo);

          /////////////////////////
      //return  (!STATUS_SUCCESS);无提示性息,显示删除了,打开仍在
            return        STATUS_ACCESS_DENIED;//返回写保护!
     }
         }

   }
  //如果文件名称不匹配,则调用原来的操作
  rc=RealZwSetInformationFile(FileHandle,IoStatusBlock,FileInformation,Length,FileInformationClass);
  RtlFreeAnsiString(&ansiFileName_Del);
  ExFreePool(puniFileName_Del);
  ExFreePool(pTemp);
}
ExFreePool(pFileInfo);
return  rc;
}

///////////////////////////////////////////////////////////////////
#define SEC_IMAGE    0x01000000

typedef struct _SECTION_IMAGE_INFORMATION {
PVOID EntryPoint;
ULONG StackZeroBits;
ULONG StackReserved;
ULONG StackCommit;
ULONG ImageSubsystem;
WORD SubsystemVersionLow;
WORD SubsystemVersionHigh;
ULONG Unknown1;
ULONG ImageCharacteristics;
ULONG ImageMachineType;
ULONG Unknown2[3];
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;

DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName)
{
    HANDLE hThread, hSection, hFile, hMod;
    SECTION_IMAGE_INFORMATION sii;
    IMAGE_DOS_HEADER* dosheader;
    IMAGE_OPTIONAL_HEADER* opthdr;
    IMAGE_EXPORT_DIRECTORY* pExportTable;
    DWORD* arrayOfFunctionAddresses;
    DWORD* arrayOfFunctionNames;
    WORD* arrayOfFunctionOrdinals;
    DWORD functionOrdinal;
    DWORD Base, x, functionAddress;
    char* functionName;
    STRING ntFunctionName, ntFunctionNameSearch;
    PVOID BaseAddress = NULL;
    SIZE_T size=0;

    OBJECT_ATTRIBUTES oa = {sizeof oa, 0, pDllName, OBJ_CASE_INSENSITIVE};

    IO_STATUS_BLOCK iosb;

    //_asm int 3;
    ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);

    oa.ObjectName = 0;

    ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);
   
    ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);
   
    ZwClose(hFile);
   
    hMod = BaseAddress;
   
    dosheader = (IMAGE_DOS_HEADER *)hMod;
   
    opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);

    pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);

    // now we can get the exported functions, but note we convert from RVA to address
    arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);

    arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);

    arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);

    Base = pExportTable->Base;

    RtlInitString(&ntFunctionNameSearch, lpFunctionName);

    for(x = 0; x < pExportTable->NumberOfFunctions; x++)
    {
        functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);

        RtlInitString(&ntFunctionName, functionName);

        functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1;
                // always need to add base, -1 as array counts from 0
        // this is the funny bit.  you would expect the function pointer to simply be arrayOfFunctionAddresses[x]...
        // oh no... thats too simple.  it is actually arrayOfFunctionAddresses[functionOrdinal]!!
        functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
        if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == 0)
        {
            ZwClose(hSection);
            return functionAddress;
        }
    }

    ZwClose(hSection);
    return 0;
}
//////////////////////////////////////////////////////////////////

NTSTATUS
OnStubDispatch(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
{
    Irp->IoStatus.Status      = STATUS_SUCCESS;
    IoCompleteRequest (Irp,
                       IO_NO_INCREMENT
                       );
    return Irp->IoStatus.Status;
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{

        UNICODE_STRING dllName;
    DWORD functionAddress;
    int    position;
    DbgPrint("My Driver unLoaded!");
   
    RtlInitUnicodeString(&dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll");
    functionAddress = GetDllFunctionAddress("ZwSetInformationFile", &dllName);
    position = *((WORD*)(functionAddress+1));


    _asm
    {
        CLI                    
        MOV    EAX, CR0        
        AND EAX, NOT 10000H
        MOV    CR0, EAX        
    }

    (NTSETINFORMATIONFILE)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + position))=RealZwSetInformationFile;

    _asm
    {
        MOV    EAX, CR0        
        OR    EAX, 10000H         
        MOV    CR0, EAX               
        STI                    
    }
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
    int i;

        UNICODE_STRING dllName;
    DWORD functionAddress;
    int    position;
    theDriverObject->DriverUnload  = OnUnload;
    RtlInitUnicodeString(&dllName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntdll.dll");
    functionAddress = GetDllFunctionAddress("ZwSetInformationFile", &dllName);
    position = *((WORD*)(functionAddress+1));

    DbgPrint("Id:%d\n", position);

        DbgPrint("My Driver Loaded!");
   
    for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
    {
            theDriverObject->MajorFunction[i] = OnStubDispatch;
    }

    theDriverObject->DriverUnload  = OnUnload;

    // save old system call locations
    RealZwSetInformationFile=(NTSETINFORMATIONFILE)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + position));


    _asm
    {
        CLI                  
        MOV    EAX, CR0      
        AND EAX, NOT 10000H
        MOV    CR0, EAX      
    }

    (NTSETINFORMATIONFILE)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + position))=  HookZwSetInformationFile;

    _asm
    {
        MOV    EAX, CR0      
        OR    EAX, 10000H        
        MOV    CR0, EAX              
        STI                    
    }
                    
    return STATUS_SUCCESS;
}

TOP

发新话题