Python NtQueryDirectoryFile(文件信息结构)
我编写了一个简单的(测试)脚本来列出选定目录中的文件。不使用Python NtQueryDirectoryFile(文件信息结构),python,python-3.x,ctypes,ntdll,nt-native-api,Python,Python 3.x,Ctypes,Ntdll,Nt Native Api,我编写了一个简单的(测试)脚本来列出选定目录中的文件。不使用FindFirstFile; 只有本机API。 当我执行脚本并观看时,Win32API监视器会告诉我状态\u SUCCESS。 我的文件信息缓冲区是c\u缓冲区(1024),不使用Unicode缓冲区查看原始数据 因此,在调用NtQueryDirectoryFile之后,一切都正常。 当我以原始模式将c_buffer写入控制台以查看目录中的文件时,输出没有结构化。 我创建了一个文件目录信息结构,但它要么不能在Windows 7 X86中
FindFirstFile
;
只有本机API。
当我执行脚本并观看时,Win32API监视器会告诉我状态\u SUCCESS。
我的文件信息缓冲区是c\u缓冲区(1024)
,不使用Unicode缓冲区查看原始数据
因此,在调用NtQueryDirectoryFile
之后,一切都正常。
当我以原始模式将c_buffer
写入控制台以查看目录中的文件时,输出没有结构化。
我创建了一个文件目录信息结构,但它要么不能在Windows 7 X86中工作,要么代码中有问题
我的问题:
请告诉我Windows 7 X86或任何变体上使用的文件目录信息结构
from ctypes import *
hFile = windll.kernel32.CreateFileW("C:\\a",0x80000000,0,0,3,0x02000000,0)
class Info(Union):
_fields_ = [('STATUS',c_long),
('Pointer',c_ulong),]
class io_stat(Structure):
_fields_ = [('Stat',Info),
('Information',c_ulong),]
class FILE_OBJECT(Structure):
_fields_ = [('Next',c_ulong),
('FileIndex',c_ulong),
('ctime',c_longlong),
('lat',c_longlong),
('wtime',c_longlong),
('ch',c_longlong),
('Endogfile',c_longlong),
('allo',c_longlong),
('Fileattr',c_ulong),
('Filenalen',c_ulong),
('Filename',c_wchar * 2),]
b = io_stat()
a = c_buffer(1024)
windll.ntdll.NtQueryDirectoryFile(hFile,0,0,0,byref(b),byref(a),sizeof(a), 1,0,None,0)
print(a.raw)
未优化。
NtQueryDirectoryFile
应在循环中调用,直到它返回状态\u无更多\u文件
。如果返回的状态为状态\缓冲区\溢出
或状态为成功(非负),且状态块信息
为0,则将缓冲区大小加倍,然后重试。对于每次成功通过,将文件\u目录\u信息
记录从缓冲区中复制出来。每个记录的大小必须包括文件名
。当Next
字段为0时,您已到达末尾
下面的示例将FILE\u DIRECTORY\u INFORMATION
子类化为DirEntry
类,该类具有listbuf
类方法来列出查询缓冲区中的记录。它跳过“.”和“.”条目。它在ntlistdir
函数中使用此类,该函数通过NtQueryDirectoryFile
列出给定目录的DirEntry
记录。它支持将打开的文件描述符作为path
参数传递,这类似于os.listdir
在POSIX系统上的工作方式
c类型定义
import os
import msvcrt
import ctypes
from ctypes import wintypes
ntdll = ctypes.WinDLL('ntdll')
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
def NtError(status):
err = ntdll.RtlNtStatusToDosError(status)
return ctypes.WinError(err)
NTSTATUS = wintypes.LONG
STATUS_BUFFER_OVERFLOW = NTSTATUS(0x80000005).value
STATUS_NO_MORE_FILES = NTSTATUS(0x80000006).value
STATUS_INFO_LENGTH_MISMATCH = NTSTATUS(0xC0000004).value
ERROR_DIRECTORY = 0x010B
INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
GENERIC_READ = 0x80000000
FILE_SHARE_READ = 1
OPEN_EXISTING = 3
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
FILE_ATTRIBUTE_DIRECTORY = 0x0010
FILE_INFORMATION_CLASS = wintypes.ULONG
FileDirectoryInformation = 1
FileBasicInformation = 4
LPSECURITY_ATTRIBUTES = wintypes.LPVOID
PIO_APC_ROUTINE = wintypes.LPVOID
ULONG_PTR = wintypes.WPARAM
class UNICODE_STRING(ctypes.Structure):
_fields_ = (('Length', wintypes.USHORT),
('MaximumLength', wintypes.USHORT),
('Buffer', wintypes.LPWSTR))
PUNICODE_STRING = ctypes.POINTER(UNICODE_STRING)
class IO_STATUS_BLOCK(ctypes.Structure):
class _STATUS(ctypes.Union):
_fields_ = (('Status', NTSTATUS),
('Pointer', wintypes.LPVOID))
_anonymous_ = '_Status',
_fields_ = (('_Status', _STATUS),
('Information', ULONG_PTR))
PIO_STATUS_BLOCK = ctypes.POINTER(IO_STATUS_BLOCK)
ntdll.NtQueryInformationFile.restype = NTSTATUS
ntdll.NtQueryInformationFile.argtypes = (
wintypes.HANDLE, # In FileHandle
PIO_STATUS_BLOCK, # Out IoStatusBlock
wintypes.LPVOID, # Out FileInformation
wintypes.ULONG, # In Length
FILE_INFORMATION_CLASS) # In FileInformationClass
ntdll.NtQueryDirectoryFile.restype = NTSTATUS
ntdll.NtQueryDirectoryFile.argtypes = (
wintypes.HANDLE, # In FileHandle
wintypes.HANDLE, # In_opt Event
PIO_APC_ROUTINE, # In_opt ApcRoutine
wintypes.LPVOID, # In_opt ApcContext
PIO_STATUS_BLOCK, # Out IoStatusBlock
wintypes.LPVOID, # Out FileInformation
wintypes.ULONG, # In Length
FILE_INFORMATION_CLASS, # In FileInformationClass
wintypes.BOOLEAN, # In ReturnSingleEntry
PUNICODE_STRING, # In_opt FileName
wintypes.BOOLEAN) # In RestartScan
kernel32.CreateFileW.restype = wintypes.HANDLE
kernel32.CreateFileW.argtypes = (
wintypes.LPCWSTR, # In lpFileName
wintypes.DWORD, # In dwDesiredAccess
wintypes.DWORD, # In dwShareMode
LPSECURITY_ATTRIBUTES, # In_opt lpSecurityAttributes
wintypes.DWORD, # In dwCreationDisposition
wintypes.DWORD, # In dwFlagsAndAttributes
wintypes.HANDLE) # In_opt hTemplateFile
class FILE_BASIC_INFORMATION(ctypes.Structure):
_fields_ = (('CreationTime', wintypes.LARGE_INTEGER),
('LastAccessTime', wintypes.LARGE_INTEGER),
('LastWriteTime', wintypes.LARGE_INTEGER),
('ChangeTime', wintypes.LARGE_INTEGER),
('FileAttributes', wintypes.ULONG))
class FILE_DIRECTORY_INFORMATION(ctypes.Structure):
_fields_ = (('_Next', wintypes.ULONG),
('FileIndex', wintypes.ULONG),
('CreationTime', wintypes.LARGE_INTEGER),
('LastAccessTime', wintypes.LARGE_INTEGER),
('LastWriteTime', wintypes.LARGE_INTEGER),
('ChangeTime', wintypes.LARGE_INTEGER),
('EndOfFile', wintypes.LARGE_INTEGER),
('AllocationSize', wintypes.LARGE_INTEGER),
('FileAttributes', wintypes.ULONG),
('FileNameLength', wintypes.ULONG),
('_FileName', wintypes.WCHAR * 1))
@property
def FileName(self):
addr = ctypes.addressof(self) + type(self)._FileName.offset
size = self.FileNameLength // ctypes.sizeof(wintypes.WCHAR)
return (wintypes.WCHAR * size).from_address(addr).value
DirEntry
和ntlistdir
class DirEntry(FILE_DIRECTORY_INFORMATION):
def __repr__(self):
return '<{} {!r}>'.format(self.__class__.__name__, self.FileName)
@classmethod
def listbuf(cls, buf):
result = []
base_size = ctypes.sizeof(cls) - ctypes.sizeof(wintypes.WCHAR)
offset = 0
while True:
fdi = cls.from_buffer(buf, offset)
if fdi.FileNameLength and fdi.FileName not in ('.', '..'):
cfdi = cls()
size = base_size + fdi.FileNameLength
ctypes.resize(cfdi, size)
ctypes.memmove(ctypes.byref(cfdi), ctypes.byref(fdi), size)
result.append(cfdi)
if fdi._Next:
offset += fdi._Next
else:
break
return result
def isdir(path):
if not isinstance(path, int):
return os.path.isdir(path)
try:
hFile = msvcrt.get_osfhandle(path)
except IOError:
return False
iosb = IO_STATUS_BLOCK()
info = FILE_BASIC_INFORMATION()
status = ntdll.NtQueryInformationFile(hFile, ctypes.byref(iosb),
ctypes.byref(info), ctypes.sizeof(info),
FileBasicInformation)
return bool(status >= 0 and info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
def ntlistdir(path=None):
result = []
if path is None:
path = os.getcwd()
if isinstance(path, int):
close = False
fd = path
hFile = msvcrt.get_osfhandle(fd)
else:
close = True
hFile = kernel32.CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
None, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, None)
if hFile == INVALID_HANDLE_VALUE:
raise ctypes.WinError(ctypes.get_last_error())
fd = msvcrt.open_osfhandle(hFile, os.O_RDONLY)
try:
if not isdir(fd):
raise ctypes.WinError(ERROR_DIRECTORY)
iosb = IO_STATUS_BLOCK()
info = (ctypes.c_char * 4096)()
while True:
status = ntdll.NtQueryDirectoryFile(hFile, None, None, None,
ctypes.byref(iosb), ctypes.byref(info),
ctypes.sizeof(info), FileDirectoryInformation,
False, None, False)
if (status == STATUS_BUFFER_OVERFLOW or
iosb.Information == 0 and status >= 0):
info = (ctypes.c_char * (ctypes.sizeof(info) * 2))()
elif status == STATUS_NO_MORE_FILES:
break
elif status >= 0:
sublist = DirEntry.listbuf(info)
result.extend(sublist)
else:
raise NtError(status)
finally:
if close:
os.close(fd)
return result
输出:
:p非常感谢您,很抱歉,我的代表
if __name__ == '__main__':
import sys
for entry in ntlistdir(sys.exec_prefix):
print(entry)