diff --git a/TODO b/TODO index 598cc05..42e71d1 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,13 @@ TODO: -=== CRITICAL BEFORE 0.4 === +=== CRITICAL BEFORE 0.5 === + +- Add news features to index.html +- Document / fix / release: + - windows.bits + - evtlog + - kernobj + - window ====== diff --git a/tests/conftest.py b/tests/conftest.py index eb24420..a69a19a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -60,7 +60,6 @@ else: - class HandleDebugger(object): def __init__(self, pid): self.pid = pid diff --git a/tests/pfwtest.py b/tests/pfwtest.py index 267bd45..4cb9b2e 100644 --- a/tests/pfwtest.py +++ b/tests/pfwtest.py @@ -1,6 +1,7 @@ +import os.path import pytest -import windows +import windows import windows.generated_def as gdef is_process_32_bits = windows.current_process.bitness == 32 @@ -24,4 +25,33 @@ check_for_gc_garbage = pytest.mark.usefixtures("check_for_gc_garbage") check_for_handle_leak = pytest.mark.usefixtures("check_for_handle_leak") test_binary_name = "notepad.exe" -DEFAULT_CREATION_FLAGS = gdef.CREATE_NEW_CONSOLE \ No newline at end of file +DEFAULT_CREATION_FLAGS = gdef.CREATE_NEW_CONSOLE + + +# Python Injection check fixture + +python_is_installed = { + windows.current_process.bitness: True +} + +if windows.current_process.bitness == 32: + with windows.utils.DisableWow64FsRedirection(): + python_is_installed[64] = os.path.exists(r"C:\Windows\system32\python27.dll") + +if windows.current_process.bitness == 64: + python_is_installed[32] = os.path.exists(r"C:\Windows\SysWOW64\python27.dll") + +@pytest.fixture +def check_injected_python_installed(request): + # Find the process parameter + procparams = [argname for argname in request.funcargnames if argname.startswith("proc")] + if len(procparams) != 1: + raise ValueError("Could not find the fixture name of the injected python") + procparam = procparams[0] + proc = request.getfuncargvalue(procparam) + if not python_is_installed[proc.bitness]: + pytest.skip("Python {0}b not installed -> skipping test with python injection into {0}b process".format(proc.bitness)) + return None + + +python_injection = pytest.mark.usefixtures("check_injected_python_installed") \ No newline at end of file diff --git a/tests/test_debugger.py b/tests/test_debugger.py index 50ef689..5574dbb 100644 --- a/tests/test_debugger.py +++ b/tests/test_debugger.py @@ -353,6 +353,8 @@ def test_memory_breakpoint_exec(proc32_64_debug): # breakpoint remove import threading + +@python_injection @pytest.mark.parametrize("bptype", [windows.debug.FunctionParamDumpHXBP, windows.debug.FunctionParamDumpBP]) def test_standard_breakpoint_self_remove(proc32_64_debug, bptype): data = [] @@ -379,6 +381,7 @@ def test_standard_breakpoint_self_remove(proc32_64_debug, bptype): d.loop() assert data == [u"FILENAME1", u"FILENAME2"] +@python_injection @pytest.mark.parametrize("bptype", [windows.debug.FunctionParamDumpHXBP, windows.debug.FunctionParamDumpBP]) def test_standard_breakpoint_remove(proc32_64_debug, bptype): data = [] diff --git a/tests/test_hook.py b/tests/test_hook.py index aebf1ee..1d83801 100644 --- a/tests/test_hook.py +++ b/tests/test_hook.py @@ -80,6 +80,7 @@ def test_self_iat_hook_multithread(): assert len(calling_thread) == 2 x.disable() +@python_injection @check_for_gc_garbage def test_remote_iat_hook(proc32_64): proc32_64.execute_python("import windows") diff --git a/tests/test_pipe.py b/tests/test_pipe.py index 3a39dc8..c18f7f2 100644 --- a/tests/test_pipe.py +++ b/tests/test_pipe.py @@ -10,6 +10,8 @@ import windows windows.pipe.send_object("{pipe}", {{'Hello': 2}}) """ + +@python_injection def test_ipc_pipe(proc32_64): with windows.pipe.create(PIPE_NAME) as np: proc32_64.execute_python(rcode_test_ipc_pipe.format(pipe=PIPE_NAME)) @@ -20,13 +22,14 @@ def test_ipc_pipe(proc32_64): rcode_test_echo_pipe = """ import windows - with windows.pipe.create("{pipe}") as np: np.wait_connection() obj = np.recv() np.send(obj) """ + +@python_injection def test_pipe_echo_server(proc32_64): t = proc32_64.execute_python_unsafe(rcode_test_echo_pipe.format(pipe=PIPE_NAME)) time.sleep(0.5) @@ -37,6 +40,8 @@ def test_pipe_echo_server(proc32_64): echoobj = pipe.recv() assert obj == echoobj + +@python_injection def test_pipe_recv_object(proc32_64): # not the good way to do the exchange (race possible) # Just for the sake of the test diff --git a/tests/test_process.py b/tests/test_process.py index ae3ac34..9058870 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -71,6 +71,10 @@ class TestCurrentProcessWithCheckGarbage(object): image_path_from_module = windows.current_process.peb.modules[0].fullname.lower() assert image_path_from_process_params == image_path_from_module + + + + @check_for_gc_garbage class TestProcessWithCheckGarbage(object): def test_pop_proc_32(self, proc32): @@ -127,7 +131,6 @@ class TestProcessWithCheckGarbage(object): assert proc32_64.read_wstring(addr) == test_string # Test native execution - def test_execute_to_proc32(self, proc32): with proc32.allocated_memory(0x1000) as addr: shellcode = x86.MultipleInstr() @@ -151,26 +154,16 @@ class TestProcessWithCheckGarbage(object): qword = proc64.read_qword(addr) assert qword == 0x4242424243434343 - # Python execution - - def _skip_if_injection_dll_not_found(self, target): - if windows.current_process.bitness == target.bitness: - return # Should never fail if we have the same bitness - try: - windows.injection.validate_python_dll_presence_on_disk(target) - except IOError as e: - pytest.skip("Python DLL to inject not installed") + @python_injection def test_execute_python(self, proc32_64): - self._skip_if_injection_dll_not_found(proc32_64) with proc32_64.allocated_memory(0x1000) as addr: proc32_64.execute_python('import ctypes; ctypes.c_uint.from_address({0}).value = 0x42424242'.format(addr)) dword = proc32_64.read_dword(addr) assert dword == 0x42424242 - + @python_injection def test_execute_python_suspended(self, proc32_64_suspended): - self._skip_if_injection_dll_not_found(proc32_64_suspended) proc = proc32_64_suspended with proc.allocated_memory(0x1000) as addr: proc.execute_python('import ctypes; ctypes.c_uint.from_address({0}).value = 0x42424242'.format(addr)) @@ -193,7 +186,7 @@ class TestProcessWithCheckGarbage(object): import time; time.sleep(0.1) assert proc32_64.peb.modules[0].name == test_binary_name - + @python_injection def test_parse_remote_pe(self, proc32_64): # Wait for PEB initialization # Yeah a don't know but on 32bits system the parsing might begin before @@ -228,8 +221,8 @@ class TestProcessWithCheckGarbage(object): assert exe.baseaddr == exe_by_module.baseaddr assert exe.bitness == exe_by_module.bitness + @python_injection def test_execute_python_raises(self, proc32_64): - self._skip_if_injection_dll_not_found(proc32_64) res = proc32_64.execute_python("import time;time.sleep(0.1); 2") assert res == True with pytest.raises(windows.injection.RemotePythonError) as ar: diff --git a/tests/test_syswow.py b/tests/test_syswow.py index f1d18d8..2db66ef 100644 --- a/tests/test_syswow.py +++ b/tests/test_syswow.py @@ -27,7 +27,7 @@ class TestSyswowCurrentProcess(object): wow64 = [m for m in peb64.modules if m.name == "wow64.dll"][0] assert "Wow64LdrpInitialize" in wow64.pe.exports - +@python_injection @windows_64bit_only class TestSyswowRemoteProcess(object): def test_remote_pebsyswow(self, proc32):