Manually propagate register values across instructions while disassembling (#2963)

* Manually propagate register values across instructions while disassembling, allowing better annotations when emulation is unavailable

* Add comment

* More comments

* Comment

* Comment fix

* Local variable change

* Print register writes in instruction debug print

* Clear register set when encountering branch with undetermined result

* Update tests

* lint

* Fix dbg tests

* Update dev docs related to reasoning about process state
pull/3350/head
OBarronCS 2 months ago committed by GitHub
parent 463a1c9904
commit 85b93a792a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -37,7 +37,7 @@ We go through the enhancement process for the instruction at the program counter
## When to use emulation / reasoning about process state
When possible, we code aims to use emulation as little as possible. If there is information that can be determined statically or without the emulator, then we try to avoid emulation. This is so we can display annotations even when the Unicorn Engine is disabled. For example, say we come to a stop, and are faced with enhancing the following three instructions in the dashboard:
In general, the code aims to be organized in a way as to allow as many features as possible even in the absence of emulation. If there is information that can be determined statically, then we try to expose it as an alternative to emulation. This is so we can display annotations even when the Unicorn Engine is disabled. For example, say we come to a stop, and are faced with enhancing the following three instructions in the dashboard:
```asm
1. lea rax, [rip + 0xd55]

@ -29,6 +29,7 @@ from pwndbg.aglib.disasm.instruction import InstructionCondition
from pwndbg.aglib.disasm.instruction import PwndbgInstruction
from pwndbg.aglib.disasm.instruction import boolean_to_instruction_condition
from pwndbg.lib.arch import PWNDBG_SUPPORTED_ARCHITECTURES_TYPE
from pwndbg.lib.regs import PseudoEmulatedRegisterFile
# Emulator currently requires GDB, and we only use it here for type checking.
if TYPE_CHECKING:
@ -144,8 +145,16 @@ def memory_or_register_assign(left: str, right: str, mem_assign: bool) -> str:
class DisassemblyAssistant:
architecture: PWNDBG_SUPPORTED_ARCHITECTURES_TYPE
manual_register_values: PseudoEmulatedRegisterFile
supports_manual_emulation = False
"""This feature relies on the Capstone .regs_access() features that not all architectures have reliable support for"""
def __init__(self, architecture: PWNDBG_SUPPORTED_ARCHITECTURES_TYPE) -> None:
self.architecture = architecture
self.manual_register_values = PseudoEmulatedRegisterFile(
pwndbg.aglib.regs.current, pwndbg.aglib.arch.ptrsize
)
self.op_handlers: Dict[
int, Callable[[PwndbgInstruction, EnhancedOperand, Emulator], int | None]
@ -253,6 +262,32 @@ class DisassemblyAssistant:
if DEBUG_ENHANCEMENT:
print("Turned off emulation for call")
# Manually propagate register values so when enhancing the next instruction, we can read from these registers
if self.supports_manual_emulation:
if (
instruction.call_like
or (set(instruction.groups) & DO_NOT_EMULATE)
or (instruction.jump_like and not instruction.jump_result_is_known)
):
# Syscalls and functions (which we step over) can clobber registers
# Also, if we encounter a control flow instruction where the result is unknown,
# we need to reset the registers because otherwise it may show annotations for instructions never actually taken.
self.manual_register_values.invalidate_all_registers()
else:
_, regs_written = instruction.cs_insn.regs_access()
for reg_id in regs_written:
reg_name: str = instruction.cs_insn.reg_name(reg_id)
# If we determined that this instruction wrote some value to this register, propagate it.
# Otherwise, invalidate the value since we cannot reason about it.
if reg_id in instruction.register_writes:
self.manual_register_values.write_register(
reg_name, instruction.register_writes[reg_id]
)
else:
self.manual_register_values.invalidate_register(reg_name)
if DEBUG_ENHANCEMENT:
print(self.dump(instruction))
print("Done enhancing")
@ -417,6 +452,9 @@ class DisassemblyAssistant:
if DEBUG_ENHANCEMENT:
print(f"Read value from process register: {pwndbg.aglib.regs[regname]}")
return pwndbg.aglib.regs[regname]
elif (reg_value := self.manual_register_values.read_register(regname)) is not None:
# If we manually tracked the value of this register while disassembling, we can read from it.
return reg_value
else:
return None
@ -506,6 +544,11 @@ class DisassemblyAssistant:
address_list = [address]
if read_size is not None and read_size < pwndbg.aglib.arch.ptrsize:
size_type = pwndbg.aglib.typeinfo.get_type(read_size)
else:
size_type = pwndbg.aglib.typeinfo.ppvoid
for _ in range(limit):
if address_list.count(address) >= 2:
break
@ -513,7 +556,9 @@ class DisassemblyAssistant:
page = pwndbg.aglib.vmmap.find(address)
if page and not page.write:
try:
address = pwndbg.aglib.memory.read_pointer_width(address)
address = int(
pwndbg.aglib.memory.get_typed_pointer_value(size_type, address)
)
address &= pwndbg.aglib.arch.ptrmask
address_list.append(address)
except pwndbg.dbg_mod.Error:
@ -1011,6 +1056,9 @@ class DisassemblyAssistant:
# If we already used emulation, use the result, otherwise take the source operand before_value
result = left.after_value or right.before_value
if result is not None and result >= 0:
# We have determined the value written to this register - propagate this to future instructions.
instruction.register_writes[left.reg] = result
TELESCOPE_DEPTH = max(0, int(pwndbg.config.disasm_telescope_depth))
telescope_addresses = self._telescope(

@ -352,6 +352,12 @@ def near(
# By using the same assistant for all the instructions disassembled in this pass, we can track and share information across the instructions
assistant = pwndbg.aglib.disasm.disassembly.get_disassembly_assistant_for_current_arch()
# Copy register values to the enhancer for use in manual register tracking
if assistant.supports_manual_emulation and address == pc:
for reg in pwndbg.aglib.regs.current.common:
if (reg_value := pwndbg.aglib.regs[reg]) is not None:
assistant.manual_register_values.write_register(reg, reg_value)
# Start at the current instruction using emulation if available.
current = one(address, emu, put_cache=True, assistant=assistant)

@ -189,6 +189,7 @@ class PwndbgInstruction(Protocol):
causes_branch_delay: bool
split: SplitType
emulated: bool
register_writes: Dict[int, int]
@property
def call_like(self) -> bool: ...
@ -208,6 +209,9 @@ class PwndbgInstruction(Protocol):
@property
def is_conditional_jump_taken(self) -> bool: ...
@property
def jump_result_is_known(self) -> bool: ...
@property
def bytes(self) -> bytearray: ...
@ -410,6 +414,12 @@ class PwndbgInstructionImpl(PwndbgInstruction):
If the enhancement successfully used emulation for this instruction
"""
self.register_writes = {}
"""
Mapping of Capstone register id to integer value. During enhancement, we might manually determine
that an instruction writes some value to a register, and this is stored here.
"""
@property
def call_like(self) -> bool:
"""
@ -498,6 +508,19 @@ class PwndbgInstructionImpl(PwndbgInstruction):
)
)
@property
def jump_result_is_known(self) -> bool:
"""
True under the following conditions:
- If it's an unconditional jump, we know the target of the jump
- If it's a conditional jump, we know the target of the branch and know whether or not we take it
Otherwise, false
"""
return self.has_jump_target and (
(self.is_unconditional_jump)
or (self.is_conditional_jump and self.condition != InstructionCondition.UNDETERMINED)
)
@property
def bytes(self) -> bytearray:
"""
@ -522,6 +545,11 @@ class PwndbgInstructionImpl(PwndbgInstruction):
def __repr__(self) -> str:
operands_str = " ".join([repr(op) for op in self.operands])
hex_register_writes = {
self.cs_insn.reg_name(reg_id): hex(reg_value)
for reg_id, reg_value in self.register_writes.items()
}
info = f"""{self.mnemonic} {self.op_str} at {self.address:#x} (size={self.size}) (arch: {CAPSTONE_ARCH_MAPPING_STRING.get(self.cs_insn._cs.arch,None)})
Bytes: {pwnlib.util.fiddling.enhex(self.bytes)}
ID: {self.id}, {self.cs_insn.insn_name()}
@ -543,7 +571,18 @@ class PwndbgInstructionImpl(PwndbgInstruction):
Syscall: {self.syscall if self.syscall is not None else ""} {self.syscall_name if self.syscall_name is not None else "N/A"}
Causes Delay slot: {self.causes_branch_delay}
Split: {SplitType(self.split).name}
Call-like: {self.call_like}"""
Call-like: {self.call_like}
Register writes: {hex_register_writes}"""
try:
regs_read, regs_written = self.cs_insn.regs_access()
info += f"\n\tCapstone regs read: {[self.cs_insn.reg_name(reg) for reg in regs_read]}"
info += (
f"\n\tCapstone regs written: {[self.cs_insn.reg_name(reg) for reg in regs_written]}"
)
except CsError:
# Not all architectures support the .reg_access() API
pass
# Hacky, but this is just for debugging
if hasattr(self.cs_insn, "cc"):
@ -715,6 +754,8 @@ class ManualPwndbgInstruction(PwndbgInstruction):
self.emulated = False
self.register_writes = {}
@property
def bytes(self) -> bytearray:
# GDB simply doesn't provide us with the raw bytes.
@ -746,6 +787,10 @@ class ManualPwndbgInstruction(PwndbgInstruction):
def is_conditional_jump_taken(self) -> bool:
return False
@property
def jump_result_is_known(self) -> bool:
return False
@override
def op_find(self, op_type: int, position: int) -> EnhancedOperand:
# raise NotImplementedError, because if this is called it indicates a bug elsewhere in the codebase.

@ -50,6 +50,8 @@ X86_MATH_INSTRUCTIONS = {
# This class handles enhancement for x86 and x86_64. This is because Capstone itself
# represents both architectures using the same class
class X86DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
supports_manual_emulation = True
def __init__(self, architecture) -> None:
super().__init__(architecture)
@ -156,6 +158,9 @@ class X86DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
TELESCOPE_DEPTH = max(0, int(pwndbg.config.disasm_telescope_depth))
if right.before_value is not None:
# We have determined the value written to this register - propagate this to future instructions.
instruction.register_writes[left.reg] = right.before_value
telescope_addresses = super()._telescope(
right.before_value, TELESCOPE_DEPTH, instruction, emu
)
@ -213,6 +218,8 @@ class X86DisassemblyAssistant(pwndbg.aglib.disasm.arch.DisassemblyAssistant):
# If zeroing the register with XOR A, A. Can reason about this no matter where the instruction is
if left.type == CS_OP_REG and right.type == CS_OP_REG and left.reg == right.reg:
# We know that 0 is written to this register - propagate this to future instructions.
instruction.register_writes[left.reg] = 0
instruction.annotation = register_assign(left.str, "0")
else:
self._common_binary_op_annotator(

@ -288,7 +288,7 @@ class RegisterSet:
yield from self.all
class PsuedoEmulatedRegisterFile:
class PseudoEmulatedRegisterFile:
"""
This class represents a set of registers that can be written, read, and invalidated.

@ -175,7 +175,7 @@ async def test_context_disasm_syscalls_args_display(ctrl: Controller) -> None:
" buf: 0xdeadbeef\n"
" nbytes: 0\n"
" 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -224,7 +224,7 @@ async def test_context_disasm_syscalls_args_display_no_emulate(ctrl: Controller)
" buf: 0xdeadbeef\n"
" nbytes: 0\n"
" 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"

@ -74,7 +74,7 @@ async def test_emulate_disasm_loop(ctrl: Controller) -> None:
disasm_without_emu_0x400080 = [
" ► 0x400080 <_start> movabs rsi, string RSI => 0x400094 (string) ◂— xor dword ptr [rdx], esi /* '12345' */",
" 0x40008a <_start+10> mov rdi, rsp",
f" 0x40008a <_start+10> mov rdi, rsp RDI => {hex(pwndbg.aglib.regs.rsp)}",
" 0x40008d <_start+13> mov ecx, 3 ECX => 3",
" 0x400092 <_start+18> rep movsb byte ptr [rdi], byte ptr [rsi]",
" 0x400094 <string> xor dword ptr [rdx], esi",

@ -137,7 +137,7 @@ async def test_nearpc_opcode_bytes(ctrl: Controller, opcode_bytes: int) -> None:
" buf: 0xdeadbeef\n"
" nbytes: 0\n"
" 0x400096 {} <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b {} <_start+27> int 0x80\n"
" 0x40009b {} <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d {} add byte ptr [rax], al\n"
" 0x40009f {} add byte ptr [rax], al\n"
" 0x4000a1 {} add byte ptr [rax], al\n"
@ -166,7 +166,7 @@ async def test_nearpc_opcode_seperator(ctrl: Controller, separator_bytes: int) -
" buf: 0xdeadbeef\n"
" nbytes: 0\n"
" 0x400096 {} <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b {} <_start+27> int 0x80\n"
" 0x40009b {} <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d {} add byte ptr [rax], al\n"
" 0x40009f {} add byte ptr [rax], al\n"
" 0x4000a1 {} add byte ptr [rax], al\n"
@ -193,9 +193,9 @@ async def test_nearpc_highlight_breakpoint(ctrl: Controller) -> None:
"b+ 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -211,9 +211,9 @@ async def test_nearpc_highlight_breakpoint(ctrl: Controller) -> None:
" ► 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -228,9 +228,9 @@ async def test_nearpc_highlight_breakpoint(ctrl: Controller) -> None:
"b+ 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -245,9 +245,9 @@ async def test_nearpc_highlight_breakpoint(ctrl: Controller) -> None:
" 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -262,9 +262,9 @@ async def test_nearpc_highlight_breakpoint(ctrl: Controller) -> None:
"b+ 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -279,9 +279,9 @@ async def test_nearpc_highlight_breakpoint(ctrl: Controller) -> None:
" 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -296,9 +296,9 @@ async def test_nearpc_highlight_breakpoint(ctrl: Controller) -> None:
" 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
" 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"

@ -165,7 +165,7 @@ def test_context_disasm_syscalls_args_display(start_binary):
" buf: 0xdeadbeef\n"
" nbytes: 0\n"
" 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -212,7 +212,7 @@ def test_context_disasm_syscalls_args_display_no_emulate(start_binary):
" buf: 0xdeadbeef\n"
" nbytes: 0\n"
" 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"

@ -71,7 +71,7 @@ def test_emulate_disasm_loop(start_binary):
disasm_without_emu_0x400080 = [
" ► 0x400080 <_start> movabs rsi, string RSI => 0x400094 (string) ◂— xor dword ptr [rdx], esi /* '12345' */",
" 0x40008a <_start+10> mov rdi, rsp",
f" 0x40008a <_start+10> mov rdi, rsp RDI => {hex(pwndbg.aglib.regs.rsp)}",
" 0x40008d <_start+13> mov ecx, 3 ECX => 3",
" 0x400092 <_start+18> rep movsb byte ptr [rdi], byte ptr [rsi]",
" 0x400094 <string> xor dword ptr [rdx], esi",

@ -135,7 +135,7 @@ def test_nearpc_opcode_bytes(start_binary, opcode_bytes):
" buf: 0xdeadbeef\n"
" nbytes: 0\n"
" 0x400096 {} <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b {} <_start+27> int 0x80\n"
" 0x40009b {} <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d {} add byte ptr [rax], al\n"
" 0x40009f {} add byte ptr [rax], al\n"
" 0x4000a1 {} add byte ptr [rax], al\n"
@ -161,7 +161,7 @@ def test_nearpc_opcode_seperator(start_binary, separator_bytes):
" buf: 0xdeadbeef\n"
" nbytes: 0\n"
" 0x400096 {} <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b {} <_start+27> int 0x80\n"
" 0x40009b {} <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d {} add byte ptr [rax], al\n"
" 0x40009f {} add byte ptr [rax], al\n"
" 0x4000a1 {} add byte ptr [rax], al\n"
@ -196,9 +196,9 @@ def test_nearpc_highlight_breakpoint(start_binary):
"b+ 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -214,9 +214,9 @@ def test_nearpc_highlight_breakpoint(start_binary):
" ► 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -231,9 +231,9 @@ def test_nearpc_highlight_breakpoint(start_binary):
"b+ 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -248,9 +248,9 @@ def test_nearpc_highlight_breakpoint(start_binary):
" 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -265,9 +265,9 @@ def test_nearpc_highlight_breakpoint(start_binary):
"b+ 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -282,9 +282,9 @@ def test_nearpc_highlight_breakpoint(start_binary):
" 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
"b+ 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"
@ -299,9 +299,9 @@ def test_nearpc_highlight_breakpoint(start_binary):
" 0x400085 <_start+5> mov edi, 0x1337 EDI => 0x1337\n"
" ► 0x40008a <_start+10> mov esi, 0xdeadbeef ESI => 0xdeadbeef\n"
" 0x40008f <_start+15> mov ecx, 0x10 ECX => 0x10\n"
" 0x400094 <_start+20> syscall \n"
" 0x400094 <_start+20> syscall <SYS_read>\n"
" 0x400096 <_start+22> mov eax, 0xa EAX => 0xa\n"
" 0x40009b <_start+27> int 0x80\n"
" 0x40009b <_start+27> int 0x80 <SYS_unlink>\n"
" 0x40009d add byte ptr [rax], al\n"
" 0x40009f add byte ptr [rax], al\n"
" 0x4000a1 add byte ptr [rax], al\n"

@ -1,6 +1,6 @@
from __future__ import annotations
from pwndbg.lib.regs import PsuedoEmulatedRegisterFile
from pwndbg.lib.regs import PseudoEmulatedRegisterFile
from pwndbg.lib.regs import aarch64
from pwndbg.lib.regs import amd64
from pwndbg.lib.regs import mips
@ -16,7 +16,7 @@ def test_emulated_register_set_amd64():
AH = top half of AX
AL = bottom half of AX
"""
new = PsuedoEmulatedRegisterFile(amd64, 8)
new = PseudoEmulatedRegisterFile(amd64, 8)
new.write_register("rax", -1)
@ -67,7 +67,7 @@ def test_emulated_register_set_amd64():
def test_emulated_register_set_amd64_more():
new = PsuedoEmulatedRegisterFile(amd64, 8)
new = PseudoEmulatedRegisterFile(amd64, 8)
# Unwritten value should return None
assert new.read_register("rbx") is None
@ -141,7 +141,7 @@ def test_emulated_register_set_amd64_more():
def test_emulated_register_set_amd64_invalidate():
new = PsuedoEmulatedRegisterFile(amd64, 8)
new = PseudoEmulatedRegisterFile(amd64, 8)
new.write_register("rax", -1)
@ -183,7 +183,7 @@ def test_emulated_register_set_amd64_invalidate():
def test_emulate_register_file_amd64_sign_extension():
new = PsuedoEmulatedRegisterFile(amd64, 8)
new = PseudoEmulatedRegisterFile(amd64, 8)
# This will sign extend the value to EAX, since the top bit in 0xFF is 1.
new.write_register("eax", 0xFF, source_width=1, sign_extend=True)
@ -204,7 +204,7 @@ def test_emulate_register_file_amd64_sign_extension():
def test_emulated_register_set_aarch64():
new = PsuedoEmulatedRegisterFile(aarch64, 8)
new = PseudoEmulatedRegisterFile(aarch64, 8)
new.write_register("w0", 0xFFFF_AABB)
@ -219,13 +219,13 @@ def test_emulated_register_set_aarch64():
def test_emulated_register_set_mips():
new = PsuedoEmulatedRegisterFile(mips, 4)
new = PseudoEmulatedRegisterFile(mips, 4)
new.write_register("v0", 0xFFFF_AABB)
assert new.read_register("v0") == 0xFFFF_AABB
new = PsuedoEmulatedRegisterFile(mips, 8)
new = PseudoEmulatedRegisterFile(mips, 8)
new.write_register("v0", 0xFF_FFFF_AABB)

Loading…
Cancel
Save