白乐天

道阻且长,行则将至。

IDA使用指南

界面

工具栏(Toolbars)

工具栏包含常用操作工具。
可在View->Toobars里显示或隐藏工具栏。

导航栏

导航栏是被加载⽂件地址空间的线性视图。

菜单栏

Edit

保存patch文件

Edit->Patch Program->Apply patches to input file

Options

在文本模式下显示机器指令:

在菜单栏找到Options->General,有一个选项Number of opcode bytes即操作码字节数,根据汇编指令长度来设置,如Arm指令长度是4字节,Thumb指令长度是2字节。

重新分析程序

在菜单栏找到Options->General->Analysis

点击如下选项重新分析程序

在IDA底部边框右键也会出现Reanalyze program选项

窗口

反汇编窗口(IDA-View)

反汇编窗口有两种显示模式,文本模式和图形模式,通过空格键来切换。

  • 文本模式
    显示指令地址、机器码。
  • 图形模式
    观察控制流。
    可通过Ctrl+鼠标滚轮进行缩放。

在文本模式下显示机器指令:

伪代码窗口(Pseudocode)

  • 将反汇编代码转换为伪代码,按下Tab键F5
  • 将伪代码转换为反汇编代码,按下Tab键
  • 在伪代码中根据光标位置按下Tab键可以快速定位到对应语句的汇编代码。

函数窗口(Functions)

显示了当前分析的二进制文件中被识别的所有函数。

输出窗口(Output)

显⽰的是 IDA 输出的信息。

  • Ctrl+X:这个快捷键在output窗口中的作用是清空当前窗口的内容。

字符串表(Strings)

字符串表会显示IDA所识别出的字符串。

  • 打开字符串表窗口的快捷键Shift+F12
  • 在菜单中打开 View->Open Subviews->Strings
  • 双击字符串会跳转到字符串所在的数据窗口的位置或反汇编窗口的位置(取决于上一步打开的窗口)。

数据窗口(Hex View)

以hexdump形式显示程序的数据。

  • 菜单中的位置 View->Open subviews->Hex dump
  • 通过F2可以进入编辑模式修改数据,再次按下F2退出编辑模式。

交叉引用(XREF)

交叉引用(XREF,Cross Reference)是一个非常重要的工具,用于追踪某个地址、变量或函数在程序中的使用情况。它可以帮助我们快速找到某个符号、数据或函数是如何以及在何处被引用的。

  • 将光标定位到要进行交叉引用的符号,按下x键打开交叉引用的窗口。

交叉引用分类

  • 代码交叉引用
  • 数据交叉引用

Xref Graph

函数调用关系及引用流向

Xref graph to

  • 显示当前函数或地址 “被哪些位置调用或引用” 的关系图。
  • 用于追踪调用者(Callers),即谁调用了当前函数或谁引用了该地址。

使用方式
选中一个函数或地址后,右键在菜单中选择Xrefs graph to...

Xref graph from

  • 显示当前函数或地址 “调用或引用了哪些目标” 的关系图。
  • 用于追踪被调用者(Callees),即当前函数或代码引用了哪些其他函数或地址。

使用方式
选中一个函数或地址后,右键在菜单中选择 Xrefs graph from...

常用快捷键

常用操作

  • F5:生成伪代码,刷新伪代码
  • ESC:后退,回到上一步操作的视图

窗口打开

  • x:交叉引用窗口
  • Shift + f12:字符串窗口
  • alt + T:文本搜索窗口(速度慢)
  • G:地址跳转窗口
  • Alt + I:快速查找二进制文件中与某个特定值相关的指令或数据
  • Alt + B:直接在二进制文件中查找特定的字节序列
  • Ctrl+S:打开Segments窗口
  • Shift+F7:打开Segments窗口

代码转换

  • N:修改变量名
  • Y:修改变量的类型
  • Shift + Del: 删除返回值
  • \ :隐藏与显示casts(类型)
  • - :代码折叠(Collapse declarations)
  • + :代码展开(Collapse declarations)
  • / :行注释
  • Ctrl+Alt+num:Lock highlight,添加高亮标记(注意:num是一个数字)

