IDAPython入门教程 基于IDA7.5_Python3 第一讲 简介与地址获取

IDA Python 7.5 python函数入门

简介

IDAPython是很强大的功能. 但是在7.5支持python3之后很多函数都改变了. 所以从头开始学一下.

要学习IDA Python 首先你要会python的基本操作. 以及IDAPython文档会查询. IDC 文档会查询. 以及差异化查询.

下面列出几个有用的链接方便直接点击学习或者查询.

python3 入门知识: 菜鸟教程Python3入门知识

IDAPython官方函数文档: IDAPython官方文档函数查询

IDC函数官方文档查询: IDC函数

IDA版本与版本之间的差异化函数查询: IDA版本函数差异化

一丶IDApython分布讲解

1.1 IDA Python 常见模块介绍与脚本使用

在IDA中.有三个重要的库.分别是IDC,idautils,idaapi

IDC 他是封装IDA与IDC函数的兼容性模块.

Idautils 这个是IDA提供给我们的一个高级实用的模块.

idaapi 他可以允许我们访问更加底层的数据.

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

第一种 .可以直接按 shift + F2 快捷键调出界面.也可以直接在菜单中选择命令脚本.

第二种 可以是写一个脚本文件直接进行引用.

如下图所示:

请更改为python来使用IDA python.当然如果拟更改为IDC 那么你只能使用IDC函数了.

第三种方式是直接在IDA底部写命令.

PS: 如果没有python选项 参考一下网上怎么修复python支持.

1.2 IDAPython 汇编界面介绍

查看IDA我们可以看到如下界面

下面以图表的形式展示一下说明

.text 这是程序的段名称
0x004010B7 这是当前的Addr地址
movups 这个汇编是当前的汇编语句操作符
movups xmmword ptr[xxx] ,xmm0 这个是汇编指令的操作数
movups xmmword ..,xmm0 这一整行是反汇编语句

1.3 IDA中获取界面中地址函数

那么下面先讲一下怎么获取界面中的地址. 至于里面的各项元素后面会一一说明.

  • 当前,最大,最小,选择开始,选择结束 等地址的获取.

    在IDA 7.5中. 我们获取地址的函数如下

    当前地址获取使用 idc.here() 函数 或者 idc.get_screen_ea() 函数

    最小地址可以使用: ida_ida.inf_get_min_ea()

    最大地址可以使用: ida_ida.inf_get_max_ea()

    当前选择地址的开始: idc.read_selection_start()

    当前选择地址的结束:idc.read_selection_end()

    如果判断地址是否存在可以使用: idaapi.BADADDR

    这些函数的返回值都是地址. 且没有参数.

    print(hex(idc.here()))          #获取当前地址
    print(hex(idc.get_screen_ea())) #另一种获取当前地址的函数
    print(hex(ida_ida.inf_get_min_ea())) #获取当前最小地址
    print(hex(ida_ida.inf_get_max_ea())) #获取当前最大地址
    print(hex(idc.read_selection_start()))#如果你选择了某块地址 那么使用此函数则返回你选择的这块地址的起始地址
    print(hex(idc.read_selection_end())) #同上 返回结束地址.
    
    if idaapi.BADADDR == idc.here(): 
        print("BadAddress addr invalid")
    else: 
        print("addr is ok")
    

    下面则使用表格来说一下上述函数的老版函数. 便于查询. 如果你使用的是7.0 那么可以使用老版函数. 没有特殊说明的说明没有新函数.可以直接使用.

    老版函数 当前7.5支持函数 作用
    idc.ScreenEA() idc.get_screen_ea() 获取当前指令地址
    idc.MinEA() idc.StartEA() idc.BeginEA() ida_ida.inf_get_min_ea() 获取当前最小地址. 其中老版的三个函数都替换为了新版.使用的是同一个函数
    idc.MaxEA() ida_ida.inf_get_max_ea() 获取当前最大地址
    idc.SelStart() idc.read_selection_start() 获取当前光标选择的的块中的 起始地址
    idc.SelEnd() idc.read_selection_end() 同上 返回结束地址

1.4 IDAPython中的数值获取

