IDA Pro 权威指南学习笔记(一) - 启动 IDA

 

启动 IDA

启动 IDA,有一个欢迎界面

img

之后有一个对话框

img

选择 New 将启动一个对话框来选择将要分析的文件

img

选择 Go 将使 IDA 打开一个空白的工作区

img

如果要选择分析的文件,可以直接拖到 IDA 工作区

也可以在菜单栏选择 File -> Open 来打开

img

选择 Previous 可以打开其下“最近用过的文件”列表中的一个文件

历史记录列表的最大长度为 10,可以通过编辑 idagui.cfg 或 idatui.cfg 来修改

文件加载

选择 File -> Open 打开一个新文件,会显示一个加载对话框

img

文件类型列表,列表中将显示最适合处理选定文件的 IDA 加载器

IDA 通过执行 loaders 目录中的每一个文件加载器,来确定能够识别新文件的加载器,从而建立了这个列表

上图中 Windows PE 加载器(pe.ldw)和 MS-DOS EXE 加载器(dos.ldw)均声称它们能够识别选定的文件,因为 PE 文件格式是 MS-DOS EXE 文件格式的扩展形式

Binary File(二进制文件)是这个列表中的最后一个选项,它会一直显示,因为它是 IDA 加载无法识别的文件的默认选项,它提供了最低级的文件加载方法

如果只有 Binary File,这表明没有加载器能够识别选定的文件

Processor Type(处理器类型)下拉菜单中可以指定在反汇编过程中使用的处理器模块(在 IDA 的 procs 目录中)

多数情况下,IDA 将根据它从可执行文件的头中读取到的信息,选择合适的处理器

如果 IDA 无法正确确定与所打开的文件关联的处理器类型,在继续文件加载操作前,需要手动选择一种处理器类型

Loading Segment(加载段)Loading Offset(加载偏移量),如果同时选择了二进制文件输入格式和一种 x86 系列处理器,Loading Segment 和 Loading Offset 字段将处于活动状态

由于二进制加载器无法提取任何内存布局信息,在这里输入的段和偏移量值将共同构成所加载文件内容的基址

在最初的加载过程中,如果忘记指定基址,可以在任何时候使用 Edit -> Segments -> Rebase Program 命令来修改 IDA 镜像的基址

Kernel Options(核心选项)用于配置特定的反汇编分析选项,IDA 可利用这些选项改进递归下降过程

绝大多数情况下,默认选项提供的都是最佳的反汇编选项

Processor Options(处理器选项)用来选择适用于选中的处理器模块的配置选项,但它不一定对每个处理器模块有效

其他选项复选框可帮助用户更好地控制文件加载过程

 

IDA Pro 权威指南学习笔记(二) - IDA 数据库文件

 

生成数据库文件

把要分析的文件用 IDA 打开后,会生成 3 个数据库文件

img

扩展名分别为 .id0,id1,nam

.id0 文件是一个二叉树形式的数据库

.id1 文件包含描述每个程序字节的标记

.nam 文件包含与 IDA 的 Names 窗口中显示的给定程序位置有关的索引信息

img

点击 OK 后,将会生成一个 .til 文件

.til 文件用于存储与一个给定数据库的本地类型定义有关的信息

在关闭当前项目时,生成的数据库文件将被存档,可以将它们压缩成一个扩展名为 idb 的文件

IDA 数据库指的是 IDB 文件

一个未压缩的数据库文件的大小一般是最初输入的二进制文件的 10 倍

如果工作目录中存在这些文件,则往往表示数据库被意外关闭(例如,IDA崩溃),这时数据库可能被损坏

一旦 IDA 为某个可执行文件创建数据库,它就不再需要访问这个可执行文件

关闭 IDA 数据库

如果关闭一个数据库,无论是完全关闭 IDA,还是切换到另一个数据库,IDA 都将显示一个 Save database(保存数据库)对话框

img

Don’t pack database(不打包数据库),这个选项仅仅刷新对 4 个数据库组件文件所做的更改,在关闭桌面前并不创建 IDB 文件

Pack database(Store)[打包数据库(存储)],选择该选项会将 4 个数据库组件文件存到一个 IDB 文件中,然后这 4 个数据库文件会被删除,Store 选项不使用压缩

Pack database(Deflate)[打包数据库(压缩)],Deflate 选项等同于 Store 选项,其唯一的差别在于数据库组件文件被压缩到 IDB 归档文件中

Collect garbage(收集垃圾),如果勾选该选项,IDA 会在关闭数据库之前,从数据库中删除任何没有用的内存页面

在选择这个选项的同时,选择 Deflate选项可创建尽可能小的 IDB文件

通常,只有在磁盘空间不足时才选择这个选项

DON’T SAVE the datebase(不保存数据库),选择这个选项时,IDA 会删除 4 个数据库组件文件,保留现有的未经修改的 IDB 文件

使用这个选项类似于在使用 IDA 时应用了撤销或还原功能

 

IDA Pro 权威指南学习笔记(三) - IDA 桌面简介

 

IDA 的默认桌面如下图

img

工具栏区域(1)包含与 IDA 的常用操作对应的工具,可以使用 View -> Toolbar 显示或隐藏工具栏

可以使用 View -> Toolbars -> Advanced mode 打开高级模式工具栏,高级模式工具栏包含整整三排工具按钮

img

彩色的水平带是 IDA 的概况导航栏(2),也叫做导航带

导航带是被加载文件地址空间的线性视图,默认情况下,它会呈现二进制文件的整个地址范围

可以右击导航带内任何位置,并选择一个可用的缩放选项,放大或缩小显示的地址范围不同的颜色表示不同类型的文件内容,如数据或代码

在导航带上,会有一个细小的当前位置指示符(默认为黄色)指向与当前反汇编窗口中显示的地址范围对应的导航带地址

将光标悬停在导航带的任何位置,IDA 会显示一个工具提示,指出其在二进制文件中的对应位置

单击导航带,反汇编视图将跳转到二进制文件中所选定的位置

可以通过 Options -> Colors 命令自定义导航带所使用的颜色

IDA 为当前打开的每一个数据显示窗口都提供了标签(3),数据显示窗口中包含从二进制文件中提取的信息,它们代表数据库的各种视图

绝大多数分析工作需要通过数据显示窗口完成

通过 View -> Open Subviews 菜单可打开其他数据显示窗口,还可恢复任何意外关闭或有意关闭的窗口

反汇编视图(4)是主要数据显示视图,它有两种不同的形式:图形视图(默认)和列表视图

在图形视图中,IDA 显示的是某个函数在某一时间的流程图

使用空格键在图形视图样式和列表视图样式之间切换

如果希望将列表视图作为默认视图,可以通过 Options -> General 菜单打开 IDA Options 复选框,取消选择 Graph 选项卡下的 Use graph view by default(默认使用图形视图)复选框

img

图形概况视图(5),仅在使用图形视图时显示,可提供基本图形结构的缩小快照,其中的虚线矩形表示其在图形视图中的当前显示位置

在图形概况窗口内单击鼠标,可重新定位图形视图的显示位置

输出窗口(6)显示的是 IDA 输出的信息

在该窗口,用户可以找到与文件分析进度有关的状态消息,以及由用户操作导致的错误消息

输出窗口基本上等同于一个控制台输出设备

函数窗口(7)是默认 IDA 显示窗口的最后一部分

IDA 桌面提示和技巧

使用 View -> Open Subviews 命令恢复无意中关闭的数据显示窗口

使用 Windows -> Reset Desktop 命令可迅速将桌面恢复到原始布局

使用 Windows -> Save Desktop 命令保存当前的桌面布局

用 Windows -> Load Desktop 命令打开之前保存的一个桌面布局

Disassembly 窗口(无论是图形视图或列表视图)是唯一一个可以修改其显示字体的窗口,使用 Options -> Font 命令可以设置字体

 

IDA Pro 权威指南学习笔记(四) - IDA 用户界面的基本规则

 

基本规则:

IDA 不提供撤销功能

如果由于不小心按下某个键,导致数据库文件发生意外,这时需要将显示窗口恢复到以前的状态

几乎所有的操作都有其对应的菜单项、热键和工具栏按钮

IDA 的工具栏高度可配置,就像热键对菜单操作的映射一样

IDA 提供方便的、基于上下文的鼠标右键操作菜单

虽然这些菜单无法提供在某个位置允许执行的操作的详尽列表,但你可以用它们执行一些最常见的操作

 

IDA Pro 权威指南学习笔记(五) - IDA 主要的数据显示窗口

 

在默认配置下,IDA(从 6.1 版开始)会在对新二进制文件的初始加载和分析阶段创建 7 个显示窗口

3 个立即可见的窗口分别为 IDA-View 窗口、函数窗口和消息输出窗口

img

可以通过 View -> Open Subviews 菜单打开这些窗口

img

在 IDA 中,ESC 键是一个非常有用的热键

在反汇编窗口中,ESC 键的作用与Web浏览器的“后退”按钮类似

在打开的其他窗口中,ESC 键用于关闭窗口

反汇编窗口

反汇编窗口也叫 IDA-View 窗口,它是操作和分析二进制文件的主要工具

反汇编窗口有两种显示格式:默认的基于图形的视图和面向文本的列表视图

可以使用空格键在图形视图与列表视图之间切换

IDA 图形视图

图形视图将一个函数分解成许多基本块,以生动显示该函数由一个块到另一个块的控制流程

基本块是一个不包含分支,从头执行到尾的最大指令序列

基本块中的第一条指令通常是分支指令的目标,而最后一条指令则往往是一条分支指令

img

IDA 使用不同的彩色箭头区分函数块之间各种类型的流

正常流(也叫做普通流)表示指令默认连续执行,跳转流表示当前的指令跳转到(或可能跳转到)某个非连续性位置,调用流表示当前指令会调用一个子例程

根据测试条件,在条件跳转位置终止的基本块可能会生成两种流:Yes 边的箭头(是的,执行分支)默认为绿色,No 边的箭头(不,不执行分支)默认为红色

只有一个后继块的基本块会利用一个正常边(默认为蓝色)指向下一个即将执行的块

在图形模式下,IDA 一次显示一个函数

使用滑轮鼠标的用户,可以使用“CTRL+鼠标滑轮”来调整图形的大小

概况窗口始终显示图形完整的块状结构,并用一个虚线框指出你当前在反汇编窗口中查看的图形区域

可以用鼠标在概况窗口中拖动该虚线框,以迅速将图形视图调整到任何想到的位置

img

控制图形视图的显示方式:

1.平移。首先,除了使用“图形概况”窗口迅速定位图形外,你还可以通过单击和拖动图形视图的背景来定位图形

2.重新调整块位置。通过单击指定块的标题栏并将其拖动到一个新位置,用户可以移动图形中的每一个块的位置

IDA 会尽可能少地重新设定一个被移动的块的连接线的位置,即连接两个块的带箭头的折线

如果想还原默认的图形布局,可以右击图形,并选择 Layout Graph

可以拖动连接线的顶点,手动更改连接线的路径

在按下 shift 键的同时,在连接线的任何位置双击鼠标,即可在该位置添加一个新顶点

3.分组和折叠块。可以对块分组,每个块单独分组,或者与其他块一起分组,并可将分组后的块折叠起来,以减少显示的混乱程度

折叠块可以帮助追踪已经分析过的块,要折叠块,可以右击块的标题栏,然后选择 Group Nodes

4.创建其他反汇编窗口。如果想要同时查看两个不同函数的图形,可以通过 Views -> Open Subviews -> Disassembly 命令打开另一个反汇编窗口

这样打开的第一个反汇编窗口叫做 IDA View-A,随后的反汇编窗口叫做 IDA View-B、IDA View-C,依次类推

每个反汇编窗口都独立于其他窗口,可以在一个窗口中查看一个图形,在另一个窗口中查看文本列表,或者在 3 个不同的窗口中查看 3 个不同的图形

IDA 文本视图

面向文本的反汇编窗口是查看和操作 IDA 生成的反汇编代码的传统显示窗口

文本显示窗口会呈现一个程序的完整反汇编代码清单(而在图形模式下一次只能显示一个函数),用户只有通过这个窗口才能查看一个二进制文件的数据部分

图形显示窗口中的所有信息均以某种形式存在于文本显示窗口中

在使用图形视图时,获得的有关每一个反汇编代码行的信息似乎要更少一些

因为 IDA 隐藏了许多与每个反汇编行有关的更加传统的信息(如虚拟地址信息),以最大限度地减少显示每个基本块所需的空间

要想显示与每个反汇编行有关的其他信息,可以通过 Options -> General 命令打开 IDA 常规选项,然后在 Disassembly 选项卡的可用的反汇编行部分选择相应的选项

例如,要给每一个反汇编行添加虚拟地址,可以启用“行前缀”

img

启用行前缀

img

函数的文本视图列表如下图

img

窗口中的反汇编代码分行显示,虚拟地址则默认显示

通常,虚拟地址以 [ 区域名称 ]:[ 虚拟地址 ] 这种格式显示,如 .text:00401589

显示窗口的左边部分叫做箭头窗口(1),用于描述函数中的非线性流程

实线箭头表示非条件跳转,虚线箭头则表示条件跳转

如果一个跳转(条件或非条件)将控制权转交给程序中的某个地址(以前的),这时会使用粗线(实线或虚线)

出现这类逆向流程,通常表示程序中存在循环

在上图中,地址 0040158E 至 00401592 之间就有一个循环箭头

img

位置 1 的声明(也出现在图形视图中)是 IDA 对于函数栈帧布局的最准确估算

IDA 会对函数栈指针及函数使用的任何栈帧指针的行为进行仔细分析,从而计算出该函数的栈帧的结构

栈帧(或激活记录)是在程序的运行时栈中分配的一个内存块,其中包含传递给一个函数的参数和该函数声明的局部变量

栈帧在函数的入口点位置分配,并在函数退出时释放

位置 2 的注释(以分号开头)属于交叉引用

代码交叉引用(而不是数据交叉引用),它表示另一个程序指令将控制权转交给交叉引用注释所在位置的指令

函数窗口

函数窗口用于列举 IDA 在数据库中识别的每一个函数

Functions 窗口中的条目如下所示:

img

在二进制文件中虚拟地址为 0040E600 的 .text 部分找到 scanf 函数,该函数长为 41 字节(十六进制为 29 字节)

它返回调用方( R ),并使用 EBP 寄存器( B )引用它的局部变量

双击 Functions 窗口中的一个条目,反汇编窗口将跳转到选定函数所在的位置

输出窗口

打开一个新文件时,IDA 工作区底部的输出窗口与其他窗口一起组成了 IDA 的默认窗口

输出窗口是 IDA 的输出控制台,从中可以找到与 IDA 所执行的任务有关的信息

例如,初次打开一个二进制文件时,IDA 将生成消息,指出它在某个时刻所处的分析阶段,以及它为创建新数据库而执行的操作

当你使用数据库时,输出窗口将输出你所执行的各种操作的状态

可以将输出窗口中的内容复制到系统剪贴板中,也可以右击窗口的任何位置,并在出现的菜单中选择相应的操作而完全删除输出窗口的内容

通常,输出窗口是显示 IDA 开发的任何脚本和插件的输出的主要窗口

 

IDA Pro 权威指南学习笔记(六) - 次要的 IDA 显示窗口

 

十六进制窗口

IDA 十六进制窗口可以配置为显示各种格式,并可作为十六进制编辑器使用

默认情况下,十六进制窗口显示程序内容和列表的标准十六进制代码,每行显示 16 个字节,以及其对应的 ASCII 字符

和在反汇编窗口中一样,用户也可以同时打开几个十六进制窗口

第一个十六进制窗口叫做 Hex View-A,第二个十六进制窗口叫做 Hex View-B,接下来的窗口叫做 Hex View-C,依次类推

默认情况下,第一个十六进制窗口会与第一个反汇编窗口同步

如果一个反汇编窗口与一个十六进制窗口同步,在一个窗口中滚动鼠标,另一个窗口也会滚动到相同的位置(同一个虚拟地址)

如果在反汇编窗口中选中一个项目,十六进制窗口中的对应字节也将突出显示

在反汇编窗口中,光标指向地址 0040E60D,这是一个 mov 指令,在十六进制窗口中,构成这个指令的全部 3 个字节均突出显示

img

右击十六进制窗口的任何位置,出现十六进制窗口的上下文菜单

使用这个菜单,可以指定与某个特殊的十六进制窗口同步的反汇编窗口(如果有的话)

如果取消选中同步选项,那么在滚动十六进制窗口时,将不会有任何反汇编窗口随之滚动

择 Edit 菜单项可将十六进制窗口转变为十六进制编辑器,完成编辑后,你必须提交或取消更改才能返回查看模式

可以使用 Data Format 菜单项选择各种显示格式,如 1、2、4、8 字节十六进制,带签名的十进制或不带签名的十进制整数及各种浮点格式

可以使用 Columns 菜单项更改显示的列数

使用 Text 选项打开或关闭文本块

如果十六进制窗口中显示的是问号,这表示 IDA 无法识别给定的虚拟地址范围内的值,如果程序中包含一个 bss 节,就会出现这种情况

通常,bss 节并不占用文件的空间,但加载器会扩展这一节,以适应程序的静态存储要求

bss 节由编译器创建,用于保存程序的所有未初始化的静态变量

既然没有为这些变量指定初始值,就没有必要在程序的文件镜像中为它们分配空间,只需在程序的一个头文件中注明它的大小

当程序执行时,加载器会为其分配所需的空间,并将整个数据块的初始值设为 0

导出窗口

导出窗口列出文件的入口点

这些入口点包括程序的执行入口点(在程序的文件头部分指定),以及任何由文件导出给其他文件使用的函数和变量

通常,用户可在共享库(如 Windows DLL 文件)中找到导出的函数

导出的项目按名称、虚拟地址和序数(如果可用)排列

共享库可能会使用导出序数,以方便用户通过序数而非名称访问函数

使用序数可以加快地址查询速度,并允许程序员隐藏函数的名称

Windows DLL 即使用导出序数

对于可执行文件,导出窗口中至少包含一个项目:程序的执行入口点,IDA 将这个入口点取名为 start

img

与许多其他 IDA 窗口一样,双击导出窗口中的一个条目,IDA 将会跳转到反汇编窗口中与该项目有关的地址

导出窗口提供与 objdump (-T) 、 readelf (-s) 和 dumpbin (/EXPORTS) 等命令行工具类似的功能

导入窗口

导入窗口的功能与导出窗口的功能正好相反

导入窗口列出由被分析的二进制文件导入的所有函数

只有在二进制文件使用共享库时,IDA 才需要用到导入窗口

静态链接的二进制文件不存在外部依赖关系,因此不需要导入其他内容

导入窗口中的每个条目列出一个导入项目(函数或数据)的名称,以及包含该项目的库的名称

由于被导入的函数的代码位于共享库中,窗口中每个条目列出的地址为相关导入表条目的虚拟地址

img

双击第一个条目,IDA 将跳转到反汇编窗口的 00412168 地址处

img

在十六进制窗口中,这个内存位置的内容显示为 ?? ?? ?? ??

img

因为 IDA 是一种静态分析工具,它无法获知程序在执行时会在这个内存位置输入什么地址

导入窗口还提供与 objdump (-T) 、 readelf (-s) 和 dumpbin (/IMPORTS) 等命令行工具类似的功能

导入窗口仅显示二进制文件想要动态加载器自动处理的符号,二进制文件选择使用 dlopen/dlsym 或 LoadLibrary/GetProcAddress 等机制自行加载的符号将不会在导入窗口中显示

结构体窗口

结构体窗口用于显示 IDA 决定在一个二进制文件中使用的任何复杂的数据结构(如 C 结构体和联合)的布局

在分析阶段,IDA 会查询它的函数类型签名扩展库,设法将函数的参数类型与程序使用的内存匹配起来

img

双击数据结构的名称,IDA 将展开该结构,这样你就可以查看该结构的详细布局,包括每个字段的名称和大小

img

结构体窗口的两个主要用途包括:

为标准数据结构的布局提供现成的参考;

提供一种方法,在发现程序使用的自定义数据结构时,帮助创建自己的、可用作内存布局模板的数据结构

枚举窗口

如果 IDA 检测到标准枚举数据类型(C enum ),它将在枚举窗口中列出该数据类型

可以使用枚举来代替整数常量,提高反汇编代码的可读性

在枚举窗口中也可以定义自己的枚举类型,并将其用在经过反汇编的二进制代码中

img

 

IDA Pro 权威指南学习笔记(七) - 其他 IDA 显示窗口

 

默认情况下 IDA 不会打开这些窗口,可通过 View -> Open Subviews 命令打开

Strings 窗口(Strings)

Strings 窗口中显示的是从二进制文件中提取出的一组字符串,以及每个字符串所在的地址

双击 Strings 窗口中的任何字符串,反汇编窗口和十六进制窗口将跳转到该字符串所在的地址

将 Strings 窗口与交叉引用相结合,可迅速定位感兴趣的字符串,并追踪到程序中任何引用该字符串的位置

例如,看到 SOFTWARE\Microsoft\Windows\CurrentVersion\Run 这个字符串,并想知道应用程序为什么会引用这个特殊的 Windows 注册表项

每次打开 Strings 窗口,IDA 都会扫描或重新扫描整个数据库,查找其中的字符串

扫描字符串的操作遵照 Strings 窗口的设置来完成,右击该窗口,在出现的菜单中选择 Setup,即可开始设置

img

Setup Strings 窗口用于指定 IDA 应扫描的字符串类型

IDA 默认扫描的字符串类型为至少包含 5 个字符的 C 风格、以 null 结尾的 7 位 ASCII 字符串

每次单击 OK 按钮关闭 Setup Strings 窗口后,IDA 都会根据新的设置重新扫描数据库,查找相应的字符串

Display only defined strings(仅显示已定义的字符串),这个选项使 Strings 窗口仅显示 IDA 自动创建或用户手动创建的已命名字符串数据项

在选中这个选项的同时禁用所有其他选项,IDA 将不会自动扫描其他类型的字符串

Ignore instructions/data definitions(忽略指令/数据定义),这个选项会使 IDA 扫描指令和现有数据定义中的字符串

使用这个选项,可以让 IDA 扫描二进制代码中错误地转换成指令的字符串,或扫描数据中非字符串格式(如字节数组或整数)的字符串

这个选项还会导致 IDA 生成许多垃圾字符串,即那些由 5 个或更多 ASCII 字符构成的字符串(无论其是否合法)

使用这个选项的效果类似于使用 strings -a 命令

Names 窗口(Names)

Names 窗口简要列举了一个二进制文件的所有全局名称

名称是指对一个程序虚拟地址的符号描述

名称可以按字母排序,也可以按虚拟地址排序(升序或降序)

双击 Names 窗口中的名称,可跳转到显示该名称的反汇编视图

img

Names 窗口中显示的名称采用了颜色和字母编码:

f 为常规函数,IDA 认为这些函数不属于库函数

i 为导入的名称,通常为共享库导入的函数名称

它与库函数的区别在于:导入的名称没有代码,而库函数的主体将在反汇编代码清单中显示

D 为数据,已命名数据的位置通常表示全局变量

C 为命名代码,这些是已命名的程序指令位置,IDA 认为它们不属于任何函数

当 IDA 在程序的符号表中找到一个名称,但没发现对程序位置的任何调用时,就会出现这种情况

A 为字符串数据,这是一个被引用的数据位置,其中包含的一串字符符合 IDA 的某种已知的字符串数据类型,如以 '\0' 字节结束的 ASCII 字符串

在对一个程序进行反汇编的过程中,IDA 会为所有直接作为代码(分支或调用目标)或数据(读取的、写入的或使用的地址)引用的位置生成名称

如果一个位置已在程序符号表中命名,IDA 将采用该名称

如果符号表中某一程序位置没有名称,则 IDA 会生成一个默认的名称,以在反汇编过程中使用

在 IDA 给某个位置命名时,它会使用该位置的虚拟地址和一个表示该位置的类型的前缀进行命名

将虚拟地址合并到生成的名称中,可确保生成的所有名称的唯一性,因为没有两个位置的虚拟地址是相同的,这种自动生成的名称并不在 Names 窗口中显示

用于自动生成名称的一些常用前缀:

sub_xxxxxx:地址 xxxxxx 处的子例程

loc_xxxxxx:地址 xxxxxx 处的一个指令

byte_xxxxxx:位置 xxxxxx 处的 8 位数据

word_xxxxxx:位置 xxxxxx 处的 16 位数据

dword_xxxxxx:位置 xxxxxx 处的 32 位数据

unk_xxxxxx:位置 xxxxxx 处的大小未知的数据

段窗口(Segments)

段窗口显示的是在二进制文件中出现的段的简要列表

在讨论二进制文件的结构时,IDA 术语段(segment)常称为节(section)

段窗口中显示的信息包括段名称、起始和结束地址以及许可标志

起始和结束地址代表程序段在运行时对应的虚拟地址范围

img

双击段窗口中的任何条目,IDA 将跳转到反汇编窗口中该段的起始位置

右击一个条目,IDA 将显示一个上下文菜单,你可以选择添加新段、删除现有段、或者编辑现有段的属性

img

段窗口所对应的命令行工具包括 objdump (-h) 、 readelf (-s) 和 dumpbin (/HEADERS)

签名窗口(Signatures)

签名窗口显示的是 IDA 对打开的二进制文件所使用的签名

签名用于识别由编译器生成的常用启动顺序,以确定可能已被用来构建给定二进制文件的编译器

签名还可用于将函数划归为由编译器插入的已知库函数,或者因为静态链接而添加到二进制文件中的函数

img

IDA 对该二进制文件应用了 vcseh 签名(来自/sigs目录),并在这个过程中将 0 个函数识别为库函数

至少在两种情况下,需要知道如何对二进制文件应用其他签名:

第一种情况:IDA 无法识别用于构建二进制文件的编译器,因而无法选择所需的相应签名

这时,需要根据自己的初步分析,确认 IDA 应尝试使用的签名,并迫使 IDA 使用一个或几个签名

第二种情况:IDA 中没有针对某些库的现成签名,这时需要自己为这些库创建你自己的签名

类型库窗口(Type libraries)

类型库保存 IDA 积累的一些信息,即 IDA 从最常用的编译器的头文件中搜集到的有关预定义数据类型和函数原型的信息

img

通过处理头文件,IDA 可确定常用库函数所需的数据类型,并为反汇编代码提供相应的注释

IDA 还可从这些头文件中了解复杂数据结构的大小和布局所有这些信息都收集在 TIL 文件(<IDADIR/til 目录>)中,并可在任何时候应用于分析的二进制文件

与应用签名时一样,在选择加载一组适当的 TIL 文件之前,IDA 必须首先确定一个程序所使用的库

要请求 IDA 加载其他类型库,可以在类型库窗口中按下 INSERT 键,或右击窗口并在出现的菜单中选择 Load Type Library(加载类型库)

函数调用窗口(Function calls)

如果 Y 函数直接调用 X 函数,或者 X 函数直接调用 Y 函数,则称 Y 函数是 X 函数的近邻

打开函数调用窗口时,IDA 会确定光标所在位置的函数的“近邻”

img

函数 _pow5mult_D2A 被 _gdtoa 从 3 个不同的位置调用,被 ___strtodg 从 2 个不同的位置调用,而这个函数又调用了另外 9 个函数

双击函数调用窗口中的任何一行,IDA 将跳转到反汇编窗口中对应的调用或被调用函数(即调用方或被调用方)

IDA 交叉引用(xrefs)是用于生成函数调用窗口的机制

问题窗口(Problems)

IDA 在问题窗口中显示它在反汇编二进制文件时遇到的困难,以及它如何处理这些困难

img

每个问题都注明了问题发生的地址、问题的类型以及问题所在位置的指令

在上图中,有一个 NODISASM 问题和一个 DECISION 问题

DECISION 问题通常表示 IDA 决定将一个地址上的字节作为指令而非数据进行反汇编,即使这个地址在递归下降指令遍历过程中从未被引用也是如此

 

IDA Pro 权威指南学习笔记(八) - 基本 IDA 导航

 

导航目标

在分析阶段,IDA 会通过检查二进制文件的符号表生成符号名称,或根据二进制文件引用位置的方式自动生成一个名称

反汇编窗口中显示的任何名称都是导航目标

双击任何一个符号,IDA 将跳转到相应的位置

img

这些是已经命名的导航目标

img

上面划红线的是交叉引用,也是导航目标

交叉引用通常被格式化成一个名称和一个十六进制偏移值

双击交叉引用文本,IDA 将跳转到引用位置

img

双击标有 1 的值,反汇编窗口将跳转到相应的位置,因为它们都属于给定二进制文件中的合法虚拟地址

双击标有 2 的值则不会有任何效果

跳转地址

如果反汇编窗口中没有可供双击导航的名称,可以使用反汇编窗口滚动条上下滚动窗口来找想要访问的地址

如果仅仅知道一个已命名的位置,如一个名为 foobar 的子程序,可以选择对函数窗口按字母排序,滚动到想要的名称,然后再双击该名称

也可以使用 IDA 的 Search 菜单的搜索功能

跳转到一个已知的反汇编位置,可以用 Jump 菜单下的 Jump to Address 选项,快捷键为 G

img

导航历史记录

IDA 具有前进和后退导航功能,基于浏览反汇编窗口的顺序

每次导航到反汇编窗口中的一个新位置,当前的位置就会添加到位置列表中

Jump -> Jump to Previous Position 命令使反汇编窗口跳转到当前位置的前一个位置,快捷键为 Esc

在反汇编窗口以外的其他窗口中,使用 ESC 键会关闭当前窗口,可以使用 View -> Open Subviews 命令重新打开关闭的窗口

Jump -> Jump to Next Position 命令将反汇编窗口移动到列表中的下一个位置,快捷键为 Ctrl+Enter

工具栏上有前进和后退按钮,每个按钮旁边还有一个历史记录下拉列表

img

 

IDA Pro 权威指南学习笔记(九) - 数据搜索

 

Search -> Next Code 命令将光标移动到下一个包含指令的位置

Jump -> Jump to Function 命令可以打开所有函数,可以迅速选择一个函数并导航到该函数所在的位置

文本搜索

IDA 文本搜索相当于对反汇编列表窗口进行子字符串搜索

通过 Search -> Text 命令启动文本搜索,快捷键为 Alt+T

img

IDA 允许搜索 POSIX 类型的正则表达式

Identifier(标识符)搜索有些用词不当

它将搜索限制于仅查找完整的词,并且能够匹配反汇编行中的任何完整的词,包括操作码助记符或常量,即对 401116 进行标识符搜索将无法找到名为 loc_401116 的符号

Find all occurences 为查找所有结果

使用 Search -> Next Text 命令查找下一个匹配结果,快捷键为 Ctrl+T

二进制搜索

使用 IDA 的二进制搜索工具搜索特定的二进制内容,如已知的字节序列

二进制搜索仅搜索十六进制视图窗口

根据指定搜索字符串的方式,可以搜索十六进制或 ASCII 字符串

使用 Search -> Sequence of Bytes 进行二进制搜索,快捷键为 Alt+B

img

如果要搜索十六进制,需要将搜索字符串以空格分隔为两位十六进制值,如 4c 2d 1a 6d,十六进制不区分大小写

如果要有效搜索十六进制窗口中的 ASCII 字符串,需要将搜索字符串用引号括起来

Case-sensitive 为区分大小写

使用 Search -> Next Sequence of Bytes 查找下一个匹配结果,快捷键为 Ctrl+B

 

IDA Pro 权威指南学习笔记(十) - 栈帧

 

栈帧(stack frame)是在程序的运行时栈中分配的内存块,用于特定的函数调用

如果一个函数没有执行则不需要内存,当函数被调用时就需要用到内存

1.传给函数的参数的值需要存储到函数能够找到它们的位置

