IDA Pro 使用

常用快捷键

  • G : 跳转地址

  • Esc:往回跳转

  • X/Ctrl+X: 查看谁调用了当前选中的函数、变量

  • 书签

  - Alt+M: 添加书签

  - Ctrl+M: 查看书签

  • Alt+T:搜索内容

  • Ctrl+T:继续查找下一个

  • Ctrl+L:跳转到指定名称处

  • Tab,F5:反汇编

  • 空格:切换视图(文本视图,图形视图)

注释,变量名

  • 冒号:单行注释

  • 封号:基本等同于常规注释,但有一个小区别:它们会在任何引用原始注释位置的地方重复出现。

  • insert:行前注释

  • N:增加、修改变量名

数据转换

  • Edit->operand type

  • Q: 十六进制

  • H:十进制

  • R: 字符

  • A:普通字符串

  • Alt+D: 选择 Q word 或者 TByte

  • Alt+A:字符串(C 或者 pascal 格式)

  • 选中,按 C,标记为 code

  • 选中,按 U,取消

偏移(Offset)

  • O,Ctrl+O:改为偏移 label

  • Ctrl+R:相对偏移

  • M:改为符号常量

新建结构体

  • shift+f1,按 insert,新建 C 语言结构体,双击后修改各个 element 的数据格式(sync, yes)

  - H:十进制

  - Q:十六进制

  - A:字符串

  • T:把偏移改为结构体

  • Alt+Q:修改数据类型为结构体类型

数组

  • 星号,新建数组

  • Alt+L,批量选择(选择后,再按星号,改为数组)

函数

  • P:创建函数

  • Y:修改函数 header

插件

IDA 常见命名意义

IDA 经常会自动生成假名字。他们用于表示子函数,程序地址和数据。根据不同的类型和值假名字有不同前缀

sub * 指令和子函数起点

locret* 返回指令

loc * 指令

off* 数据,包含偏移量

seg * 数据,包含段地址值

asc* 数据,ASCII 字符串

byte * 数据,字节(或字节数组)

word* 数据,16 位数据(或字数组)

dword * 数据,32 位数据(或双字数组)

qword* 数据,64 位数据(或 4 字数组)

flt * 浮点数据,32 位(或浮点数组)

dbl* 浮点数,64 位(或双精度数组)

tbyte * 浮点数,80 位(或扩展精度浮点数)

stru* 结构体 (或结构体数组)

algn * 对齐指示

unk* 未处理字节

IDA 中有常见的说明符号,如 db、dw、dd 分别代表了 1 个字节、2 个字节、4 个字节

IDA 反编译代码中的各种 call

在 IDA 和其他反汇编、编译器工具中,__stdcall__thiscall__cdecl 等调用约定 (calling conventions) 定义了函数调用时参数的传递方式、调用者和被调用者的职责等。以下是常见的调用约定及其含义:

 __cdecl

  • 含义: C declaration

  • 参数传递: 参数从右到左推入栈中。

  • 返回值传递: 通过寄存器 EAX 返回。

  • 栈清理: 调用者负责清理栈。

  • 用途: 标准的 C 函数调用约定,多用于 C 语言编译的函数。

 __stdcall

  • 含义: Standard call

  • 参数传递: 参数从右到左推入栈中。

  • 返回值传递: 通过寄存器 EAX 返回。

  • 栈清理: 被调用者负责清理栈。

  • 用途: 多用于 WinAPI 函数调用。

 __fastcall

  • 含义: Fast call

  • 参数传递: 前两个参数通过寄存器 (ECXEDX) 传递,剩余参数从右到左推入栈中。

  • 返回值传递: 通过寄存器 EAX 返回。

  • 栈清理: 被调用者负责清理栈。

  • 用途: 用于需要高效调用的函数。

 __thiscall

  • 含义: This call

  • 参数传递: this 指针通过寄存器 ECX 传递,其他参数从右到左推入栈中。

  • 返回值传递: 通过寄存器 EAX 返回。

  • 栈清理: 被调用者负责清理栈。

  • 用途: 用于 C++ 类的成员函数调用。

 __vectorcall

  • 含义: Vector call

  • 参数传递: 首先通过寄存器(包括 SIMD 寄存器)传递,剩余参数通过栈传递。

  • 返回值传递: 通过寄存器返回。

  • 栈清理: 被调用者负责清理栈。

  • 用途: 用于需要高效传递 SIMD 类型参数的函数。

 __syscall

  • 含义: System call

  • 参数传递: 根据特定操作系统的系统调用约定传递参数。

  • 返回值传递: 通过寄存器返回。

  • 栈清理: 操作系统内核负责栈清理。

  • 用途: 用于系统调用。

__usercall

__usercall 是一个用于定义自定义调用约定的标识符。这意味着函数的调用和参数传递方式是由用户定义的,而不是由标准调用约定(如 __stdcall__cdecl 等)决定的。使用 __usercall 可以帮助分析器识别参数和返回值的位置。

例如,假设你有一个函数,它接受两个参数并返回一个值,但这些参数和返回值的位置与标准调用约定不同:

 
int __usercall my_function<eax>(int param1<ecx>, int param2<edx>);
 

在这个例子中,my_function 接受两个参数 param1param2,并且这些参数分别通过 ecxedx 寄存器传递,返回值通过 eax 寄存器返回。

__userpurge

__userpurge__usercall 类似,但它还包括调用方负责清理堆栈的约定。这通常用于类似于 __stdcall 的约定,其中被调用者负责清理堆栈,但在 __userpurge 中,由调用者清理堆栈。

例如,假设你有一个函数,它接受两个参数,参数传递方式是自定义的,并且调用方负责清理堆栈:

 
int __userpurge my_function<eax>(int param1<ecx>, int param2<edx>);
 

在这个例子中,函数的参数通过寄存器传递,并且调用者在调用函数后负责清理堆栈。

__usercall__userpurge 区别

  • __usercall 允许定义自定义的调用约定,但不指定堆栈清理责任。

  • __userpurge 也是定义自定义的调用约定,但明确指定调用者负责堆栈清理。

如何在 IDA 中识别调用约定

在 IDA 中,你可以通过反汇编代码和调用图识别调用约定。一般来说,观察函数的 prologue 和 epilogue 可以帮助你确定调用约定。例如:

  • __cdecl: 函数结束时有类似 add esp, N 的栈清理代码。

  • __stdcall: 函数结束时没有 add esp, N,栈指针由 ret N 指令自动调整。

  • __thiscall: 函数的第一个参数是 this 指针,传递通过 ECX 寄存器。