C++使用NtQueryDirectoryFile枚举文件
话说这个东西支持Unicode和多字节的环境……其实这东西是翻译以前不知在哪看到过的vb代码来的
封装了一个类:CNtQuery
话说好久没来了……:D
代码有点长,就发附件吧,对了,话说为什么不能上传7z格式的文件? 补上个代码吧:
//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
//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 );
} 没有用ntddk.h,所以结构申明有点长 哇,一句话,小孩没娘,说来话长!~····· WIN64上這個還有用嗎 TengAttack 发表于 2010-7-31 16:16 static/image/common/back.gif
收下先
页:
[1]