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.
76 lines
2.7 KiB
Python
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()
|