IDA

常用快捷键

Shift+F12:查看所有字符串

F5:查看伪代码

Alt+T:查找字符串

空格:切换图形视图&汇编视图

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

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

n:改变量名

y:改变量类型

IDAPython

在IDA中要使用脚本有三种方式:

第一种,直接按Shift+F2快捷键调出界面,也可以直接在菜单中选择命令脚本(File -> Script command);

第二种,写一个脚本文件直接进行引用(File -> Script file);

第三种,直接在IDA底部写命令。

IDAPython由三个独立模块组成:

idc: idc函数的兼容模块,包含IDA内置函数声明和内部定义

idautils: 实用函数模块

idaapi: 用于访问更多底层数据的模块

指令操作

1
2
3
4
5
6
7
8
9
10
import idc
import idaapi
import idautils

ea = idc.here();
print("当前模块基址为: {}".format(hex(idaapi.get_imagebase())))
print("当前的汇编语句为: {}".format(idc.GetDisasm(ea)))
print("当前的汇编指令为: {}".format(idc.print_insn_mnem(ea)))
print("当前的操作数为: {}".format(idc.print_operand(ea,0)))
print("当前的操作数值为: {}".format(idc.get_operand_value(ea,0)))

img

段操作

1
2
3
4
5
6
7
8
9
import idc
import idaapi
import idautils

for seg in idautils.Segments():
segname = idc.get_segm_name(seg)
segstart = idc.get_segm_start(seg)
segend = idc.get_segm_end(seg)
print("段名 = {} 起始地址= {} 结束地址 = {} ".format(segname,hex(segstart),hex(segend)));

img

函数操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import idc
import idaapi
import idautils

for seg in idautils.Segments():
segname = idc.get_segm_name(seg)
segstart = idc.get_segm_start(seg)
segend = idc.get_segm_end(seg)
print("段名 = {} 起始地址 = {} 结束地址 = {} ".format(segname,hex(segstart),hex(segend)));
if (segname == '.text'):
for funcaddr in Functions(segstart,segend):
funname = idc.get_func_name(funcaddr)
funend = idc.find_func_end(funcaddr)
funnext = idc.get_next_func(funcaddr)
funnextname = idc.get_func_name(funnext)
print("当前函数名 = {} 当前结束地址 = {} 下一个函数地址 = {} 下一个函数名 = {}".format(funname,hex(funend),hex(funnext),funnextname))

ea = idc.get_screen_ea()
funnextoffset = idc.get_func_off_str(ea)
print("当前选择地址距离当前函数的偏移为: {} ".format(funnextoffset))

img

搜索

在IDAPython中如果想查询某些数据、代码、二进制,都可以用都搜索函数。搜索函数可以是向上搜索,也可以是向下搜索,搜索失败就会返回-1,也就是BADADDR,而搜索功能也常常用于去除花指令当中。

1
2
3
4
5
ea = here()
value = idc.find_binary(ea,SEARCH_DOWN,'8B 4D 08') #从ea位置向下查找 查找的二进制为8B 4D 08 返回查找到的地址

value1 = idc.find_code(ea,SEARCH_DOWN) #从ea还是查找找到ea下的第一行code代码地址
value2 = idc.find_data(ea,SEARCH_DOWN)

数据校验

1
2
3
4
5
6
7
8
9
import idc
ea = here()
value1 = idc.find_code(ea,SEARCH_DOWN)
print(hex(value1))

flag = ida_bytes.get_full_flags(value1) #获取标志
print(flag)

print(ida_bytes.is_code(flag)) #判断是否是代码传入标志,根据标志返回True/False

交叉引用

1
2
3
4
5
import idc
ea = here()
for i in CodeRefsTo(ea,False):
print(hex(i))
# 获取地址处引用位置。A调用B,对B函数地址使用此函数则找到A调用,返回列表,遍历列表则可以找出所有引用位置。参数1是ea也就是地址,参数2告诉IDA是否跟踪这些代码。