2.函数在执行过程中可能需要临时的存储空间,通过声明局部变量来分配这类临时空间,这些变量在函数内部使用,函数调用完后,就无法再访问它们

在将控制权转交给函数之前,编译器会插入代码,将函数参数放入栈帧内,并分配足够的内存,以保存函数的局部变量

函数的返回地址也存储在新的栈帧内

使用栈帧使得递归成为可能,因为每个递归函数调用都有它自己的栈帧,这恰好将当前调用与前一次调用分隔开来。

调用一个函数时的步骤:

(1) 调用方将被调用函数所需的参数放到该函数的调用约定指定的位置,如果参数被放到运行时栈上,该操作可能导致程序的栈指针发生改变

(2) 调用方将控制权转交给被调用的函数,这个过程通常由 x86 CALL 或 MIPS JAL 等指令执行,然后,返回地址被保存到程序栈或 CPU 寄存器中

(3) 如有必要,被调用的函数会配置一个栈指针,并保存调用方希望保持不变的任何寄存器值

帧指针是一个指向栈帧位置的寄存器,栈帧内的变量根据它们与帧指针所指向的位置的相对距离来引用

(4) 被调用的函数为它可能需要的任何局部变量分配空间,一般通过调整程序栈指针在运行时栈上保留空间来完成

(5) 被调用的函数执行其操作,可能返回一个结果,该结果通常被放置到一个特定的寄存器中,或者放置到函数返回后调用方可立即访问的寄存器中

(6) 函数完成其操作后,任何为局部变量保留的栈空间将被释放,通常逆向执行第(4)步中的操作就可以完成这个任务

(7) 如果某个寄存器的值还为调用方保存(第(3)步)着,就会把它恢复到原始值,包括恢复调用方的帧指针寄存器

(8) 被调用的函数将控制权返还给调用方,实现这一操作的主要指令是 x86 RET 和 MIPS JR,该操作可能还会从程序栈中清除一个或多个参数

(9) 调用方重新获得控制权后,可能需要删除程序栈中的参数,这时可能需要对栈进行调整,来将程序栈指针恢复到第(1)步以前的值

第(3)步和第(4)步通常在进入函数时执行,它们共同称为该函数的序言

第(5)步则代表函数的主体,是调用一个函数时执行的全部操作

第(6)步到第(8)步一般在函数结束时执行,它们共同构成该函数的尾声

 

IDA Pro 权威指南学习笔记(十一) - 名称与命名

 

多数情况下,要修改一个名称,只需单击想要修改的名称(使其突出显示),并使用快捷键 N 打开更名对话框

右击需要修改的名称,并在出现的上下文菜单中选择 Rename 选项,也可以更改名称

img

参数和局部变量

程序中的每个函数可能都有一个名为 arg_0 的栈变量,但没有一个函数拥有一个以上的 arg_0 变量

img

在栈变量处按快捷键 N 进行重命名栈变量

img

重命名后,IDA 会对当前函数中的每一个旧名称进行重命名

img

第一个的 var_18 修改为 var_2 后,之后的 var_18 也被修改为 var_2

如果想要恢复默认名称,将输入框置空,IDA 将会把变量名恢复到默认的名称

img

置空,点击 OK

img

var_2 恢复到 var_18

已命名的位置

重命名一个已命名的位置或给一个未命名的位置取名,使用快捷键 N 打开对话框

img

该对话框显示命名的具体地址,以及一些与该名称有关的特性

Local names 为局部名称

局部名称的作用域仅限于当前函数,局部名称的唯一性仅在某个给定的函数中有效

两个不同的函数可能含有完全相同的局部名称,但一个函数不可能包含两个完全相同的局部名称

在函数边界以外的已命名的位置不能被指定为局部名称,包括表示函数及全局变量的名称

局部名称最常用于为函数中的跳转目标提供符号名称,如那些与分支控制结构有关的名称

Include in names list 为包含在名称列表中

选择这个选项将有一个名称被添加到名称窗口中,当需要返回该名称所在位置时,就更容易找到这个名称

默认情况下,自动生成的名称(哑名)不包含在名称窗口中

Public name 为公共名称

通常,公共名称是指由二进制文件(如共享库)输出的名称

在最初加载数据库的过程中,IDA 的解析器会在解析文件头的同时查找公共名称

选择这个特性,会强制 IDA 将一个符号看成是公共名称,这样除了给反汇编代码清单和名称窗口中的名称添加公共注释外,不会对反汇编代码造成任何影响

Autogenerated name 为自动生成的名称

这个特性不会对反汇编代码产生任何明显的影响,选择它并不会使 IDA 自动生成一个名称

Weak name 为弱名称

弱符号(weak symbol)是公共符号的一种特殊形式,只有没有找到相同名称的公共符号来重写时,才会使用弱符号

Create name anyway 为无论如何都要创建名称

在函数以外(全局范围内),不能有两个位置使用相同的名称

如果在全局范围内编辑一个名称(如函数名称或全局变量),并且尝试分配一个数据库中已经存在的名称,IDA 会显示名称冲突对话框

img

同时 IDA 会自动生成一个唯一的数字后缀,以解决冲突

无论是否选择Create name anyway选项,这个对话框都会出现

如果编辑某个函数中的一个局部名称,并且尝试分配一个已经存在的名称,默认情况下,IDA 会拒绝这种尝试

如果一定要使用这个名称,必须选择 Create name anyway 选项,来强制 IDA 为局部名称生成一个唯一的数字后缀

寄存器名称

如果编译器选择将变量分配到寄存器中而不是程序栈上,并且想要使用一个比 EDX 更恰当的名称来引用这个变量,这时重命名寄存器才有用

使用快捷键 N,或右击寄存器名称并在出现的菜单中选择 Rename,打开“寄存器重命名”对话框

重命名寄存器时,实际上是提供了一个别名,并使用它在当前函数执行期间引用该寄存器

IDA 甚至在函数开始部分用 alias=register 语法来表示这个别名

如果一段代码不属于某个函数,就不能重命名这段代码中的寄存器

 

IDA Pro 权威指南学习笔记(十二) - IDA 中的注释

 

注释有助于以一种更高级的方式描述汇编语言指令序列

IDA 提供了几种不同类型的注释,每种注释适用于不同的目的

使用 Edit -> Comments 命令的选项,可以为反汇编代码清单中的任何一行代码添加注释

这是一个 scanf() 函数

img

某一行分号之后的内容都是注释

常规注释

常规注释位于现有汇编代码行的尾部

img

右击反汇编窗口右边空白的地方

img

