|
|
|
@ -273,7 +273,7 @@ class Emulator:
|
|
|
|
debug(DEBUG_INIT, "# Setting TLB mode to virtual")
|
|
|
|
debug(DEBUG_INIT, "# Setting TLB mode to virtual")
|
|
|
|
self.uc.ctl_set_tlb_mode(U.UC_TLB_VIRTUAL) # type: ignore[attr-defined]
|
|
|
|
self.uc.ctl_set_tlb_mode(U.UC_TLB_VIRTUAL) # type: ignore[attr-defined]
|
|
|
|
|
|
|
|
|
|
|
|
self.regs: pwndbg.lib.regs.RegisterSet = pwndbg.aglib.regs.current
|
|
|
|
self.reg_set: pwndbg.lib.regs.RegisterSet = pwndbg.aglib.regs.current
|
|
|
|
|
|
|
|
|
|
|
|
# Whether the emulator is allowed to emulate instructions
|
|
|
|
# Whether the emulator is allowed to emulate instructions
|
|
|
|
# There are cases when the emulator is incorrect or we want to disable it for certain instruction types,
|
|
|
|
# There are cases when the emulator is incorrect or we want to disable it for certain instruction types,
|
|
|
|
@ -292,7 +292,7 @@ class Emulator:
|
|
|
|
self.last_single_step_result = InstructionExecutedResult(None, None)
|
|
|
|
self.last_single_step_result = InstructionExecutedResult(None, None)
|
|
|
|
|
|
|
|
|
|
|
|
# Initialize the register state
|
|
|
|
# Initialize the register state
|
|
|
|
for emu_reg in self.regs.emulated_regs_order:
|
|
|
|
for emu_reg in self.reg_set.emulated_regs_order:
|
|
|
|
reg = emu_reg.name
|
|
|
|
reg = emu_reg.name
|
|
|
|
enum = self.get_reg_enum(reg)
|
|
|
|
enum = self.get_reg_enum(reg)
|
|
|
|
|
|
|
|
|
|
|
|
@ -344,6 +344,9 @@ class Emulator:
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
# raise AttributeError(f"AttributeError: {self!r} object has no register {name!r}")
|
|
|
|
# raise AttributeError(f"AttributeError: {self!r} object has no register {name!r}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pc(self) -> int:
|
|
|
|
|
|
|
|
return self.read_register(self.reg_set.pc)
|
|
|
|
|
|
|
|
|
|
|
|
# Read size worth of memory, return None on error
|
|
|
|
# Read size worth of memory, return None on error
|
|
|
|
def read_memory(self, address: int, size: int) -> bytes | None:
|
|
|
|
def read_memory(self, address: int, size: int) -> bytes | None:
|
|
|
|
# Don't attempt if the address is not mapped on the host process
|
|
|
|
# Don't attempt if the address is not mapped on the host process
|
|
|
|
@ -587,18 +590,10 @@ class Emulator:
|
|
|
|
|
|
|
|
|
|
|
|
return sz[:max_string_len] + "..."
|
|
|
|
return sz[:max_string_len] + "..."
|
|
|
|
|
|
|
|
|
|
|
|
def __getattr__(self, name: str):
|
|
|
|
|
|
|
|
reg = self.get_reg_enum(name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if reg:
|
|
|
|
|
|
|
|
return self.uc.reg_read(reg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
raise AttributeError(f"AttributeError: {self!r} object has no attribute {name!r}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_pc(self, pc=None) -> None:
|
|
|
|
def update_pc(self, pc=None) -> None:
|
|
|
|
if pc is None:
|
|
|
|
if pc is None:
|
|
|
|
pc = pwndbg.aglib.regs.pc
|
|
|
|
pc = pwndbg.aglib.regs.pc
|
|
|
|
self.uc.reg_write(self.get_reg_enum(self.regs.pc), pc)
|
|
|
|
self.uc.reg_write(self.get_reg_enum(self.reg_set.pc), pc)
|
|
|
|
|
|
|
|
|
|
|
|
def read_thumb_bit(self) -> int:
|
|
|
|
def read_thumb_bit(self) -> int:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
@ -612,10 +607,10 @@ class Emulator:
|
|
|
|
Mimics the `read_thumb_bit` function defined in aglib/arch.py
|
|
|
|
Mimics the `read_thumb_bit` function defined in aglib/arch.py
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
if self.arch == "arm":
|
|
|
|
if self.arch == "arm":
|
|
|
|
if (cpsr := self.cpsr) is not None:
|
|
|
|
if (cpsr := self.read_register("cpsr")) is not None:
|
|
|
|
return (cpsr >> 5) & 1
|
|
|
|
return (cpsr >> 5) & 1
|
|
|
|
elif self.arch == "armcm":
|
|
|
|
elif self.arch == "armcm":
|
|
|
|
if (xpsr := self.xpsr) is not None:
|
|
|
|
if (xpsr := self.read_register("xpsr")) is not None:
|
|
|
|
return (xpsr >> 24) & 1
|
|
|
|
return (xpsr >> 24) & 1
|
|
|
|
return 0
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
@ -717,35 +712,15 @@ class Emulator:
|
|
|
|
|
|
|
|
|
|
|
|
Also supports general registers like 'sp' and 'pc'.
|
|
|
|
Also supports general registers like 'sp' and 'pc'.
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
if not self.regs:
|
|
|
|
if not self.reg_set:
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
# If we're looking for an exact register ('eax', 'ebp', 'r0') then
|
|
|
|
# Look up the Unicorn enum for an exact register ('eax', 'ebp', 'r0')
|
|
|
|
# we can look those up easily.
|
|
|
|
# This does not handle aliases, such as "sp" or "pc"
|
|
|
|
#
|
|
|
|
|
|
|
|
# 'eax' ==> enum
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# if reg in self.regs.all:
|
|
|
|
|
|
|
|
e = self.const_regs.get(reg.upper(), None)
|
|
|
|
e = self.const_regs.get(reg.upper(), None)
|
|
|
|
if e is not None:
|
|
|
|
if e is not None:
|
|
|
|
return e
|
|
|
|
return e
|
|
|
|
|
|
|
|
|
|
|
|
# If we're looking for an abstract register which *is* accounted for,
|
|
|
|
|
|
|
|
# we can also do an indirect lookup.
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# 'pc' ==> 'eip' ==> enum
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
if hasattr(self.regs, reg):
|
|
|
|
|
|
|
|
return self.get_reg_enum(getattr(self.regs, reg))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# If we're looking for an abstract register which does not exist on
|
|
|
|
|
|
|
|
# the RegisterSet objects, we need to do an indirect lookup.
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# 'sp' ==> 'stack' ==> 'esp' ==> enum
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
elif reg == "sp":
|
|
|
|
|
|
|
|
return self.get_reg_enum(self.regs.stack)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def hook_add(self, *a, **kw):
|
|
|
|
def hook_add(self, *a, **kw):
|
|
|
|
@ -769,7 +744,7 @@ class Emulator:
|
|
|
|
def emulate_with_hook(self, hook, count=512) -> None:
|
|
|
|
def emulate_with_hook(self, hook, count=512) -> None:
|
|
|
|
ident = self.hook_add(U.UC_HOOK_CODE, hook)
|
|
|
|
ident = self.hook_add(U.UC_HOOK_CODE, hook)
|
|
|
|
|
|
|
|
|
|
|
|
pc: int = self.pc
|
|
|
|
pc: int = self.pc()
|
|
|
|
# Unicorn appears to disregard the UC_MODE_THUMB mode passed into the constructor, and instead
|
|
|
|
# Unicorn appears to disregard the UC_MODE_THUMB mode passed into the constructor, and instead
|
|
|
|
# determines Thumb mode based on the PC that is passed to the `emu_start` function
|
|
|
|
# determines Thumb mode based on the PC that is passed to the `emu_start` function
|
|
|
|
# https://github.com/unicorn-engine/unicorn/issues/391
|
|
|
|
# https://github.com/unicorn-engine/unicorn/issues/391
|
|
|
|
@ -884,7 +859,7 @@ class Emulator:
|
|
|
|
|
|
|
|
|
|
|
|
self.last_single_step_result = InstructionExecutedResult(None, None)
|
|
|
|
self.last_single_step_result = InstructionExecutedResult(None, None)
|
|
|
|
|
|
|
|
|
|
|
|
pc = pc or self.pc
|
|
|
|
pc = pc or self.pc()
|
|
|
|
|
|
|
|
|
|
|
|
if instruction is None:
|
|
|
|
if instruction is None:
|
|
|
|
instruction = pwndbg.aglib.disasm.disassembly.one_raw(pc)
|
|
|
|
instruction = pwndbg.aglib.disasm.disassembly.one_raw(pc)
|
|
|
|
@ -912,7 +887,7 @@ class Emulator:
|
|
|
|
|
|
|
|
|
|
|
|
# If above call does not throw an Exception, we successfully executed the instruction
|
|
|
|
# If above call does not throw an Exception, we successfully executed the instruction
|
|
|
|
self.last_pc = pc
|
|
|
|
self.last_pc = pc
|
|
|
|
debug(DEBUG_EXECUTING, "Unicorn now at pc=%#x", self.pc)
|
|
|
|
debug(DEBUG_EXECUTING, "Unicorn now at pc=%#x", self.pc())
|
|
|
|
except U.unicorn.UcError:
|
|
|
|
except U.unicorn.UcError:
|
|
|
|
debug(DEBUG_EXECUTING, "Emulator failed to execute instruction")
|
|
|
|
debug(DEBUG_EXECUTING, "Emulator failed to execute instruction")
|
|
|
|
self.last_single_step_result = InstructionExecutedResult(None, None)
|
|
|
|
self.last_single_step_result = InstructionExecutedResult(None, None)
|
|
|
|
@ -940,10 +915,10 @@ class Emulator:
|
|
|
|
# For debugging
|
|
|
|
# For debugging
|
|
|
|
def dumpregs(self) -> None:
|
|
|
|
def dumpregs(self) -> None:
|
|
|
|
for reg in (
|
|
|
|
for reg in (
|
|
|
|
list(self.regs.retaddr)
|
|
|
|
list(self.reg_set.retaddr)
|
|
|
|
+ list(self.regs.misc)
|
|
|
|
+ list(self.reg_set.misc)
|
|
|
|
+ list(self.regs.common)
|
|
|
|
+ list(self.reg_set.common)
|
|
|
|
+ list(self.regs.flags)
|
|
|
|
+ list(self.reg_set.flags)
|
|
|
|
):
|
|
|
|
):
|
|
|
|
enum = self.get_reg_enum(reg)
|
|
|
|
enum = self.get_reg_enum(reg)
|
|
|
|
|
|
|
|
|
|
|
|
@ -960,4 +935,4 @@ class Emulator:
|
|
|
|
debug(DEBUG_TRACE, "# trace_hook: %#-8x %r", (address, data))
|
|
|
|
debug(DEBUG_TRACE, "# trace_hook: %#-8x %r", (address, data))
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
return f"Valid: {self.valid}, PC: {self.pc:#x}"
|
|
|
|
return f"Valid: {self.valid}, PC: {self.pc():#x}"
|
|
|
|
|