Wii-U-Firmware-Emulator/main.py
2019-05-02 22:44:23 +02:00

130 lines
4 KiB
Python

from Crypto.Cipher import AES
import pyemu
import struct
import sys
import armemu
import ppcemu
import hardware
import debug
class Scheduler:
def __init__(self):
self.scheduler = pyemu.Scheduler()
self.scheduler.add_alarm(1, self.check_interrupts)
self.emulators = []
def add(self, emulator, steps):
self.emulators.append(emulator)
self.scheduler.add(emulator.interpreter, steps)
def resume(self, emulator):
self.scheduler.resume(self.emulators.index(emulator))
def run(self): self.scheduler.run()
def add_alarm(self, interval, callback):
self.scheduler.add_alarm(interval, callback)
def current(self): return self.emulators[self.scheduler.index]
def pc(self): return self.current().debugger.pc()
def check_interrupts(self):
for emulator in self.emulators:
emulator.check_interrupts()
class Emulator:
def __init__(self, filename):
self.scheduler = Scheduler()
self.shell = debug.DebugShell(self.scheduler)
self.init_physmem()
self.init_hardware()
self.init_cpu()
self.init_elffile(filename)
self.armemu.breakpoints.add(0x5015E70, lambda addr: self.armemu.core.setreg(0, 0))
self.armemu.breakpoints.add(0x503409C, lambda addr: self.reset_ppc())
def init_physmem(self):
self.physmem = pyemu.PhysicalMemory()
self.physmem.add_range(0x10000000, 0x28000000) #IOSU processes and ram disk
self.physmem.add_range(0x08000000, 0x082E0000) #MEM0
self.physmem.add_range(0xFFF00000, 0xFFFFF000) #Kernel stuff
self.physmem.add_range(0x28000000, 0x34000000) #MEM2
self.physmem.add_range(0x00000000, 0x02000000) #MEM1
def init_hardware(self):
self.hw = hardware.HardwareController(self.scheduler, self.physmem)
self.physmem.add_special(0xD000000, 0xD1A0000, self.hw.read, self.hw.write)
self.physmem.add_special(0xD800000, 0xD9A0000, self.hw.read, self.hw.write)
self.physmem.add_special(0xC000000, 0xC400000, self.hw.read, self.hw.write)
self.physmem.add_special(0xD0000000, 0xD0000004, self.hw.read, self.hw.write) #Used by tcl.rpl
def init_cpu(self):
reservation = pyemu.PPCLockMgr()
self.armemu = armemu.ARMEmulator(self, self.physmem, self.hw)
self.ppcemu = [ppcemu.PPCEmulator(self, self.physmem, self.hw, reservation, core) for core in range(3)]
self.scheduler.add(self.armemu, 1000)
self.scheduler.add(self.ppcemu[0], 500)
self.scheduler.add(self.ppcemu[1], 2000)
self.scheduler.add(self.ppcemu[2], 500)
self.scheduler.resume(self.armemu)
def init_elffile(self, filename):
with open(filename, "rb") as f:
data = f.read()
elf = pyemu.ELFFile(data)
for program in elf.programs:
if program.type == pyemu.ELFProgram.PT_LOAD:
if program.filesize:
self.physmem.write(program.physaddr, data[program.fileoffs : program.fileoffs + program.filesize])
self.armemu.core.setreg(pyemu.ARMCore.PC, elf.entry_point)
def reset_ppc(self):
size = struct.unpack(">I", self.physmem.read(0x080000AC, 4))[0]
data = self.physmem.read(0x08000100, size)
with open("espresso_key.txt") as f:
key = bytes.fromhex(f.read())
cipher = AES.new(key, AES.MODE_CBC, bytes(16))
self.physmem.write(0x08000100, cipher.decrypt(data))
for emu in self.ppcemu:
emu.core.setpc(0xFFF00100)
self.scheduler.resume(emu)
def print_traceback(self):
import traceback
traceback.print_exc()
print("An error occurred:")
print("\tARM: PC=%08X LR=%08X%s" %(self.armemu.core.reg(15), self.armemu.core.reg(14), " (current)" if self.scheduler.current == self.armemu else ""))
for i in range(3):
emu = self.ppcemu[i]
current = " (current)" if emu == self.scheduler.current else ""
print("\tPPC%i: PC=%08X LR=%08X%s" %(i, emu.core.pc(), emu.core.spr(pyemu.PPCCore.LR), current))
def run(self):
try:
if "break" in sys.argv: self.shell.show(False)
else: self.scheduler.run()
except:
self.print_traceback()
self.armemu.cleanup()
for e in self.ppcemu: e.cleanup()
self.hw.nand.close()
self.hw.sdio1.close()
if __name__ == "__main__":
emulator = Emulator("C:/Users/Yannik/Downloads/openssl/fwdec.elf")
emulator.run()