Files
dolphin/Tools/disassemble-process-memory.py
Yaya48 a77c156bc8 IOS: add Starlet LLE milestone through HBC
Boot original Wii firmware through boot0, boot1, boot2 and IOS on an emulated ARM Starlet. Model the required IPC, memory, SD, USB and Bluetooth hardware behavior, including IOS reload into IOS58, and add focused tests, launch utilities and architecture documentation.
2026-08-25 17:11:49 +02:00

76 lines
2.7 KiB
Python

#!/usr/bin/env python3
import argparse
import ctypes
import pathlib
import sys
REPOSITORY_ROOT = pathlib.Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPOSITORY_ROOT / "capstone_local"))
from capstone import CS_ARCH_ARM, CS_ARCH_PPC, CS_MODE_32, CS_MODE_ARM, CS_MODE_BIG_ENDIAN, Cs
PROCESS_VM_READ = 0x0010
PROCESS_QUERY_INFORMATION = 0x0400
def read_process_memory(process_id: int, address: int, length: int) -> bytes:
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
kernel32.OpenProcess.argtypes = [ctypes.c_uint32, ctypes.c_bool, ctypes.c_uint32]
kernel32.OpenProcess.restype = ctypes.c_void_p
kernel32.ReadProcessMemory.argtypes = [
ctypes.c_void_p,
ctypes.c_void_p,
ctypes.c_void_p,
ctypes.c_size_t,
ctypes.POINTER(ctypes.c_size_t),
]
kernel32.ReadProcessMemory.restype = ctypes.c_bool
kernel32.CloseHandle.argtypes = [ctypes.c_void_p]
kernel32.CloseHandle.restype = ctypes.c_bool
process = kernel32.OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, False, process_id)
if not process:
raise ctypes.WinError(ctypes.get_last_error())
try:
buffer = ctypes.create_string_buffer(length)
bytes_read = ctypes.c_size_t()
if not kernel32.ReadProcessMemory(
process, ctypes.c_void_p(address), buffer, length, ctypes.byref(bytes_read)
):
raise ctypes.WinError(ctypes.get_last_error())
if bytes_read.value != length:
raise RuntimeError(f"short read: requested {length} bytes, got {bytes_read.value}")
return buffer.raw
finally:
kernel32.CloseHandle(process)
def main() -> None:
parser = argparse.ArgumentParser(
description="Disassemble big-endian 32-bit PowerPC code from a live Windows process."
)
parser.add_argument("process_id", type=int)
parser.add_argument("host_address", type=lambda value: int(value, 0))
parser.add_argument("guest_address", type=lambda value: int(value, 0))
parser.add_argument("length", type=lambda value: int(value, 0))
parser.add_argument("--arch", choices=("ppc", "arm"), default="ppc")
args = parser.parse_args()
code = read_process_memory(args.process_id, args.host_address, args.length)
if args.arch == "arm":
disassembler = Cs(CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_BIG_ENDIAN)
else:
disassembler = Cs(CS_ARCH_PPC, CS_MODE_32 | CS_MODE_BIG_ENDIAN)
for instruction in disassembler.disasm(code, args.guest_address):
operands = f" {instruction.op_str}" if instruction.op_str else ""
print(f"{instruction.address:08x}: {instruction.bytes.hex(' '):11} "
f"{instruction.mnemonic}{operands}")
if __name__ == "__main__":
main()