squall001
驱动牛犊
驱动牛犊
  • 注册日期2010-05-07
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望11点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:1711回复:1

【求助】关于通过hook实现文件隐藏的问题

楼主#
更多 发布于:2010-05-17 22:45
在驱动程序里面,通过hook ZwQueryDirectoryFile()来实现的隐藏文件, 可以实现隐藏了,但是有一点小的问题,下面是hook ZwQueryDirectoryFile()过后的过程函数HookZwQueryDirectoryFile(),我把要hook的文件名放在链表里面,而链表的内容是通过外面的程序传给驱动程序的 具体的代码可以看附件,下面是链表和hook函数

#define dprintf if (DBG) DbgPrint
#define nprintf DbgPrint

//定义FILE_INFORMATION_CLASS的第3号结构:_FILE_BOTH_DIR_INFORMATION,这个结构是ZwQueryDirectoryFile必须参数。
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;

//定义链表
typedef struct FileProtectLink
{
    UNICODE_STRING fileName;   //只是文件名如:abc.txt
    UNICODE_STRING allName;    //全路径如:c:\aaaa\abc.txt
    UNICODE_STRING nameWithoutDiskName; //除去盘符的路径 如 \aaaa\abc.txt
    UNICODE_STRING passWord;   //连接密码 
    struct FileProtectLink *next;     //指到下一个结点
} FileProtectLink, *PFileProtectLink;

FileProtectLink fileProtectLinkHand;   //申请的全局链表指针变量

//hook函数过程
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 = STATUS_SUCCESS;
    UNICODE_STRING uniFileName;
    PCWSTR pProcPath = NULL;

    // 执行真正的 ZwQueryDirectoryFile 函数
    rc = OriginalZwQueryDirectoryFile(
        hFile, 
        hEvent, 
        IoApcRoutine,
        IoApcContext,
        pIoStatusBlock,
        FileInformationBuffer,
        FileInformationBufferLength,
        FileInfoClass,
        bReturnOnlyOneEntry,
        PathMask,
        bRestartQuery);

    // 如果执行成功,而且 FILE_INFORMATION_CLASS 的值为 FileBothDirectoryInformation,我们就进行处理,过滤
    if (NT_SUCCESS(rc) && FileInfoClass == FileBothDirectoryInformation)
    {
        PFileProtectLink pLink = fileProtectLinkHand.next;
        while( pLink != NULL)
        {
            // 把执行结果赋给 pFileInfo
            PFILE_BOTH_DIR_INFORMATION pFileInfo = (PFILE_BOTH_DIR_INFORMATION)FileInformationBuffer;
            PFILE_BOTH_DIR_INFORMATION pLastFileInfo = NULL;
            BOOLEAN bLastOne = FALSE;
        
            // 循环检查
            do
            {
                bLastOne = !pFileInfo->NextEntryOffset;
                RtlInitUnicodeString(&uniFileName, pFileInfo->FileName);
                
                dprintf("pFileInfo %d %d %wZ\n", (int)pFileInfo, (int)pFileInfo->NextEntryOffset, &uniFileName);

                            

                // 开始进行比较,如果找到了就隐藏这个文件或者目录
                if (RtlCompareMemory(uniFileName.Buffer, pLink->fileName.Buffer, pLink->fileName.Length) == pLink->fileName.Length)
                {
                    if (bLastOne)
                    {
                        dprintf("bLastOne %wZ\n", &uniFileName);
                        if (pFileInfo == (PFILE_BOTH_DIR_INFORMATION)FileInformationBuffer)
                        {

                            rc = STATUS_NO_MORE_FILES;    // 隐藏文件或者目录;
                        }
                        else
                            pLastFileInfo->NextEntryOffset = 0;
                        
                        break;
                    }
                    else    // 指针往后移动
                    {
                        int iPos = (ULONG)pFileInfo - (ULONG)FileInformationBuffer;
                        int iLeft = (ULONG)FileInformationBufferLength - iPos - pFileInfo->NextEntryOffset;
                        RtlCopyMemory((PVOID)pFileInfo, (PVOID)((PCHAR)pFileInfo + pFileInfo->NextEntryOffset), (ULONG)iLeft);
                        
                                                dprintf("enter bLastOne else and  iPos is %d  iLeft is %d  is %ld\n",iPos,iLeft,(ULONG)FileInformationBufferLength);
                                                continue;
                    }
                }
                pLastFileInfo = pFileInfo;
                pFileInfo = (PFILE_BOTH_DIR_INFORMATION)((PCHAR)pFileInfo + pFileInfo->NextEntryOffset);
            } while (!bLastOne);

            pLink = pLink->next;
        }
    }

    return rc;
}