数据转换

  • A:把数据转换为"\0"结尾的字符串

  • U:取消定义(Undefine)
    可取消函数、代码或数据的定义。取消定义后,其基础字节将作为原始字节值重新格式化。

  • C:反汇编一组未定义的字节

  • D:将代码转换为数据

    整数的数据类型

    1
    2
    3
    4
    db // 1字节
    dw // 2字节
    dd // 4字节
    dq // 8字节
  • P:在代码数据起始位置,按下P键,识别函数(注意光标需要位于起始位置)。

  • H:在十进制数据和十六进制数据之间切换

  • R:将数据切换为char类型

动态调试

调试器

配置调试信息

调试器选择完毕,打开Debugger菜单,选择Process options
配置调试器在加载目标程序时的运行参数和环境

  • Application:指定要调试的目标程序路径
  • Input file:指定程序运行时需要的输入文件路径
  • Parameters:为目标程序提供运行时的命令行参数。
  • HostnamePort:填写主机名和端口

Win本地调试

本地调试无需配置server文件。

远程调试

在IDA的安装目录下,有一个dbgsrv文件夹,里面是各个系统架构的远程调试server文件。

Linux

把linux_server拷贝到Linux主机上,添加可执行权限,然后启动

Android

把android_server远程调试文件push到手机上的/data/local/tmp目录下,改名字为as

  • 添加可执行权限

    1
    chmod +x as
  • 启动as

    1
    ./as -p 1234  //-p选项用于设置端口

  • 端口转发

    1
    adb forward tcp:1234 tcp:1234

调试模式

Start Process

Start Process 是指直接从 IDA 中启动一个可执行文件(如 .exe 程序)进行调试。IDA 会加载目标文件,并启动一个新的调试会话。

Attach to Process

Attach to Process 是指将调试器附加到一个已经运行的进程。IDA 不会启动新的程序,而是连接到当前运行中的目标进程,实时分析其运行状态。

调试窗口

General registers窗口(寄存器)

  寄存器内容在相关寄存器右边显示,后面显示对每个寄存器的说明,最右边的列中显示CPU标志位。

  • 鼠标右键单击一个寄存器或标志位,会出现一个modify选项,可以更改寄存器或CPU标志位的值。
  • 如果一个寄存器指向一个有效的地址,那么该寄存器值右侧会出现一个直角箭头并有突出显示,单击箭头,会跳转到相应的内存位置。

Modules窗口(模块)

Modules窗⼝显⽰所有加载到进程内存空间中的可执⾏⽂件和动态链接库。

  • 双击任何模块名称,将打开该模块导出的符号列表,双击符号,进行跳转。

Threads窗口(线程)

Threads 窗口会列出当前进程中所有活动的线程,并显示每个线程的详细信息。

Stack view窗口(堆栈)

显示当前线程调用堆栈的内容,用于观察函数调用之间的堆栈数据变化。

快捷键

  • F2:设置断点
  • F7:步入
  • F8:步过
  • F9:启动调试,及运行至下一断点
  • Ctrl+F7:指定到当前函数的返回后位置
  • F4:运行至光标处
  • Ctrl+N:set IP,可以直接修改程序的执行路径。强制代码从光标位置开始执行

硬件断点

  硬件断点用于在调试过程中实时监控内存区域的访问,硬件断点不会修改目标程序的代码,而是通过硬件的调试功能直接监控特定的内存地址或代码区域。

设置硬件断点

先设置普通断点,右键选择Breakpoint settints,勾选Hardware,选择硬件断点模式,勾选Execute

硬件断点模式

  • Read:断点地址被读取时命中
  • Write:断点地址被写入时命中
  • Execute:断点地址被执行时命中
  • Size:地址范围的大小

内存断点

  内存断点(也称为 memory breakpoint 或数据断点)是用于监控特定内存区域访问的工具。它可以捕获对目标内存地址的 读取写入执行 操作。

设置内存断点

设置普通断点,右键选择Breakpoint settints,勾选Hardware,选择硬件断点模式,勾选ReadWrite

API 断点

  API 断点是设置在目标程序调用的 API 函数入口或关键位置的断点,目的是拦截程序调用该函数时的执行流程。

设置API断点

设置方式与设置普通断点一致。

IDA-Trace

Trace

