阅读:3941回复:2
Win7下Hook ZwQueryDirectoryFile 蓝屏问题
下面的代码是我从网上搜索的.已经使用过一段时间.
在windows xp下使用正常.但在win7下就出现了很严重的问题:驱动加载后马上蓝屏. 蓝屏上提示是说向只读区域写入 不知问题是出在哪里....求各位大牛帮忙 #include <wdm.h> typedef unsigned int UINT; typedef char * PCHAR; typedef unsigned long BOOL; typedef unsigned long DWORD; #define FileBothDirectoryInformation 3 #define FileIdBothDirectoryInformation 37 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; VOID RtlUpperString(IN OUT PSTRING DestinationString, IN PSTRING SourceString); extern NTSYSAPI NTSTATUS NTAPI ZwQueryDirectoryFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, OUT PVOID FileInformationBuffer, IN ULONG FileInformationBufferLength, IN FILE_INFORMATION_CLASS FileInfoClass, IN BOOLEAN bReturnOnlyOneEntry, IN PUNICODE_STRING PathMask OPTIONAL, IN BOOLEAN bRestartQuery); typedef NTSTATUS (* REALZWQUERYDIRECTORYFILE)(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, OUT PVOID FileInformationBuffer, IN ULONG FileInformationBufferLength, IN FILE_INFORMATION_CLASS FileInfoClass, IN BOOLEAN bReturnOnlyOneEntry, IN PUNICODE_STRING PathMask OPTIONAL, IN BOOLEAN bRestartQuery); // 定义一个原函数指针 REALZWQUERYDIRECTORYFILE RealZwQueryDirectoryFile; // 3. 定义替换 API 函数的原型: // NTSTATUS HookZwQueryDirectoryFile( IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, OUT PVOID FileInformationBuffer, IN ULONG FileInformationBufferLength, IN FILE_INFORMATION_CLASS FileInfoClass, IN BOOLEAN bReturnOnlyOneEntry, IN PUNICODE_STRING PathMask OPTIONAL, IN BOOLEAN bRestartQuery); // -=描述 SYSTEMSERVICE 的定义=- typedef struct ServiceDescriptorEntry { unsigned int * ServiceTableBase; // 关键字段, 指向系统服务分发例程的基地址 unsigned int * ServiceCounterTableBase; unsigned int NumberOfServices; unsigned char * ParamTableBase; } ServiceDescriptorTableEntry_t, * PServiceDescriptorTableEntry_t; __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; #define SYSTEMSERVICE(_function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)_function+1)] NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath); void HideFile_Unload(PDRIVER_OBJECT DriverObject); NTSTATUS HookZwQueryDirectoryFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, OUT PVOID FileInformationBuffer, IN ULONG FileInformationBufferLength, IN FILE_INFORMATION_CLASS FileInfoClass, IN BOOLEAN bReturnOnlyOneEntry, IN PUNICODE_STRING PathMask OPTIONAL, IN BOOLEAN bRestartQuery); #pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(PAGE, HideFile_Unload) #pragma alloc_text (PAGE, HookZwQueryDirectoryFile) NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) { NTSTATUS NtStatus = STATUS_SUCCESS; UINT uiIndex = 0; PDEVICE_OBJECT pDeviceObject = NULL; UNICODE_STRING usDriverName, usDosDeviceName; PAGED_CODE(); DbgPrint("DriverEntry Called\r\n"); RtlInitUnicodeString(&usDriverName, L"\\Device\\HideFile"); RtlInitUnicodeString(&usDosDeviceName, L"\\DosDevices\\HideFile"); NtStatus = IoCreateDevice(pDriverObject, 0, &usDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject); if (STATUS_SUCCESS == NtStatus) { pDriverObject->DriverUnload = HideFile_Unload; } pDeviceObject->Flags |= DO_DIRECT_IO; pDeviceObject->Flags &= (~DO_DEVICE_INITIALIZING); IoCreateSymbolicLink(&usDosDeviceName, &usDriverName); // 4. 在 DriverEntry(驱动入口)函数中加入如下申明: // 保存真正的 ZwQueryDirectoryFile 函数地址 RealZwQueryDirectoryFile = (REALZWQUERYDIRECTORYFILE)(SYSTEMSERVICE(ZwQueryDirectoryFile)); // 把自定义的替换函数指针指向真正的ZwQueryDirectoryFile函数 (REALZWQUERYDIRECTORYFILE)(SYSTEMSERVICE(ZwQueryDirectoryFile)) = HookZwQueryDirectoryFile; return NtStatus; } void HideFile_Unload(PDRIVER_OBJECT DriverObject) { UNICODE_STRING usDosDeviceName; PAGED_CODE(); // 5.在DriverUnload(驱动卸载函数)函数中加入恢复代码: //恢复原来的函数指针 (REALZWQUERYDIRECTORYFILE)(SYSTEMSERVICE(ZwQueryDirectoryFile)) = RealZwQueryDirectoryFile; DbgPrint("HideFile_Unload Called\r\n"); RtlInitUnicodeString(&usDosDeviceName, L"\\DosDevices\\HideFile"); IoDeleteSymbolicLink(&usDosDeviceName); IoDeleteDevice(DriverObject->DeviceObject); } // 6. 现在准备工作做好了, 函数指针都已经设置转向了, 剩下的是实现这个我们自定义的 // 替换函数 HookZwQueryDirectoryFile, 代码如下: // NTSTATUS HookZwQueryDirectoryFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, OUT PVOID FileInformationBuffer, IN ULONG FileInformationBufferLength, IN FILE_INFORMATION_CLASS FileInfoClass, IN BOOLEAN bReturnOnlyOneEntry, IN PUNICODE_STRING PathMask OPTIONAL, IN BOOLEAN bRestartQuery) { NTSTATUS rc; ANSI_STRING ansiHideDirFile; // 初始化要过滤的文件名这里是 debug.exe // 这里字符串是常量, 不用释放 RtlInitAnsiString(&ansiHideDirFile, "DBGVIEW.EXE"); // 执行真正的 ZwQueryDirectoryFile 函数 rc = ((REALZWQUERYDIRECTORYFILE)(RealZwQueryDirectoryFile))( hFile, hEvent, IoApcRoutine, IoApcContext, pIoStatusBlock, FileInformationBuffer, FileInformationBufferLength, FileInfoClass, bReturnOnlyOneEntry, PathMask, bRestartQuery); // 如果执行成功, 而且 FILE_INFORMATION_CLASS 的值为 FileBothDirectoryInformation, 我们就进行处理, 过滤 // if(NT_SUCCESS(rc) && (FileInfoClass == FileBothDirectoryInformation)) if(NT_SUCCESS(rc)) { if ((FileInfoClass == FileBothDirectoryInformation) || (FileInfoClass == FileIdBothDirectoryInformation)) { UNICODE_STRING uniFileName; PFILE_BOTH_DIR_INFORMATION pFileInfo; PFILE_BOTH_DIR_INFORMATION pLastFileInfo; BOOL bLastOne=FALSE; // 把执行结果赋给 pFileInfo pFileInfo = (PFILE_BOTH_DIR_INFORMATION)FileInformationBuffer; pLastFileInfo = NULL; // 循环检查 do { ANSI_STRING ansiDesFileName, ansiSrcFileName; bLastOne = (0 == pFileInfo->NextEntryOffset); RtlInitUnicodeString(&uniFileName, pFileInfo->FileName); // uniFileName 不用释放 RtlUnicodeStringToAnsiString(&ansiDesFileName, &uniFileName, TRUE); // TRUE, 必须释放 RtlUnicodeStringToAnsiString(&ansiSrcFileName, &uniFileName, TRUE); RtlUpperString(&ansiDesFileName, &ansiSrcFileName); // 打印结果, 用 debugview 可以查看打印结果 DbgPrint("ansiFileName :%s\n", ansiDesFileName.Buffer); DbgPrint("HideDirFile :%s\n", ansiHideDirFile.Buffer); // 开始进行比较, 如果找到了就隐藏这个文件或者目录 if( RtlCompareMemory(ansiDesFileName.Buffer, ansiHideDirFile.Buffer, ansiHideDirFile.Length) == ansiHideDirFile.Length) { DbgPrint("This is HideDirFile!\n"); if(bLastOne) { if(pFileInfo == (PFILE_BOTH_DIR_INFORMATION)FileInformationBuffer ) { rc = 0x80000006; // 隐藏文件或者目录; } else { pLastFileInfo->NextEntryOffset = 0; } RtlFreeAnsiString(&ansiSrcFileName); //=========================== RtlFreeAnsiString(&ansiDesFileName); //=========================== break; } else //指针往后移动 { int iPos = ((ULONG)pFileInfo) - (ULONG)FileInformationBuffer; int iLeft = (DWORD)FileInformationBufferLength - iPos - pFileInfo->NextEntryOffset; RtlCopyMemory( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), (DWORD)iLeft ); RtlFreeAnsiString(&ansiSrcFileName); //=========================== RtlFreeAnsiString(&ansiDesFileName); //=========================== continue; } } pLastFileInfo = pFileInfo; pFileInfo = (PFILE_BOTH_DIR_INFORMATION) ((char *)pFileInfo + pFileInfo->NextEntryOffset); RtlFreeAnsiString(&ansiSrcFileName); //=========================== RtlFreeAnsiString(&ansiDesFileName); //=========================== } while ( FALSE == bLastOne ); } } return(rc); } |
|
沙发#
发布于:2010-03-24 08:17
该问题我已经解决.
1.vista或win7返回的结构不再是FileBothDirectoryInformation.而是FileidBothDirectoryInformation 2.蓝屏的原因是驱动向一个只读的位置写入了数据.所以要先把WP bit置为可写后,即可完成api hook了. 在driveentry函数的末尾加入以下代码 _asm { MOV EAX, CR0 //move CR0 register into EAX OR EAX, 10000H //enable WP bit MOV CR0, EAX //write register back STI //enable interrupt } 在unload的末尾加入以下代码,恢复标志 _asm { MOV EAX, CR0 //move CR0 register into EAX OR EAX, 10000H //enable WP bit MOV CR0, EAX //write register back STI //enable interrupt } 以上就是我的解决办法. |
|
板凳#
发布于:2010-05-28 18:04
|
|