​ 在IDA中.如果我们想获取一个地址处的值可以使用以下几个函数

函数 说明
Byte(addr) 以字节为单位获取地址处的值
Word(addr) 同上. 以2字节(字)的单位获取
Dword(addr) 4字节
Qword(addr) 8字节

但是在IDA 7.5 支持python3之后这些函数都变了.

下面是变换之后的函数

旧的函数 新的函数
Byte(addr) idc.get_wide_byte(addr)
Word(addr) idc.get_wide_word(addr)
Dword(addr) idc.get_wide_dword(addr)
Qword(addr) idc.get_qword(addr)

当然与之对应的还有其判断函数
idc.isByte() Word Dwrd Qwrd
但在高版本中都变成了
ida_bytes.is_byte word dword qword
上面的word dword qword 都省略了前边的字段.使用的时候自己加上即可.
指令实战如下:

import idc

ea = idc.get_screen_ea()
value = idc.get_wide_byte(ea)
print("当前指令的硬编码为 {}".format(hex(value)));

1.5 IDAPython中的数值操作.

在上面我们讲了如何获取地址.如何获取地址指令处的值.那么我们就可以说一下如何修改指令的值.

对应的函数如下:

指令 说明
idc.PatchByte(addr,value) 修改addr地址的值为value.每次修改一个字节
idc.PatchWord(addr,value) 同上一次修改变为2个字节
idc.PatchDword(addr,value) 4
idc.PatchQword(addr,value) 8

这些指令在IDA7.5中统统不使用了. 统统移植到 ida_bytes里面了

下面说一下这些新函数

旧函数 新函数
idc.PatchByte(addr,value) ida_bytes.patch_byte(addr,value)
idc.PatchWord(addr,value) ida_bytes.patch_word(addr,value)
idc.PatchDword(addr,value) ida_bytes.patch_Dword(addr,value)
idc.PatchQword(addr,value) ida_bytes.patch_Qword(addr,value)

下面看一下指令操作.

ea = idc.get_screen_ea()
value = idc.get_wide_byte(ea)
print("我是没被修改的当前=  {}".format(hex(value)))
ida_bytes.patch_byte(ea,0x90)

value = idc.get_wide_byte(ea)
print("我被修改过了当前我的值为 {} ".format(hex(value)))

二丶IDAPython实战

​ 通过上面我们介绍的一些IDA Python的操作. 你现在能进行简单的脚本制作了.

如遇到 简单的花指令 我们可以手动写脚本去除. 现在我们写一个脚本. 脚本的作用是

获取我们选择区域的所有二进制值. 如果二进制数值是0x66 那么我们就替换成 0x90 (nop)

如下图原图所示:

首先选择这一块内容 (0x004015D1 - 0X0040166B)

然后进行脚本编写

import idc
import idaapi
import idautils

#获取当前选择的起始地址
StartSeclectAddr = idc.read_selection_start()

#获取当前选择的终止地址
EndSeclectAddr = idc.read_selection_end()

#计算出当前指令长度
SelLen = EndSeclectAddr - StartSeclectAddr;

#从选择地址开始 - 选择地址结束进行遍历. 获取其指令字节. 如果是0x66 则替换成0xFF

for index in range(SelLen):
    curaddr = StartSeclectAddr+index
    tmpValue = idc.get_wide_byte(curaddr)
    if (tmpValue == 0x66):
        ida_bytes.patch_byte(curaddr,0x70)

PS: 虽然脚本没有任何意义.但是可以带我们熟悉下python与函数的结合使用.

修改后如下:

作者:IBinary


坚持两字,简单,轻便,但是真正的执行起来确实需要很长很长时间.当你把坚持两字当做你要走的路,那么你总会成功. 想学习,有问题请加群.群号:725864912(收费)群名称: 逆向学习小分队 群里有大量学习资源. 以及定期直播答疑.有一个良好的学习氛围. 涉及到外挂反外挂病毒 司法取证加解密 驱动过保护 VT 等技术,期待你的进入。

详情请点击链接查看置顶博客 https://www.cnblogs.com/iBinary/p/7572603.html
原文地址:https://www.cnblogs.com/iBinary/p/14642662.html