Registers and Expressions
What is an Expression?
An expression is a statement evaluated in the context of the debugger. It can be as simple as 2+2, or a complex calculation involving symbols, scales, and segments. x64dbg Automate provides the debugger's full evaluation capabilities, and adds some convenience methods.
When you request a register in x64dbg Automate it's really just shorthand for evaluating an expression where the only value is your register. This is true unless a full register dump is requested. This is the exception to the above rule - instead providing a full thread context dump in the format the debugger uses internally.
The full register dump can be useful for accessing more nuanced parts of thread state, but is generally overkill for common tasks like retrieving a common register value.
Example: Expressions and Registers
"""
Example: Expressions and Registers (64 bit)
"""
import sys
from x64dbg_automate import X64DbgClient
from x64dbg_automate.models import RegDump64
if len(sys.argv) != 2:
print("Usage: python hello64.py <x64dbg_path>")
quit(1)
print('[+] Creating a new x64dbg Automate session')
client = X64DbgClient(x64dbg_path=sys.argv[1])
client.start_session(r'c:\Windows\system32\winver.exe')
print('[+] Getting the value of RIP')
rip = client.get_reg('rip')
print(f'\tRIP: 0x{rip:X}')
print('[+] Setting the value of RIP')
client.set_reg('rip', 0x1234)
print('[+] Setting the value of RIP to an expression')
value, _ = client.eval_sync('LoadLibraryA + 0x20')
client.set_reg('rip', value)
print('[+] Setting the value of a subregister')
client.set_reg('rax', 0)
client.set_reg('ah', 0x99)
print('[+] Performing a full register dump')
dump: RegDump64 = client.get_regs()
print(f'\tRIP: 0x{dump.context.rip:X}')
print(f'\tRAX: 0x{dump.context.rax:X}')
print('[+] Cleaning up')
client.terminate_session()
[+] Creating a new x64dbg Automate session
[+] Getting the value of RIP
RIP: 0x7FFC97E6142A
[+] Setting the value of RIP
[+] Setting the value of RIP to an expression
[+] Setting the value of a subregister
[+] Performing a full register dump
RIP: 0x7FFC973C2DA0
RAX: 0x9900
[+] Cleaning up
API Method Reference
get_reg(reg)
Get a single register or subregister
Parameters:
Name | Type | Description | Default |
---|---|---|---|
reg
|
MutableRegister | str
|
Register to get |
required |
Returns:
Type | Description |
---|---|
int
|
Success |
Source code in x64dbg_automate/hla_xauto.py
def get_reg(self, reg: MutableRegister | str) -> int:
"""
Get a single register or subregister
Args:
reg: Register to get
Returns:
Success
"""
reg = MutableRegister(str(reg).lower())
res, success = self.eval_sync(f'{reg}')
if not success:
raise ValueError(f"Failed to evaluate register {reg}")
return res
get_regs()
Dump the registers of the debugee
Returns:
Type | Description |
---|---|
list[RegDump32] | list[RegDump64]
|
A list of RegDump objects |
Source code in x64dbg_automate/commands_xauto.py
def get_regs(self) -> list[RegDump32] | list[RegDump64]:
"""
Dump the registers of the debugee
Returns:
A list of RegDump objects
"""
raw_regs = self._send_request(XAutoCommand.XAUTO_REQ_DBG_READ_REGISTERS)
bitness = raw_regs[0]
raw_regs = raw_regs[1:]
if bitness == 64:
ctx = {k: v for k, v in zip(Context64.model_fields.keys(), raw_regs[0])}
ctx['x87_fpu'] = X87Fpu(**{k: v for k, v in zip(X87Fpu.model_fields.keys(), ctx['x87_fpu'])})
ctx['xmm_regs'] = [ctx['xmm_regs'][i:i+16] for i in range(0, len(ctx['xmm_regs']), 16)]
ctx['ymm_regs'] = [ctx['ymm_regs'][i:i+32] for i in range(0, len(ctx['ymm_regs']), 32)]
return RegDump64(
context=Context64(**ctx),
flags=Flags(**{k: v for k, v in zip(Flags.model_fields.keys(), raw_regs[1])}),
fpu=[FpuReg(data=raw_regs[2][i][0], st_value=raw_regs[2][i][1], tag=raw_regs[2][i][2]) for i in range(len(raw_regs[2]))],
mmx=raw_regs[3],
mxcsr_fields=MxcsrFields(**{k: v for k, v in zip(MxcsrFields.model_fields.keys(), raw_regs[4])}),
x87_status_word_fields=X87StatusWordFields(**{k: v for k, v in zip(X87StatusWordFields.model_fields.keys(), raw_regs[5])}),
x87_control_word_fields=X87ControlWordFields(**{k: v for k, v in zip(X87ControlWordFields.model_fields.keys(), raw_regs[6])}),
last_error=(raw_regs[7][0], raw_regs[7][1].decode().strip('\0')),
last_status=(raw_regs[8][0], raw_regs[8][1].decode().strip('\0'))
)
else:
ctx = {k: v for k, v in zip(Context32.model_fields.keys(), raw_regs[0])}
ctx['x87_fpu'] = X87Fpu(**{k: v for k, v in zip(X87Fpu.model_fields.keys(), ctx['x87_fpu'])})
ctx['xmm_regs'] = [ctx['xmm_regs'][i:i+16] for i in range(0, len(ctx['xmm_regs']), 16)]
ctx['ymm_regs'] = [ctx['ymm_regs'][i:i+32] for i in range(0, len(ctx['ymm_regs']), 32)]
return RegDump32(
context=Context32(**ctx),
flags=Flags(**{k: v for k, v in zip(Flags.model_fields.keys(), raw_regs[1])}),
fpu=[FpuReg(data=raw_regs[2][i][0], st_value=raw_regs[2][i][1], tag=raw_regs[2][i][2]) for i in range(len(raw_regs[2]))],
mmx=raw_regs[3],
mxcsr_fields=MxcsrFields(**{k: v for k, v in zip(MxcsrFields.model_fields.keys(), raw_regs[4])}),
x87_status_word_fields=X87StatusWordFields(**{k: v for k, v in zip(X87StatusWordFields.model_fields.keys(), raw_regs[5])}),
x87_control_word_fields=X87ControlWordFields(**{k: v for k, v in zip(X87ControlWordFields.model_fields.keys(), raw_regs[6])}),
last_error=(raw_regs[7][0], raw_regs[7][1]),
last_status=(raw_regs[8][0], raw_regs[8][1])
)
set_reg(reg, val)
Set a single register or subregister to a value
Parameters:
Name | Type | Description | Default |
---|---|---|---|
reg
|
MutableRegister | str
|
Register to set |
required |
val
|
int
|
Value to set |
required |
Returns:
Type | Description |
---|---|
bool
|
Success |
Source code in x64dbg_automate/hla_xauto.py
def set_reg(self, reg: MutableRegister | str, val: int) -> bool:
"""
Set a single register or subregister to a value
Args:
reg: Register to set
val: Value to set
Returns:
Success
"""
reg = MutableRegister(str(reg).lower())
if not isinstance(val, int):
raise TypeError("val must be an integer")
return self.cmd_sync(f'{reg}=0x{val:X}')
eval_sync(eval_str)
Evaluates an expression that results in a numerical output
Returns:
Type | Description |
---|---|
list[int, bool]
|
A list containing the result and a boolean indicating success |
Source code in x64dbg_automate/commands_xauto.py
def eval_sync(self, eval_str) -> list[int, bool]:
"""
Evaluates an expression that results in a numerical output
Returns:
A list containing the result and a boolean indicating success
"""
return self._send_request(XAutoCommand.XAUTO_REQ_DBG_EVAL, eval_str)
get_symbol_at(addr)
Retrieves the symbol at the specified address
Parameters:
Name | Type | Description | Default |
---|---|---|---|
addr
|
int
|
The address to get the symbol for |
required |
Returns:
Type | Description |
---|---|
Symbol | None
|
A Symbol object or None if no symbol was found |
Source code in x64dbg_automate/commands_xauto.py
def get_symbol_at(self, addr: int) -> Symbol | None:
"""
Retrieves the symbol at the specified address
Args:
addr: The address to get the symbol for
Returns:
A Symbol object or None if no symbol was found
"""
res = self._send_request(XAutoCommand.XAUTO_REQ_GET_SYMBOL, addr)
if not res[0]:
return ""
return Symbol(
addr=res[1],
decoratedSymbol=res[2],
undecoratedSymbol=res[3],
type=SymbolType(res[4]),
ordinal=res[5]
)
API Model Reference
RegDump
Bases: BaseModel
Source code in x64dbg_automate/models.py
class RegDump(BaseModel):
flags: Flags
fpu: list[FpuReg]
mmx: list[int]
mxcsr_fields: MxcsrFields
x87_status_word_fields: X87StatusWordFields
x87_control_word_fields: X87ControlWordFields
last_error: tuple[int, str]
last_status: tuple[int, str]
RegDump64
Bases: RegDump
Source code in x64dbg_automate/models.py
class RegDump64(RegDump):
context: Context64
RegDump32
Bases: RegDump
Source code in x64dbg_automate/models.py
class RegDump32(RegDump):
context: Context32
Context64
Bases: BaseModel
Source code in x64dbg_automate/models.py
class Context64(BaseModel):
rax: int
rbx: int
rcx: int
rdx: int
rbp: int
rsp: int
rsi: int
rdi: int
r8: int
r9: int
r10: int
r11: int
r12: int
r13: int
r14: int
r15: int
rip: int
eflags: int
cs: int
ds: int
es: int
fs: int
gs: int
ss: int
dr0: int
dr1: int
dr2: int
dr3: int
dr6: int
dr7: int
reg_area: bytes
x87_fpu: X87Fpu
mxcsr: int
xmm_regs: list[bytes]
ymm_regs: list[bytes]
Context32
Bases: BaseModel
Source code in x64dbg_automate/models.py
class Context32(BaseModel):
eax: int
ebx: int
ecx: int
edx: int
ebp: int
esp: int
esi: int
edi: int
eip: int
eflags: int
cs: int
ds: int
es: int
fs: int
gs: int
ss: int
dr0: int
dr1: int
dr2: int
dr3: int
dr6: int
dr7: int
reg_area: bytes
x87_fpu: X87Fpu
mxcsr: int
xmm_regs: list[bytes]
ymm_regs: list[bytes]
X87Fpu
Bases: BaseModel
Source code in x64dbg_automate/models.py
class X87Fpu(BaseModel):
ControlWord: int
StatusWord: int
TagWord: int
ErrorOffset: int
ErrorSelector: int
DataOffset: int
DataSelector: int
Cr0NpxState: int
Flags
Bases: BaseModel
Source code in x64dbg_automate/models.py
class Flags(BaseModel):
c: bool
p: bool
a: bool
z: bool
s: bool
t: bool
i: bool
d: bool
o: bool
FpuReg
Bases: BaseModel
Source code in x64dbg_automate/models.py
class FpuReg(BaseModel):
data: bytes
st_value: int
tag: int
MxcsrFields
Bases: BaseModel
Source code in x64dbg_automate/models.py
class MxcsrFields(BaseModel):
FZ: bool
PM: bool
UM: bool
OM: bool
ZM: bool
IM: bool
DM: bool
DAZ: bool
PE: bool
UE: bool
OE: bool
ZE: bool
DE: bool
IE: bool
RC: int
X87StatusWordFields
Bases: BaseModel
Source code in x64dbg_automate/models.py
class X87StatusWordFields(BaseModel):
B: bool
C3: bool
C2: bool
C1: bool
C0: bool
ES: bool
SF: bool
P: bool
U: bool
O: bool
Z: bool
D: bool
I: bool
TOP: int
X87ControlWordFields
Bases: BaseModel
Source code in x64dbg_automate/models.py
class X87ControlWordFields(BaseModel):
IC: bool
IEM: bool
PM: bool
UM: bool
OM: bool
ZM: bool
DM: bool
IM: bool
RC: int
PC: int
Symbol
Bases: BaseModel
Source code in x64dbg_automate/models.py
class Symbol(BaseModel):
addr: int
decoratedSymbol: str
undecoratedSymbol: str
type: int
ordinal: int
SymbolType
Bases: IntEnum
Source code in x64dbg_automate/models.py
class SymbolType(IntEnum):
SymImport = 0
SymExport = 1
SymSymbol = 2
MutableRegister
Bases: StrEnum
Source code in x64dbg_automate/models.py
class MutableRegister(StrEnum):
cip = 'cip'
rax = 'rax'
rbx = 'rbx'
rcx = 'rcx'
rdx = 'rdx'
rbp = 'rbp'
rsp = 'rsp'
rsi = 'rsi'
rdi = 'rdi'
r8 = 'r8'
r9 = 'r9'
r10 = 'r10'
r11 = 'r11'
r12 = 'r12'
r13 = 'r13'
r14 = 'r14'
r15 = 'r15'
rip = 'rip'
eip = 'eip'
eflags = 'eflags'
rflags = 'rflags'
cs = 'cs'
ds = 'ds'
es = 'es'
fs = 'fs'
gs = 'gs'
ss = 'ss'
dr0 = 'dr0'
dr1 = 'dr1'
dr2 = 'dr2'
dr3 = 'dr3'
dr6 = 'dr6'
dr7 = 'dr7'
eax = 'eax'
ebx = 'ebx'
ecx = 'ecx'
edx = 'edx'
ebp = 'ebp'
esp = 'esp'
esi = 'esi'
edi = 'edi'
ax = 'ax'
bx = 'bx'
cx = 'cx'
dx = 'dx'
si = 'si'
di = 'di'
bp = 'bp'
sp = 'sp'
al = 'al'
bl = 'bl'
cl = 'cl'
dl = 'dl'
ah = 'ah'
bh = 'bh'
ch = 'ch'
dh = 'dh'
sil = 'sil'
dil = 'dil'
bpl = 'bpl'
spl = 'spl'
r8d = 'r8d'
r9d = 'r9d'
r10d = 'r10d'
r11d = 'r11d'
r12d = 'r12d'
r13d = 'r13d'
r14d = 'r14d'
r15d = 'r15d'
r8w = 'r8w'
r9w = 'r9w'
r10w = 'r10w'
r11w = 'r11w'
r12w = 'r12w'
r13w = 'r13w'
r14w = 'r14w'
r15w = 'r15w'
r8b = 'r8b'
r9b = 'r9b'
r10b = 'r10b'
r11b = 'r11b'
r12b = 'r12b'
r13b = 'r13b'
r14b = 'r14b'
r15b = 'r15b'