started device implementation

This commit is contained in:
Eljakim Herrewijnen 2024-06-17 20:15:08 +02:00
parent a1ab8650bc
commit 59eaf299ad
54 changed files with 360 additions and 52 deletions

8
.vscode/launch.json vendored
View File

@ -35,6 +35,14 @@
"program": "GA_debugger.py", "program": "GA_debugger.py",
"console": "integratedTerminal", "console": "integratedTerminal",
"justMyCode": false "justMyCode": false
},
{
"name": "Emulate BootROM",
"type": "python",
"request": "launch",
"program": "partial_emulation.py",
"console": "integratedTerminal",
"justMyCode": false
} }
] ]
} }

View File

@ -1,4 +1,4 @@
import typing, pathlib, struct import typing, pathlib, struct, argparse
from ghidra_assistant.utils.archs.arm.arm_emulator import * from ghidra_assistant.utils.archs.arm.arm_emulator import *
from ghidra_assistant.ghidra_assistant import GhidraAssistant from ghidra_assistant.ghidra_assistant import GhidraAssistant
from ghidra_assistant.concrete_device import ConcreteDevice from ghidra_assistant.concrete_device import ConcreteDevice
@ -21,20 +21,121 @@ acces_str = {
def p8(value): def p8(value):
return struct.pack("<B", value) return struct.pack("<B", value)
class TegraDevice():
BASE = 0x0
SIZE = 0x1000
NAME = "Generic Tegra Device"
NV_ADDRESS_MAP_CLK_RST_BASE = 0x60006000
CLK_RST_CONTROLLER_MISC_CLK_ENB_0 = NV_ADDRESS_MAP_CLK_RST_BASE + 0x48
class PartialEmu(ARM_Emulator): def __init__(self, emulator : "TegraEmulator") -> None:
def __init__(self, init_uc=True) -> None: self.emulator = emulator
self.fuses_visible = 0
def read(self, address, size):
if address == TegraDevice.CLK_RST_CONTROLLER_MISC_CLK_ENB_0:
self.emulator.write_ptr(TegraDevice.CLK_RST_CONTROLLER_MISC_CLK_ENB_0, self.fuses_visible)
return True
raise NotImplemented
def write(self, address, data):
if address == TegraDevice.CLK_RST_CONTROLLER_MISC_CLK_ENB_0:
self.fuses_visible = data
return True
raise NotImplemented
class FuseDevice(TegraDevice):
BASE = 0x7000F000
SIZE = 0x1000
NAME = "Fuse"
FUSE_ODM_INFO_0 = BASE + 0x99c
FUSE_FUSEADDR_0 = BASE + 0x804
FUSE_FUSECTRL_0 = BASE + 0x800
CMD_READ = 1
CMD_IDLE = 0
FUSE_DAT = BytesIO()
def __init__(self, emulator: "TegraEmulator") -> None:
super().__init__(emulator)
self.fuse_ctr_cmd = 0xc0040000
self.fuse_addr = 0x0
def read(self, address, size):
if address == FuseDevice.FUSE_ODM_INFO_0:
self.emulator.write_ptr(FuseDevice.FUSE_ODM_INFO_0, 2)
elif address == FuseDevice.FUSE_FUSECTRL_0:
# get last int from fuse_ctr_cmd
cmd = self.fuse_ctr_cmd & 0xffffffff
if cmd == FuseDevice.CMD_READ:
# Handle read
# Set idle, set last byte of cmd to 0
self.fuse_ctr_cmd = cmd & 0xffffff00
self.emulator.write_ptr(FuseDevice.FUSE_FUSECTRL_0, self.fuse_ctr_cmd)
self.emulator.write_ptr(FuseDevice.FUSE_FUSECTRL_0, self.fuse_ctr_cmd)
else:
raise NotImplemented
return True
def write(self, address, value):
if address == FuseDevice.FUSE_FUSEADDR_0:
self.fuse_addr = value
elif address == FuseDevice.FUSE_FUSECTRL_0:
self.emulator.write_ptr(FuseDevice.FUSE_FUSECTRL_0, value)
self.fuse_ctr_cmd = value
else:
raise NotImplemented
return True
pass
class TimerDevice(TegraDevice):
BASE = 0x60005000
SIZE = 0x1000
NAME = "Timer"
READ_TIME_OFFSET = BASE + 0x10
def __init__(self, emulator: "TegraEmulator") -> None:
super().__init__(emulator)
def read(self, address, size):
if address == TimerDevice.READ_TIME_OFFSET:
val = int(time.clock_gettime_ns(0)/1000) & 0xffffffff
self.emulator.write_ptr(TimerDevice.READ_TIME_OFFSET, val)
return True
class EmmcDevice(TegraDevice):
BASE = 0x700b0000
SIZE = 0x1000
NAME = "Emmc"
def __init__(self, emulator: "TegraEmulator") -> None:
super().__init__(emulator)
class CryptoDevice(TegraDevice):
BASE = 0x70012000
SIZE = 0x1000
NAME = "Crypto"
def __init__(self, emulator: "TegraEmulator") -> None:
super().__init__(emulator)
class TegraEmulator(ARM_Emulator):
def __init__(self, hw_itm=True, init_uc=True) -> None:
super().__init__(init_uc) super().__init__(init_uc)
self.log_hw_access = True self.log_hw_access = True
self.hw_itm = hw_itm
self.saved_blocks = {} self.saved_blocks = {}
try: try:
self.ghidra = GhidraAssistant() self.ghidra = GhidraAssistant()
except: except:
pass pass
def setup(self): def setup(self, target="bootrom"):
self.target = target
self.setup_memory() self.setup_memory()
self.setup_registers() self.setup_registers()
if not self.hw_itm:
self.setup_devices()
self.setup_hooks() self.setup_hooks()
self.apply_patches() self.apply_patches()
@ -49,77 +150,199 @@ class PartialEmu(ARM_Emulator):
self.uc.mem_write(0x100000, self.bootrom) self.uc.mem_write(0x100000, self.bootrom)
# map IMEM # map IMEM
self.imem_path = pathlib.Path("imem3_bct")
self.imem = self.imem_path.read_bytes()
self.uc.mem_map(0x40000000, 0x40000, UC_PROT_EXEC | UC_PROT_READ | UC_PROT_WRITE) self.uc.mem_map(0x40000000, 0x40000, UC_PROT_EXEC | UC_PROT_READ | UC_PROT_WRITE)
self.uc.mem_write(0x40000000, self.imem) if self.target == "bootrom":
pass
else:
self.imem_path = pathlib.Path("imem3_bct")
self.imem = self.imem_path.read_bytes()
self.uc.mem_write(0x40000000, self.imem)
# DRAM # DRAM
DRAM_BASE = 0x80000000 DRAM_BASE = 0x80000000
DRAM_SIZE = 2 * GB DRAM_SIZE = 2 * GB
self.uc.mem_map(DRAM_BASE, DRAM_SIZE, UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC) self.uc.mem_map(DRAM_BASE, DRAM_SIZE, UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC)
def setup_registers(self): def setup_registers(self, target="bootrom"):
self.sp = 0x4000d000 if self.target == "bootrom":
self.pc = 0x4000e000 self.pc = 0x100000 | 1
self.is_thumb = False self.sp = 0x4000d000
self.is_thumb = True
else:
self.sp = 0x4000d000
self.pc = 0x4000e000
self.is_thumb = False
def setup_devices(self):
self.devices = {}
self.devices['fuse'] = FuseDevice(self)
self.devices['timer'] = TimerDevice(self)
self.devices['emmc'] = EmmcDevice(self)
self.devices['crypto'] = CryptoDevice(self)
self.devices['tegra'] = TegraDevice(self) # For all other devices
def hook_unmapped(self, uc, access, address, size, value, user_data): def hook_unmapped(self, uc, access, address, size, value, user_data):
print(f"Unmapped memory access at 0x{address:x} with size {size} and access {acces_str[access]}") print(f"Unmapped memory access at 0x{address:x} with size {size} and access {acces_str[access]}")
pass pass
def hook_mem_access(self, uc, access, address, size, value, user_data):
# Hook all memory accesses
# if self.log_hw_access:
# p_info(f"{hex(self.pc)} HW access at 0x{address:x} with size {size}, value={hex(value)} and access {acces_str[access]}")
def hook_hw_access(self, uc, access, address, size, value, user_data): # Try and keep memory in sync with target device
if self.log_hw_access:
p_info(f"{hex(self.pc)} HW access at 0x{address:x} with size {size} and access {acces_str[access]}") if access == UC_MEM_WRITE:
self.debugger.memwrite_region(address, self.uc.mem_read(address, size))
if access == UC_MEM_READ:
self.uc.mem_write(address, self.debugger.memdump_region(address, size))
pass
def hw_itm_handle(self, access, address, size, value):
# All unmapped memory is send to the debugger # All unmapped memory is send to the debugger
if self.log_hw_access:
if access == UC_MEM_READ:
val = self.debugger.memdump_region(address, size)
if len(val) == 4:
val = struct.unpack("<I", val)[0]
elif len(val) == 1:
val = struct.unpack("<B", val)[0]
p_info(f"{hex(self.pc)} READ at 0x{address:x} with size {size} value={hex(val)} | {hex(address)} <- {hex(val)}")
elif access == UC_MEM_WRITE:
p_info(f"{hex(self.pc)} WRITE at 0x{address:x} with size {size} value={hex(value)} | {hex(address)} -> {hex(value)}")
try: try:
if address == 0x70012800:
# self.ghidra.ghidra.set_background_color(self.saved_blocks)
sys.exit(0)
pass
if access == UC_MEM_WRITE: if access == UC_MEM_WRITE:
if size == 4: if size == 4:
self.debugger.memwrite_region(address, p32(value)) self.debugger.memwrite_region(address, p32(value))
self.uc.mem_write(address, p32(value)) # self.uc.mem_write(address, p32(value))
# self.uc.mem_write(address, self.debugger.memdump_region(address, size)) # self.uc.mem_write(address, self.debugger.memdump_region(address, size))
elif size == 1: elif size == 1:
self.debugger.memwrite_region(address, p8(value)) self.debugger.memwrite_io(address, p8(value))
self.uc.mem_write(address, p8(value)) # self.uc.mem_write(address, p8(value))
# self.uc.mem_write(address, self.debugger.memdump_region(address, size)) # self.uc.mem_write(address, self.debugger.memdump_region(address, size))
else: else:
raise Exception("Unhandled write!") raise Exception("Unhandled write!")
elif access == UC_MEM_READ: elif access == UC_MEM_READ:
uc.mem_write(address, self.debugger.memdump_region(address, size)) if size == 1:
pass
self.uc.mem_write(address, self.debugger.memdump_region(address, size))
else: else:
raise Exception("Not handled!") raise Exception("Not handled!")
except Exception as e: except Exception as e:
print(e)
sys.exit(0)
pass pass
return True return True
def get_device_at(self, address):
for devname in self.devices:
dev = self.devices[devname]
if address >= dev.BASE and address < dev.BASE + dev.SIZE:
return dev
return self.devices['tegra']
# raise Exception(f"No device found at address {hex(address)} pc={hex(sef.pc)}")
def hw_emulation_handle(self, access, address, size, value):
dev = self.get_device_at(address)
print(f"Device={dev.NAME} pc={hex(self.pc)} target=0x{address:x} size={size} access={acces_str[access]}")
if access == UC_MEM_READ:
dev.read(address, size)
elif access == UC_MEM_WRITE:
dev.write(address, value)
return True
def hook_hw_access(self, uc, access, address, size, value, user_data):
if self.hw_itm:
return self.hw_itm_handle(access, address, size, value)
return self.hw_emulation_handle(access, address, size, value)
def setup_hooks(self): def setup_hooks(self):
# hook unmapped # hook unmapped
self.uc.hook_add(UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_UNMAPPED, self.hook_unmapped) self.uc.hook_add(UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_UNMAPPED, self.hook_unmapped)
# 0x6000f000 # 0x6000f000
self.uc.mem_map(0x60000000, 0x10000, UC_PROT_READ | UC_PROT_WRITE) self.uc.mem_map(0x60000000, 0x20000, UC_PROT_READ | UC_PROT_WRITE)
self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.hook_hw_access, begin=0x60000000, end=0x60000000 + 0x10000) self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.hook_hw_access, begin=0x60000000, end=0x60000000 + 0x10000)
self.uc.mem_map(0x70000000, 0x100000, UC_PROT_READ | UC_PROT_WRITE) self.uc.mem_map(0x70000000, 0x100000, UC_PROT_READ | UC_PROT_WRITE)
self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.hook_hw_access, begin=0x70000000, end=0x70000000 + 0x100000) self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.hook_hw_access, begin=0x70000000, end=0x70000000 + 0x100000)
self.setup_log_hook()
self.setup_hook_blocks() #ROM
# self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.hook_mem_access, self, 0x100000, 0x100000 + len(self.bootrom))
#IMEM access
# self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.hook_mem_access, self, 0x40000000, 0x40000000 + 0x40000)
# DRAM
# self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, self.hook_mem_access, self, 0x80000000, 0x80000000 + 2 * GB)
if self.target == "bootrom":
self.setup_warmboot_hook()
self.setup_hook_blocks()
self.setup_rcm_hooks()
else:
self.setup_log_hook()
self.setup_hook_blocks()
# self.setup_hook_EmmcValidateResponse() # self.setup_hook_EmmcValidateResponse()
def setup_coldboot_hook(self):
def hook_coldboot(uc, address, size, user_data):
logging.info(f"Reached coldboot target.")
self.print_ctx()
return True
self.uc.hook_add(UC_HOOK_CODE, hook_coldboot, begin=0x0010145e, end=0x0010145e + 1)
def setup_rcm_hooks(self):
def hook_rcm(uc, address, size, user_data):
self.R0 = 0
self.R1 = 0
return True
self.uc.hook_add(UC_HOOK_CODE, hook_rcm, begin=0x00101414, end=0x00101414 + 1)
def setup_warmboot_hook(self):
def hook_warmboot(uc, address, size, user_data):
logging.info(f"Hooking warmboot, forcing coldboot.")
self.R0 = 0
return True
self.uc.hook_add(UC_HOOK_CODE, hook_warmboot, begin=0x00101f3a, end=0x00101f3a + 1)
def apply_patches(self): def apply_patches(self):
# Nop out 400101f0 to 0x40010220, maybe this is restricting access to IMEM and ROM? # Nop out 400101f0 to 0x40010220, maybe this is restricting access to IMEM and ROM?
self.sc.mov_0_r0 = self.ks.asm("mov r0, #0", as_bytes=True)[0] self.sc.mov_0_r0 = self.ks.asm("mov r0, #0", as_bytes=True)[0]
# self.uc.mem_write(0x400101e4, self.sc.mov_0_r0 * ((0x40010220 - 0x400101e4) // 4)) # self.uc.mem_write(0x400101e4, self.sc.mov_0_r0 * ((0x40010220 - 0x400101e4) // 4))
# Patch EMMCVerifyResponse # Patch EMMCVerifyResponse
self.sc.bx_lr = self.ks.asm("bx lr", as_bytes=True)[0] self.sc.bx_lr = self.ks.asm("bx lr", as_bytes=True)[0]
bx_lr_thumb = self.ksT.asm("bx lr", as_bytes=True)[0]
movs_0_r0_thumb = self.ksT.asm("movs r0, #0", as_bytes=True)[0]
# self.uc.mem_write(0x4001dfb0, self.sc.mov_0_r0 + self.sc.bx_lr) # self.uc.mem_write(0x4001dfb0, self.sc.mov_0_r0 + self.sc.bx_lr)
if self.target == "bootrom":
#NvBootClocksIsPllStable, ret
# self.uc.mem_write(0x00101730, bx_lr_thumb)
# # NvBootClocksStartPll
self.uc.mem_write(0x00101866, bx_lr_thumb)
# NvBootClocksPllDivRstCtrl
self.uc.mem_write(0x001016ce, bx_lr_thumb)
#usb init?
self.uc.mem_write(0x00103bf4, bx_lr_thumb)
#SE engine always ready
# self.uc.mem_write(0x00102b24, movs_0_r0_thumb)
pass pass
def run(self): def run(self):
try: try:
self.uc.emu_start(self.pc, 0) self.uc.emu_start(self.pc, 0)
pass
except Exception as e: except Exception as e:
print(str(e)) print(str(e))
self.print_ctx(print) self.print_ctx(print)
@ -173,12 +396,19 @@ class PartialEmu(ARM_Emulator):
# And patch function to just return # And patch function to just return
self.uc.mem_write(UART_LOG_HOOK, self.ks.asm("bx lr", as_bytes=True)[0]) self.uc.mem_write(UART_LOG_HOOK, self.ks.asm("bx lr", as_bytes=True)[0])
def setup_hook_blocks(self): def setup_hook_blocks(self, only_blocks=False):
def hook_block(uc, address, size, user_data): if only_blocks:
# print(f"Block at {hex(self.LR)}") def hook_block(uc, address, size, user_data):
self.saved_blocks[self.LR] = self.get_registers() # print(f"Block at {hex(self.LR)}")
return True self.saved_blocks[self.LR] = self.get_registers()
self.uc.hook_add(UC_HOOK_BLOCK, hook_block) return True
self.uc.hook_add(UC_HOOK_BLOCK, hook_block)
else:
def hook_all(uc, address, size, user_data):
# print(f"Block at {hex(self.LR)}")
self.saved_blocks[self.pc] = self.get_registers()
return True
self.uc.hook_add(UC_HOOK_CODE, hook_all, self)
def setup_interrupt_hook(self): def setup_interrupt_hook(self):
RAISE_INTERRUPT = 0x4001cab8 RAISE_INTERRUPT = 0x4001cab8
@ -196,8 +426,14 @@ class PartialEmu(ARM_Emulator):
self.uc.hook_add(UC_HOOK_CODE, hook_emmc, begin=0x4001dfb0, end=0x4001e160) self.uc.hook_add(UC_HOOK_CODE, hook_emmc, begin=0x4001dfb0, end=0x4001e160)
def do_partial_emu(debugger : ConcreteDevice): def do_partial_emu(debugger : ConcreteDevice, real_hw=True):
emu = PartialEmu() if real_hw:
emu.install_debugger(debugger) emu = TegraEmulator()
emu.setup() emu.install_debugger(debugger)
emu.run() else:
emu = TegraEmulator(hw_itm=False)
emu.setup(target="bootrom")
emu.run()
if __name__ == "__main__":
do_partial_emu(None, real_hw=False)