问题:如果链表里面fileName的值是111.txt那么在C盘根目录下有这个文件的话就全部隐藏了
他是会执行rc = STATUS_NO_MORE_FILES;这条语句引起的,下面是我的分析。

分析:
通过调试 我发现  HOOK函数也是要枚举所有当前目录下的文件的,然后而且文件名都是在内核里面用的大写字母来比较的,所以即使我们建立的文件名是小写字母的,也会被转换为大写字母来比较,但只是比较的时候是这样,文件名本身不会被改变。也就是说假设C盘根目录下面有这几个文件(当然这是举例,不是实际情况) 123.txt, aaa.txt,nina.txt,CONFIG.SYS,CAD.EXE; 那么 系统会自动创立一个链表(其实不是链表,因为和链表的情况很相似,一个文件接一个文件的,所以我把他说成链表,便于理解),把我们这几个文件根据文件名链起来,分别是123.txt->aaa.txt->CAD.EXE->CONFIG.SYS->nina.txt ,是根据文件名来的  数字的永远都是在开头,如果我们在这个文件夹里面新建立一个文件a.txt 那么这个文件会自动插入上面的那个文件链表里面 结果就是:123.txt->a.txt->aaa.txt->CAD.EXE->CONFIG.SYS->nina.txt

通过调试 发现  程序只要不把上面那个链表的第一个文件隐藏 隐藏其他的都正常运行

整个隐藏的原理其实就是调整了这个文件链,通过hook那个函数的下面这几行 把链表里面信息改了

     int iPos = ((ULONG)pFileInfo) - (ULONG)FileInformationBuffer;
     int iLeft = (DWORD)FileInformationBufferLength - iPos - pFileInfo->NextEntryOffset;
     RtlCopyMemory( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), (DWORD)iLeft );
     continue;


也就是说如果本来目录下的文件链表是:
123.txt->a.txt->aaa.txt->CAD.EXE->CONFIG.SYS->nina.txt  
那么 我要隐藏a.txt 我就通过上面那几句,找准位置后把链表改为:
123.txt->aaa.txt->aaa.txt->CAD.EXE->CONFIG.SYS->nina.txt
也就是把要隐藏节点的后面一个节点放到当前节点上面来 那么在函数返回后 用户就不会发现有a.txt这个文件了  

至于我们遇到的问题 为什么会全部隐藏  因为我们隐藏的是第一文件 而且pFileInfo->NextEntryOffset==0 所以他执行了rc= STATUS_NO_MORE_FILES所以 只要返回这个rc 就返回这个目录里面没有文件的tag,所以就全部看不到了 实现了一次性全部隐藏,根据我们的要求,根本不需要这里的对rc的改变,所以我把包括if(bLastOne)在内里面的东西全部注释起来了, 在上面的if语句里面,只要判断出名字相匹配了,就直接运行else里面的东西,不用去判断if(bLastOne),程序照样运行,只是不能隐藏第一个文件而已~~~~~~~~~

最后至于为什么不能隐藏链表的第一个文件?因为通过dbgview看到,第一个文件的pFileInfo->NextEntryOffset为0,(这个我也不知道为什么) 而且传进来的参数FileInformationBufferLength在枚举第一个文件的时候的值是616  而在第二个的时候就变成了4096 以后都是4096  而且整个过程没有看到它在哪点赋值过, 就是调用一次 然后居然在没有任何赋值的情况下自己被改变了?? 难道是在这里使用了多线程而又没有做同步?[/COLOR]

还有就是如果隐藏第一个文件那么由于pFileInfo->NextEntryOffset==0 那么在RtlCopyMemory( (PVOID)pFileInfo, (PVOID)( (char *)pFileInfo + pFileInfo->NextEntryOffset ), (DWORD)iLeft );的时候,拷贝内存的目的地和起始地都是同一个地方,可能这个就是不能实现隐藏的原因。

请问如果要隐藏第一个文件 该怎么解决~~~~
[/COLOR]
ycmint
驱动牛犊
驱动牛犊
  • 注册日期2011-05-07
  • 最后登录2012-03-19
  • 粉丝0
  • 关注0
  • 积分12分
  • 威望141点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2011-09-13 11:34
游客

返回顶部