简单实现文件防删除,说简单是因为没有用很底层的技术,例如文件驱动之类。我只用最简单的方法实现了, 使用 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;

}


这只是一个证明性代码,要实战的兄弟自己动点手吧。