View File

@ -9,8 +9,8 @@ ghidra_assistant/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
ghidra_assistant/__pycache__/__init__.cpython-310.pyc,, ghidra_assistant/__pycache__/__init__.cpython-310.pyc,,
ghidra_assistant/__pycache__/concrete_device.cpython-310.pyc,, ghidra_assistant/__pycache__/concrete_device.cpython-310.pyc,,
ghidra_assistant/__pycache__/ghidra_assistant.cpython-310.pyc,, ghidra_assistant/__pycache__/ghidra_assistant.cpython-310.pyc,,
ghidra_assistant/concrete_device.py,sha256=llVfmejKwBl8lohEhcpTeKvepguJ0dhUKGlZQL2wV0Y,8228 ghidra_assistant/concrete_device.py,sha256=MF6X-DZpPN9UhZzmrXUyM_GbGdJKQVziNAJ9RjOzyLI,8418
ghidra_assistant/ghidra_assistant.py,sha256=CYJw9zTDB6QdXes0oebg2HRjIDdEc_SwqVdBY7iJQpY,497 ghidra_assistant/ghidra_assistant.py,sha256=tlpbxh9-V29IVN_tBiE6hOc7nuWa9zZt-z1AwGZpRD8,728
ghidra_assistant/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 ghidra_assistant/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
ghidra_assistant/utils/__pycache__/__init__.cpython-310.pyc,, ghidra_assistant/utils/__pycache__/__init__.cpython-310.pyc,,
ghidra_assistant/utils/__pycache__/bit_helper.cpython-310.pyc,, ghidra_assistant/utils/__pycache__/bit_helper.cpython-310.pyc,,
@ -22,12 +22,12 @@ ghidra_assistant/utils/archs/__pycache__/asm_utils.cpython-310.pyc,,
ghidra_assistant/utils/archs/arm/__pycache__/armT_processor_state.cpython-310.pyc,, ghidra_assistant/utils/archs/arm/__pycache__/armT_processor_state.cpython-310.pyc,,
ghidra_assistant/utils/archs/arm/__pycache__/arm_emulator.cpython-310.pyc,, ghidra_assistant/utils/archs/arm/__pycache__/arm_emulator.cpython-310.pyc,,
ghidra_assistant/utils/archs/arm/armT_processor_state.py,sha256=ZdsI6Q9mLv-YZEmJSEwKUmsh7903--nfa-dlhfi8QtQ,9466 ghidra_assistant/utils/archs/arm/armT_processor_state.py,sha256=ZdsI6Q9mLv-YZEmJSEwKUmsh7903--nfa-dlhfi8QtQ,9466
ghidra_assistant/utils/archs/arm/arm_emulator.py,sha256=Wq7Tyiph3KYmvmMnRG8dl4TFKJEeNP8dtDrm_XpBLew,7798 ghidra_assistant/utils/archs/arm/arm_emulator.py,sha256=dL86jwUMYON5Ry_OcDPDjvEYp4LYCZcadW3yiiG26fk,7841
ghidra_assistant/utils/archs/arm64/__pycache__/arm64_emulator.cpython-310.pyc,, ghidra_assistant/utils/archs/arm64/__pycache__/arm64_emulator.cpython-310.pyc,,
ghidra_assistant/utils/archs/arm64/__pycache__/arm64_processor_state.cpython-310.pyc,, ghidra_assistant/utils/archs/arm64/__pycache__/arm64_processor_state.cpython-310.pyc,,
ghidra_assistant/utils/archs/arm64/__pycache__/asm_arm64.cpython-310.pyc,, ghidra_assistant/utils/archs/arm64/__pycache__/asm_arm64.cpython-310.pyc,,
ghidra_assistant/utils/archs/arm64/__pycache__/uc_emulator.cpython-310.pyc,, ghidra_assistant/utils/archs/arm64/__pycache__/uc_emulator.cpython-310.pyc,,
ghidra_assistant/utils/archs/arm64/arm64_emulator.py,sha256=MtAM0DjxagGJZfN5SQuzKJ2tf7kqcYs4r_9a07pZg9o,17044 ghidra_assistant/utils/archs/arm64/arm64_emulator.py,sha256=h19lNQvT9RSHeN4MrUagqq7coo0tbTHzlofsNtAFcmI,16964
ghidra_assistant/utils/archs/arm64/arm64_processor_state.py,sha256=GqKoqwbCDhznJEbIgefvlsTcn6ensMD-q70bQMWsgvo,17633 ghidra_assistant/utils/archs/arm64/arm64_processor_state.py,sha256=GqKoqwbCDhznJEbIgefvlsTcn6ensMD-q70bQMWsgvo,17633
ghidra_assistant/utils/archs/arm64/asm_arm64.py,sha256=k96Xp7hEhQWD6lbbmT2bAKuwJCz5VDRF6gx2koMuDW8,2562 ghidra_assistant/utils/archs/arm64/asm_arm64.py,sha256=k96Xp7hEhQWD6lbbmT2bAKuwJCz5VDRF6gx2koMuDW8,2562
ghidra_assistant/utils/archs/arm64/misc/MMU/__pycache__/arm64_mmu.cpython-310.pyc,, ghidra_assistant/utils/archs/arm64/misc/MMU/__pycache__/arm64_mmu.cpython-310.pyc,,
@ -60,13 +60,13 @@ ghidra_assistant/utils/debugger/debugger_archs/__pycache__/ga_arm_thumb.cpython-
ghidra_assistant/utils/debugger/debugger_archs/base_arch.py,sha256=uzyYUm_xEekk3j8uHx8blaKDbK8VR_gMU-Br8RY0tCs,1244 ghidra_assistant/utils/debugger/debugger_archs/base_arch.py,sha256=uzyYUm_xEekk3j8uHx8blaKDbK8VR_gMU-Br8RY0tCs,1244
ghidra_assistant/utils/debugger/debugger_archs/ga_arm.py,sha256=lPecV5UyTBErJgIkfrAa1d3kiH3PN_gaD5zhA4uzU4A,2745 ghidra_assistant/utils/debugger/debugger_archs/ga_arm.py,sha256=lPecV5UyTBErJgIkfrAa1d3kiH3PN_gaD5zhA4uzU4A,2745
ghidra_assistant/utils/debugger/debugger_archs/ga_arm64.py,sha256=_195wxctqIBidDfHjSn-bicrsAbOtnhQGta4LgfiOog,9363 ghidra_assistant/utils/debugger/debugger_archs/ga_arm64.py,sha256=_195wxctqIBidDfHjSn-bicrsAbOtnhQGta4LgfiOog,9363
ghidra_assistant/utils/debugger/debugger_archs/ga_arm_thumb.py,sha256=tZsQk6hnduZBy6n7g6x7tBhutpTmDk4W1wrNSbSaSsE,4946 ghidra_assistant/utils/debugger/debugger_archs/ga_arm_thumb.py,sha256=v8qwn7DsI2Hl38bzzybpfmwhYi82o5i_-8Pva5gtFDw,5339
ghidra_assistant/utils/definitions.py,sha256=tsk4MkEz510JN9-T1ZZExq61uZ32MVPc-0JljHQSde0,3511 ghidra_assistant/utils/definitions.py,sha256=tsk4MkEz510JN9-T1ZZExq61uZ32MVPc-0JljHQSde0,3511
ghidra_assistant/utils/ga_client.py,sha256=dQeJdxL8z48WOw0cHf7sNtqlCVS3ZJ9FSTiB5om-ojM,2065 ghidra_assistant/utils/ga_client.py,sha256=dQeJdxL8z48WOw0cHf7sNtqlCVS3ZJ9FSTiB5om-ojM,2065
ghidra_assistant/utils/ga_server.py,sha256=gchzEPmEtT8kigVB3Jnnv35nsB2k3_dSrQ5_BD8UgUA,5067 ghidra_assistant/utils/ga_server.py,sha256=gchzEPmEtT8kigVB3Jnnv35nsB2k3_dSrQ5_BD8UgUA,5067
ghidra_assistant/utils/ghidra/__pycache__/ghidra_connect.cpython-310.pyc,, ghidra_assistant/utils/ghidra/__pycache__/ghidra_connect.cpython-310.pyc,,
ghidra_assistant/utils/ghidra/__pycache__/pyhidra.cpython-310.pyc,, ghidra_assistant/utils/ghidra/__pycache__/pyhidra.cpython-310.pyc,,
ghidra_assistant/utils/ghidra/ghidra_connect.py,sha256=UUBAzRq4WraqBewi-gH-bXyoAkydBUpVvuVYthNjoUU,13856 ghidra_assistant/utils/ghidra/ghidra_connect.py,sha256=69JunNjWcNc4uBLw5u3S0KAzBY9yeF_QQjvnTdI2Fwg,15506
ghidra_assistant/utils/ghidra/pyhidra.py,sha256=amdhJcj4Fw3INuAqtIl7DfXNTtTwzPmj2FnyM0sNOFY,412 ghidra_assistant/utils/ghidra/pyhidra.py,sha256=amdhJcj4Fw3INuAqtIl7DfXNTtTwzPmj2FnyM0sNOFY,412
ghidra_assistant/utils/utils.py,sha256=Ij9FiQsuCWAA8iIWt_3aO46E5K4e5zqaA7DCeqB7sk0,7372 ghidra_assistant/utils/utils.py,sha256=Ij9FiQsuCWAA8iIWt_3aO46E5K4e5zqaA7DCeqB7sk0,7372
ghidra_assistant/venv/bin/__pycache__/rst2html.cpython-310.pyc,, ghidra_assistant/venv/bin/__pycache__/rst2html.cpython-310.pyc,,

