x86-x64汇编语言、反汇编知识和IDA

x86-x64汇编语言

基础知识

x86寄存器:
通用寄存器:EAX, EBX, ECX, EDX, ESI, EDI
栈顶指针寄存器:ESP
栈底指针寄存器:EBP
指令计数器:EIP
段寄存器:CS, DS, ES, FS, GS, SS

x86-64寄存器:(把E改成R)
通用寄存器:RAX, RBX, RCX, RDX, RSI, RDI,R8-R15
栈顶指针寄存器:RSP
栈底指针寄存器:RBP
指令计数器:RIP
段寄存器:CS, DS, ES, FS, GS, SS

16位寄存器:(把E或R删了)
通用寄存器:AX, BX, CX, DX, SI, DI
栈顶指针寄存器:SP
栈底指针寄存器:BP
指令计数器:IP
段寄存器:CS, DS, ES, FS, GS, SS

通用寄存器:

EAX: Extended Accumulator Register (扩展累加器)
EBX: Extended Base Register (扩展基址寄存器)
ECX: Extended Counter Register (扩展计数器)
EDX: Extended Data Register (扩展数据寄存器)
ESI: Extended Source Index (扩展源索引)
EDI: Extended Destination Index (扩展目的索引)
栈顶指针寄存器:

ESP:Extended Stack Pointer (扩展栈指针)
栈底指针寄存器:

EBP:Extended Base Pointer (扩展基址指针)
指令计数器:

EIP:Extended Instruction Pointer (扩展指令指针)
段寄存器:

CS: Code Segment (代码段)
DS: Data Segment (数据段)
ES: Extra Segment (附加段)
FS: Extra Segment (F segment) (附加段F)
GS: Extra Segment (G segment) (附加段G)
SS: Stack Segment (栈段)

我们熟知的x86和x64是两种处理器架构:x86代表的是32位机器,而x64则是64位机器。这两种架构主要由Intel和AMD(而非AT&1)所发展,并且这两种架构都拥有自己的显示和书写风格。此处,我们将讲述的是Intel风格。

新的概念:机器码、汇编语言。

首先来说一下机器码:机器码是在CPU上直接执行的二进制指令,它是计算机可以直接识别和执行的最基本的语言。

再来说一下汇编语言:汇编语言是机器语言的助记符,每一个汇编指令都对应到一条或者几条机器码,它们之间是一一对应的关系,在可读性上更符合人的认知。

机器码和汇编指令都是依赖于特定CPU架构的,不同的CPU架构会有不同的指令集。当我们在进行CTF比赛或者进行其他计算机相关的任务时,最常见的CPU架构就是x86和x86-64(即x64)。

X86和x86-64的基本汇编知识

基本汇编指令的基本格式:操作码 操作数1 操作数2

操作数的存在与否及形式由操作码的类型决定

我们需要了解下面的一张表格,熟悉的记住这个内容

1.指令: 这一列会包含一些基本的X86和x86-64汇编指令,例如MOV(移动), ADD(加), SUB(减), MUL(乘), DIV(除)等。

2.描述: 这一列将详细介绍每个指令的基本功能和作用。

3.操作码/操作数1/操作数2格式: 这一列详细描述了每个指令的操作码和操作数的格式,以帮助你理解如何使用和编写这些指令。

4.示例: 这是一个示例列,它包含实际的指令例子,以帮助理解如何在实际问题中使用这些指令。

举例如下:

指令 描述 操作码/操作数1/操作数2格式 示例
MOV 这个指令用于传送数据。 MOV dest, src MOV AX, 10
ADD 这个指令用于对两个操作数进行相加。 ADD operand1, operand2 ADD AX, BX
SUB 这个指令用于对两个操作数进行相减。 SUB operand1, operand2 SUB AX, BX
MUL 该指令用于将两个操作数相乘。 MUL operand MUL AX
DIV 该指令用于将一个操作数除以另一个操作数。 DIV operand DIV AX

操作码

