[原创]ring3 下挂钩Native API 简单实现文件防删除
[文章作者]zhouzhen[E.S.T][信息来源]邪恶八进制信息安全团队 & 安全代码 [url]http://www.securitycode.cn/bbs[/url]
简单实现文件防删除,说简单是因为没有用很底层的技术,例如文件驱动之类。我只用最简单的方法实现了, 使用 ring3 的API hook 技术。随着技术的发展这种技术已经过不了很多的主动防御技术了。主要是思路和方法和分析过程。(高手飘过)
ring3 下挂钩 API 基本上也就是修改导入表,和Inline hook 修改前5个字节这几种方法。挂钩Native API 没有什么区别,也就是多声明几个结构和变量类型。
关于挂钩API 请参见:[url]www.xfocus.net/articles/200403/681.html[/url]
文件删除的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;
}
这只是一个证明性代码,要实战的兄弟自己动点手吧。 不错,Ring3下的稳定,这点很重要 [s:267] 删除是不行,但是可以重命名,重命名之后,就可以删除了。。。 想问下zhouzhen大哥,怎样才能获得FileHandle的句柄? 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 是其它地方传到我们的函数里的,这里不关心它具体的值 NtQueryDirectoryFile 好了... [quote]引用第2楼asm于2007-09-20 21:52发表的 :
[s:267] 删除是不行,但是可以重命名,重命名之后,就可以删除了。。。[/quote]
呵呵,CreateFile独占之~
其实弄个DLL注入所有进程,然后每一个都CreateFile独占文件,能够对付大多数用户
FSD钩子好是好,就是容易blue掉 为什么这里 psi = (FILE_NAME_INFORMATION*)new WCHAR[sizeof(FILE_NAME_INFORMATION) + 1024];还要加个1024?这个值怎样确定的? 好象没什么意义.
就是欲留点空间吧. sunwear 说的没有错,就是分配一点空间了
typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
看这个结构,如果不多分配一些,文件名一长就崩溃了。 哦,原来这样,明白了,谢谢楼上两位 [s:269] 请问一下ring3 和ring0 下的挂钩怎么区分的,徘徊hook ring3 还是hook ring0,我也想按楼主的思路模仿一下!
刚刚入门的菜鸟呀 呵呵。不用挂钩也可以。直接文件占亢也行。
DebugMan上一大牛给了个很猥亵的方法。打开要保护的文件句柄。NtDuplicateObject复制System的句柄权限给它。然后就可以很XX啦~~~
360的文件粉碎机只能看重启后才能删除它,其他的直接无视。。。 [s:267] [quote]引用第12楼sudami于2008-01-17 21:39发表的 :
呵呵。不用挂钩也可以。直接文件占亢也行。
DebugMan上一大牛给了个很猥亵的方法。打开要保护的文件句柄。NtDuplicateObject复制System的句柄权限给它。然后就可以很XX啦~~~
360的文件粉碎机只能看重启后才能删除它,其他的直接无视。。。 [s:267][/quote]
汗.......NtDuplicateObject,够委琐..... 很久以前就看到这个帖子了,那时候一窍不通呀,那时候就想当成填空题做了,现在我终于拼出来了,
注意用这个工具加载
[url]http://bbs.pediy.com/showthread.php?t=60689[/url] 在7楼
其实这些代码早就满天飞了,就被传烂了!:sweat:
希望能给后来的朋友们多一种选择,因为系统最终是通过发irp来删除的,所以无法过那些发irp的工具,
如果你看过2000的源码,你就会知道也不能重命名!
因为是从ntdll中导出函数,应该通用,(仅测试过xp)
源码如下:[code]#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;
}
[/code]
页:
[1]