用于记录程序在运行过程中执行的指令、访问的内存、调用的函数或其他关键事件。

启用trace

启动动态调试之后进行trace

打开Debugger->Tracing->Tracing Options,配置trace选项。

选择trace方式

  • Instruction tracing:跟踪指令执行。
  • Function tracing:跟踪函数调用。
  • Basic block tracing:跟踪基本块。

打开Tracing window,可查看trace到的内容。

IDA插件

LazyIDA.py

https://github.com/P4nda0s/LazyIDA

提取数据

  • 将数据转换为python/C的数组形式
  • 选中数据后,右键,选择Convert,然后选择相应的格式。(注意:这里选中的地址要包含所需地址范围的下一地址)

Paste Data

插件修改数据,光标定位到数据窗口中要修改的数据的位置,右键,选择Paste Data,然后输入要修改的内容。

dump内存

将光标定位到需要dump的数据的起始地址,右键,选择Lazy Dumper

Keypatch

GitHub - keystone-engine/keypatch: Multi-architecture assembler for IDA Pro. Powered by Keystone Engine.

安装python库

1
2
pip install keystone-engine
pip install six

Patcher

在 IDA 反汇编视图中,跳转到需要修改的地址->右键在Keypatch子目录下选择合适的选项

IDA脚本编程

脚本智能提示,自动补全

在环境变量里添加IDAPYTHONPATH,值为IDA的python目录的完整路径

添加到环境变量

另一种方式

在vscode的settings(json)中把本地IDA Python库的位置添加进去例如我的是 E:\IDA9.0\python, 则settings中添加的项为:

1
2
"python.autoComplete.extraPaths": ["E:\\IDA9.0\\python"],
"python.analysis.extraPaths": ["E:\\IDA9.0\\python"],

然后导入ida相关的包就可以自动补全了

参考文章:VSCode IDAPython 开发环境配置 – itewqq’s blog

IDA Python

寄存器

1
2
idc.get_reg_value('rax')
idaapi.set_reg_val("rax",1234)

调试内存

1
2
3
4
5
idc.read_dbg_byte(addr)
idc.read_dbg_dword(addr)
idc.read_dbg_qword(addr)
idc.read_dbg_memory(addr, size)
idc.patch_dbg_byte(addr, val) # 只能单字节patch,可对这个api进行封装

封装idc.patch_dbg_byte(addr, val)

1
2
3
4
5
6
7
8
9
10
11
def patch_dbg_mem(addr, data):
for i in range(len(data)):
idc.patch_dbg_byte(addr + i, data[i])



def read_dbg_mem(addr, size):
dd = []
for i in range(size):
dd.append(idc.read_dbg_byte(addr + i))
return bytes(dd)

本地内存

1
2
3
4
5
6
7
idc.get_qword(addr)
idc.patch_qword(addr, val)
idc.patch_dword(addr, val)
idc.patch_word(addr, val)
idc.patch_byte(addr, val)
idc.get_db_byte(addr)
idc.get_bytes(addr, size)

反汇编

1
2
GetDisasm(addr) # 获取反汇编文本
idc.next_head(ea) # 获取下一条指令地址

交叉引用

1
2
for ref in idautils.XrefsTo(ea):
print(hex(ref.frm)) # frm是交叉引用的来源地址

其他常用接口

1
2
3
4
5
idc.add_bpt(addr) # 添加断点
idaapi.get_imagebase() # 获取基地址
idc.create_insn(addr) # C, Make Code
ida_funcs.add_func(addr) # P , create function
ida_bytes.create_strlit(addr) # 创建字符串,A键效果

函数遍历

1
2
for func in idautils.Functions():
print("0x%x,%s" % (func,idc.get_func_name(func)))

基本块的遍历

1
2
3
4
fn = addr
f_blocks = idaapi.FlowChart(idaapi.get_func(fn), flags = idaapi.FC_PREDS)
for block in f_blocks:
print hex(block.start_ea)

基本块的前驱

1
2
for pred in block.preds():
print hex(pred.start_ea)

基本块的后继

1
2
for succ in block.succs():
print hex(succ.start_ea)

指令遍历

1
2
for ins in idautils.FuncItems(addr):
print(hex(ins))