操作码 指令示例 指令类型 对应作用
mov mov rax, rbx 数据传送指令 rax = rbx
mov mov qword [rdi], rax 数据传送指令 将rax的内容放在rdi所指向的内存地址中
lea lea rax, [rsi] 取地址指令 rax = &(rsi 的值)
add add qword [rdi], rax 算数运算指令 *(rdi) += rax
add add rax, rbx 算数运算指令 rax += rbx
sub sub rax, rbx 算数运算指令 rax -= rbx
and and rax, rbx 逻辑运算指令 rax &= rbx
xor xor rax, rbx 逻辑运算指令 rax ^= rbx
call call 0x401000 函数调用指令 执行0x401000地址处的函数
ret ret 函数返回指令 结束当前函数并返回
cmp cmp rax, rbx 比较指令 根据rax与rbx的比较结果设定标志位
jmp jmp 0x401000 无条件跳转指令 程序调到0x401000地址处执行
push push rax 栈操作指令 将rax的值压入栈中
pop pop rax 栈操作指令 从栈顶弹出一个元素放入rax

反汇编知识和IDA

可执行文件的编译都是通过相应的语言编译到汇编语言再编译到机器语言的。汇编语言和机器语言是一一对应的。 机器语言可以反汇编到机器语言。 同样的,我们的C语言也是用翻译器将C代码翻译为汇编,最后编译为机器语言,所以我们也可以使用汇编代码进行反编译为高级语言,但是通常我们称之为伪代码

C 语言→DeVH→汇编→可执行文件→pe(exe、dll)

线性扫描反汇编算法
递归下降反汇编算法
 

C++的调用约定

_cdecl、_stdcall、thiscall、和_fastcall。以下是这些调用约定的基础知识解析:

  1. _cdecl: 这是C/C++的默认函数调用约定。在这种调用约定下,函数参数从右向左依次压入栈。由调用者负责清理堆栈,通常用于变参函数。函数返回值将存储在EAX寄存器中。

  2. _stdcall: 存在于Windows编程的DLL中。参数与_cdecl一样,从右往左依次压栈。不同的是,被调用函数自身负责清理堆栈。Windows API就使用了这种调用约定。

  3. thiscall: 这是为C++的类成员函数制定的调用约定。与前两者的主要区别在于,它会将this指针作为一个隐含的参数。通常,this指针通过ECX寄存器传递。

  4. _fastcall: 这种调用约定会尽可能的利用寄存器传递函数参数,而不是完全依赖堆栈。在32-bit x86架构中,前两个参数会被放在edx和eax寄存器中,剩余的参数则是按照从右往左的顺序被压入堆栈。函数的返回值存储在EAX寄存器中。

x86-64架构下的函数调用约定

参数的传递方式会因操作系统和编译器的不同而不同

  1. Microsoft x64 calling convention(微软x64调用约定): 这是在Windows下使用的调用约定。前四个参数分别通过寄存器RCX、RDX、R8和R9传递,如果有更多的参数,它们会按照从右到左的顺序压入栈中。与其他机器字大小相关的操作一样,如果参数的大小小于8字节(64位),它会在复制到寄存器或推入堆栈之前扩展到8字节。函数的返回值存储在RAX中。

  2. System V AMD64 ABI(System V x64调用约定): 这是Linux和macOS等Unix-like操作系统下采用的调用约定。前六个整型或指针类型的参数通过寄存器RDI、RSI、RDX、RCX、R8和R9传递,浮点参数通过XMM寄存器传递。更多的参数将会被压入栈中。函数的返回值存储在RAX或者XMM0中。

内存管理中常用的两种数据结构

堆和栈。这两种数据结构在C++编程或许多其他编程语言中都有使用。它们的主要区别是他们的内存分配和生命周期管理方式。

  1. 栈: 栈内存是由编译器自动管理的。局部变量,函数参数,返回值都保存在栈中。栈是具有 "Last In, First Out"(LIFO)特性的数据结构,也就是先进后出。当你在函数中创建一个局部变量时,变量将被压入栈顶;当函数执行结束后,这些局部变量将被自动弹出。因此,栈上分配的内存无需程序员手动管理。

  2. 堆: 堆是用于动态内存分配的区域,并且其大小不固定。当你使用C++的new操作符或C语言的malloc函数时,这些操作将会在堆上分配内存。与栈不同,你需手动管理堆上的内存。当你在堆中分配内存后,需要在程序结束或不再使用该片内存时,显式地使用delete或free将其释放掉,否则可能造成内存泄漏。

