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與函數的結合使用.
修改后如下:

