X64Dbg-命令详解
值
很多命令都接受表达式和值作为参数.下面是所有受支持的数值:
数字
默认情况下,所有数字都解释为16进制,也可以在值前加x或0x作为前缀来表明该数值为16进制.
如果想要该数字解释为10进制,可以在数字前面加一个点: .123 = 7B
变量
变量可以选择以$
开头,并且只能存储一个DWORD(在x64上为QWORD).这意味着myvar
和$myvar
是等同的.
寄存器
除浮点寄存器外的所有寄存器(如RAX、EAX、AL)都可以用作变量.
像XMM0、YMM0以及ST(0)这样的浮点寄存器不能用作变量使用,但它们可以通过字符串格式的浮点类型进行记录.目前不支持AVX-512寄存器.
- 除以下寄存器外,大多数寄存器的变量名称和它们的名称相同
- x86控制字标志被命名为_x87CW_UM
- 除架构中的寄存器外,x64Dbg还提供了以下寄存器:CAX、CBX、CCX、CDX、CSP、CBP、CSI、CDI、CIP.这些寄存器在32位平台上映射为32位寄存器,在64位平台上映射为64位寄存器
标志
调试标志可以作为输入,在标志名称前加_即为有效输入.示例如下:
|
|
内存位置
可以使用以下表达式对内存位置进行读取或写入.
语法 | 含义 |
---|---|
[addr] | 从addr指向的内存读取4或8字节内容 |
n:[addr] | 从addr指向的内存读取n字节内容 |
seg:[addr] | 从addr的段读取DWORD或QWORD大小内容 |
byte:[addr] | 从addr指向的内存读取1字节内容 |
word:[addr] | 从addr指向的内存读取2字节内容 |
dword:[addr] | 从addr指向的内存读取4字节内容 |
qword:[addr] | 从addr指向的内存读取8字节内容 |
- n是要读取的字节数,在x32上应小于4,在x64上应小于8,否则会出错
- seg可以是gs、es、cs、fs、ds以及ss.只有fs和gs有效
标签/符号
用户定义的标签和符号是一个有效的表达式(它们解析到所述标签/符号的地址).
DLL导出
从指定模块获取API地址可以使用module.dll:api、module:api或module:ordinal
|
|
- 当module为空字符串时,将默认为当前CPU窗口显示的模块
- 使用.或:是等价的
模块基地址
可以使用下述命令来获取模块的基地址.
|
|
RVA/文件偏移
- RVA->VA:module+rva或module:$rva
- FOA->VA:module:#offset
|
|
模块入口点
可以使用下述命令来获取模块的入口点.
|
|
表达式
调试器允许使用基本表达式.除了计算之外,还允许使用类C语法进行变量赋值.
运算符
- 圆括号/方括号:(1+2),[1+6]比其他运算有优先权
- 一元负号/二进制非/逻辑非:-1,~1,!1
- 乘法/除法:2*3,6/3,5%3
- 加法/减法:1+3,5+2
- 左/右移动/轮换:1«2,10»1,1«<2,1»>2
- 小于(等于)/大于(等于):4<10,3>6,1<=2,6>=7
- 等于/不等于:1==1,2!=6
- 二进制与:12&2
- 二进制异或:2^1
- 二进制或:2|8
- 逻辑与:0&&3
- 逻辑或:0||3
- 逻辑隐含:0->1
快速赋值
更改内存、变量、寄存器或标志.
- a?=b:?可以是任何非逻辑运算符.a可以是任何寄存器、标志、变量或内存位置.b可以是被确定为表达式的任何东西.
- a++/a–:a可以是任何寄存器、标志、变量或内存位置.
表达式函数
字符串
语法 | 含义 | 示例命令 | 结果 |
---|---|---|---|
ansi(addr[, count]) | 从addr打印以空字符结尾的ANSI字符串.当count指定时,字符串将被截断. | log “{ansi(0x402000,10)}” | Hello XiaLuoHun! |
utf8(addr[, count]) | 从addr打印以空字符结尾的UTF-8字符串.当count指定时,字符串将被截断. | log “{utf8(0x402000)}” | Hello XiaLuoHun! |
utf16(addr[, count]) | 从addr打印以空字符结尾的UTF-16字符串.当count指定时,字符串将被截断. | log “{utf16(0x405000,2)}” | He |
strstr(str1, str2) | 查找子字符串 | log “{strstr(utf8(0x402000),“Luo”)}” | 1 |
streq(str1, str2) | 比较两个字符串 | log “{streq(utf8(0x402000),“Luo”)}” | 0 |
strlen(str) | 计算字符串的长度 | log “{strlen(utf8(0x402000))}” | 10 |
模块
语法 | 含义 |
---|---|
mod.party(addr) | 获取addr的模块编号.0表示用户模块,1表示系统模块 |
mod.base(addr) | 获取addr模块基址 |
mod.size(addr) | 获取addr模块大小 |
mod.hash(addr) | 获取addr模块Hash |
mod.entry(addr) | 获取addr模块入口 |
mod.system(addr) | 判断addr是属于系统模块.若是返回1,否则返回0 |
mod.user(addr) | 判断addr是属于用户模块.若是返回1,否则返回0 |
mod.main() | 获取主模块基地址 |
mod.rva(addr) | 获取addr所属模块的RVA.若地址不在模块中,返回0 |
mod.offset(addr) | 获取addr的文件偏移量.若地址不在模块中,返回0 |
mod.isexport(addr) | 判断addr是否是模块导出函数.若是返回1 |
mod.fromname(str) | 获取str模块基址 |
进程信息
语法 | 含义 |
---|---|
peb() | 获取PEB地址 |
teb() | 获取TEB地址 |
tid() | 获取当前线程ID |
kusd(),KUSD(),KUSER_SHARED_DATA() | 获取KUSER_SHARED_DATA结构地址 |
常规函数
语法 | 含义 | 示例命令 | 结果 |
---|---|---|---|
bswap(value) | 反转字节 | log “{bswap(0x12345678)}” | 78563412 |
ternary(condition, val1, val2) | 如果条件为真, 返回val1,否则返回val2 | log “{ternary(0,1,2)}” | 2 |
GetTickCount() | 获取从操作系统启动所经过的毫秒数 | log “{GetTickCount()}” | 121A1D0 |
rdtsc() | 获取RDTSC指令结果,该指令返回CPU自启动以来的时钟周期数 | log “{rdtsc()}” | 5C51E17C |
isdebuggerfocused() | 判断是否聚焦x64dbg.若是返回1,否则返回0 | log “{isdebuggerfocused()}” | 1 |
isdebuggeefocused() | 判断是否聚焦调试程序.若是返回1,否则返回0 | log “{isdebuggeefocused()}” | 0 |
内存
语法 | 含义 |
---|---|
mem.valid(addr) | 判断addr是否有效.若是返回1,否则返回0 |
mem.base(addr) | 获取addr内存页的基地址 |
mem.size(addr) | 获取addr内存页的大小 |
mem.iscode(addr) | 判断addr是否是可执行页面.若是返回1,否则返回0 |
mem.decodepointer(ptr) | 调用了API DecodePointer |
反汇编
语法 | 含义 |
---|---|
dis.len(addr) | 获取addr指令长度 |
dis.iscond(addr) | 判断addr处是否为条件指令(JCC).若是返回1,否则返回0 |
dis.isbranch(addr) | 判断addr处是否为分支指令(JCC/CALL).同上 |
dis.isret(addr) | 判断addr处是否为RET指令.同上 |
dis.iscall(addr) | 判断addr处是否为CALL指令.同上 |
dis.ismem(addr) | 判断addr处指令是否有内存操作数.同上 |
dis.isnop(addr) | 判断addr处是为NOP指令.同上 |
dis.isunusual(addr) | 判断addr处是为异常指令.同上 |
dis.branchdest(addr) | 获取addr处的分支目标地址(即在addr处按下Enter键后的地址) |
dis.branchexec(addr) | 判断addr处分支是否执行.若是返回1,否则返回0 |
dis.imm(addr) | 获取addr处指令中的立即数 |
dis.brtrue(addr) | 获取addr处的分支目标地址 |
dis.brfalse(addr) | 如果addr处是条件跳转指令则返回下一条指令地址,否则返回0 |
dis.next(addr) | 获取addr处下一条指令地址 |
dis.prev(addr) | 获取addr处前一条指令地址 |
dis.iscallsystem(addr) | 判断addr处的指令是否进入系统模块.如是返回1,否则返回0 |
dis.mnemonic(addr) | 返回addr处指令的助记符(str).可以和字符串表达式函数配合使用,如str.streq(dis.mnemonic(cip), “cpuid”) |
dis.text(addr) | 获取addr处的指令文本 |
dis.match(addr, str) | 判断addr处指令是否匹配正则表达式str.如是返回1,否则返回0 |
跟踪
语法 | 含义 |
---|---|
tr.enabled(addr) | 判断addr是否启用了跟踪覆盖.如是返回1,否则返回0 |
tr.hitcount(addr) | 判断addr是否已被跟踪覆盖.同上 |
tr.isrecording(),tr.runtraceenabled() | 判断是否启用跟踪记录.同上 |
内存指针
语法 | 含义 |
---|---|
ReadByte(addr),Byte(addr),byte(addr) | 从addr读取1字节并返回 |
ReadWord(addr),Word(addr),word(addr) | 从addr读取2字节并返回 |
ReadDword(addr),Dword(addr),dword(addr) | 从addr读取4字节并返回 |
ReadQword(addr),Qword(addr),qword(addr) | 从addr读取8字节并返回(仅限x64) |
ReadPtr(addr),ReadPointer(addr),ptr(addr),Pointer(addr),pointer(addr) | 从addr读取一个指针(4/8字节)并返回 |
函数
语法 | 含义 |
---|---|
func.start(addr) | 获取addr所在的函数头地址 |
func.end(addr) | 获取addr所在的函数尾地址 |
引用
语法 | 含义 |
---|---|
ref.count() | 获取当前引用视图中的条目数 |
ref.addr(index) | 获取index引用的地址 |
参数
假设此时堆栈顶部为返回地址
语法 | 含义 |
---|---|
arg.get(index) | 获取第index参数(从0开始) |
arg.set(index, value) | 设置第index处的参数(从0开始) |
异常
语法 | 含义 |
---|---|
ex.firstchance() | 最后一个异常是否为首次偶发异常 |
ex.addr() | 最后一个异常地址.即导致异常的指令地址 |
ex.code() | 最后一个异常代码 |
ex.flags() | 最后一个异常标志 |
ex.infocount() | 最后一个异常信息计数(参数个数) |
ex.info(index) | 最后一个异常信息,如果索引超过范围则为0 |
插件
插件注册表达式示例- _plugin_registerexprfunction
- _plugin_registerexprfunctionex
- _plugin_unregisterexprfunction
变量
调试器支持以下三种类型的变量:
-
用户变量:用户通过var/mov创建变量
-
系统变量:由x64Dbg创建的变量,可读可写,但不能删除
-
只读变量:由x64Dbg创建的变量,可以读取,但不能写入和删除
设置变量
可以通过以下方式进行变量设置
|
|
保留变量
-
$res
/$result
:常规结果变量 -
$resN
/$resultN
:可选的其他结果变量(N=1-4) -
$pid
:被调试进程的PID -
$hp
/$hProcess
:被调试进程的handle -
$lastalloc
:alloc命令的最后结果 -
$breakpointcondition
:控制条件断点命中时的暂停行为 -
$breakpointcounter
:断点命中的次数 -
$breakpointlogcondition
:条件断点的日志条件.它不能用于控制日志记录行为
条件断点
当断点命中时,x64Dbg将执行下述操作.
- 将系统变量$breakpointexceptionaddress设置为触发断点的地址(内存地址)
- 将命中计数器增加1
- 将系统变量$breakpointcounter设置为命中计数器的值
- 如果设置了中断条件,计算表达式的值(默认为1)
- 如果设置了快速恢复且中断条件为0:
- 跳过接下来的步骤继续执行被调试对象,这也将跳过执行插件回调和GUI更新
- 如果设置了日志条件,计算表达式的值(默认为1)
- 如果设置了命令条件,计算表达式的值(默认为1)
- 如果中断条件求值结果为1(或非0值):
- 打印标准日志消息(如果断点设置为静默,则不支持标准日志消息)
- 执行插件回调
- 如果设置了日志文本且日志条件表达式求值结果为1(或非0值):
- 格式化并打印日志文本(参考字符串格式化)
- 如果设置了命令文本且命令条件表达式求值结果为1(或非0值):
- 将系统变量$breakpointcondition设置为中断条件
- 将系统变量$breakpointlogcondition设置为日志条件
- 执行命令文本
- 将中断条件设置为
$breakpointcondition
的值.因此,如果在脚本中修改$breakpointcondition
的值,你就能控制调试对象是否被中断
- 如果中断条件求值结果为1(或非0值):
- 中断调试对象并等待用户继续执行
如果上述条件表达式无效,则将触发该条件.(即无效的条件表达式作为条件将导致断点始终中断、打印日志以及执行命令)
在平时的调试过程中,命中计数器的值会无条件进行递增,可以调用下述API函数进行重置.
|
|
条件表达式示例如下:
|
|
条件跟踪
当跟踪命中时,x64Dbg将执行下述操作:
-
将跟踪计数器增加1
-
将系统变量$tracecounter设置为跟踪计数器的值
-
如果设置了中断条件,计算表达式的值(默认为0)
-
执行插件回调(允许插件更改终端条件)
-
如果设置了日志条件,计算表达式的值(默认为1)
-
如果设置了命令条件,计算表达式的值(默认为中断条件)
-
如果设置了日志文本且日志条件表达式求值结果为1:
- 格式化并打印日志文本(参考字符串格式化).要将日志重定向到文件,请使用TraceSetLogFile
-
如果设置了命令文本且命令表达式求值结果为1:
- 将系统变量$tracecondition设置为中断条件
- 将系统变量$tracelogcondition设置为日志条件
- 执行命令文本
- 将中断条件设置为
$tracecondition
的值.因此,如果在脚本中修改$tracecondition
的值,你就能控制调试对象是否被中断
-
如果中断条件求值为1:
- 打印标准日志条件
- 中断调试对象并等待用户继续执行
如果想要通过日志跟踪记录所有指令的地址和汇编,可以使用下述命令
|
|
字符串格式
基本语法如下:
|
|
简单类型如下:
类型 | 含义 | 示例命令 | 结果 |
---|---|---|---|
d | 有符号十进制 | log “{d:FFFFFFFF}” | -1 |
u | 无符号十进制 | log “{u:FFFFFFFF}” | 4294967295 |
p | 零前缀指针 | log “{p:0x401000}” | 00401000 |
s | 字符串指针 | log “{s:0x402000}” | “Hello XiaLuoHun!” |
x | 十六进制 | log “{x:0x10}” | 10 |
a | 地址信息 | log “{a:0x401000}” | x32dbg.00401000 |
i | 输出汇编指令 | log “{i:0x405102}” | call 0x0040B122 |
f | 单精度浮点指针或寄存器 | log “{f:0x401000}” | 9.86338 |
F | 双精度浮点指针或寄存器 | log “{F:0x401000}” | 3.72778552425271e-095 |
复杂类型如下:
语法 | 含义 | 示例命令 | 结果 |
---|---|---|---|
{mem;size@address} | 从address开始打印size个字节 | log “{mem;2@0x400108}” | 504A |
{winerror@code} | 输出Windows错误码名称以及描述 | log “{winerror@0x5}” | ERROR_ACCESS_DENIED:拒绝访问. |
{ntstatus@code} | 输出NTSTATUS错误码名称以及描述 | log “{ntstatus@0}” | STATUS_SUCCESS:STATUS_SUCCESS |
{ascii[;length]@address} | 以ascii编码进行解析,从address开始打印length个字节 | log “{ascii;10@0x00402000}” | Hello XiaLuoHun! |
{ansi[;length]@address} | 以ansi编码进行解析,从address开始打印length个字节 | log “{ansi;c@0x00402000}” | Hello XiaLuo |
{utf8[;length]@address} | 以utf8编码进行解析,从address开始打印length个字节 | log “{utf8;10@0x00402000}” | Hello XiaLuoHun! |
{utf16[;length]@address} | 以utf16编码进行解析,从address开始打印length个双字节 | log “{utf16;2@0x00405000}” | He |
{disasm@address} | 输出address处的汇编,同{i:address} | log “{disasm@0x405102}” | call 0x0040B122 |
{modname@address} | 输出address所属的模块名 | log “{modname@0x401000}” | x32dbg.exe |
log “{bswap[;size]@value}” | 从value的低位开始倒数打印size个字节 | log “{bswap;1@0x12345678}” | 78 |
{label@address} | 输出address处的标签 | log “{label@0x405102}” | OptionalHeader.AddressOfEntryPoint |
{comment@address} | 输出address处的注释 | log “{comment@0x405107}” | XiaLuoHun |