选择 Enter comment,可以打开“Enter comment”对话框

或者使用快捷键“:”

img

输入一行注释

img

默认情况下,常规注释以蓝色显示

如果输入了多行注释,常规注释将跨越多行

每一行注释将排到反汇编窗口的右侧,并同样以分号开头,且与最第一个分号对齐

img

要编辑或删除一段注释,需要打开该注释的对话框“Enter comment”,进行编辑或删除

在分析阶段,IDA 插入常规注释说明为调用函数而压入的参数

只有当 IDA 拥有被调用函数的参数名称或类型信息时,才会使用常规注释

可重复注释

可重复注释一旦输入,将会自动出现在反汇编窗口中的许多位置

img

可重复注释的颜色也是蓝色的

如果一个程序位置引用了另一个包含可重复注释的位置,则该注释会在第一个位置回显

默认情况下,回显的注释以灰色文本显示

可重复注释的快捷键为分号“;”

右键反汇编窗口右边空白的地方

img

选择 Enter repeatable comment,也能进行注释

img

输入注释的内容,hello

img

点击 OK

img

如果在一个显示可重复注释的位置添加一段常规注释,则可重复注释将被常规注释覆盖,该位置将仅显示常规注释

任何时候,如果 IDA 自动创建一个字符串变量,字符串变量所在的位置都将添加一段虚拟的可重复注释

这种称为虚拟注释,因为用户无法编辑这段注释

虚拟注释的内容被设置为字符串变量的内容,并且会在整个数据库中显示,就像是一段可重复注释一样

任何引用字符串变量的位置都将以重复注释的形式显示字符串变量的内容

img

这类注释是因为引用了字符串变量才显示的

在前注释和在后注释

在前注释和在后注释是出现在指定的反汇编行之前或之后的全行注释,它们是 IDA 中仅有的不以分号为前缀的注释

通过将与某个行相关的地址与该行之后或之前的指令进行比较,即可区分“在前”注释与“在后”注释

函数注释

通过函数注释,可以为函数的反汇编代码清单顶部显示的注释分组

img

上图就为函数注释,其中也包含函数原型

要输入函数注释,首先应突出显示函数顶部的函数名称,然后再输入一段常规注释或可重复注释

img

可重复函数注释将在调用该函数的任何位置回显

 

IDA Pro 权威指南学习笔记(十三) - 基本代码转换

 

IDA提供的代码转换包括:

1.将数据转换为代码

2.将代码转换为数据

3.指定一个指令序列为函数

4.更改现有函数的起始或结束地址

5.更改指令操作数的显示格式

代码显示选项

通过 Options -> General 命令打开“IDA Options”对话框,并选择“Disassembly”选项卡

img

右上角的 Display disassembly line parts(显示反汇编行部分)区域提供的选项,可以对反汇编行进行自定义

IDA 反汇编文本视图会默认选择行前缀、注释和可重复注释

Line prefixes 为行前缀,行前缀是每个反汇编行的 section:address 部分

如果不选这个选项,每个反汇编行将不会显示行前缀(图形视图的默认设置)

Stack Pointer 为栈指针

选择该选项,IDA 将会显示栈指针在每个函数执行过程中的相对变化

这有助于识别调用约定方面的差异(例如,IDA 可能不知道某个特殊的函数使用的是 stdcall 调用约定),或者确定对栈指针的不寻常操纵

Comments 为注释,Repeatable comments 为可重复注释

取消任何一个选项,IDA 将不会显示相应类型的注释

Auto comments 为自动注释

IDA 可能会为某些指令类型自动添加注释,这种注释可以作为一种提醒,以帮助用户了解特殊指令的行为

IDA 不会为 x86 mov 等简单的指令添加注释

用户注释优先于自动注释

Bad instructions marks 为无效指令 标记

IDA 可以标记出处理器认为合法,但一些汇编器可能无法识别的指令,如未记入文档的 CPU 指令(而非非法指令)

IDA 会将这种指令作为一个数据字节序列进行反汇编,并将未记入文档的指令显示为一段以 开头的注释,目的是生成大多数汇编程序都可以处理的反汇编代码

Numbers of opcode bytes 为操作码字节数

指定 IDA 应为每个指令显示的机器语言字节的数量,选择性地查看与汇编语言指令混杂在一起的机器语言字节

不管指令多长,IDA 都会在反汇编代码清单中为指定的字节数预留显示空间,而将反汇编代码行的剩余部分移向右边,从而为指定的操作码字节数提供空间

img

+ 号表示:根据当前设置,该位置的指令过长,因而无法完整显示

格式化指令操作数

右击反汇编窗口中的任何常量

img

菜单提供的选项可将常量 41h 重新格式化成十进制、八进制或二进制值

常量 41h 属于 ASCII 可打印常量,菜单中还提供了一个选项,可将该常量格式化成一个字符常量,快捷键为 R

常量可能是使用了 #define 语句(或其等效语句)的结果,也可能属于一组枚举常量

如果编译器已经完成对源代码的编译,它就不再可能确定源代码使用的是符号常量、文字常量还是数字常量

可以通过常量值的上下文菜单中的 Use standard symbolic constant(使用标准符号常量)选项来访问这些常量

img

快捷键为 M

img

这是所有 IDA 认为与 0AH 相等的常量

根据我们尝试格式化的常量值进行过滤后,这个对话框中的常量从IDA的内部常量列表导入

标准常量列表可用于确定某个特殊的常量是否与一个已知的名称有关,使我们免于在 API 文档中搜索潜在的匹配项

数据与代码互相转换

数据字节可能被错误地归类为代码字节,并被反汇编成指令

代码字节可能被错误地归类为数据字节,并被格式化成数据值

对反汇编代码重新格式化之前,首先必须删除其当前的格式(代码或数据)

右击想要取消定义的项目,选择 Undefine,即可取消函数、代码或数据的定义,快捷键为 U

img

可以使用 Edit -> Undefine

img

取消某个项目的定义后,其基础字节将作为原始字节值重新格式化

在执行取消定义操作之前,使用“单击并拖动”操作选择一个地址范围,可以取消大范围内的定义

img

取消这个函数的定义将得到下面这些未分类的字节 img

要反汇编一组未定义的字节,右击其中的第一个字节,在菜单中选择 Code,快捷键为 C,也可以使用 Edit -> Code

可以使用 Edit -> Data 将代码转换为数据,快捷键为 D

 

IDA Pro 权威指南学习笔记(十四) - 操纵函数

 

IDA 无法定位一个函数调用,由于没有直接的方法到达函数,IDA 将无法识别它们