把栈比作一个垃圾桶,你可以往里扔东西,但随后,你必须将这些东西按照一定的顺序拿出来,而且这个过程是自动的;把堆比作垃圾堆,你可以在任何地方随意丢东西,但你需要明确地记住,何时放入的东西,何时去收拾掉,否则它就会永远占据那个位置。

栈指针

"栈指针"是一个用于跟踪当前栈顶位置的指针。在许多硬件架构和操作系统中,栈指针是一个特殊的寄存器,也称为"堆栈指针"或"栈针"。

对于x86和x86-64架构,栈指针由"ESP"(扩展堆栈指针)寄存器在32位模式下管理,由"RSP"(寄存器堆栈指针)寄存器在64位模式下管理。

这个指针永远指向栈顶。每当压入或者弹出一个元素时,栈指针都会相应地移动。栈指针是实现函数调用、参数传递以及局部变量存储等操作的关键。

需要注意的是,栈是向下增长的,也就是说,当你向栈中添加一个新元素时,栈指针将会减小(假设地址空间从上到下排列),反之,当从栈中移除一个元素,栈指针将会增大。

反汇编器和调试器工具

  1. IDA Pro(Interactive DisAssembler): IDA Pro是一款高级的,交互式,多处理器的反汇编器。它可用于反汇编、浏览和分析二进制程序的结构和代码。IDA Pro广泛应用于软件安全和二进制分析领域。

  2. OllyDbg: OllyDbg是一个Windows平台下的32位汇编级别调试器,对于软件调试和逆向分析都非常有用。它的用户接口直观,功能强大,且免费。

  3. x64dbg: x64dbg是一个开源的64位(兼容32位)分析器和调试器,用于Windows。它具有用户友好的界面和丰富的功能,例如内存查找、插件支持以及图形反汇编等。

  4. GNU Binary Utilities(Binutils): Binutils是一套开源的二进制工具集,包含了一系列用于处理二进制文件的程序,例如ld链接器、as汇编器和objdump反汇编器等。这些工具在Linux系统中发挥着重要作用。

  5. GDB(GNU Debugger): GDB是GNU项目的官方调试器,用于调试各种编程语言(如C、C++和FORTRAN等)编写的程序。GDB提供了控制程序执行的丰富功能,例如设置断点、查看内存和寄存器状态、追踪和控制线程等。

一些二进制工具

在《IDA pro权威指南》的开篇一两章中,先是介绍了几款常用于二进制研究的工具,我这里简单的记了几个,介绍一波:

C++filt: 可以用于显示出c++中复杂的重载后的函数名称

PE tools: 是一组用于分析Windows系统中正在运行的进程和可执行文件的工具

string: 可以用于直接搜索出elf文件中的所有字符串 参数-a 表示搜索整个文件,参数-t 可以显示出每一个字符串的偏移,参数-e 可以用于搜索更多的字符编码的字符串,如Unicode编码

strip:

可用于elf去符号,去符号后仍然保持正常功能但增加了逆向的难度,出题恶人必备

开发了IDA的天才是Ilfak,他的个人博客有很多IDA的教程 Hex-Rays Blog – Hex Rays

IDA目录结构

在IDA的安装根目录下有许多文件夹,各个文件夹存储不同的内容

cfg:包含各种配置文件,基本IDA配置文件ida.cfg,GUI配置文件idagui.cfg,文本模式用户界面配置文件idatui.cfg, idc:包含IDA内置脚本语言IDC所需要的核心文件 ids:包含一些符号文件 loaders:包含用于识别和解析PE或者ELF plugins:附加的插件模块 procs:包含处理器模块

常用快捷键

IDA中的快捷键都是和菜单栏的各个功能选项一一对应的,基本上你只要能在菜单栏上找到某个功能,也就能看到相应的快捷键,这里记录几个常用的:

a:将数据转换为字符串

f5:一键反汇编

esc:回退键,能够倒回上一部操作的视图(只有在反汇编窗口才是这个作用,如果是在其他窗口按下esc,会关闭该窗口)

