Skip to content

Commit 8eb3384

Browse files
committed
Change test exe to msiexec.exe + pop_proc64 force machine AMD64 with PROC_THREAD_ATTRIBUTE_MACHINE_TYPE
1 parent b4c0223 commit 8eb3384

4 files changed

Lines changed: 43 additions & 11 deletions

File tree

tests/conftest.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ def pop_proc_64(dwCreationFlags=DEFAULT_CREATION_FLAGS):
3030
assert p.bitness == 64
3131
return p
3232
else:
33+
# Force creation of AMD64 process on arm system
34+
# TODO: also pop an ARM64 process when code works better with it
35+
machine = gdef.IMAGE_FILE_MACHINE_AMD64 if windows.system.architecture == gdef.PROCESSOR_ARCHITECTURE_ARM64 else None
3336
def pop_proc_64(dwCreationFlags=DEFAULT_CREATION_FLAGS):
34-
p = windows.utils.create_process(r"C:\Windows\system32\{0}".format(test_binary_name).encode("ascii"), dwCreationFlags=dwCreationFlags, show_windows=True)
37+
p = windows.utils.create_process(r"C:\Windows\system32\{0}".format(test_binary_name).encode("ascii"), dwCreationFlags=dwCreationFlags, show_windows=True, machine=machine)
3538
assert p.bitness == 64
3639
return p
3740

tests/pfwtest.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ def cross_heaven_gates(tstfunc):
4646
check_for_gc_garbage = pytest.mark.usefixtures("check_for_gc_garbage")
4747
check_for_handle_leak = pytest.mark.usefixtures("check_for_handle_leak")
4848

49-
test_binary_name = "winver.exe"
49+
# msiexec.exe is new best choice:
50+
# - a real process (looking at calc.exe)
51+
# - GUI and wait for a click to close when no param
52+
# - Is ARM64CE on arm -> can be exec as AMD64 or ARM64 with `machine`` param
53+
test_binary_name = "msiexec.exe"
5054
DEFAULT_CREATION_FLAGS = gdef.CREATE_NEW_CONSOLE
5155

5256

@@ -89,8 +93,8 @@ def check_dll_injection_target_architecture(request):
8993

9094

9195

92-
dll_injection = pytest.mark.usefixtures("check_dll_injection_target_architecture")
93-
python_injection = pytest.mark.usefixtures("check_dll_injection_target_architecture", "check_injected_python_installed")
96+
dll_injection = pytest.mark.usefixtures("check_dll_injection_target_architecture", "check_cross_heaven_gate_arm64_xfail")
97+
python_injection = pytest.mark.usefixtures("check_dll_injection_target_architecture", "check_injected_python_installed", "check_cross_heaven_gate_arm64_xfail")
9498

9599

96100
## P2 VS PY3

tests/test_parse_pe.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99

1010
@pytest.fixture(params=[None, pop_proc_32, pop_proc_64], ids=["local-pe", "remote-pe32", "remote-pe64"])
1111
def pe(request):
12-
# Pe will be kernelbase.dll
12+
# Pe will be kernelbase.dll or kernel32.dll
13+
# Cannot hardcode peb.modules[2] as it may be xtajitX.dll on arm64
1314
if request.param is None:
14-
yield windows.current_process.peb.modules[2].pe
15+
yield [mod for mod in windows.current_process.peb.modules if mod.name.lower().startswith("kernel")][0].pe
1516
return
1617

1718
pop_proc = request.param
@@ -20,7 +21,8 @@ def pe(request):
2021
for i in range(10):
2122
try:
2223
time.sleep(0.1)
23-
yield proc.peb.modules[2].pe
24+
# Pe will be kernelbase.dll or kernel32.dll
25+
yield [mod for mod in windows.current_process.peb.modules if mod.name.lower().startswith("kernel")][0].pe
2426
break
2527
except ValueError:
2628
if i == 9:

windows/utils/winutils.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,35 @@ def create_console():
7373
sys.stderr = console_stderr
7474

7575

76-
def create_process(path, args=None, dwCreationFlags=0, show_windows=True):
77-
"""A convenient wrapper arround :func:`windows.winproxy.CreateProcessW`"""
76+
def create_process(path, args=None, dwCreationFlags=0, show_windows=True, machine=None):
77+
"""A convenient wrapper arround :func:`windows.winproxy.CreateProcessW`
78+
..note:
79+
The machine param only works starting at vista and should be used on arm64 computer
80+
"""
7881
proc_info = PROCESS_INFORMATION()
82+
StartupInfo = None
7983
lpStartupInfo = None
84+
85+
if machine is not None:
86+
buffer = ctypes.create_string_buffer(0x100)
87+
size = gdef.DWORD64(len(buffer))
88+
machine = gdef.WORD(machine)
89+
windows.winproxy.InitializeProcThreadAttributeList(buffer, 1, 0, size)
90+
windows.winproxy.UpdateProcThreadAttribute(buffer, 0, gdef.PROC_THREAD_ATTRIBUTE_MACHINE_TYPE, ctypes.addressof(machine), ctypes.sizeof(machine), None, None)
91+
92+
startup_infoex = gdef.STARTUPINFOEXW()
93+
startup_infoex.StartupInfo.cb = ctypes.sizeof(gdef.STARTUPINFOEXW)
94+
startup_infoex.lpAttributeList = ctypes.cast(buffer, gdef.PVOID)
95+
StartupInfo = startup_infoex.StartupInfo
96+
97+
dwCreationFlags |= gdef.EXTENDED_STARTUPINFO_PRESENT
98+
8099
if show_windows:
81-
StartupInfo = STARTUPINFOW()
82-
StartupInfo.cb = ctypes.sizeof(StartupInfo)
100+
if StartupInfo is None:
101+
StartupInfo = STARTUPINFOW()
102+
StartupInfo.cb = ctypes.sizeof(StartupInfo)
83103
StartupInfo.dwFlags = 0
104+
if StartupInfo:
84105
lpStartupInfo = ctypes.byref(StartupInfo)
85106
lpCommandLine = None
86107
if isinstance(path, bytes):
@@ -97,6 +118,8 @@ def create_process(path, args=None, dwCreationFlags=0, show_windows=True):
97118
dbgprint("CreateProcessW new thread handle {:#x}".format(proc_info.hThread), "HANDLE")
98119
dbgprint("Automatic close of thread handle {:#x}".format(proc_info.hThread), "HANDLE")
99120
windows.winproxy.CloseHandle(proc_info.hThread) # Give access to a WinThread in addition of the WinProcess ?
121+
if machine:
122+
windows.winproxy.DeleteProcThreadAttributeList(buffer)
100123
return windows.winobject.process.WinProcess(pid=proc_info.dwProcessId, handle=proc_info.hProcess)
101124

102125

0 commit comments

Comments
 (0)