diff --git a/doc/NtCreateThreadStub_64b.asm b/doc/NtCreateThreadStub_64b.asm index 39d3c97..e05b13c 100644 --- a/doc/NtCreateThreadStub_64b.asm +++ b/doc/NtCreateThreadStub_64b.asm @@ -16,7 +16,6 @@ MY_FUNC PROC push r11 push r12 push r13 - ;TODO save the QUEEN (and the registers !) mov rax, 0h push rax mov rax, 7845646165726854h diff --git a/injection.py b/injection.py index 12c17d8..2f85fe3 100644 --- a/injection.py +++ b/injection.py @@ -7,13 +7,28 @@ import windows.utils as utils from .native_exec import simple_x86 as x86 from .native_exec import simple_x64 as x64 + +def get_loadlib_getproc(target): + if windows.current_process.bitness == target.bitness: + LoadLibraryA = utils.get_func_addr('kernel32', 'LoadLibraryA') + GetProcAddress = utils.get_func_addr('kernel32', 'GetProcAddress') + return LoadLibraryA, GetProcAddress + else: + k32 = [x for x in target.peb.modules if x.name == "kernel32.dll"][0] + exp = k32.pe.exports + return exp['LoadLibraryA'], exp['GetProcAddress'] + + + + # 32 to 32 injection -def generate_python_exec_shellcode_32(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR): - LoadLibraryA = utils.get_func_addr('kernel32', 'LoadLibraryA') - GetProcAddress = utils.get_func_addr('kernel32', 'GetProcAddress') +def generate_python_exec_shellcode_32(target, PYDLL_addr, PyInit, PyRun, PYCODE_ADDR): + #LoadLibraryA = utils.get_func_addr('kernel32', 'LoadLibraryA') + #GetProcAddress = utils.get_func_addr('kernel32', 'GetProcAddress') + LoadLibraryA, GetProcAddress = get_loadlib_getproc(target) print("LoadLibraryA = {0}".format(hex(LoadLibraryA))) print("LoadLibraryA = {0}".format(hex(GetProcAddress))) - + code = x86.MultipleInstr() # Load python27.dll code += x86.Push(PYDLL_addr) @@ -40,10 +55,9 @@ def generate_python_exec_shellcode_32(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR): return code.get_code() # 64 to 64 injection -def generate_python_exec_shellcode_64(PYDLL_addr, PyInit, PyRun, PYCODE_ADDR): - - LoadLibraryA = utils.get_func_addr('kernel32', 'LoadLibraryA') - GetProcAddress = utils.get_func_addr('kernel32', 'GetProcAddress') +def generate_python_exec_shellcode_64(target, PYDLL_addr, PyInit, PyRun, PYCODE_ADDR): + + LoadLibraryA, GetProcAddress = get_loadlib_getproc(target) Reserve_space_for_call = x64.MultipleInstr([x64.Push('RDI')] * 4) Clean_space_for_call = x64.MultipleInstr([x64.Pop('RDI')] * 4) @@ -115,9 +129,9 @@ def inject_python_command(process, code_injected, PYDLL="python27.dll\x00"): SHELLCODE_ADDR = remote_addr if process.bitness == 32: - shellcode = generate_python_exec_shellcode_32(PYDLL_addr, PyInitT_ADDR, Pyrun_ADDR, PYCODE_ADDR) + shellcode = generate_python_exec_shellcode_32(process, PYDLL_addr, PyInitT_ADDR, Pyrun_ADDR, PYCODE_ADDR) else: - shellcode = generate_python_exec_shellcode_64(PYDLL_addr, PyInitT_ADDR, Pyrun_ADDR, PYCODE_ADDR) + shellcode = generate_python_exec_shellcode_64(process, PYDLL_addr, PyInitT_ADDR, Pyrun_ADDR, PYCODE_ADDR) process.write_memory(SHELLCODE_ADDR, shellcode) return SHELLCODE_ADDR @@ -127,6 +141,7 @@ def execute_python_code(process, code): print("me = {0}".format(windows.current_process.bitness)) print("him = {0}".format(process.bitness)) if windows.current_process.bitness != process.bitness: - raise NotImplementedError("Cannot perform 32 <-> 64 injection") + if windows.current_process.bitness == 64 and process.bitness == 32: + raise NotImplementedError("Cannot perform 64 -> 32 injection") shellcode_remote_addr = inject_python_command(process, code) return process.create_thread(shellcode_remote_addr, 0) diff --git a/pe_parse.py b/pe_parse.py index 9ba389e..b224e57 100644 --- a/pe_parse.py +++ b/pe_parse.py @@ -3,6 +3,7 @@ import ctypes import struct import windows import windows.hooks as hooks +import windows.utils as utils from windows.generated_def.winstructs import * import windows.remotectypes as rctypes @@ -26,25 +27,32 @@ def transform_ctypes_fields(struct, replacement): return [(name, replacement.get(name, type)) for name, type in struct._fields_] def PEFile(baseaddr, target=None): + # TODO: 32 with target 32 + # 64 with target 64 + # For now you can do it by injecting a remote python.. proc_bitness = windows.current_process.bitness if target is None: targetedbitness = proc_bitness else: targetedbitness = target.bitness - + if targetedbitness == 32 and proc_bitness == 64: raise NotImplementedError("Parse 32bits PE with 64bits current_process") elif targetedbitness == 64 and proc_bitness == 32: ctypes_structure_transformer = rctypes.transform_type_to_remote64bits def create_structure_at(structcls, addr): - return rctypes.transform_type_to_remote64bits(structcls)(addr, target) + # try: + return rctypes.transform_type_to_remote64bits(structcls)(addr, target) + #except: + #import pdb;pdb.set_trace() + #return rctypes.transform_type_to_remote64bits(structcls)(addr, target) elif targetedbitness == proc_bitness: # Does not handle remote of same bitness.. ctypes_structure_transformer = lambda x: x def create_structure_at(structcls, addr): return structcls.from_address(addr) else: raise NotImplementedError("Parsing {0} PE from {1} Process".format(targetedbitness, proc_bitness)) - + if targetedbitness == 32: IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG32 else: @@ -54,30 +62,19 @@ def PEFile(baseaddr, target=None): @property def addr(self): return baseaddr + self.value - + def __repr__(self): return "".format(self.value, hex(self.addr)) - - #class RVA(ctypes.Structure): - # _fields_ = [("Whatever", DWORD)] - # @property - # def addr(self): - # return baseaddr + self.Whatever - # - # def __repr__(self): - # return "".format(self.Whatever, hex(self.addr)) class StringRVa(RVA): - if proc_bitness == 32 and ctypes_structure_transformer == rctypes.transform_type_to_remote64bits: + if proc_bitness == 32 and targetedbitness == 64: @property def str(self): - #return rctypes.rctypes.Remote_c_char_p64.from_buffer_with_target(struct.pack("".format(self.value, self.str) @@ -103,7 +100,7 @@ def PEFile(baseaddr, target=None): @classmethod def create(cls, addr, ord, name): - self = create_structure_at(cls, addr) + self = create_structure_at(cls, addr) self.addr = addr self.ord = ord self.name = name @@ -158,7 +155,7 @@ def PEFile(baseaddr, target=None): #current_import_descriptor = self.IMAGE_IMPORT_DESCRIPTOR.from_address(import_descriptor_addr) current_import_descriptor = create_structure_at(self.IMAGE_IMPORT_DESCRIPTOR, import_descriptor_addr) return res - + def get_EXPORT_DIRECTORY(self): export_directory_rva = self.get_DataDirectory()[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress if export_directory_rva == 0: @@ -168,19 +165,24 @@ def PEFile(baseaddr, target=None): #return self._IMAGE_EXPORT_DIRECTORY.from_address(export_directory_addr) - @property + @utils.fixedpropety def exports(self): + print("ASK FOR EXPORTS {0}".format(target)) + res = {} - raw_exports = self.get_EXPORT_DIRECTORY().get_exports() + exp_dir = self.get_EXPORT_DIRECTORY() + if exp_dir is None: + return res + raw_exports = exp_dir.get_exports() for id, rva_addr, rva_name in raw_exports: res[id] = rva_addr.addr if rva_name is not None: res[rva_name.str] = rva_addr.addr return res - + # TODO: get imports by parsing other modules exports if no INT - @property + @utils.fixedpropety def imports(self): res = {} for import_descriptor in self.get_IMPORT_DESCRIPTORS(): @@ -189,8 +191,8 @@ def PEFile(baseaddr, target=None): if INT is not None: for iat_entry, (ord, name) in zip(IAT, INT): # str(name.decode()) -> python2 and python3 compatible for str result - iat_entry.name = str(name.decode()) if name else name iat_entry.ord = ord + iat_entry.name = str(name.decode()) if name else "" res.setdefault(import_descriptor.Name.str.lower(),[]).extend(IAT) return res @@ -199,57 +201,45 @@ def PEFile(baseaddr, target=None): _fields_ = transform_ctypes_fields(IMAGE_IMPORT_DESCRIPTOR, {"Name" : StringRVa, "OriginalFirstThunk" : RVA, "FirstThunk" : RVA}) def get_INT(self): - + if not self.OriginalFirstThunk.value: return None int_addr = self.OriginalFirstThunk.addr - #int_entry = THUNK_DATA.from_address(int_addr) int_entry = create_structure_at(THUNK_DATA, int_addr) res = [] while int_entry.Ordinal: if int_entry.Ordinal & IMAGE_ORDINAL_FLAG: res += [(int_entry.Ordinal & 0x7fffffff, None)] else: - #import_by_name = IMPORT_BY_NAME.from_address(baseaddr + int_entry.AddressOfData) - import_by_name = create_structure_at(IMPORT_BY_NAME, baseaddr + int_entry.AddressOfData) - - if proc_bitness == 32 and ctypes_structure_transformer == rctypes.transform_type_to_remote64bits: - name = rctypes.Remote_c_char_p64(baseaddr + int_entry.AddressOfData + type(import_by_name).Name.offset, target=target).value - #name = rctypes.Remote_c_char_p64.from_buffer_with_target(bytearray(struct.pack("".format(self.real_pointer_type._type_.__name__) - -# 64bits pointers + + +def create_remote_array(subtype, len): + class RemoteArray(_ctypes.Array): + _length_ = len + _type_ = subtype + def __init__(self, addr, target): + self._base_addr = addr + self.target = target + + def __getitem__(self, slice): + if not isinstance(slice, (int, long)): + raise NotImplementedError("RemoteArray slice __getitem__") + if slice >= len: + raise IndexError("Access to {0} for a RemoteArray of size {1}".format(slice, len)) + item_addr = self._base_addr + (ctypes.sizeof(subtype) * slice) + #TODO: do better ? + class TST(ctypes.Structure): + _fields_ = [("TST", subtype)] + return RemoteStructure.from_structure(TST)(item_addr, target=self.target).TST + #return subtype(item_addr, target=self.target) + return RemoteArray + + +# 64bits pointers class RemotePtr64(RemoteValue): def __init__(self, value, target): @@ -127,13 +145,11 @@ class RemotePtr64(RemoteValue): my_addr = ctypes.addressof(self) return ctypes.c_ulonglong.from_address(my_addr).value return ctypes.cast(self, ctypes.c_ulonglong).value - - #def from_value(self): - - + + class Remote_c_void_p64(RemotePtr64, c_void_p64): pass - + # base explanation: # RemotePtr64 for the good `raw_value` implem # RemoteCCharP for the good `value` implem @@ -141,16 +157,16 @@ class Remote_c_void_p64(RemotePtr64, c_void_p64): class Remote_c_char_p64(c_char_p64, RemotePtr64, RemoteCCharP): def __repr__(self): return "".format(self.raw_value) - + class Remote_w_char_p64(c_wchar_p64, RemotePtr64, RemoteWCharP): def __repr__(self): return "".format(self.raw_value) - + class RemoteStructurePointer64(Remote_c_void_p64): @property def raw_value(self): return self.value - + @classmethod def from_buffer_with_target_and_ptr_type(cls, buffer, offset=0, target=None, ptr_type=None): x = cls.from_buffer(buffer) @@ -163,29 +179,25 @@ class RemoteStructurePointer64(Remote_c_void_p64): remote_pointed_type = transform_type_to_remote64bits(self.real_pointer_type._sub_ctypes_) return remote_pointed_type(self.raw_value, self.target) - + type_32_64_translation_table = { ctypes.c_void_p : Remote_c_void_p64, ctypes.c_char_p : Remote_c_char_p64, ctypes.c_wchar_p: Remote_w_char_p64, - #ctypes.wintypes.WPARAM : ctypes.c_ulonglong, - #ctypes.wintypes.LPARAM : ctypes.c_longlong, - #ctypes.c_size_t : c_size_t64, # don't know how to handle size_t size it's non-distinguable from c_ulong - #ctypes.c_ssize_t: c_ssize_t64 - } - + } + class RemoteStructureUnion(object): """Target is a process object""" _reserved_name = ["_target", "_fields_", "_fields_dict_", "_base_addr", "_get_field_by_name", - "_get_field_descrptor_by_name", "_handle_field_getattr", "_field_type_to_remote_type", "__getattribute__", "_fields_"] - + "_get_field_descrptor_by_name", "_handle_field_getattr", "_field_type_to_remote_type", "__getattribute__", "_fields_"] + _field_type_to_remote_type = { ctypes.c_char_p : RemoteCCharP, ctypes.c_wchar_p : RemoteWCharP, Remote_c_void_p64 : Remote_c_void_p64, Remote_c_char_p64 : Remote_c_char_p64, Remote_w_char_p64 : Remote_w_char_p64} - + def __init__(self, base_addr, target): if type(base_addr) not in (int, long): @@ -211,24 +223,24 @@ class RemoteStructureUnion(object): return RemoteStructurePointer.from_buffer_with_target_and_ptr_type(bytearray(s), target=self._target, ptr_type=ftype) if issubclass(ftype, RemotePtr64): # Pointer to remote64 bits process return RemoteStructurePointer64.from_buffer_with_target_and_ptr_type(bytearray(s), target=self._target, ptr_type=ftype) - if issubclass(ftype, RemoteStructureUnion): # Structure already transfomed in remote + if issubclass(ftype, RemoteStructureUnion): # Structure|Union already transfomed in remote return ftype(self._base_addr + fosset, self._target) if issubclass(ftype, ctypes.Structure): # Structure that must be transfomed return RemoteStructure.from_structure(ftype)(self._base_addr + fosset, self._target) - if issubclass(ftype, ctypes.Union): # Structure that must be transfomed - return RemoteUnion.from_structure(ftype)(self._base_addr + fosset, self._target) - if issubclass(ftype, _ctypes.Array): - return ftype.from_buffer(bytearray(s)) + if issubclass(ftype, ctypes.Union): # Union that must be transfomed + return RemoteUnion.from_structure(ftype)(self._base_addr + fosset, self._target) + if issubclass(ftype, _ctypes.Array): # Arrays + return create_remote_array(ftype._type_, ftype._length_)(self._base_addr + fosset, self._target) + #return ftype.from_buffer(bytearray(s)) # Normal types # Follow the ctypes usage: if it's not directly inherited from _SimpleCData # We do not apply the .value # Seems weird but it's mandatory AND useful :D (in pe_parse) - if _SimpleCData not in ftype.__bases__: return ftype.from_buffer(bytearray(s)) return ftype.from_buffer(bytearray(s)).value - def __getattribute__(self, fieldname): + def __getattribute__(self, fieldname): if fieldname in type(self)._reserved_name: #Prevent recursion ! return super(RemoteStructureUnion, self).__getattribute__(fieldname) try: @@ -242,11 +254,11 @@ class RemoteStructureUnion(object): def from_structure(cls, structcls): class MyStruct(cls, structcls): # inherit of structcls to keep property (see winobject.LoadedModule) _fields_ = structcls._fields_ - + MyStruct.__name__ = "Remote" + structcls.__name__ return MyStruct - - @classmethod + + @classmethod def from_fields(cls, fields, base_cls=None): bases = [cls] if base_cls: @@ -256,15 +268,13 @@ class RemoteStructureUnion(object): if base_cls: RemoteStruct.__name__ = "Remote" + base_cls.__name__ return RemoteStruct - + class RemoteStructure(RemoteStructureUnion, ctypes.Structure): pass class RemoteUnion(RemoteStructureUnion, ctypes.Union): - pass + pass - - remote_struct = RemoteStructure.from_structure if ctypes.sizeof(ctypes.c_void_p) == 4: @@ -281,7 +291,7 @@ if ctypes.sizeof(ctypes.c_void_p) == 4: ftype = transform_type_to_remote64bits(ftype) new_fields.append((fname, ftype)) return RemoteStructure.from_fields(new_fields, base_cls=structcls) - + def transform_union_to_remote64bits(structcls): """Create a remote structure for a 64bits target process""" new_fields = [] @@ -289,21 +299,15 @@ if ctypes.sizeof(ctypes.c_void_p) == 4: ftype = transform_type_to_remote64bits(ftype) new_fields.append((fname, ftype)) return RemoteUnion.from_fields(new_fields, base_cls=structcls) - + def transform_type_to_remote64bits(ftype): if is_pointer_type(ftype): return MakePtr(ftype._type_) if is_array_type(ftype): - return (transform_type_to_remote64bits(ftype._type_) * ftype._length_) + return create_remote_array(transform_type_to_remote64bits(ftype._type_), ftype._length_) if is_structure_type(ftype): return transform_structure_to_remote64bits(ftype) if is_union_type(ftype): return transform_union_to_remote64bits(ftype) # Normal types - return type_32_64_translation_table.get(ftype, ftype) - - -def dump_type(t): - fields_name = t._fields_ - for fn in fields_name: - print getattr(t, fn[0]) \ No newline at end of file + return type_32_64_translation_table.get(ftype, ftype) \ No newline at end of file diff --git a/syswow64.py b/syswow64.py index 7d01c45..a814471 100644 --- a/syswow64.py +++ b/syswow64.py @@ -5,7 +5,6 @@ import windows.native_exec.simple_x64 as x64 from generated_def.winstructs import * # Special code for syswow64 process - CS_32bits = 0x23 CS_64bits = 0x33 @@ -71,132 +70,4 @@ def NtCreateThreadEx_32_to_64(process, addr, param): shellcode = NtCreateThreadStub.replace("\x40" * 8, struct.pack(" not loaded in target <{1}>".format(dll_name, target)) + mod = name_modules[0] + return mod.pe.exports[func_name] + def is_wow_64(hProcess): try: fnIsWow64Process = get_func_addr("kernel32.dll", "IsWow64Process") @@ -63,19 +82,19 @@ def create_console(): console_stderr = create_file_from_handle(stderr_handle, "w") #print(stderr_handle, console_stderr) import os - #os.dup2(console_stderr.fileno(), 2) + #os.dup2(console_stderr.fileno(), 2) sys.stderr = console_stderr - + class FixedInteractiveConsole(code.InteractiveConsole): def raw_input(self, prompt=">>>"): sys.stdout.write(prompt) return raw_input("") - + def pop_shell(): create_console() FixedInteractiveConsole(locals()).interact() - - + + class VirtualProtected(object): """A context manager usable like `VirtualProtect` that will restore the old protection at exit diff --git a/winobject.py b/winobject.py index 5c6a4c2..95ba323 100644 --- a/winobject.py +++ b/winobject.py @@ -14,14 +14,13 @@ import windows.native_exec.simple_x86 as x86 import windows.native_exec.simple_x64 as x64 from . import utils - +from .dbgprint import dbgprint from windows.generated_def.winstructs import * from .generated_def import windef import windows.pe_parse as pe_parse - class AutoHandle(object): """An abstract class that allow easy handle creation/destruction""" def _get_handle(self): @@ -66,7 +65,7 @@ class System(object): """ return self.enumerate_threads() - @property + @utils.fixedpropety def bitness(self): """The bitness of the system @@ -78,7 +77,7 @@ class System(object): if "PROCESSOR_ARCHITEW6432" in os.environ: return 64 return 32 - + @staticmethod def enumerate_processes(): process_entry = WinProcess() @@ -90,7 +89,7 @@ class System(object): while kernel32proxy.Process32Next(snap, process_entry): res.append(utils.swallow_ctypes_copy(process_entry)) return res - + @staticmethod def enumerate_threads(): thread_entry = WinThread() @@ -106,12 +105,12 @@ class System(object): class WinThread(THREADENTRY32, AutoHandle): """Represent a thread """ - @property + @utils.fixedpropety def tid(self): """Thread ID""" return self.th32ThreadID - @property + @utils.fixedpropety def owner(self): """The Process owning the thread @@ -125,23 +124,23 @@ class WinThread(THREADENTRY32, AutoHandle): except IndexError: return None return self._owner - + @property def context(self): x = windows.vectored_exception.EnhancedCONTEXT() x.ContextFlags = CONTEXT_FULL kernel32proxy.GetThreadContext(self.handle, x) return x - + def set_context(self, context): return kernel32proxy.SetThreadContext(self.handle, context) - + def exit(self, code=0): return kernel32proxy.TerminateThread(self.handle, code) - + def resume(self): return kernel32proxy.ResumeThread(self.handle) - + def suspend(self): return kernel32proxy.SuspendThread(self.handle) @@ -155,8 +154,8 @@ class WinThread(THREADENTRY32, AutoHandle): else: owner_name = owner.name return '<{0} {1} owner "{2}" at {3}>'.format(self.__class__.__name__, self.tid, owner_name, hex(id(self))) - - @staticmethod + + @staticmethod def _from_handle(handle): tid = kernel32proxy.GetThreadId(handle) print(tid) @@ -164,9 +163,9 @@ class WinThread(THREADENTRY32, AutoHandle): return [t for t in System().threads if t.tid == tid][0] except IndexError: return (tid, handle) - + class Process(AutoHandle): - @property + @utils.fixedpropety def is_wow_64(self): """Is True if the process is a SysWow64 process @@ -176,7 +175,7 @@ class Process(AutoHandle): """ return utils.is_wow_64(self.handle) - @property + @utils.fixedpropety def bitness(self): """The bitness of the process @@ -208,12 +207,12 @@ class Process(AutoHandle): class CurrentThread(AutoHandle): """The current thread""" - @property + @utils.fixedpropety def tid(self): """Thread ID""" return kernel32proxy.GetCurrentThreadId() - @property + @utils.fixedpropety def owner(self): """The current process @@ -226,12 +225,12 @@ class CurrentThread(AutoHandle): def __del__(self): pass - + def exit(self, code=0): """Exit the thread""" return kernel32proxy.ExitThread(code) - - + + class CurrentProcess(Process): """The current process""" @@ -256,7 +255,7 @@ class CurrentProcess(Process): def _get_handle(self): return kernel32proxy.GetCurrentProcess() - + def __del__(self): pass @@ -269,7 +268,7 @@ class CurrentProcess(Process): return os.getpid() # Is there a better way ? - @property + @utils.fixedpropety def ppid(self): """Parent Process ID @@ -277,7 +276,7 @@ class CurrentProcess(Process): """ return [p for p in windows.system.processes if p.pid == self.pid][0].ppid - @property + @utils.fixedpropety def peb(self): """The Process Environment Block of the current process @@ -285,11 +284,12 @@ class CurrentProcess(Process): """ return PEB.from_address(self.get_peb_builtin()()) - @property + @utils.fixedpropety def bitness(self): """The bitness of the process :returns: int -- 32 or 64""" + print("FAIL") import platform bits = platform.architecture()[0] return int(bits[:2]) @@ -309,6 +309,7 @@ class CurrentProcess(Process): def read_memory(self, addr, size): """Read size from adddr""" + dbgprint('Read CurrentProcess Memory', 'READMEM') buffer = (c_char * size).from_address(addr) return buffer[:] @@ -330,7 +331,7 @@ class WinProcess(PROCESSENTRY32, Process): is_pythondll_injected = 0 is_remote_slave_running = False - @property + @utils.fixedpropety def name(self): """Name of the process @@ -338,7 +339,7 @@ class WinProcess(PROCESSENTRY32, Process): """ return self.szExeFile[:].decode() - @property + @utils.fixedpropety def pid(self): """Process ID @@ -346,7 +347,7 @@ class WinProcess(PROCESSENTRY32, Process): """ return self.th32ProcessID - @property + @utils.fixedpropety def ppid(self): """Parent Process ID @@ -373,28 +374,29 @@ class WinProcess(PROCESSENTRY32, Process): def low_read_memory(self, addr, buffer_addr, size): if windows.current_process.bitness == 32 and self.bitness == 64: - NtWow64ReadVirtualMemory64Addr = windows.utils.get_func_addr("ntdll.dll", "NtWow64ReadVirtualMemory64") - NtWow64ReadVirtualMemory64 = WINFUNCTYPE(HRESULT, HANDLE, ULONG64, PVOID, ULONG64, PULONG64)(NtWow64ReadVirtualMemory64Addr) - return NtWow64ReadVirtualMemory64(self.handle, addr, buffer_addr, size, None) + if not hasattr(self, "NtWow64ReadVirtualMemory64"): # TODO: better stuff : (in k32testing?) + NtWow64ReadVirtualMemory64Addr = windows.utils.get_func_addr("ntdll.dll", "NtWow64ReadVirtualMemory64") + self.NtWow64ReadVirtualMemory64 = WINFUNCTYPE(HRESULT, HANDLE, ULONG64, PVOID, ULONG64, PULONG64)(NtWow64ReadVirtualMemory64Addr) + return self.NtWow64ReadVirtualMemory64(self.handle, addr, buffer_addr, size, None) return kernel32proxy.ReadProcessMemory(self.handle, addr, lpBuffer=buffer_addr, nSize=size) def read_memory(self, addr, size): """Read `size` from `addr`""" - print("Read on page {0}".format(hex(addr & 0xfffffffffffff000))) buffer = ctypes.create_string_buffer(size) self.low_read_memory(addr, ctypes.byref(buffer), size) return buffer[:] - + #Simple cache test real_read = read_memory - + def read_memory(self, addr, size): """Cached version for test""" + dbgprint('Read remote Memory of {0}'.format(self), 'READMEM') if not hasattr(self, "_cache_cache"): self._cache_cache = {} page_addr = addr & 0xfffffffffffff000 if page_addr in self._cache_cache: - print("CACHED Read on page {0}".format(hex(page_addr))) + #print("CACHED Read on page {0}".format(hex(page_addr))) page_data = self._cache_cache[page_addr] return page_data[addr & 0xfff: (addr & 0xfff) + size] else: @@ -423,7 +425,7 @@ class WinProcess(PROCESSENTRY32, Process): def execute_python(self, pycode): """Execute Python code into the remote process""" return injection.execute_python_code(self, pycode) - + def get_peb_addr(self): get_peb_32_code = codecs.decode(b'64a130000000', 'hex') get_peb_64_code = codecs.decode(b"65488B042560000000", 'hex') @@ -452,13 +454,14 @@ class WinProcess(PROCESSENTRY32, Process): time.sleep(0.01) peb_addr = struct.unpack("