shift+f12:可以打开string窗口,一键找出所有的字符串,右击setup,还能对窗口的属性进行设置

ctrl+w:保存ida数据库

ctrl+s:选择某个数据段,直接进行跳转

ctrl+鼠标滚轮:能够调节流程视图的大小

x:对着某个函数、变量按该快捷键,可以查看它的交叉引用

g:直接跳转到某个地址

n:更改变量的名称

y:更改变量的类型

/ :在反编译后伪代码的界面中写下注释

:在反编译后伪代码的界面中隐藏/显示变量和函数的类型描述,有时候变量特别多的时候隐藏掉类型描述看起来会轻松很多

;:在反汇编后的界面中写下注释

ctrl+shift+w:拍摄IDA快照

u:undefine,取消定义函数、代码、数据的定义

常用设置

拍摄快照

由于IDA不提供撤销的功能,如果你不小心按到某个键,导致ida数据库发生了改变,就得重新来过,所以要记得在经常操作的时候,加上快照:file-->take database snapshot 加完快照后,会生成一个新的ida数据库文件,本质上是有点像另存的操作

快捷键:ctrl+shift+w

菜单栏常用设置

view-->open subviews: 可以恢复你无意中关闭的数据显示窗口

windows-->reset desktop: 可以恢复初始ida布局

option-->font: 可以改变字体的相关属性

在流程视图中添加地址偏移

IDA中的流程视图可以说是非常的好用,简单明了地能看出程序的执行流程,尤其是在看if分支代码和循环代码的时候,能够非常直观

image-20240120122219119

但是,我们还可以改得更加好用,在这个视图中添加地址偏移的话,我们取地址就非常方便,不再需要按空格切换视图去找,在菜单栏中设置:option-->general

image-20240120122240502

将该选项打钩后就可以看到效果了:

image-20240120122306806

自动添加反汇编注释

这个功能对于萌新来说非常友好,在刚刚初学汇编的时候, 难免遇到几个不常用的蛇皮汇编指令,就得自己一个个去查,很麻烦,开启了自动注释的功能后,IDA就可以直接告诉你汇编指令的意思

同样是在菜单栏中设置:option-->general(自动注释 auto comment)

image-20240120122423412

效果如下:

image-20240120122449466

常用操作

创建数组

在操作IDA的时候,经常会遇到需要创建数组的情况,尤其是为了能方便我们看字符串的时候,创建数组显得非常必要,以下我随便找了个数据来创建数组

首先点击选中你想要转换成数组的一块区域:

image-20240120122506473

接着在菜单栏中选择:edit-->array,就会弹出如下的选项框

image-20240120122519977

下面来解释一下各个参数的意思:

Array element size 这个值表示各数组元素的大小(这里是1个字节),是根据你选中的数据值的大小所决定的

Maximum possible size 这个值是由自动计算得出的,他表示数组中的元素的可能的最大值

Array size 表示数组元素的数量,一般都根据你选定的自动产生默认值

Items on a line 这个表示指定每个反汇编行显示的元素数量,它可以减少显示数组所需的空间

Element print width 这个值用于格式化,当一行显示多个项目时,他控制列宽

Use “dup” construct :使用重复结构,这个选项可以使得相同的数据值合并起来,用一个重复说明符组合成一项

Signed elements 表示将数据显示为有符号数还是无符号数

Display indexes 显示索引,使得数组索引以常规的形式显示,如果选了这个选项,还会启动右边的Indexes选项栏,用于选择索引的显示格式

Create as array 创建为数组,这个一般默认选上的

创建好了以后,就变成了这样:

image-20240120122531157

可以看到这些数据已经被当成一个数组折叠到了一起,其中2 dup(0FFh)这样的,表示有两个重复的数据0xff

流程图

折叠流程图中的分支

在流程视图中,分支过多的时候,可以在窗口标题处右击选择group nodes,就能把当前块折叠起来

image-20240120122546216

效果如下:

image-20240120122602678

分支块是可以自己命名的,方便自己逆向理解

函数调用图

菜单栏中:view-->graphs-->Function calls(快捷键Ctrl+F12)