View File

@ -111,6 +111,12 @@ class ConcreteDevice():
Sync processor state from memory region to registers on device. Sync processor state from memory region to registers on device.
''' '''
raise NotImplemented raise NotImplemented
def memwrite_io(self, address, data):
'''
Write some data byte by byte
'''
raise NotImplemented
def memdump_region(self, offset, size): def memdump_region(self, offset, size):
''' '''
@ -194,6 +200,7 @@ class ConcreteDevice():
self.read = self.arch_dbg.read self.read = self.arch_dbg.read
self.write = self.arch_dbg.write self.write = self.arch_dbg.write
self.memdump_region = self.arch_dbg.memdump_region self.memdump_region = self.arch_dbg.memdump_region
self.memwrite_io = self.arch_dbg.memwrite_io
# self.memdump_region_small = self.arch_dbg.memdump_region_small # self.memdump_region_small = self.arch_dbg.memdump_region_small
self.memwrite_region = self.arch_dbg.memwrite_region self.memwrite_region = self.arch_dbg.memwrite_region
self.get_debugger_location = self.arch_dbg.get_debugger_location self.get_debugger_location = self.arch_dbg.get_debugger_location

View File

@ -17,6 +17,12 @@ def main():
''' '''
info("Running tests") info("Running tests")
ga = GhidraAssistant() ga = GhidraAssistant()
# Test colouring lines
# Generate a list of fake PC values from 0x4001ed94 to 0x4001ed94 + 0x1000
pc_values = [0x4001ed94 + i for i in range(0, 0x1000, 4)]
ga.ghidra.set_background_color(pc_values, "red")
dat = ga.ghidra.get_ghidra_memory_maps() dat = ga.ghidra.get_ghidra_memory_maps()
# Test concrete device # Test concrete device

View File

@ -8,6 +8,7 @@ from ...utils import *
class ARM_Emulator: class ARM_Emulator:
''' '''
Class that will interact with the unicorn engine for emulating ARM code. Class that will interact with the unicorn engine for emulating ARM code.
Supports both ARM and Thumb modes.
''' '''
def __init__(self, init_uc = True): def __init__(self, init_uc = True):
if init_uc: if init_uc:

View File

@ -22,7 +22,7 @@ class ARM64UC_Emulator():
def setup_shellcode(self): def setup_shellcode(self):
self.sc = ShellcodeCrafter(self.ks, self.cs) self.sc = ShellcodeCrafter(self.ks, self.cs)
def get_mapping(self, address): def get_mapping(self, address):
for mem in self.uc.mem_regions(): for mem in self.uc.mem_regions():
if address >= mem[0] and address < mem[1]: if address >= mem[0] and address < mem[1]:
@ -33,7 +33,7 @@ class ARM64UC_Emulator():
if self.get_mapping(address) != None: if self.get_mapping(address) != None:
return True return True
return False return False
def read_string(self, at): def read_string(self, at):
if at == 0: if at == 0:
return b'' return b''
@ -45,13 +45,13 @@ class ARM64UC_Emulator():
return s return s
s += b s += b
return s return s
def write_ptr(self, at, ptr): def write_ptr(self, at, ptr):
return self.uc.mem_write(at, p32(ptr)) return self.uc.mem_write(at, p32(ptr))
def read_ptr(self, at): def read_ptr(self, at):
return u32(self.uc.mem_read(at, 4)) return u32(self.uc.mem_read(at, 4))
def add_breakpoint(self, at, target_fun): def add_breakpoint(self, at, target_fun):
self.uc.hook_add(UC_HOOK_CODE, target_fun, None, at, at + 1) self.uc.hook_add(UC_HOOK_CODE, target_fun, None, at, at + 1)
@ -106,7 +106,7 @@ class ARM64UC_Emulator():
@sp.setter @sp.setter
def sp(self, value): def sp(self, value):
self.uc.reg_write(UC_ARM64_REG_SP, value) self.uc.reg_write(UC_ARM64_REG_SP, value)
@property @property
def lr(self): def lr(self):
return self.uc.reg_read(UC_ARM64_REG_LR) return self.uc.reg_read(UC_ARM64_REG_LR)
@ -114,7 +114,7 @@ class ARM64UC_Emulator():
@lr.setter @lr.setter
def lr(self, value): def lr(self, value):
self.uc.reg_write(UC_ARM64_REG_LR, value) self.uc.reg_write(UC_ARM64_REG_LR, value)
@property @property
def vbar_el1(self): def vbar_el1(self):
return self.uc.reg_read(UC_ARM64_REG_VBAR_EL1) return self.uc.reg_read(UC_ARM64_REG_VBAR_EL1)
@ -122,7 +122,7 @@ class ARM64UC_Emulator():
@vbar_el1.setter @vbar_el1.setter
def vbar_el1(self, value): def vbar_el1(self, value):
self.uc.reg_write(UC_ARM64_REG_VBAR_EL1, value) self.uc.reg_write(UC_ARM64_REG_VBAR_EL1, value)
@property @property
def vbar_el2(self): def vbar_el2(self):
return self.uc.reg_read(UC_ARM64_REG_VBAR_EL2) return self.uc.reg_read(UC_ARM64_REG_VBAR_EL2)
@ -130,7 +130,7 @@ class ARM64UC_Emulator():
@vbar_el2.setter @vbar_el2.setter
def vbar_el2(self, value): def vbar_el2(self, value):
self.uc.reg_write(UC_ARM64_REG_VBAR_EL2, value) self.uc.reg_write(UC_ARM64_REG_VBAR_EL2, value)
@property @property
def vbar_el3(self): def vbar_el3(self):
return self.uc.reg_read(UC_ARM64_REG_VBAR_EL3) return self.uc.reg_read(UC_ARM64_REG_VBAR_EL3)
@ -138,7 +138,7 @@ class ARM64UC_Emulator():
@vbar_el3.setter @vbar_el3.setter
def vbar_el3(self, value): def vbar_el3(self, value):
self.uc.reg_write(UC_ARM64_REG_VBAR_EL3, value) self.uc.reg_write(UC_ARM64_REG_VBAR_EL3, value)
@property @property
def elr_el0(self): def elr_el0(self):
return self.uc.reg_read(UC_ARM64_REG_ELR_EL0) return self.uc.reg_read(UC_ARM64_REG_ELR_EL0)
@ -146,7 +146,7 @@ class ARM64UC_Emulator():
@elr_el0.setter @elr_el0.setter
def elr_el0(self, value): def elr_el0(self, value):
self.uc.reg_write(UC_ARM64_REG_ELR_EL0, value) self.uc.reg_write(UC_ARM64_REG_ELR_EL0, value)
@property @property
def elr_el1(self): def elr_el1(self):
return self.uc.reg_read(UC_ARM64_REG_ELR_EL1) return self.uc.reg_read(UC_ARM64_REG_ELR_EL1)
@ -154,7 +154,7 @@ class ARM64UC_Emulator():
@elr_el1.setter @elr_el1.setter
def elr_el1(self, value): def elr_el1(self, value):
self.uc.reg_write(UC_ARM64_REG_ELR_EL1, value) self.uc.reg_write(UC_ARM64_REG_ELR_EL1, value)
@property @property
def elr_el2(self): def elr_el2(self):
return self.uc.reg_read(UC_ARM64_REG_ELR_EL2) return self.uc.reg_read(UC_ARM64_REG_ELR_EL2)
@ -162,7 +162,7 @@ class ARM64UC_Emulator():
@elr_el2.setter @elr_el2.setter
def elr_el2(self, value): def elr_el2(self, value):
self.uc.reg_write(UC_ARM64_REG_ELR_EL2, value) self.uc.reg_write(UC_ARM64_REG_ELR_EL2, value)
@property @property
def elr_el3(self): def elr_el3(self):
return self.uc.reg_read(UC_ARM64_REG_ELR_EL3) return self.uc.reg_read(UC_ARM64_REG_ELR_EL3)

