这一部分主要是粗略阅读IdaPro权威指南
的阅读笔记
主要记录一些使用idaPro
的一些技巧
以及重点会放在ida python
脚本的编写
以及idc
ida基本常识
ida 目录结构
-
IDA 的任务是将选定的可执行文件加载到内存中,并对相关部分进行分析。随后,IDA 会创建一个数据库,其组件分别保存在4 个文件中,这些文件的名称与选定的可执行文件的名称相同,扩展名分别为.id0 、.id1 、.nam 和.til。.id0 文件是一个二叉树形式的数据库,.id1 文件包含描述每个程序字节的标记。.nam 文件包含与IDA 的Names 窗口(将在第 5 章详细介绍)中显示的给定程序位置有关的索引信息。最后,.til文件用于存储与一个给定数据库的本地类型定义有关的信息。这些文件的格式为 IDA 专用,在 IDA 环境以外很难对它们编辑。
为了方便,在你关闭当前项目时,这4 个文件将被存档,你还可以选择将它们压缩成一个IDB文件。
-
在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,取消定义函数、代码、数据的定义
使用技巧
流程图添加地址偏移
想在流程图中添加地址偏移的话,我们取地址就非常方便,不再需要按空格切换视图去找,在菜单栏中设置:option–>general
创建数组
选中想要转换成数组的一块区域
然后Edit->Array
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
创建为数组,这个一般默认选上的
函数调用图
View
->graphs
->function calls
快捷键F12
创建结构体
有些情况反汇编的数据结构不准确就需要我们手动恢复创建结构体
有以下这种方法
-
导入C语言申明的结构体
在View–>Open Subviews–>Local Types中可以看到本地已有的结构体,在该窗口中右击insert
可以添加新的结构体:
-
手工创建结构体
创建结构体的快捷键是
insert
在弹出的窗口可以编辑结构体的名字
这底下有三个复选框,第一个表示显示在当前结构体之前(就会排列在第一位,否则排列在你鼠标选定的位置),第二个表示是否在窗口中显示新的结构体,第三个表示是否创建联合体。
需要注意的是,结构体的大小是它所包含的字段大小的总和,而联合体的大小则等于其中最大字段的大小
在单击ok以后,就定好了一个空的结构体:
将鼠标放在 ends这一行,单击快捷键D即可添加结构体成员,成员的命名默认是以field_x表示的,x代表了该成员在结构体中的偏移
同时,可以把鼠标放在结构体成员所在的行,按D,就可以切换不同的字节大小
默认情况下可供选择的就只有db,dw,dd(1,2,4字节大小)
如果想添加型的类型,可以在option–>setup data types(快捷键Alt+D),进行设置
勾选了第五个和第九个的话,就会出现dq和xmmword了(代表了8字节和16字节)
如果要添加数组成员则可以对着成员所在的那一行,右击选择array
给结构体的成员重命名可以用快捷键N
应用我们创建好的结构体就需要使用快捷键Y
快捷键Y可以更改函数、变量的类型和参数
将变量的类型更改为我们定义的结构体的名称即可
动态调试
注意,application和input file 都是填写在虚拟机中的elf的路径,记得要加文件名
而directory 填写elf所在目录,不用加文件名
hostname是虚拟机的ip地址,port是默认的连接端口
parameter和password一般都不用填
设置好了以后点击ok
接着可以直接在反汇编视图中下断点,只要点击左边的小蓝点即可
这时按下快捷键F9,可以直接开始调试
按下快捷键F4,则直接运行到断点处停下
动态调试常用快捷键
F7
单步步入,遇到函数,将进入函数代码内部
F8
单步步过,执行下一条指令,不进入函数代码内部
F4
运行到光标处(断点处)
F9
继续运行
CTRL+F2
终止一个正在运行的调试进程
CTRL+F7
运行至返回,直到遇到RETN(或断点)时才停止.
打PATCH
可以安装一个keypatch
的插件增强ida的patch功能
修改程序本身的命令
然后Apply patches to input file
导出数据文件
.map文件描述二进制文件的总体结构,包括与构成改二进制文件的节有关的信息,以及每个节中符号的位置。
.asm文件,也就是汇编了,直接能导出ida中反汇编的结果,这个非常实用,有的时候在逆向中经常遇到大量数据加解密的情况,如果在从IDA中一个个慢慢复制可就太没效率了,直接导出生成asm,在里面复制数据快很多
常见命名含义
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反编译报错
一是由于程序存在动态加密,导致程序的某些代码段被修改,(smc)
二是存在junk code,需要我们手动修复错误识别的结果
配置ida
一、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这两个选项是全局选项,修改一次就永久生效的,不用在以上三个配置文件中改
数据与代码的互转
在自动分析阶段,字节有时可能被错误地归类。数据字节可能被错误地归类为代码字节,并被反汇编成指令;而代码字节可能被错误地归类为数据字节,并被格式化成数据值。有许多原因会导致这类情况,如一些编译器将数据嵌入在程序的代码部分,或者一些代码字节从未被作为代码直接引用,因而IDA 选择不对它们反汇编。模糊程序则特别容易模糊代码部分与数据部分之间的区别。
。在重新格式化之前,首先必须删除其当前的格式(代码或数据)。右击你希望取消定义的项目,在结果上下文菜单中选择Undefine(也可使用Edit▶Undefine命令或热键U),即可取消函数、代码或数据的定义。取消某个项目的定义后,其基础字节将作为原始字节值重新格式化。在执行取消定义操作之前,使用“单击并拖动”操作选择一个地址范围,可以取消大范围内的定义。下面以一个简单的函数为例:
.text:004013E0 sub_4013E0 proc near
.text:004013E0 push ebp
.text:004013E1 mov ebp, esp
.text:004013E3 pop ebp
.text:004013E4 retn
.text:004013E4 sub_4013E0 endp
取消这个函数的定义将得到下面这些未分类的字节,我们几乎可以以任何方式重新对它们进 行格式化:
.text:004013E0 unk_4013E0 db 55h ; U
.text:004013E1 db 89h ; ë
.text:004013E2 db 0E5h ; s
.text:004013E3 db 5Dh ; ]
.text:004013E4 db 0C3h ; +
要反汇编一组未定义的字节,右击其中的第一个字节,在上下文菜单中选择Code(也可使用Edit▶Code或热键C)。这样,IDA 将开始反汇编所有字节,直到它遇到一个已定义的项目或非法指令。在执行代码转换操作之前,使用“单击并拖动”操作选择一个地址范围,可以进行大范围代码转换操作。
将代码转换为数据的逆向操作要复杂一些。首先,使用上下文菜单不可能将代码转换为数据。你可以通过EditData 和热键D来完成。要想将指令批量转换为数据,最简单的方法是取消你希望转换为数据的所有指令的定义,然后对数据进行相应的格式化。基本的数据格式化将在下一节讨论。
IDA-Python
IDAPYTHON 官方文档hex-rays.com/products/ida/support/idapython_docs/
总结idapython在逆向中的应用 - 『脱壳破解区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn
IDAPython常用API整理 - 『脱壳破解区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn
在IDA中.有三个重要的库.分别是IDC,idautils,idaapi
IDC 他是封装IDA与IDC函数的兼容性模块.
Idautils 这个是IDA提供给我们的一个高级实用的模块.
idaapi 他可以允许我们访问更加底层的数据.
在IDA中我们要使用脚本有三种方式
第一种 .可以直接按 shift + F2 快捷键调出界面.也可以直接在菜单中选择命令脚本.
第二种 可以是写一个脚本文件直接进行引用.
第三种 就是在导航栏底部直接写命令
ida-python的常用api
- idc.MinEA():获取载入程序的最小的有效地址,兼容函数,等价于“get_inf_attr(INF_MIN_EA)”;
- idc.MaxEA():获取载入的程序最大的有效地址,兼容函数,等价于“get_inf_attr(INF_MAX_EA)”;
- ida_idaapi.get_inf_structure():获取当前打开的IDA的版本的信息,返回的是一个idainfo类型的结构体。
- ida_ida.is_32bit()/is_64bit():判断IDA是否为32位的还是64位的,属于idainfo的一个方法属性。
- idautils.Assemble(head, line):从head地址开始反汇编,寻找直到遇到line这条指令时停止,返回两个变量,一个表示是否成功,另外一个是最后这条line指令的字节表示,例如:
ret
就会是'\xc3'
这一个字节来表示,有些指令可能由多个字节表示。 - idc.GetMnem(ea):获取ea地址处的指令助记符,兼容函数,同“print_insn_mnem(ea)”功能相同。
- idc.MakeCode(ea):从ea地址处开始尝试将数据转换为汇编代码,兼容函数,等价于“create_insn(ea)”。
- ida_bytes.next_not_tail(ea):往下走一个指令,如果不是尾部,则返回下一条指令的起始地址。
- idc.GetDisasm(ea):获取ea地址开始的一条汇编指令,等价于“generate_disasm_line(ea, 0)”。
- idc.GetFlags(addr):获取addr地址处的一系列标志位,可用来判断属于code还是data,等价于ida_bytes.get_full_flags(ea),返回一个flags_t类型的实例。
- idc.isCode(Flags):通过Flags判断是否是汇编代码,其中“Flags”为flags_t的一个实例,等价于“is_code(F)”。
- idc.MakeUnkn(ea, flags):取消对ea地址处的定义,暂不清楚该地址是代码还是数据时可以使用,兼容函数,等价于“del_items(ea, flags)”。
- idc.GetOpnd(addr, index):取addr地址处的指令的第index个操作数,从零开始,从左开始,依次为intel汇编语法中的目的操作数、源操作数,兼容函数,等价于“print_operand(ea, n)”。
- ida_name.get_name_ea(min_ea, name):从min_ea地址开始,寻找名为name的有效地址,该name可以为函数名、label名。
- ida_bytes.get_dword(addr):从addr地址处获取一个大小为dword的数据。
- idc.MakeDword(addr):将addr开始的一个DWORD大小的数据定义为双字形式,举一反三,Q代表四字节数据,API形式一致,兼容函数,等价于create_data(ea, dataflag, size, tid)的不同参数形式。
- idc.SegName(ea):得到ea地址所处的区段名,返回字符串,兼容函数,等价于“get_segm_name()”。
- idc.MakeFunction(start, end):将start到end地址处定义为一个函数,相当于快捷键“P”,兼容函数,等价于“add_func(start, end)”。
- idc.GetSpd(ea):获取ea地址处的栈指针SP的值,而在IDA中显示的值则是SP到BP基址针的差值,例如获取到的值为“-4”,在IDA中显示栈指针的情况时则为4,兼容函数,等价于“get_spd(ea)”。
- idc.SetSpDiff(ea, delta):设置ea地址处的Sp指针与Bp指针的差值为“delta”,兼容函数,等价于“add_user_stkpnt(ea, delta)”。
- ida_bytes.next_head(ea, maxea):在ea到maxea之间遍历下一条指令,返回下一条指令的地址,与“next_not_tail”功能相似。
- ida_ua.ua_mnem(ea):返回ea地址处的指令助记符,等价于“print_insn_mnem(ea)”。
- idc.MakeName(ea, label):给ea地址处一个标记label,兼容函数,等价于“set_name(ea, name, SN_CHECK)”。
- idc.FindFuncEnd(ea): ea为函数的起始地址,找到该函数的结尾地址并返回,兼容函数,等价于“find_func_end(ea)”。