image-20240120122612419

这个图能很清楚地看到函数之间是如何相互调用的

函数流程图

菜单栏中:view-->graphs-->flowt chart(快捷键F12)

image-20240120122623623

这个其实跟IDA自带的反汇编流程视图差不多,他可以导出来作为单独的一张图

创建结构体:

手工创建结构体

创建结构体是在IDA的structures窗口中进行的,这个操作在堆漏洞的pwn题中经常使用

image-20240120122636517

可以看到,这里已经存在了四个结构体,程序本身存在的,可以右击选择hide/unhide,来看具体的结构体的内容

image-20240120122645343

创建结构体的快捷键是:insert

image-20240120122654273

在弹出的窗口中,可以编辑结构体的名字

这底下有三个复选框,第一个表示显示在当前结构体之前(就会排列在第一位,否则排列在你鼠标选定的位置),第二个表示是否在窗口中显示新的结构体,第三个表示是否创建联合体。

需要注意的是,结构体的大小是它所包含的字段大小的总和,而联合体的大小则等于其中最大字段的大小

在单击ok以后,就定好了一个空的结构体:

image-20240120122731761

将鼠标放在 ends这一行,单击快捷键D即可添加结构体成员,成员的命名默认是以field_x表示的,x代表了该成员在结构体中的偏移

image-20240120122743591

同时,可以把鼠标放在结构体成员所在的行,按D,就可以切换不同的字节大小

默认情况下可供选择的就只有db,dw,dd(1,2,4字节大小)

如果想添加型的类型,可以在option-->setup data types(快捷键Alt+D),进行设置

image-20240120122755747

如图,勾选了第五个和第九个的话,就会出现dq和xmmword了(代表了8字节和16字节)

image-20240120122808204

如果要添加数组成员则可以对着成员所在的那一行,右击选择array

image-20240120122817695

如图,要创建的是16个元素的4字节数组

如果要删除结构体,那么对着结构体按下delete键即可删除

如果要删除成员,则对着成员按下u(undefine)但是需要注意的是,这里只是删除了成员的名字,而没有删除它所分配的空间

如图,我们删除了中间的field_10的数组成员:

image-20240120122854391

会变成这样:

image-20240120122900799

数组所分配的20个字节的空间并没有被删除,这时如果要删除掉这些空间,就需要在原来数组成员所在的第一行中按下Ctrl+S,删除空间(Edit-->shrink struct types)

就可以真正的删除掉成员

给结构体的成员重命名可以用快捷键N

我们在IDA中创建好了结构体以后,就是去应用它了

如图,这是一个典型的堆的题目

image-20240120122918469

可以看到v1是一个新建的chunk的地址指针,而后的操作都是往chunk不同的偏移位置写入内容,为了方便我们逆向观察,可以将其变成一个结构体,通过v1 v1+4 v1+0x48 这样的偏移,创建好结构体后,将char *v1的类型改成mail *v1,(快捷键Y可以更改函数、变量的类型和参数)这个mail是我们创建的结构体的名称,效果如下:

image-20240120122934509

导入C语言声明的结构体

实际上,IDA有提供一个更方便的创建结构体的方法,就是直接写代码导入

在View-->Open Subviews-->Local Types中可以看到本地已有的结构体,在该窗口中右击insert

可以添加新的结构体:

image-20240120122946273

这样就导入了新的结构体:

image-20240120122955368

但同时我们发现structure视图里面,并没有这个结构体,我们需要对着my_structure右击,选择 synchronize to idb

这样structure视图就有了,如图

image-20240120123007989

这里你会发现,多出来两个db的undefined的成员,这是因为ida默认是会把结构体统一4字节对齐的,满足结构体的大小为0x28

IDA动态调试elf:

这里我以一个在Ubuntu虚拟机中的elf为例子,进行调试

首先把ida目录中的dbgsrv文件夹中的linux_server64拷贝到Ubuntu的elf的文件夹下,这个elf是64位的所有用的是linux_server64,如果你调试的是32位的程序,你就需要拷贝linux_server

记得给他们权限,然后在终端运行,这个程序的作用就像是连接ida和虚拟机中elf的桥梁

image-20240120123017921

