Change test exe to msiexec.exe + pop_proc64 force machine AMD64 with PROC_THREAD_ATTRIBUTE_MACHINE_TYPE

This commit is contained in:
hakril
2025-02-14 18:52:22 +01:00
parent b4c0223377
commit 8eb3384fcf
4 changed files with 43 additions and 11 deletions
+4 -1
View File
@@ -30,8 +30,11 @@ else:
assert p.bitness == 64
return p
else:
# Force creation of AMD64 process on arm system
# TODO: also pop an ARM64 process when code works better with it
machine = gdef.IMAGE_FILE_MACHINE_AMD64 if windows.system.architecture == gdef.PROCESSOR_ARCHITECTURE_ARM64 else None
def pop_proc_64(dwCreationFlags=DEFAULT_CREATION_FLAGS):
p = windows.utils.create_process(r"C:\Windows\system32\{0}".format(test_binary_name).encode("ascii"), dwCreationFlags=dwCreationFlags, show_windows=True)
p = windows.utils.create_process(r"C:\Windows\system32\{0}".format(test_binary_name).encode("ascii"), dwCreationFlags=dwCreationFlags, show_windows=True, machine=machine)
assert p.bitness == 64
return p
+7 -3
View File
@@ -46,7 +46,11 @@ def cross_heaven_gates(tstfunc):
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 = "winver.exe"
# msiexec.exe is new best choice:
# - a real process (looking at calc.exe)
# - GUI and wait for a click to close when no param
# - Is ARM64CE on arm -> can be exec as AMD64 or ARM64 with `machine`` param
test_binary_name = "msiexec.exe"
DEFAULT_CREATION_FLAGS = gdef.CREATE_NEW_CONSOLE
@@ -89,8 +93,8 @@ def check_dll_injection_target_architecture(request):
dll_injection = pytest.mark.usefixtures("check_dll_injection_target_architecture")
python_injection = pytest.mark.usefixtures("check_dll_injection_target_architecture", "check_injected_python_installed")
dll_injection = pytest.mark.usefixtures("check_dll_injection_target_architecture", "check_cross_heaven_gate_arm64_xfail")
python_injection = pytest.mark.usefixtures("check_dll_injection_target_architecture", "check_injected_python_installed", "check_cross_heaven_gate_arm64_xfail")
## P2 VS PY3
+5 -3
View File
@@ -9,9 +9,10 @@ from .pfwtest import *
@pytest.fixture(params=[None, pop_proc_32, pop_proc_64], ids=["local-pe", "remote-pe32", "remote-pe64"])
def pe(request):
# Pe will be kernelbase.dll
# Pe will be kernelbase.dll or kernel32.dll
# Cannot hardcode peb.modules[2] as it may be xtajitX.dll on arm64
if request.param is None:
yield windows.current_process.peb.modules[2].pe
yield [mod for mod in windows.current_process.peb.modules if mod.name.lower().startswith("kernel")][0].pe
return
pop_proc = request.param
@@ -20,7 +21,8 @@ def pe(request):
for i in range(10):
try:
time.sleep(0.1)
yield proc.peb.modules[2].pe
# Pe will be kernelbase.dll or kernel32.dll
yield [mod for mod in windows.current_process.peb.modules if mod.name.lower().startswith("kernel")][0].pe
break
except ValueError:
if i == 9:
+27 -4
View File
@@ -73,14 +73,35 @@ def create_console():
sys.stderr = console_stderr
def create_process(path, args=None, dwCreationFlags=0, show_windows=True):
"""A convenient wrapper arround :func:`windows.winproxy.CreateProcessW`"""
def create_process(path, args=None, dwCreationFlags=0, show_windows=True, machine=None):
"""A convenient wrapper arround :func:`windows.winproxy.CreateProcessW`
..note:
The machine param only works starting at vista and should be used on arm64 computer
"""
proc_info = PROCESS_INFORMATION()
StartupInfo = None
lpStartupInfo = None
if machine is not None:
buffer = ctypes.create_string_buffer(0x100)
size = gdef.DWORD64(len(buffer))
machine = gdef.WORD(machine)
windows.winproxy.InitializeProcThreadAttributeList(buffer, 1, 0, size)
windows.winproxy.UpdateProcThreadAttribute(buffer, 0, gdef.PROC_THREAD_ATTRIBUTE_MACHINE_TYPE, ctypes.addressof(machine), ctypes.sizeof(machine), None, None)
startup_infoex = gdef.STARTUPINFOEXW()
startup_infoex.StartupInfo.cb = ctypes.sizeof(gdef.STARTUPINFOEXW)
startup_infoex.lpAttributeList = ctypes.cast(buffer, gdef.PVOID)
StartupInfo = startup_infoex.StartupInfo
dwCreationFlags |= gdef.EXTENDED_STARTUPINFO_PRESENT
if show_windows:
StartupInfo = STARTUPINFOW()
StartupInfo.cb = ctypes.sizeof(StartupInfo)
if StartupInfo is None:
StartupInfo = STARTUPINFOW()
StartupInfo.cb = ctypes.sizeof(StartupInfo)
StartupInfo.dwFlags = 0
if StartupInfo:
lpStartupInfo = ctypes.byref(StartupInfo)
lpCommandLine = None
if isinstance(path, bytes):
@@ -97,6 +118,8 @@ def create_process(path, args=None, dwCreationFlags=0, show_windows=True):
dbgprint("CreateProcessW new thread handle {:#x}".format(proc_info.hThread), "HANDLE")
dbgprint("Automatic close of thread handle {:#x}".format(proc_info.hThread), "HANDLE")
windows.winproxy.CloseHandle(proc_info.hThread) # Give access to a WinThread in addition of the WinProcess ?
if machine:
windows.winproxy.DeleteProcThreadAttributeList(buffer)
return windows.winobject.process.WinProcess(pid=proc_info.dwProcessId, handle=proc_info.hProcess)