Fixed get_kernel_modules for syswow64 process

This commit is contained in:
Clement Rouault
2017-08-17 13:51:36 +02:00
parent 16e29bd938
commit c75dda60b5
2 changed files with 37 additions and 9 deletions
+26 -8
View File
@@ -42,7 +42,7 @@ def generate_64bits_execution_stub_from_syswow(x64shellcode):
def execute_64bits_code_from_syswow(x64shellcode):
return generate_64bits_execution_stub_from_syswow(x64shellcode)()
def generate_syswow64_call(target):
def generate_syswow64_call(target, errcheck=None):
nb_args = len(target.prototype._argtypes_)
target_addr = get_syswow_ntdll_exports()[target.__name__]
argument_buffer_len = (nb_args * 8)
@@ -107,15 +107,14 @@ def generate_syswow64_call(target):
code_64b += x64.Pop('RCX')
code_64b += x64.Pop('RBX')
code_64b += x64.Ret()
return try_generate_stub_target(code_64b.get_code(), argument_buffer, target)
return try_generate_stub_target(code_64b.get_code(), argument_buffer, target, errcheck=errcheck)
def try_generate_stub_target(shellcode, argument_buffer, target):
"""shellcode must NOT end by a ret"""
def try_generate_stub_target(shellcode, argument_buffer, target, errcheck=None):
if not windows.current_process.is_wow_64:
raise ValueError("Calling execute_64bits_code_from_syswow from non-syswow process")
native_caller = generate_64bits_execution_stub_from_syswow(shellcode)
native_caller.errcheck = target.errcheck
native_caller.errcheck = errcheck if errcheck is not None else target.errcheck
# Generate the wrapper function that fill the argument_buffer
expected_arguments_number = len(target.prototype._argtypes_)
def wrapper(*args):
@@ -133,6 +132,8 @@ def try_generate_stub_target(shellcode, argument_buffer, target):
# Build buffer
buffer = struct.pack("<" + "Q" * len(writable_args), *writable_args)
ctypes.memmove(argument_buffer, buffer, len(buffer))
# Copy origincal args in function, for errcheck if needed
native_caller.current_original_args = args # TODO: THIS IS NOT THREAD SAFE
return native_caller()
wrapper.__name__ = "{0}<syswow64>".format(target.__name__,)
wrapper.__doc__ = "This is a wrapper to {0} in 64b mode, it accept <{1}> args".format(target.__name__, expected_arguments_number)
@@ -191,9 +192,10 @@ get_syswow_ntdll_exports.value = None
class Syswow64ApiProxy(object):
"""Create a python wrapper around a function"""
def __init__(self, winproxy_function):
def __init__(self, winproxy_function, errcheck=None):
self.winproxy_function = winproxy_function
self.raw_call = None
self.errcheck = errcheck
if winproxy_function is not None:
self.params_name = [param[1] for param in winproxy_function.params]
@@ -208,7 +210,7 @@ class Syswow64ApiProxy(object):
if self.raw_call:
return True
try:
self.raw_call = generate_syswow64_call(self.winproxy_function)
self.raw_call = generate_syswow64_call(self.winproxy_function, errcheck=self.errcheck)
except KeyError:
raise windows.winproxy.ExportNotFound(self.winproxy_function.__name__, "SysWow[ntdll64]")
@@ -230,6 +232,23 @@ class Syswow64ApiProxy(object):
setattr(python_proxy, "force_resolution", force_resolution)
return python_proxy
def ntquerysysteminformation_syswow64_error_check(result, func, args):
args = func.current_original_args
if result == 0:
return args
# Ignore STATUS_INFO_LENGTH_MISMATCH if SystemInformation is None
if result == STATUS_INFO_LENGTH_MISMATCH and not args[1]:
return args
raise Kernel32Error("{0} failed with NTStatus {1}".format(func_name, hex(result)))
@Syswow64ApiProxy(winproxy.NtQuerySystemInformation, errcheck=ntquerysysteminformation_syswow64_error_check)
# @Syswow64ApiProxy(winproxy.NtQuerySystemInformation)
def NtQuerySystemInformation_32_to_64(SystemInformationClass, SystemInformation=None, SystemInformationLength=0, ReturnLength=NeededParameter):
if SystemInformation is not None and SystemInformationLength == 0:
SystemInformationLength = ctypes.sizeof(SystemInformation)
if SystemInformation is None:
SystemInformation = 0
return NtQuerySystemInformation_32_to_64.ctypes_function(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength)
@Syswow64ApiProxy(winproxy.NtCreateThreadEx)
@@ -280,7 +299,6 @@ def NtProtectVirtualMemory_32_to_64(ProcessHandle, BaseAddress, NumberOfBytesToP
return NtProtectVirtualMemory_32_to_64.ctypes_function(ProcessHandle, BaseAddress, NumberOfBytesToProtect, NewAccessProtection, OldAccessProtection)
@Syswow64ApiProxy(winproxy.NtGetContextThread)
def NtGetContextThread_32_to_64(hThread, lpContext):
if type(lpContext) == windows.winobject.exception.ECONTEXT64:
+11 -1
View File
@@ -193,8 +193,9 @@ def pop_shell(locs=None):
def get_kernel_modules():
if windows.current_process.is_wow_64:
return get_kernel_modules_syswow64()
cbsize = DWORD()
winproxy.NtQuerySystemInformation(SystemModuleInformation, None, 0, byref(cbsize))
raw_buffer = (cbsize.value * c_char)()
buffer = SYSTEM_MODULE_INFORMATION.from_address(ctypes.addressof(raw_buffer))
@@ -202,6 +203,15 @@ def get_kernel_modules():
modules = (SYSTEM_MODULE * buffer.ModulesCount).from_address(addressof(buffer) + SYSTEM_MODULE_INFORMATION.Modules.offset)
return list(modules)
def get_kernel_modules_syswow64():
cbsize = DWORD()
windows.syswow64.NtQuerySystemInformation_32_to_64(SystemModuleInformation, None, 0, ctypes.addressof(cbsize))
raw_buffer = (cbsize.value * c_char)()
buffer = SYSTEM_MODULE_INFORMATION64.from_address(ctypes.addressof(raw_buffer))
windows.syswow64.NtQuerySystemInformation_32_to_64(SystemModuleInformation, byref(raw_buffer), sizeof(raw_buffer), byref(cbsize))
modules = (SYSTEM_MODULE64 * buffer.ModulesCount).from_address(addressof(buffer) + SYSTEM_MODULE_INFORMATION64.Modules.offset)
return list(modules)
# String stuff
def ntstatus(code):