mirror of
https://github.com/hakril/PythonForWindows
synced 2026-06-08 14:31:45 +00:00
Add test / fix Winprocess.load_library / free some of the memory
This commit is contained in:
@@ -10,11 +10,6 @@ TODO:
|
||||
- Clean / (rethink?) vectored_exception (+rename exception.py? context.py?)
|
||||
- Test !! (bp, BP_HX, bp on only on process, bp_hx on only one thread..)
|
||||
|
||||
- Injection with suspended process ?
|
||||
- FIX/add test (inject suspended 32 -> 64)
|
||||
|
||||
- Free all the virtual_alloc
|
||||
- Real API arround alloc/free memory in WinProcess..
|
||||
|
||||
- Threading
|
||||
- Quid IAT hook stub ? just einit threads and remove this ?
|
||||
@@ -24,7 +19,6 @@ TODO:
|
||||
Just need to passe the address of the python string as argument
|
||||
|
||||
|
||||
|
||||
FIXME:
|
||||
- WMI
|
||||
- COM initialisation when injected in another process
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -129,6 +129,8 @@ class Debugger(object):
|
||||
# Valid addr ? (in non-loaded module: raise / pass ?)
|
||||
if expected_target is None or expected_target.pid == target.pid:
|
||||
if isinstance(target, WinThread):
|
||||
if bp.type == STANDARD_BP:
|
||||
continue # Standard BP are set on wide process, nothing to do on a thread
|
||||
x = self._hardware_breakpoint[target.tid]
|
||||
# Ignore BP on thread_create that have already been
|
||||
# put by the process_create event
|
||||
@@ -332,7 +334,7 @@ class Debugger(object):
|
||||
|
||||
|
||||
class Breakpoint(object):
|
||||
type = "BP" # REAL BP
|
||||
type = STANDARD_BP # REAL BP
|
||||
def __init__(self, addr):
|
||||
self.addr = addr
|
||||
|
||||
|
||||
+33
-35
@@ -32,20 +32,20 @@ def perform_manual_getproc_loadlib_32(target, dll_name):
|
||||
|
||||
RemoteManualLoadLibray += GetProcAddress32
|
||||
|
||||
addr = target.virtual_alloc(0x1000)
|
||||
addr2 = addr + len(dll)
|
||||
addr3 = addr2 + len(api)
|
||||
addr4 = addr3 + len(dll_to_load)
|
||||
with target.allocated_memory(0x1000) as addr:
|
||||
addr2 = addr + len(dll)
|
||||
addr3 = addr2 + len(api)
|
||||
addr4 = addr3 + len(dll_to_load)
|
||||
|
||||
target.write_memory(addr, dll)
|
||||
target.write_memory(addr2, api)
|
||||
target.write_memory(addr3, dll_to_load)
|
||||
target.write_qword(addr4, addr)
|
||||
target.write_qword(addr4 + 4, addr2)
|
||||
target.write_qword(addr4 + 0x8, addr3)
|
||||
target.write_memory(addr, dll)
|
||||
target.write_memory(addr2, api)
|
||||
target.write_memory(addr3, dll_to_load)
|
||||
target.write_qword(addr4, addr)
|
||||
target.write_qword(addr4 + 4, addr2)
|
||||
target.write_qword(addr4 + 0x8, addr3)
|
||||
|
||||
t = target.execute(RemoteManualLoadLibray.get_code(), addr4)
|
||||
t.wait()
|
||||
t = target.execute(RemoteManualLoadLibray.get_code(), addr4)
|
||||
t.wait()
|
||||
return True
|
||||
|
||||
def perform_manual_getproc_loadlib_64(target, dll_name):
|
||||
@@ -71,20 +71,20 @@ def perform_manual_getproc_loadlib_64(target, dll_name):
|
||||
|
||||
RemoteManualLoadLibray += GetProcAddress64
|
||||
|
||||
addr = target.virtual_alloc(0x1000)
|
||||
addr2 = addr + len(dll)
|
||||
addr3 = addr2 + len(api)
|
||||
addr4 = addr3 + len(dll_to_load)
|
||||
with target.allocated_memory(0x1000) as addr:
|
||||
addr2 = addr + len(dll)
|
||||
addr3 = addr2 + len(api)
|
||||
addr4 = addr3 + len(dll_to_load)
|
||||
|
||||
target.write_memory(addr, dll)
|
||||
target.write_memory(addr2, api)
|
||||
target.write_memory(addr3, dll_to_load)
|
||||
target.write_qword(addr4, addr)
|
||||
target.write_qword(addr4 + 8, addr2)
|
||||
target.write_qword(addr4 + 0x10, addr3)
|
||||
target.write_memory(addr, dll)
|
||||
target.write_memory(addr2, api)
|
||||
target.write_memory(addr3, dll_to_load)
|
||||
target.write_qword(addr4, addr)
|
||||
target.write_qword(addr4 + 8, addr2)
|
||||
target.write_qword(addr4 + 0x10, addr3)
|
||||
|
||||
t = target.execute(RemoteManualLoadLibray.get_code(), addr4)
|
||||
t.wait()
|
||||
t = target.execute(RemoteManualLoadLibray.get_code(), addr4)
|
||||
t.wait()
|
||||
return True
|
||||
|
||||
|
||||
@@ -106,11 +106,10 @@ def load_dll_in_remote_process(target, dll_name):
|
||||
except KeyError:
|
||||
raise ValueError("Kernel32 have no export <LoadLibraryA> (wtf)")
|
||||
|
||||
addr = target.virtual_alloc(0x1000)
|
||||
target.write_memory(addr, dll_name + "\x00")
|
||||
t = target.create_thread(load_libraryA, addr)
|
||||
t.wait()
|
||||
windows.winproxy.VirtualFreeEx(target.handle, addr)
|
||||
with target.allocated_memory(0x1000) as addr:
|
||||
target.write_memory(addr, dll_name + "\x00")
|
||||
t = target.create_thread(load_libraryA, addr)
|
||||
t.wait()
|
||||
dbgprint("DLL Injected via LoadLibray", "DLLINJECT")
|
||||
return True
|
||||
# Hardcore mode
|
||||
@@ -244,7 +243,7 @@ def generate_python_exec_shellcode_64(target, PYCODE_ADDR, PyDll):
|
||||
def inject_python_command(target, code_injected, PYDLL):
|
||||
"""Postulate: PYDLL is already loaded in target process"""
|
||||
PYCODE = code_injected + "\x00"
|
||||
|
||||
# TODO: free this (how ? when ?)
|
||||
remote_addr = target.virtual_alloc(len(PYCODE) + 0x100)
|
||||
target.write_memory(remote_addr, PYCODE)
|
||||
SHELLCODE_ADDR = remote_addr + len(PYCODE)
|
||||
@@ -295,11 +294,10 @@ buff[:] = txt
|
||||
"""
|
||||
|
||||
def retrieve_last_exception_data(process):
|
||||
# TODO : FREE THIS
|
||||
mem = process.virtual_alloc(0x1000)
|
||||
execute_python_code(process, retrieve_exc.format(mem))
|
||||
size = struct.unpack("<I", process.read_memory(mem, ctypes.sizeof(ctypes.c_uint)))[0]
|
||||
data = process.read_memory(mem + ctypes.sizeof(ctypes.c_uint), size)
|
||||
with process.allocated_memory(0x1000) as mem:
|
||||
execute_python_code(process, retrieve_exc.format(mem))
|
||||
size = struct.unpack("<I", process.read_memory(mem, ctypes.sizeof(ctypes.c_uint)))[0]
|
||||
data = process.read_memory(mem + ctypes.sizeof(ctypes.c_uint), size)
|
||||
return data
|
||||
|
||||
class RemotePythonError(Exception):
|
||||
|
||||
+71
-4
@@ -51,17 +51,17 @@ else:
|
||||
|
||||
|
||||
@contextmanager
|
||||
def Calc64(exit_code=0):
|
||||
def Calc64(dwCreationFlags=0, exit_code=0):
|
||||
try:
|
||||
calc = pop_calc_64()
|
||||
calc = pop_calc_64(dwCreationFlags)
|
||||
yield calc
|
||||
finally:
|
||||
calc.exit(exit_code)
|
||||
|
||||
@contextmanager
|
||||
def Calc32(exit_code=0):
|
||||
def Calc32(dwCreationFlags=0, exit_code=0):
|
||||
try:
|
||||
calc = pop_calc_32()
|
||||
calc = pop_calc_32(dwCreationFlags)
|
||||
yield calc
|
||||
finally:
|
||||
calc.exit(exit_code)
|
||||
@@ -147,6 +147,32 @@ class WindowsTestCase(unittest.TestCase):
|
||||
dword = struct.unpack("<I", calc.read_memory(data, 4))[0]
|
||||
self.assertEqual(dword, 0x42424242)
|
||||
|
||||
def test_execute_python_to_32_suspended(self):
|
||||
with Calc32(dwCreationFlags=CREATE_SUSPENDED) as calc:
|
||||
data = calc.virtual_alloc(0x1000)
|
||||
calc.execute_python('import ctypes; ctypes.c_uint.from_address({0}).value = 0x42424242'.format(data))
|
||||
dword = struct.unpack("<I", calc.read_memory(data, 4))[0]
|
||||
self.assertEqual(dword, 0x42424242)
|
||||
# Check calc32 is still suspended:
|
||||
# 1 thread
|
||||
# suspend count == 1
|
||||
self.assertEqual(len(calc.threads), 1)
|
||||
self.assertEqual(calc.threads[0].suspend(), 1)
|
||||
|
||||
@windows_64bit_only
|
||||
def test_execute_python_to_64_suspended(self):
|
||||
with Calc64(dwCreationFlags=CREATE_SUSPENDED) as calc:
|
||||
data = calc.virtual_alloc(0x1000)
|
||||
calc.execute_python('import ctypes; ctypes.c_uint.from_address({0}).value = 0x42424242'.format(data))
|
||||
dword = struct.unpack("<I", calc.read_memory(data, 4))[0]
|
||||
self.assertEqual(dword, 0x42424242)
|
||||
# Check calc32 is still suspended:
|
||||
# 1 thread
|
||||
# suspend count == 1
|
||||
self.assertEqual(len(calc.threads), 1)
|
||||
self.assertEqual(calc.threads[0].suspend(), 1)
|
||||
|
||||
|
||||
def test_parse_remote_32_peb(self):
|
||||
with Calc32() as calc:
|
||||
# Wait for PEB initialization
|
||||
@@ -340,6 +366,20 @@ class WindowsTestCase(unittest.TestCase):
|
||||
time.sleep(0.1)
|
||||
self.assertEqual(t.exit_code, 0x11223344)
|
||||
|
||||
def test_load_library_32(self):
|
||||
DLL = "wintrust.dll"
|
||||
with Calc32() as calc:
|
||||
calc.load_library(DLL)
|
||||
self.assertIn(DLL, [m.name for m in calc.peb.modules])
|
||||
|
||||
@windows_64bit_only
|
||||
def test_load_library_64(self):
|
||||
DLL = "wintrust.dll"
|
||||
with Calc64() as calc:
|
||||
calc.load_library(DLL)
|
||||
self.assertIn(DLL, [m.name for m in calc.peb.modules])
|
||||
|
||||
|
||||
class WindowsAPITestCase(unittest.TestCase):
|
||||
def test_createfileA_fail(self):
|
||||
with self.assertRaises(WindowsError) as ar:
|
||||
@@ -442,6 +482,33 @@ class DebuggerTestCase(unittest.TestCase):
|
||||
d.add_bp(TSTBP(LdrLoadDll32))
|
||||
d.loop()
|
||||
|
||||
def test_standard_breakpoint_multiple_threads(self):
|
||||
TEST_CASE = self
|
||||
data = [0]
|
||||
|
||||
class TSTBP(windows.debug.Breakpoint):
|
||||
def trigger(self, dbg, exc):
|
||||
TEST_CASE.assertEqual(dbg.current_process.pid, calc.pid)
|
||||
TEST_CASE.assertEqual(dbg.current_process.read_memory(self.addr, 1), "\xcc")
|
||||
TEST_CASE.assertEqual(dbg.current_thread.context.pc - 1, self.addr)
|
||||
d.current_process.exit()
|
||||
|
||||
calc = pop_calc_32(dwCreationFlags=DEBUG_PROCESS)
|
||||
|
||||
if windows.current_process.bitness == 32:
|
||||
LdrLoadDll32 = windows.current_process.peb.modules[1].pe.exports["LdrLoadDll"]
|
||||
else:
|
||||
calcref = pop_calc_32()
|
||||
LdrLoadDll32 = calcref.peb.modules[1].pe.exports["LdrLoadDll"]
|
||||
calcref.exit()
|
||||
|
||||
d = windows.debug.Debugger(calc)
|
||||
calc.execute("\xc3")
|
||||
calc.execute("\xc3")
|
||||
calc.execute("\xc3")
|
||||
d.add_bp(TSTBP(LdrLoadDll32))
|
||||
d.loop()
|
||||
|
||||
def test_simple_hwx_breakpoint(self):
|
||||
TEST_CASE = self
|
||||
|
||||
|
||||
+4
-13
@@ -32,7 +32,7 @@ import windows.pe_parse as pe_parse
|
||||
class AutoHandle(object):
|
||||
"""An abstract class that allow easy handle creation/destruction/wait"""
|
||||
# Big bypass to prevent missing reference at programm close..
|
||||
CLOSE_FUNCTION = ctypes.WinDLL("kernel32").CloseHandle
|
||||
_close_function = ctypes.WinDLL("kernel32").CloseHandle
|
||||
def _get_handle(self):
|
||||
raise NotImplementedError("{0} is abstract".format(type(self).__name__))
|
||||
|
||||
@@ -58,7 +58,7 @@ class AutoHandle(object):
|
||||
def __del__(self):
|
||||
if hasattr(self, "_handle") and self._handle:
|
||||
dbgprint("Closing Handle {0} for {1}".format(hex(self._handle), self), "HANDLE")
|
||||
self.CLOSE_FUNCTION(self._handle)
|
||||
self._close_function(self._handle)
|
||||
|
||||
|
||||
class System(object):
|
||||
@@ -343,7 +343,7 @@ class Process(AutoHandle):
|
||||
|
||||
:return: The return value of the native code
|
||||
:rtype: :class:`int`"""
|
||||
x = self.virtual_alloc(len(code))
|
||||
x = self.virtual_alloc(len(code)) #Todo: free this ? when ? how ? reuse ?
|
||||
self.write_memory(x, code)
|
||||
return self.create_thread(x, parameter)
|
||||
|
||||
@@ -704,16 +704,7 @@ class WinProcess(PROCESSENTRY32, Process):
|
||||
|
||||
def load_library(self, dll_path):
|
||||
"""Load the library in remote process"""
|
||||
x = self.virtual_alloc(0x1000)
|
||||
self.write_memory(x, dll_path)
|
||||
LoadLibrary = utils.get_func_addr('kernel32', 'LoadLibraryA')
|
||||
return self.create_thread(LoadLibrary, x)
|
||||
|
||||
def tst_load_library(self, dll_path, target_addr):
|
||||
"""Load the library in remote process"""
|
||||
x = self.virtual_alloc(0x1000)
|
||||
self.write_memory(x, dll_path)
|
||||
return self.create_thread(target_addr, x)
|
||||
return windows.injection.load_dll_in_remote_process(self, dll_path)
|
||||
|
||||
def execute_python(self, pycode):
|
||||
"""Execute Python code into the remote process.
|
||||
|
||||
Reference in New Issue
Block a user