TengAttack 发表于 2010-7-31 16:15:28

C++使用NtQueryDirectoryFile枚举文件

话说这个东西支持Unicode和多字节的环境……
其实这东西是翻译以前不知在哪看到过的vb代码来的

封装了一个类:CNtQuery

话说好久没来了……:D

代码有点长,就发附件吧,对了,话说为什么不能上传7z格式的文件?

TengAttack 发表于 2010-7-31 16:16:37

补上个代码吧:
//NtQuery.h By 腾袭 2010-7-25

#ifndef _NT_QUERY_H_INCLUDE_
#define _NT_QUERY_H_INCLUDE_ 1

#pragma once

typedef struct _LSA_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PCHAR Buffer;
} LSA_STRING, *PLSA_STRING, ANSI_STRING, *PANSI_STRING;

typedef struct _LSA_UNICODE_STRING {
        USHORT Length;
        USHORT MaximumLength;
        PWSTRBuffer;
} LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;

typedef struct _IO_STATUS_BLOCK {
        NTSTATUS Status;
        ULONG Information;
}IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

typedef struct _OBJECT_ATTRIBUTES
{
        ULONG Length;
        HANDLE RootDirectory;
        PUNICODE_STRING ObjectName;
        ULONG Attributes;
        PVOID SecurityDescriptor;
        PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

typedef struct _FILE_DIRECTORY_INFORMATION {
        ULONG NextEntryOffset;
        ULONG Unknown;
        LARGE_INTEGER CreationTime;
        LARGE_INTEGER LastAccessTime;
        LARGE_INTEGER LastWriteTime;
        LARGE_INTEGER ChangeTime;
        LARGE_INTEGER EndOfFile;
        LARGE_INTEGER AllocationSize;
        ULONG FileAttributes;
        ULONG FileNameLength;
        WCHAR FileName;
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;

//FileFullDirectoryInformation:
typedef struct _FILE_FULL_DIRECTORY_INFORMATION {
        ULONG NextEntryOffset;
        ULONG Unknown;
        LARGE_INTEGER CreationTime;
        LARGE_INTEGER LastAccessTime;
        LARGE_INTEGER LastWriteTime;
        LARGE_INTEGER ChangeTime;
        LARGE_INTEGER EndOfFile;
        LARGE_INTEGER AllocationSize;
        ULONG FileAttributes;
        ULONG FileNameLength;
        ULONG EaInformationLength;
        WCHAR FileName;
} FILE_FULL_DIRECTORY_INFORMATION, *PFILE_FULL_DIRECTORY_INFORMATION;

//FileBothDirectoryInformation:
typedef struct _FILE_BOTH_DIRECTORY_INFORMATION {
        ULONG NextEntryOffset;
        ULONG Unknown;
        LARGE_INTEGER CreationTime;
        LARGE_INTEGER LastAccessTime;
        LARGE_INTEGER LastWriteTime;
        LARGE_INTEGER ChangeTime;
        LARGE_INTEGER EndOfFile;
        LARGE_INTEGER AllocationSize;
        ULONG FileAttributes;
        ULONG FileNameLength;
        ULONG EaInformationLength;
        UCHAR AlternateNameLength;
        WCHAR AlternateName;
        WCHAR FileName;
} FILE_BOTH_DIRECTORY_INFORMATION, *PFILE_BOTH_DIRECTORY_INFORMATION;

//FileNamesInformation:
typedef struct _FILE_NAMES_INFORMATION {
        ULONG NextEntryOffset;
        ULONG Unknown;
        ULONG FileNameLength;
        WCHAR FileName;
} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;

typedef enum _FILE_INFORMATION_CLASS {
        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
        FileIdBothDirectoryInformation, // 37
        FileIdFullDirectoryInformation, // 38
        FileValidDataLengthInformation, // 39
        FileShortNameInformation, // 40
        FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;

#ifndef SYNCHRONIZE
#define SYNCHRONIZE 0x100000
#endif

#ifndef FILE_ANY_ACCESS
#define FILE_ANY_ACCESS 0
#endif

#ifndef FILE_LIST_DIRECTORY
#define FILE_LIST_DIRECTORY 1
#endif

#ifndef FILE_DIRECTORY_FILE
#define FILE_DIRECTORY_FILE 1
#endif

#ifndef FILE_SYNCHRONOUS_IO_NONALERT
#define FILE_SYNCHRONOUS_IO_NONALERT 0x20
#endif

#ifndef FILE_OPEN_FOR_BACKUP_INTENT
#define FILE_OPEN_FOR_BACKUP_INTENT 0x4000
#endif

#ifndef OBJ_CASE_INSENSITIVE
#define OBJ_CASE_INSENSITIVE 0x40
#endif

typedef NTSTATUS (NTAPI *FN_NtQueryDirectoryFile)( IN HANDLE FileHandle,
        IN HANDLE Event OPTIONAL,
        IN PVOID ApcRoutine OPTIONAL, /*PIO_APC_ROUTINE*/
        IN PVOID ApcContext OPTIONAL,
        OUT PIO_STATUS_BLOCK IoStatusBlock,
        OUT PVOID FileInformation,
        IN ULONG FileInformationLength,
        IN FILE_INFORMATION_CLASS FileInformationClass,
        IN BOOLEAN ReturnSingleEntry,
        IN PUNICODE_STRING FileName OPTIONAL,
        IN BOOLEAN RestartScan );

typedef NTSTATUS (NTAPI *FN_NtOpenFile)(
        __outPHANDLE FileHandle,
        __in   ACCESS_MASK DesiredAccess,
        __in   POBJECT_ATTRIBUTES ObjectAttributes,
        __outPIO_STATUS_BLOCK IoStatusBlock,
        __in   ULONG ShareAccess,
        __in   ULONG OpenOptions
);

typedef NTSTATUS (NTAPI *FN_NtClose)(
        __inHANDLE Handle
);

typedef void (NTAPI *FN_RtlInitUnicodeString)(
        __inout   PUNICODE_STRING DestinationString,
        __in_optPCWSTR SourceString
);

typedef void (NTAPI *FN_RtlInitAnsiString)(
        __inout PANSI_STRING DestinationString,
        __inout PCSTR SourceString
);

typedef NTSTATUS (NTAPI *FN_RtlAnsiStringToUnicodeString)(
        PUNICODE_STRING DestinationString,
        PANSI_STRING SourceString,
        BOOLEAN AllocateDestinationString
);

typedef NTSTATUS (NTAPI *FN_RtlUnicodeStringToAnsiString)(
        PANSI_STRING DestinationString,
        PUNICODE_STRING SourceString,
        BOOLEAN AllocateDestinationString
);

typedef void (NTAPI *FN_RtlFreeUnicodeString)(
      PUNICODE_STRING UnicodeString
);

typedef void (NTAPI *FN_RtlFreeAnsiString)(
      PANSI_STRING AnsiString
);

class CNtQuery
{
public:
        CNtQuery(void);
        virtual ~CNtQuery(void);
        static bool CNtQuery::GetAddr();
        static bool m_bInit;

        HANDLE FindFirstFile(LPCTSTR strDirectory,PBYTE bytBuffer,ULONG size);
        bool FindNextFile(HANDLE hFind,PBYTE bytBuffer,ULONG size);
        void Enum(LPCTSTR lpszPath);

        NTSTATUS CNtQuery::ANSI2UNICODE(LPCSTR lpBuf, PUNICODE_STRING pUnicodeString, BOOLEAN AllocateDestinationString = TRUE);
        NTSTATUS CNtQuery::UNICODE2ANSI(LPCWSTR lpBuf, PANSI_STRING pAnsiString, BOOLEAN AllocateDestinationString = TRUE);
private:
        static HMODULE m_hNtdll;
protected:
        static FN_NtQueryDirectoryFile fn_NtQueryDirectoryFile;
        static FN_NtOpenFile fn_NtOpenFile;
        static FN_NtClose fn_NtClose;
        static FN_RtlInitUnicodeString fn_RtlInitUnicodeString;
        static FN_RtlInitAnsiString fn_RtlInitAnsiString;
        static FN_RtlAnsiStringToUnicodeString fn_RtlAnsiStringToUnicodeString;
        static FN_RtlUnicodeStringToAnsiString fn_RtlUnicodeStringToAnsiString;
        static FN_RtlFreeUnicodeString fn_RtlFreeUnicodeString;
        static FN_RtlFreeAnsiString fn_RtlFreeAnsiString;
};

#endif

TengAttack 发表于 2010-7-31 16:16:55


//NtQuery.cpp By 腾袭 2010-7-25

#include "StdAfx.h"
#include "NtQuery.h"

HMODULE CNtQuery::m_hNtdll = NULL;
FN_NtQueryDirectoryFile CNtQuery::fn_NtQueryDirectoryFile;
FN_NtOpenFile CNtQuery::fn_NtOpenFile;
FN_NtClose CNtQuery::fn_NtClose;
FN_RtlInitUnicodeString CNtQuery::fn_RtlInitUnicodeString;
FN_RtlInitAnsiString CNtQuery::fn_RtlInitAnsiString;
FN_RtlAnsiStringToUnicodeString CNtQuery::fn_RtlAnsiStringToUnicodeString;
FN_RtlUnicodeStringToAnsiString CNtQuery::fn_RtlUnicodeStringToAnsiString;
FN_RtlFreeUnicodeString CNtQuery::fn_RtlFreeUnicodeString;
FN_RtlFreeAnsiString CNtQuery::fn_RtlFreeAnsiString;

bool CNtQuery::m_bInit = false;

bool CNtQuery::GetAddr()
{
        m_hNtdll = GetModuleHandle(_T("ntdll.dll"));
        if (m_hNtdll == NULL)
                return false;

        fn_NtQueryDirectoryFile = (FN_NtQueryDirectoryFile)GetProcAddress(m_hNtdll,"NtQueryDirectoryFile");
        fn_NtOpenFile = (FN_NtOpenFile)GetProcAddress(m_hNtdll,"NtOpenFile");
        fn_NtClose = (FN_NtClose)GetProcAddress(m_hNtdll,"NtClose");
        fn_RtlInitUnicodeString = (FN_RtlInitUnicodeString)GetProcAddress(m_hNtdll,"RtlInitUnicodeString");
        fn_RtlInitAnsiString = (FN_RtlInitAnsiString)GetProcAddress(m_hNtdll,"RtlInitAnsiString");
        fn_RtlAnsiStringToUnicodeString = (FN_RtlAnsiStringToUnicodeString)GetProcAddress(m_hNtdll,"RtlAnsiStringToUnicodeString");
        fn_RtlUnicodeStringToAnsiString = (FN_RtlUnicodeStringToAnsiString)GetProcAddress(m_hNtdll,"RtlUnicodeStringToAnsiString");
        fn_RtlFreeUnicodeString = (FN_RtlFreeUnicodeString)GetProcAddress(m_hNtdll,"RtlFreeUnicodeString");
        fn_RtlFreeAnsiString = (FN_RtlFreeAnsiString)GetProcAddress(m_hNtdll,"RtlFreeAnsiString");

        if (!(fn_NtQueryDirectoryFile && fn_NtOpenFile && fn_NtClose && fn_RtlInitUnicodeString))
        {
                return false;
        }
        return true;
}

CNtQuery::CNtQuery(void)
{
        if (!m_bInit)
                m_bInit = GetAddr();
}


CNtQuery::~CNtQuery(void)
{
}

HANDLE CNtQuery::FindFirstFile(LPCTSTR strDirectory,PBYTE bytBuffer,ULONG size)
{
        if (!m_bInit)
                return INVALID_HANDLE_VALUE;

    TCHAR strFolder;
        OBJECT_ATTRIBUTES obAttr;
    IO_STATUS_BLOCK objIoStatus;
    NTSTATUS ntStatus;
    HANDLE hFind = NULL;
    UNICODE_STRING strUnicode;
   
        wsprintf(strFolder,_T("\\??\\%s"),strDirectory);

        //'初始化Unicode字符串
#ifdef UNICODE
    fn_RtlInitUnicodeString(&strUnicode, strFolder);
#else
        ANSI2UNICODE(strFolder,&strUnicode);
#endif

        memset(&objIoStatus,0,sizeof(IO_STATUS_BLOCK));
        memset(&obAttr,0,sizeof(OBJECT_ATTRIBUTES));

    obAttr.Length = sizeof(OBJECT_ATTRIBUTES); //'初始化OBJECT_ATTRIBUTES结构
    obAttr.Attributes = OBJ_CASE_INSENSITIVE;
    obAttr.ObjectName = &strUnicode; //'需要打开的文件夹路径
        obAttr.RootDirectory = NULL;
    obAttr.SecurityDescriptor = NULL;
    obAttr.SecurityQualityOfService = NULL;
    //'获取文件夹句柄
    ntStatus = fn_NtOpenFile(&hFind,
                        FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_ANY_ACCESS,
                        &obAttr,
                        &objIoStatus,
                        3,
                        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);
#ifndef UNICODE
        //释放内存
        fn_RtlFreeUnicodeString(&strUnicode);
#endif
    if (ntStatus == 0 && hFind != INVALID_HANDLE_VALUE)
        {
               
      //'获取文件夹文件/目录信息,其实这个函数是Kernel32里的FindFirstFile的封装
      ntStatus = fn_NtQueryDirectoryFile(hFind,
                                     NULL,
                                     NULL,
                                     NULL,
                                     &objIoStatus,
                                     bytBuffer,
                                     size,
                                     FileBothDirectoryInformation,
                                     TRUE,
                                     NULL,
                                     NULL);
      if (ntStatus == 0)        //'Nt系列函数一般返回大于零表示成功,而NtQueryDirectoryFile返回零表示成功
                {
                        //_tprintf(_T("Succeed!\n"));
            return hFind;
                }else{
            fn_NtClose(hFind);
                }
        }
        return INVALID_HANDLE_VALUE;
}

bool CNtQuery::FindNextFile(HANDLE hFind,PBYTE bytBuffer,ULONG size)
{
        if (!m_bInit)
                return false;
    NTSTATUS ntStatus;
    IO_STATUS_BLOCK objIoStatus;
    //'这是Kernel32 FindNextFile的封装,只是是一次把所有文件/目录都取出来了
    ntStatus = fn_NtQueryDirectoryFile(hFind,
                                 NULL,
                                 NULL,
                                 NULL,
                                 &objIoStatus,
                                 bytBuffer,
                                 size,
                                 FileBothDirectoryInformation,
                                 FALSE,
                                 NULL,
                                 NULL);
        //_tprintf(_T("ntStatus\n"));
    return (ntStatus == 0);
}

void CNtQuery::Enum(LPCTSTR lpszPath)
{
        if (!m_bInit)
                return;
#ifndef UNICODE
        ANSI_STRING asfn,asan;
#endif

    PFILE_BOTH_DIRECTORY_INFORMATION pDir;
    HANDLE hFind;
    LPBYTE bytBuffer;
    wchar_t fileName;
        wchar_t AlternateName;
    TCHAR strPath;
    TCHAR strFileName;

    ULONG dwDirOffset;
        ULONG iCount = 0;
        ULONG usize = sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + MAX_PATH * 2 - 3;
    bytBuffer = new BYTE;
        //memset(bytBuffer,0,usize);

        lstrcpy(strPath,lpszPath);

    hFind = FindFirstFile(strPath,bytBuffer,usize);        //'获取第一个文件/目录对象
        if (hFind == INVALID_HANDLE_VALUE)
                return ;
        pDir = (PFILE_BOTH_DIRECTORY_INFORMATION)bytBuffer;
        //获取FILE_BOTH_DIRECTORY_INFORMATION结构,目的是获取FileNameLength和NextEntryOffset数据

    memcpy(fileName, pDir->FileName, pDir->FileNameLength);
        memcpy(AlternateName,pDir->AlternateName,pDir->AlternateNameLength);        //8.3短文件名
        fileName = 0;
        AlternateName = 0;                        //这里的长度都是字节数

#ifndef UNICODE
        UNICODE2ANSI(fileName, &asfn);
        UNICODE2ANSI(AlternateName, &asan);
        wsprintf(strFileName,_T("%s%s"),strPath, asfn.Buffer);
        _tprintf(_T("%02d %8s\t%s\n"),pDir->AlternateNameLength, asan.Buffer, strFileName);
        fn_RtlFreeAnsiString(&asfn);
        fn_RtlFreeAnsiString(&asan);
#else
        wsprintf(strFileName,_T("%s%s"),strPath,fileName);
        _tprintf(_T("%02d %8s\t%s\n"),pDir->AlternateNameLength, AlternateName, strFileName);
#endif
       
    delete[] bytBuffer;
       
        usize = (sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + (260 * 2 - 3)) * 0x2000;
        bytBuffer = new BYTE;

        iCount = 1;
    while (FindNextFile(hFind,bytBuffer,usize))        //虽然分配了许多空间了,但是仍可能不能把全部文件列举出来,因此,这里需要进一步测试
        {
      dwDirOffset = 0;
      //遍历缓存
      while(true)
                {
                        //移动指针
            pDir = (PFILE_BOTH_DIRECTORY_INFORMATION)(bytBuffer + dwDirOffset);
                        //得到FILE_BOTH_DIRECTORY_INFORMATION结构
                       
                        memcpy(fileName, pDir->FileName, pDir->FileNameLength);                                        //文件名
                        memcpy(AlternateName,pDir->AlternateName,pDir->AlternateNameLength);        //8.3短文件名
                        AlternateName = 0;                        //这里的长度都是字节数
                        fileName = 0;

#ifndef UNICODE
                        UNICODE2ANSI(fileName, &asfn);
                        UNICODE2ANSI(AlternateName, &asan);
                        wsprintf(strFileName,_T("%s%s"),strPath, asfn.Buffer);
                        _tprintf(_T("%02d %8s\t%s\n"),pDir->AlternateNameLength, asan.Buffer, strFileName);
                        fn_RtlFreeAnsiString(&asfn);
                        fn_RtlFreeAnsiString(&asan);
#else
                        wsprintf(strFileName,_T("%s%s"),strPath,fileName);
                        _tprintf(_T("%02d %8s\t%s\n"),pDir->AlternateNameLength, AlternateName, strFileName);
#endif
                        //这里如果是目录可以递归遍历目录下所有文件/目录,可以自己封装一个递归函数吧

                        iCount++;
            if (pDir->NextEntryOffset == 0)
                                break;
            dwDirOffset += pDir->NextEntryOffset; //这里指向下一个FILE_BOTH_DIRECTORY_INFORMATION结构在内存中的位置
                }
        }

        delete[] bytBuffer;
    fn_NtClose(hFind);
        _tprintf(_T("\nfilecount: %d\n"),iCount);
}


//RtlAnsiStringToUnicodeString()
//RtlUnicodeStringToAnsiString()
//当第3个参数为TRUE时,系统将新分配内存,所以要记得调用RtlFreeUnicodeString()和RtlFreeAnsiString()释放掉。

NTSTATUS CNtQuery::ANSI2UNICODE(LPCSTR lpBuf, PUNICODE_STRING pUnicodeString, BOOLEAN AllocateDestinationString)
{
        ANSI_STRING as;
        fn_RtlInitAnsiString( &as, lpBuf );
        return fn_RtlAnsiStringToUnicodeString( pUnicodeString, &as, AllocateDestinationString );
}

NTSTATUS CNtQuery::UNICODE2ANSI(LPCWSTR lpBuf, PANSI_STRING pAnsiString, BOOLEAN AllocateDestinationString)
{
        UNICODE_STRING ns;
        fn_RtlInitUnicodeString( &ns, lpBuf );
        return fn_RtlUnicodeStringToAnsiString( pAnsiString, &ns, AllocateDestinationString );
}

TengAttack 发表于 2010-7-31 16:17:35

没有用ntddk.h,所以结构申明有点长

8013 发表于 2010-8-3 20:48:57

哇,一句话,小孩没娘,说来话长!~·····

k1e0a2v5 发表于 2013-2-2 17:51:09

WIN64上這個還有用嗎

kk1025 发表于 2013-3-30 17:08:48

TengAttack 发表于 2010-7-31 16:16 static/image/common/back.gif


收下先
页: [1]
查看完整版本: C++使用NtQueryDirectoryFile枚举文件