然后再到ida中进行配置:

在菜单栏中选择:debugger-->process options

image-20240120123025676

注意,application和input file 都是填写在虚拟机中的elf的路径,记得要加文件名

而directory 填写elf所在目录,不用加文件名

hostname是虚拟机的ip地址,port是默认的连接端口

parameter和password一般都不用填

设置好了以后点击ok

接着可以直接在反汇编视图中下断点,只要点击左边的小蓝点即可

image-20240120123041403

这时按下快捷键F9,可以直接开始调试

按下快捷键F4,则直接运行到断点处停下

image-20240120123055766

这个就是基本的各个功能区的介绍,上面是我比较喜欢的常用布局,和ida默认的不太一样,想要自定义添加一些视图的话,可以在debugger-->quick debug view中添加

另外可以在Windows-->save desktop来保持当前的视图布局,以后就可以直接加载使用

下面介绍一些常用的快捷键

F7 单步步入,遇到函数,将进入函数代码内部 F8 单步步过,执行下一条指令,不进入函数代码内部 F4 运行到光标处(断点处) F9 继续运行 CTRL+F2 终止一个正在运行的调试进程 CTRL+F7 运行至返回,直到遇到RETN(或断点)时才停止.

知道了这些快捷键后,调试起来就比较容易了,ida调试有个比较方便的地方在于能直接看到函数的真实地址,下断点也非常直观易操作

IDA-python

在IDA的最下面有个不起眼的Output Window的界面,其实是一个终端界面,这里有python终端和IDC终端

image-20240120123154738

这里的python是3.8.10(ida 7.7版本)的版本,虽然老了点,但已经足够我们用了,在IDA的运用中,我们经常需要计算地址,计算偏移,就可以直接在这个终端界面进行操作,非常方便


当然上面说的只是很简单的python用法,真正的IDA-python的用法是这样的:

这里以简单的一道逆向题来做个例子

image-20240120123320952

这个程序很简单,一开始来个for循环,把judge函数的内容全部异或0xc,这样就导致了程序一运行就会直接破坏掉judge函数

image-20240120123335892

从而使得没法进行后面的flag判断

这里我们就需要写一个脚本来先把被破坏的内容还原,这里IDA提供了两种写脚本操作的方法,一种就是IDC脚本,一种就是python脚本

这里只简单的介绍IDA-python

而IDA-python通过三个python模块将python代码注入IDA中:

idaapi模块负责访问核心IDA API

idc模块负责提供IDA中的所有函数功能

idautils模块负责提供大量实用函数,其中许多函数可以生成各种数据库相关对象的python列表

所有的IDApython脚本会自动导入idc和idautils模块,而idaapi模块得自己去导入

这里贴上IDApython的官方函数文档,这里包含了所有函数,值得一看

针对以上的题目,我们只需要做一个脚本,指定judg函数的0-181范围的字节异或0xc,即可恢复

judge=0x600B00
for i in range(182):
    addr=0x600B00+i
    byte=get_bytes(addr,1)#获取指定地址的指定字节数
    byte=ord(byte)^0xC
    patch_byte(addr,byte)#打patch修改字节

在菜单栏中file-->script file,加载python脚本

接着在judge函数中undefined掉原来的函数,在重新生成函数(快捷键p),就可以重新f5了 脚本中出现的函数都是已经封装在idc模块中的,具体可查官方文档

image-20240120123410825

这只是一个简单的IDApython的使用例子,实际上这个功能非常强大,能弄出非常骚的操作

打PATCH

打patch,其实就是给程序打补丁,本质上是修改程序的数据,指令等,这在CTF中的AWD赛制中经常用到,发现程序漏洞后马上就要用这个功能给程序打好patch,防止其他队伍攻击我们的gamebox

这里,我是用一个叫keypatch的插件进行操作的,IDA自带的patch功能不太好用

安装keypatch

这个很简单,教程在github就有

下载Keypatch.py复制到插件目录

IDA 7.0pluginsKeypatch.py

下载安装keystone python模块,64位系统只需要安装这一个就行

https://github.com/keystone-engine/keystone/releases/download/0.9.1/keystone-0.9.1-python-win64.msi