View File

@ -10,6 +10,15 @@ class GA_arm_thumb_debugger(BaseArch_debugger):
self.ks = Ks(KS_MODE_ARM, KS_MODE_THUMB) self.ks = Ks(KS_MODE_ARM, KS_MODE_THUMB)
self.sc = ShellcodeCrafterARMThumb(self.ks, self.cs) self.sc = ShellcodeCrafterARMThumb(self.ks, self.cs)
self.state = ARMThumb_Concrete_State(storage_addr, self) self.state = ARMThumb_Concrete_State(storage_addr, self)
def memwrite_io(self, address, data):
assert len(data) < (0x20 - 12), "Data length is too long for IO write"
self.write("HWIO")
packet = struct.pack('<III', address, 0, len(data)) + data
# fill the block up to 0x20 bytes
packet += b"\x00" * (0x20 - len(packet))
self.write(packet)
self.read(DEBUGGER_BLOCKSIZE_TRANSMISSION)
def memdump_region(self, offset, size): def memdump_region(self, offset, size):
''' '''

View File

@ -109,14 +109,25 @@ class Ghidra:
def _jaddr(self, addr): def _jaddr(self, addr):
# The string that's fed to getAddress NEEDS to be hex for some godawful reason # The string that's fed to getAddress NEEDS to be hex for some godawful reason
return self.address_factory.getAddress(hex(addr)) return self.address_factory.getAddress(hex(addr))
def _jbytes(self, dat):
return bytes(dat)
def startTransaction(self, name):
self.stopTransaction()
self.transaction = currentProgram.startTransaction(f"Coloring lines")
def stopTransaction(self):
if hasattr(self, "transaction"):
currentProgram.endTransaction(self.transaction, True)
def set_background_color(self, addresses): def set_background_color(self, addresses, color="java.awt.Color.YELLOW"):
''' '''
Highlight a list of addresses Highlight a list of addresses
''' '''
tr = currentProgram.startTransaction(f"Coloring lines") tr = currentProgram.startTransaction(f"Coloring lines")
d = self.bridge.remote_eval("[currentProgram.getAddressFactory().getAddress(addr) for addr in addresses]", addresses=[hex(addr) for addr in addresses]) d = self.bridge.remote_eval("[currentProgram.getAddressFactory().getAddress(addr) for addr in addresses]", addresses=[hex(addr) for addr in addresses])
self.bridge.remote_eval("[setBackgroundColor(addr, java.awt.Color.YELLOW) for addr in d]", d=d) self.bridge.remote_eval(f"[setBackgroundColor(addr, {color}) for addr in d]", d=d)
currentProgram.endTransaction(tr, True) currentProgram.endTransaction(tr, True)
def clear_background_color(self): def clear_background_color(self):
@ -264,6 +275,36 @@ class Ghidra:
#name: unicode, start: ghidra.program.model.address.Address, fileBytes: ghidra.program.database.mem.FileBytes, offset: long, size: long, overlay: bool) -> ghidra.program.model.mem.MemoryBlock: #name: unicode, start: ghidra.program.model.address.Address, fileBytes: ghidra.program.database.mem.FileBytes, offset: long, size: long, overlay: bool) -> ghidra.program.model.mem.MemoryBlock:
self.memory.setBytes(toAddr(start), bytes(data)) self.memory.setBytes(toAddr(start), bytes(data))
currentProgram.endTransaction(tr, True) currentProgram.endTransaction(tr, True)
def mmap_region(self, addr, name, size, read=True, write=True, execute=False):
tr = currentProgram.startTransaction(f"Mapping memory region {name} at {hex(addr)}")
self.memory.createInitializedBlock(name, toAddr(addr), size, 0, monitor, False)
block = self.memory.getBlock(toAddr(hex(addr)))
block.setPermissions(read, write, execute)
currentProgram.endTransaction(tr, True)
def write_mem(self, addr, data):
'''
write data to memory, if region is available
'''
# check if address is in a block
block = self.get_memory_block(addr)
if block is None:
warn(f"Address {hex(addr)} is not in a block")
return
# check if len(data) is too big
if len(data) > block.getSize():
warn(f"Data is too big for block {block.name}")
return
tr = currentProgram.startTransaction(f"Writing memory at {hex(addr)}")
self.memory.setBytes(toAddr(addr), bytes(data))
currentProgram.endTransaction(tr, True)
def get_memory_block(self, addr):
for block in self.memory.getBlocks():
if block.contains(toAddr(hex(addr))):
return block
return None
def get_function_decompiled_code(self, func): def get_function_decompiled_code(self, func):
# decompile the function and print the pseudo C # decompile the function and print the pseudo C