Added some code to play with extended attributes

This commit is contained in:
hakril
2020-01-26 16:02:38 +01:00
parent b490130585
commit 2e1043ead4
3 changed files with 127 additions and 7 deletions
+3 -3
View File
@@ -1,3 +1,3 @@
from pythonutils import *
from winutils import *
from improved_buffer import *
from .pythonutils import *
from .winutils import *
from .improved_buffer import *
+4
View File
@@ -1,3 +1,4 @@
import sys
import ctypes
import _ctypes
import windows.generated_def as gdef
@@ -17,6 +18,9 @@ import windows.generated_def as gdef
# On peut vouloir creer un buffer avec 12 elts de type X
# Ou creer un buffer avec 12 elt de type X mais une sub-size de 1000
if sys.version_info.major >= 3:
long = int
class ImprovedCtypesBufferBase(object):
def cast(self, type):
return ctypes.cast(self, type)
+120 -4
View File
@@ -96,6 +96,22 @@ def create_process(path, args=None, dwCreationFlags=0, show_windows=True):
return windows.winobject.process.WinProcess(pid=proc_info.dwProcessId, handle=proc_info.hProcess)
def device_io_control(handle, iocode, buffer):
outbuffer = ctypes.c_buffer(0x1000)
returned_size = gdef.DWORD()
windows.winproxy.DeviceIoControl(handle, iocode, buffer, lpOutBuffer=outbuffer, lpBytesReturned=returned_size)
return outbuffer[:returned_size.value]
def tmp_cp_as(path, token):
proc_info = PROCESS_INFORMATION()
windows.winproxy.CreateProcessAsUserA(token, path, lpCommandLine=None, dwCreationFlags=gdef.CREATE_NEW_CONSOLE, lpProcessInformation=ctypes.byref(proc_info), lpStartupInfo=None)
return windows.winobject.process.WinProcess(pid=proc_info.dwProcessId, handle=proc_info.hProcess)
def find_handle(proc, value):
return [h for h in windows.system.handles if h.dwProcessId == proc.pid and h.wValue == value]
def lookup_privilege_value(privilege_name):
luid = LUID()
winproxy.LookupPrivilegeValueA(None, privilege_name, byref(luid))
@@ -244,8 +260,30 @@ def get_kernel_modules_syswow64():
modules = (SYSTEM_MODULE64 * buffer.ModulesCount).from_address(addressof(buffer) + SYSTEM_MODULE_INFORMATION64.Modules.offset)
return list(modules)
class FileStreamInformation(gdef.FILE_STREAM_INFORMATION):
@property
def name(self):
return gdef.LPWSTR(ctypes.addressof(self) + type(self).StreamName.offset).value
@property
def next(self):
if not self.NextEntryOffset:
return None
return type(self).from_address(ctypes.addressof(self) + self.NextEntryOffset)
def all(self):
return list(self)
def __iter__(self):
while self:
yield self
self = self.next
def __repr__(self):
return "<ADS name='{0}'>".format(self.name)
# Split winutils.py ?
ntqueryinformationfile_info_structs = {
gdef.FileAccessInformation: gdef.FILE_ACCESS_INFORMATION,
gdef.FileAlignmentInformation: gdef.FILE_ALIGNMENT_INFORMATION,
@@ -261,11 +299,12 @@ ntqueryinformationfile_info_structs = {
gdef.FilePositionInformation: gdef.FILE_POSITION_INFORMATION,
gdef.FileStandardInformation: gdef.FILE_STANDARD_INFORMATION,
gdef.FileIsRemoteDeviceInformation: gdef.FILE_IS_REMOTE_DEVICE_INFORMATION,
gdef.FileStreamInformation: FileStreamInformation,
}
def query_file_information(file_or_handle, file_info_class):
if isinstance(file_or_handle, file):
file_or_handle = get_handle_from_file(file_or_handle)
file_or_handle = windows.utils.get_handle_from_file(file_or_handle)
handle = file_or_handle
io_status = gdef.IO_STATUS_BLOCK()
info = ntqueryinformationfile_info_structs[file_info_class]()
@@ -274,6 +313,7 @@ def query_file_information(file_or_handle, file_info_class):
try:
windows.winproxy.NtQueryInformationFile(handle, io_status, pinfo, ctypes.sizeof(info), FileInformationClass=file_info_class)
except Exception as e:
# import pdb;pdb.set_trace()
if not (e.winerror & 0xffffffff) == gdef.STATUS_BUFFER_OVERFLOW:
raise
# STATUS_BUFFER_OVERFLOW -> Guess we have a FILE_NAME_INFORMATION somewhere that need a bigger buffer
@@ -281,6 +321,8 @@ def query_file_information(file_or_handle, file_info_class):
file_name_length = pinfo[0].FileNameLength
elif file_info_class == gdef.FileAllInformation:
file_name_length = pinfo[0].NameInformation.FileNameLength
elif file_info_class == gdef.FileStreamInformation:
file_name_length = 0x10000
else:
raise
full_size = ctypes.sizeof(info) + file_name_length # We add a little too much size for the sake of simplicity
@@ -288,9 +330,67 @@ def query_file_information(file_or_handle, file_info_class):
windows.winproxy.NtQueryInformationFile(handle, io_status, buffer, full_size, FileInformationClass=file_info_class)
pinfo = ctypes.cast(buffer, ctypes.POINTER(ntqueryinformationfile_info_structs[file_info_class]))
info = pinfo[0]
# return list of ADS if FileStreamInformation ?
return info
class EAInfo(gdef.FILE_FULL_EA_INFORMATION):
@property
def name(self):
return gdef.LPCSTR(ctypes.addressof(self) + type(self).EaName.offset).value
@property
def value(self):
value_addr = ctypes.addressof(self) + type(self).EaName.offset + self.EaNameLength + 1 # +1 -> Name \x00
return (ctypes.c_char * self.EaValueLength).from_address(value_addr)[:]
@property
def next(self):
# NextEntryOffset is Relative to our current offset
if not self.NextEntryOffset:
return None
try: # First entry
raw_buffer = self._b_base_._raw_buffer_
except AttributeError as e:
raw_buffer = self._raw_buffer_
curoffset = getattr(self, "_raw_buffer_offset_", 0)
new = type(self).from_buffer(raw_buffer, curoffset + self.NextEntryOffset)
# Keep the underlying buffer easily accessible
new._raw_buffer_ = raw_buffer
new._raw_buffer_offset_ = curoffset + self.NextEntryOffset
return new
def __iter__(self):
while self:
yield self
self = self.next
def __repr__(self):
return '<{0} name="{1}">'.format(type(self).__name__, self.name)
MAXIMUM_EA_SIZE = 0x0000ffff
def query_extended_attributes(file_or_handle):
if isinstance(file_or_handle, file):
file_or_handle = windows.utils.get_handle_from_file(file_or_handle)
# Check EaSize
x = windows.utils.query_file_information(file_or_handle, gdef.FileEaInformation)
if not x.EaSize:
return
io_status = gdef.IO_STATUS_BLOCK()
# Handle Win10 / Win7
# Saw on Win10 -> EaSize > MAXIMUM_EA_SIZE
# Saw on Win7 -> EaSize not enought (STATUS_BUFFER_OVERFLOW)
buffsize = max(MAXIMUM_EA_SIZE, x.EaSize)
buffer = windows.utils.BUFFER(EAInfo)(size=buffsize)
windows.winproxy.NtQueryEaFile(file_or_handle, io_status, buffer, buffsize, False, None, 0, None, True)
return buffer[0]
ntqueryvolumeinformationfile_info_structs = {
gdef.FileFsAttributeInformation: gdef.FILE_FS_ATTRIBUTE_INFORMATION,
gdef.FileFsControlInformation: gdef.FILE_FS_CONTROL_INFORMATION,
@@ -339,6 +439,18 @@ def ntstatus(code):
return windows.generated_def.ntstatus.NtStatusException(code)
_WINERROR_BY_VALUE = None
def winerror(code):
global _WINERROR_BY_VALUE
if not _WINERROR_BY_VALUE: # Lazy init
_WINERROR_BY_VALUE = gdef.FlagMapper(*(getattr(gdef, error) for error in gdef.meta.errors))
val = _WINERROR_BY_VALUE[code]
if val is code: # Not found
val = _WINERROR_BY_VALUE[code & 0xffff] # Hresult: extract code (https://en.wikipedia.org/wiki/HRESULT)
return val
def get_long_path(path):
"""Return the long path form for ``path``.
@@ -380,12 +492,16 @@ def dospath_to_ntpath(dospath):
return ustring.str
def get_shared_mapping(name, size=0x1000):
def get_shared_mapping(name=None, handle=INVALID_HANDLE_VALUE, size=0x1000):
# TODO: real code
h = windows.winproxy.CreateFileMappingA(INVALID_HANDLE_VALUE, dwMaximumSizeLow=size, lpName=name)
h = windows.winproxy.CreateFileMappingA(handle, dwMaximumSizeLow=size, lpName=name)
addr = windows.winproxy.MapViewOfFile(h, dwNumberOfBytesToMap=size)
return addr
def create_file(name, access=gdef.GENERIC_READ, share=gdef.FILE_SHARE_READ, security=None, creation=gdef.OPEN_EXISTING, flags=gdef.FILE_ATTRIBUTE_NORMAL):
return windows.winproxy.CreateFileA(name, access, share, security, creation, flags, 0)
#def mapfile(file):
# fhandle = get_handle_from_file(file)
# h = windows.winproxy.CreateFileMappingA(fhandle, None, PAGE_READONLY, 0, 1, None)