安装好后,你就会发现这里有个keypatch的选项

image-20240120123431554

修改程序指令

如果我们要修改程序本身的指令,怎么做呢

image-20240120123442573

如图,我们要修改63h这个值

将鼠标指向改行,按快捷键Ctrl+Alt+K

image-20240120123450718

直接输入汇编语句即可修改,打好patch后效果如图:

image-20240120123459499

这里会生成注释告诉你,这里打过patch,非常人性化

接着还要在菜单栏进行设置才能真正使得patch生效

image-20240120123513086

这样一来,原来的程序就已经被修改了

撤销patch

如果不小心打错了patch,就可以在这里进行撤销上一次patch的操作了

image-20240120123527615

但是如果打了很多次patch,不好分清该撤销哪一次的patch,那么可以在菜单栏中打开patched bytes界面

image-20240120123541464

看到所有的patch,要撤销哪一个就右击选择 revert

image-20240120123554560

IDA导出数据文件

在菜单栏中,这里有个选项可以生成各种不同的输出文件

image-20240120123602770

这里简单的介绍前两个文件,后面的大家可以自己去生成测试一下用途,我这里就不详细介绍了

.map文件描述二进制文件的总体结构,包括与构成改二进制文件的节有关的信息,以及每个节中符号的位置。

.asm文件,也就是汇编了,直接能导出ida中反汇编的结果,这个非常实用,有的时候在逆向中经常遇到大量数据加解密的情况,如果在从IDA中一个个慢慢复制可就太没效率了,直接导出生成asm,在里面复制数据快很多

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反编译报错

目前来说, 我遇到的反编译报错的情况,一般是两种

  • 一是由于程序存在动态加密,导致程序的某些代码段被修改,从而反编译出错,这种情况,就需要去使用IDA-python解密一波,再进行F5反汇编

  • 二是由于某些玄学问题,直接提示了某个地方出错,一般来说,就按照IDA的提示,去进行修改

    比如,出现如下报错:

image-20240120123626252

那我们就去找413238这个地址的地方,提示是说sp指针的值没有被找到,说明是这里出错了,那么就去修改sp的值,修改方法如下:

image-20240120123639796

也可以使用快捷键 Alt+K

有的时候,遇到的这种报错

image-20240120123650703

就尝试着把报错的地址的汇编语句改一哈,改成nop,就可以解决问题

目前来说,我遇到报错的情况不多,一般都可以通过以上方法解决

配置IDA

在ida的根目录的cfg文件夹是专门用来存储配置文件的

ida的主配置文件为ida.cfg,另外的还有idagui.cfg,idatui.cfg这两个配置文件对应IDA的GUI配置和文本模式的版本

一、ida.cfg

该文件包含了option-->general中的所有选项的配置,可以通过选项中的描述在配置文件总找到相应的选项

这里举几个例子:

SHOW_AUTOCOMMENTS 表示是否自动生成汇编指令的注释

GRAPH_SHOW_LINEPREFIXES 表示是否在流程控制视图中显示地址

VPAGESIZE 表示内存调整参数,当处理非常大的输入文件时,IDA可能报告内存不足而无法创建新数据库,在这种情况下增大该参数,重新打开输入文件即可解决问题

OPCODE_BYTES 表示要显示的操作码字节数的默认值

INDENTATION 表示指令缩进的距离

NameChars 表示IDA支持的变量命令使用的字符集,默认是数字+字母还有几个特殊符号,如果需要添加就改变该参数

二、idagui.cfg

这个文件主要配置默认的GUI行为,键盘的快捷键等,这个很少需要修改,不做过多介绍。感兴趣的可以自己打开该文件观察,并不难懂,改改快捷键还是很容易的

三、idatui.cfg

这个似乎更加不常用。。。不多说了

需要注意的是,以上三个文件是默认配置,也就是说,每次打开创建新的ida数据库的时候,都会以这三个配置文件的设置进行创建,之前临时在菜单栏的设置就会消失,要永久设置ida的配置,就改这三个文件

但,凡是都有例外,在option-->font和option-->colors这两个选项是全局选项,修改一次就永久生效的,不用在以上三个配置文件中改