IDA 可能无法正确确定函数的结束部分,需要手动干预,以更正反汇编代码中的错误

如果编译器已经将函数分割到几个地址范围,或者在优化代码的过程中,编译器为节省空间,将两个或几个函数的共同结束序列合并在一起,这时 IDA 同样无法确定函数的结束部分

新建函数

在某些情况下,可以在没有函数的地方创建新函数

新函数可以由已经不属于某个函数的现有指令创建,或者由尚未被 IDA 以任何其他方式定义(如双字或字符串)的原始数据字节创建

将光标放在将要包含在新函数中的第一个字节或指令上,然后选择 Edit -> Functions -> Create Function,即可创建一个新函数,快捷键为 Alt+P

在必要时,IDA 会将数据转换成代码

接下来,它会向前扫描,分析函数的结构,并搜索返回语句

如果 IDA 能够找到正确的函数结束部分,它将生成一个新的函数名,分析栈帧,并以函数的形式重组代码

如果它无法找到函数的结束部分,或者发现任何非法指令,则这个操作将以失败告终

删除函数

可以使用 Edit -> Functions -> Delete Function 命令删除现有函数

img

点 Yes,当前函数将被删除

img

点击 Yes 后

img

函数块

在由 Microsoft Visual C++ 编译器生成的代码中,经常可以找到函数块

编译器移动不常执行的代码段,用以将经常执行的代码段“挤入”不大可能被换出的内存页,由此便产生了函数块

如果一个函数以这种方式被分割,IDA 会通过跟踪指向每个块的跳转,尝试定位所有相关的块

多数情况下,IDA 都能找到所有这些块,并在函数的头部列出每一个块

img

有时候,IDA 可能无法确定与函数关联的每一个块,或者函数可能被错误地识别成函数块,而非函数本身

在这种情况下,需要创建自己的函数块,或删除现有的函数块

在反汇编代码清单中,函数块就叫做函数块;在 IDA 的菜单系统中,函数块叫做函数尾(function tail)

要删除现有的函数块,将光标放在要删除的块中的任何一行上,然后选择 Edit -> Functions -> Remove Function Tail

在初次将文件加载到 IDA 时,取消选择 Create function tails 加载器选项,IDA 将不创建函数块

如果禁用了函数尾,已经包含函数尾的函数将包含指向函数边界以外区域的跳转,IDA 会在反汇编代码清单左侧的箭头窗口中用红线和箭头突出显示这些跳转

函数特性

IDA 为它识别的每一个函数提供许多特性

函数属性对话框可用于编辑其中的某些特性

img

Name of function 为函数名称,提供另外一种更改函数名称的方法

Start address 为起始地址,函数中第一条指令的地址

通常,IDA 会在分析过程中,或根据创建函数时所使用的地址,自动识别这个地址

End address 为结束地址,函数中最后一条指令之后的地址

通常,它是函数的返回语句之后的指令的地址

这个地址并不是函数的一部分,而是函数的最后一条指令之后的地址

Local variables area 为局部变量区,函数的局部变量(如下图)专用的栈字节数

img

多数情况下,IDA 会通过分析函数的栈指针的行为,自动计算出这个值

Save registers 为保存的寄存器

为调用方保存寄存器(如上图)所使用的字节数,IDA 认为保存的寄存器区域放在保存的返回地址顶部、与函数有关的所有局部变量的下方

一些编译器选择将寄存器保存在函数局部变量的顶部

IDA 认为保存这些寄存器所使用的空间属于局部变量区域,而非保存的寄存器区域

Purged bytes 为已删除字节

已删除字节表示当函数返回调用方时,IDA 从栈中删除的参数的字节数

对 cdecl 函数而言,这个值始终为0

对 stdcall 函数来说,这个值表示传递到栈上的所有参数占用的空间

在 x86 程序中,如果 IDA 观察到程序使用了返回指令的 RET N 变体,它将自动确定这个值

Frame pointer delta 为帧指针增量

有时候,编译器可能会对函数的帧指针进行调整,使其指向局部变量区域的中间,而不是指向保存在局部变量区域底部的帧指针

调整后的帧指针到保存的帧指针之间的这段距离叫做帧指针增量

多数情况下,IDA 会在分析函数的过程中自动计算出帧指针增量

使用增量的目的,是在离帧指针 1 字节(带符号)的偏移量(-128 ~ +127)内保存尽可能多的栈帧变量

复选框为 IDA 自动分析得到的结果,以下是可启用也可禁用的属性

Does not return 为不返回,函数不返回到它的调用方

如果调用这样的函数,在相关的调用指令之后,IDA 认为函数不会继续执行

Far function 为远函数

这个属性用于在分段体系结构上将一个函数标记为远函数

在调用该函数时,函数的调用方需要指定一个段和一个偏移值

是否使用远调用,应由程序中使用的内存模式决定

Library func 为库函数

这个属性将一个函数标记为库代码

库代码可能包括静态链接库中的编译器或函数所包含的支持例程

将一个函数标记为库函数后,该函数将以分配给库函数的颜色显示,从而与非库代码区分开来

Static func 为静态函数,静态函数只在函数的特性列表中显示静态修饰符

BP based frame 为基于BP的帧

这个特性表示函数利用了一个帧指针

如果选择了这个特性,一定要相应地调整保存的寄存器的大小(通常指根据保存的帧指针的大小增大)和局部变量的大小(通常指根据保存的帧指针的大小减少)

对基于帧指针的帧而言,使用帧指针的内存引用被格式化,以利用符号栈变量名称,而非数字偏移量

如果没有设置这个特性,则认为栈帧引用与栈指针寄存器有关

BP equals to SP 为 BP 等于 SP

它的作用等同于将帧指针增量的大小设置为等于局部变量区域

一些函数将帧指针配置为在进入一个函数时指向栈帧(以及栈指针)的顶端,这时候需要设置该属性

栈指针调整

IDA 会尽其所能跟踪函数内每一条指令上的栈指针的变化

如果 IDA 无法确定一条指令是否更改了栈指针,就需要手动调整栈指针

如果一个函数调用了另一个使用 stdcall 调用约定的函数,就会出现上述情况,这是最简单的一种情况

如果被调用的函数位于 IDA 无法识别的共享库中,IDA 不知道该函数使用了 stdcall 调用约定,也就无法认识到:被调用的函数会将栈指针修改后返回

进行栈调整,首先选中进行调整的地址,选择 Edit -> Functions -> Change Stack Pointer(快捷键为 Alt+K),然后指定栈指针更改的字节数