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位寄存器

标志

调试标志可以作为输入,在标志名称前加_即为有效输入.示例如下:

1
_cf、_pf、_af、_zf、_sf、_tf、_if、_df、_of、_rf、_vm _ac、_vif、_vip以及_id

内存位置

可以使用以下表达式对内存位置进行读取或写入.

语法 含义
[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

1
2
3
4
5
ntdll.dll:ZwContinue
ntdll:memcmp
ntdll.memcmp
ntdll:1D
:LuoExport
注意
  • 当module为空字符串时,将默认为当前CPU窗口显示的模块
  • 使用.或:是等价的

模块基地址

可以使用下述命令来获取模块的基地址.

1
module、module:0、module:base、module:imagebase、module:header

RVA/文件偏移

  • RVA->VA:module+rva或module:$rva
  • FOA->VA:module:#offset
1
2
3
4
5
6
7
//RVA->VA
ntdll.dll:$1000
:$1000

//FOA->VA
ntdll.dll:#400
:#400
注意
当module为空字符串时(如:$1000),默认为当前CPU窗口显示的模块

模块入口点

可以使用下述命令来获取模块的入口点.

1
module:entry、module:oep、module:ep
注意
当模块中有名为entry、oep或ep时,将返回这个导出函数的地址.

表达式

调试器允许使用基本表达式.除了计算之外,还允许使用类C语法进行变量赋值.

运算符

  1. 圆括号/方括号:(1+2),[1+6]比其他运算有优先权
  2. 一元负号/二进制非/逻辑非:-1,~1,!1
  3. 乘法/除法:2*3,6/3,5%3
  4. 加法/减法:1+3,5+2
  5. 左/右移动/轮换:1«2,10»1,1«<2,1»>2
  6. 小于(等于)/大于(等于):4<10,3>6,1<=2,6>=7
  7. 等于/不等于:1==1,2!=6
  8. 二进制与:12&2
  9. 二进制异或:2^1
  10. 二进制或:2|8
  11. 逻辑与:0&&3
  12. 逻辑或:0||3
  13. 逻辑隐含: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创建的变量,可以读取,但不能写入和删除

设置变量

可以通过以下方式进行变量设置

1
2
3
4
mov myvar, 1234
mov $myvar, 1234
myvar = 1234
$myvar = 1234

保留变量

  • $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函数进行重置.

1
2
//对addr处命中计数器的值进行重置.若hitCount未指定,默认为0
ResetBreakpointHitCount(addr,hitCount) 

条件表达式示例如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//永不中断的条件断点
0

//当EAX和ECX都为1时中断
EAX==1&&ECX==1

//当第一个参数为1时中断
arg.get(0)==1

//当EAX是一个有效地址时中断
mem.valid(EAX)

//当命中计算器的值为3时中断
$breakpointcounter==3

//当线程ID为0x1C0时中断
tid()==1C0

//当ECX指向一个包含LuoHun的UTF-16字符串时中断
strstr(utf16(ECX), "LuoHun")

条件跟踪

当跟踪命中时,x64Dbg将执行下述操作:

  • 将跟踪计数器增加1

  • 将系统变量$tracecounter设置为跟踪计数器的值

  • 如果设置了中断条件,计算表达式的值(默认为0)

  • 执行插件回调(允许插件更改终端条件)

  • 如果设置了日志条件,计算表达式的值(默认为1)

  • 如果设置了命令条件,计算表达式的值(默认为中断条件)

  • 如果设置了日志文本且日志条件表达式求值结果为1:

    • 格式化并打印日志文本(参考字符串格式化).要将日志重定向到文件,请使用TraceSetLogFile
  • 如果设置了命令文本且命令表达式求值结果为1:

    • 将系统变量$tracecondition设置为中断条件
    • 将系统变量$tracelogcondition设置为日志条件
    • 执行命令文本
    • 将中断条件设置为$tracecondition的值.因此,如果在脚本中修改$tracecondition的值,你就能控制调试对象是否被中断
  • 如果中断条件求值为1:

    • 打印标准日志条件
    • 中断调试对象并等待用户继续执行

如果想要通过日志跟踪记录所有指令的地址和汇编,可以使用下述命令

1
{p:cip} {i:cip}
注意
当使用跟踪步过时,即使条件为真,被调试对象也不会在已跳过的调用中暂停.如果需要暂停应使用跟踪步进

字符串格式

基本语法如下:

1
2
3
//?是表达式可选的类型
//若要在结果中输出{ 或 },可将它们转义为{{ 或 }}
{?:expression}

简单类型如下:

类型 含义 示例命令 结果
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

参考链接

x64Dbg帮助文档


相关内容

0%