创建结构体

View -> Open subviews -> Local types,右键->Insert,即可输入结构体定义,示例如下:

1
2
3
4
5
6
struct hello
{
_BYTE a;
_BYTE c;
_WORD b;
};

如果要修改,选中相应行,右键->Edit 即可。

位操作

1
2
3
4
5
6
def LOBYTE(x): return x & 0xff
def HIBYTE(x): return (x >> 8) & 0xff
def LOWORD(x): return x & 0xffff
def HIWORD(x): return (x >> 16) & 0xffff
def LODWORD(x): return x & 0xffffffff
def HIDWORD(x): return (x >> 32) & 0xffffffff

其他操作

导出array为数组

右键array变量名 → 转为dword → Export as → C unsigned char array (hex)

170006lwwoowsvm945je22

手动修复栈指针(Decompilation failure: positive sp value has been found)

现象:无法反编译

170016mnj324snrxkrg1ug

修复:

170018czryr5u500vy20yn

170020nngx262sktesf18k

对标红位置按 Alt+K 修改栈偏移:

170022vp515f5fdgd0pdkd

修改后 F5 即可。

手动修改汇编或二进制代码(Patch)

  • 激活功能

    Edit▶Patch Program菜单GUI版本的IDA的一项隐藏功能,用户需要编辑idagui.cfg配置文件才能激活该菜单。

    20160210203642536

  • 改字节(Change word)

    IDA——Edit——Patch Program——Change word

    用于编辑IDA数据库中的字节值。
    这里写图片描述
    这个对话框显示了从光标所在位置开始的16个字节的值。你可以更改显示的部分或全部字节。
    同时,Address表示了虚拟地址,File offset表示了文件偏移量。

    实际上,Hex View可以直接改字节,右键Edit即可。

  • 改内容(Assemble)

    IDA——Edit——Patch Program——Assemble

    利用“汇编”选项可以输入使用一个内部汇编器汇编的汇编语言语句。然后,IDA会将得到的指令字节写入当前的屏幕位置。
    QQ截图20200520215855

  • 应用修改(Apply patches to input file)

    IDA——Edit——Patch Program——Apply patches to input file

    把改动更新到二进制文件中。

手动定义为函数(恢复伪代码)

来到一处看似很像关键代码处的位置:

ezgif-7-c652b68cc595

在这部分代码的头部按 P 键定义为函数,接着尝试查看伪代码,得到的伪代码没有变量识别,非常难看。

ezgif-7-c5059efb62fd

于是我们尝试修复堆栈信息,让 IDA 能够识别出来变量。

ezgif-7-46fb759d5fab

如图所示,我们可以尝试着在这部分之上使用 Keypatch 手动加入一个 push rbp; mov rbp, rsp

让 IDA 能够识别出堆栈上的变量,紧接着再 F5,就可以看到比较舒服的伪代码了。

ezgif-7-d9941cfe65f7

Dump代码生成新脚本

使用IDA Pro调试程序时偶尔会遇到dump内存的需求,IDA Pro并没有直接提供内存dump的功能,但可以通过其提供的接口用脚本来实现相关功能。

  • IDC脚本
    1
    2
    3
    4
    auto i,fp;
    fp = fopen("d:\\dump.dex","wb");
    for (i = start_address; i <= end_address; i++)
    fputc(Byte(i),fp);
  • Python脚本
    1
    2
    3
    4
    5
    import idaapi
    data = idaapi.dbg_read_memory(start_address, data_length)
    fp = open('d:\\dump', 'wb')
    fp.write(data)
    fp.close()

异常处理

选择本地Windows调试器后点击debugger选项卡中的debugger options,选择左下角的edit exceptions,如触发了除零异常,可以找到整数除零异常(EXCEPTION_INT_DIVIDE_BY_ZERO),选择pass to application和silent,下断调试即可。

f_c