获取当前光标所指向的地址
idaapi.here()
idc.get_screen_ea()
返回一个整型地址,为光标所在行的地址
curEA = idc.here()
print("CurEA: %08X" % curEA)
通过一个地址 获得命中的函数
idc.GetFunctionAttr(EA, idc.FUNCATTR_START)
idc.GetFunctionAttr(EA, idc.FUNCATTR_END)
分别得到IDA自动分析得到的函数头和函数尾部的地址
dwFunStart = idc.GetFunctionAttr(curEA, idc.FUNCATTR_START)
dwFunEnd = idc.GetFunctionAttr(curEA, idc.FUNCATTR_END)
通过一个地址 获得已分析的函数名
idc.GetFunctionName(ea)
获得指定地址的函数名
Python>print hex(ea), idc.GetDisasm(ea)
0x401040 push ebp
Python>idc.GetFunctionName(ea)
sub_401040
通过一个地址,得到一个函数对象
idaapi.get_func(EA)
通过一个地址,得到一个函数对象,对象类型(idaapi.func_t)
curFun = idaapi.get_func(dwFunStart)
if curFun is not None:
dwFunStart = curFun.start_ea
dwFunEnd = curFun.end_ea
print("GetFunSucess\r\nFunStart: %08X\r\nFunEnd: %08X" % (dwFunStart, dwFunEnd))
else:
print ("GetFunError")
通过一个地址,得到一个函数中,所有行的地址
idautils.FuncItems(EA)
传入一个函数的开始地址,然后返回一个生成器
每次调用生成器,返回一条指令地址
lstFunAddr = list(idautils.FuncItems(dwFunStart))
lstFunAddr = list(idautils.FuncItems(dwFunStart))
print ("ShowLst:")
for i in lstFunAddr:
print ('Addr: %08X' % i)
通过一个地址,获得当前行的注释
idaapi.get_cmt(EA, flag)
参数1,地址;参数2,是否获取重复,返回一个注释字符串
cmt = idaapi.get_cmt(addr, 0)
print(cmt)
给地址设置名称
idc.MakeNameEx(ea, name, flags)
地址, 名称字符串, 什么类型的名称
idc.set_name(0x004086B9, "Test1", idc.SN_NOWARN)
扫描特征码
decode_func_code = '\x55\x8B\xEC\x51\xC7\x45\xFC\x00\x00\x00\x00\xEB\x09\x8B\x45\xFC\x83\xC0\x01\x89\x45\xFC\x8B\x4D\xFC\x3B\x4D\x0C\x73\x2C\x8B\x55\x08\x03\x55\xFC\x0F\xB6\x02\x8B\x4D\xFC\x81\xE1\x3F\x00\x00\x80' # 绝对地址特征码
def get_decode_func_addr():
for func in idautils.Functions(): # 获得已解析的函数
func_code = idc.GetManyBytes( func, len(decode_func_code) ) # 得到特征码长度的二进制字符串
#print 'func=%08X, func_code=%s, decode_code=%s' %(func,func_code,decode_func_code)
if func_code == decode_func_code: # 比对特征码
print 'decode addr = %08X' %( func )
return func
return idc.BADADDR # 返回一个错误值
通过一个地址得到数据
idc.Byte(EA) # 得到指定地址的一个字节数据
idc.Word(EA) # 得到一个DWORD
idc.QWord(EA) # 得到一个QWORD
通过名称得到函数地址
idc.LocByName(str)
Python>wf_addr = idc.LocByName("WriteFile")
Python>print hex(wf_addr), idc.GetDisasm(wf_addr)
0x1000e1b8 extrn WriteFile:dword
Python>for addr in idautils.CodeRefsTo(wf_addr, 0):\
print hex(addr), idc.GetDisasm(addr)
0x10004932 call ds:WriteFile
0x10005c38 call ds:WriteFile
0x10007458 call ds:WriteFile
通过地址 得到汇编代码
idc.GetDisasm(ea)
Python>ea = 0x10004932
Python>print hex(ea), idc.GetDisasm(ea)
0x10004932 call ds:WriteFile
Python>for addr in idautils.CodeRefsFrom(ea, 0):\
print hex(addr), idc.GetDisasm(addr)
Python>
0x1000e1b8 extrn WriteFile:dword
交叉引用
idautils.CodeRefsTo(ea, 0)
获得代码引用idautils.DataRefsTo(ea)
获得数据引用
idautils.XrefsTo(ea, flag=0)
获得所有的引用(数据和代码??)idautils.XrefTypeName(xref.type)
获得引用的类型
xrefType类型如下:
数值 | 类型 |
---|---|
0 | ‘Data_Unknown’ |
1 | ‘Data_Offset’ |
2 | ‘Data_Write’ |
3 | ‘Data_Read’ |
4 | ‘Data_Text’ |
5 | ‘Data_Informational’ |
16 | ‘Code_Far_Call’ |
17 | ‘Code_Near_Call’ |
18 | ‘Code_Far_Jump’ |
19 | ‘Code_Near_Jump’ |
20 | ‘Code_User’ |
21 | ‘Ordinary_Flow’ |
def get_to_xrefs(ea):
xref_set = set([])
for xref in idautils.XrefsTo(ea, 1):
xref_set.add(xref.frm)
return xref_set
def get_frm_xrefs(ea):
xref_set = set([])
for xref in idautils.XrefsFrom(ea, 1):
xref_set.add(xref.to)
return xref_set
已分析代码中 最大 最小界限
MinEA()
最小的可分析界限MaxEA()
最大的可分析界限
二进制搜索
idc.FindBinary(ea, flag, searchstr, radix=16)
参数 | 作用 |
---|---|
EA | 为起始地址 |
flag | 为搜索方式(见下表) |
searchstr | 为搜索内容 |
radix | 暂未知 |
枚举 | 数值 | 作用 | 备注 |
---|---|---|---|
SEARCH_UP | 0 | 向上搜索 | |
SEARCH_DOWN | 1 | 向下搜索 | |
SEARCH_NEXT | 2 | 下一个匹配项 | |
SEARCH_CASE | 4 | 大小写敏感? | |
SEARCH_REGEX | 8 | 正则? | |
SEARCH_NOBRK | 16 | ||
SEARCH_NOSHOW | 32 | 不显示搜索状态?? | |
SEARCH_UNICODE | 64 | 搜索结果未Unicode |
** |
SEARCH_IDENT | 128 | ** | |
SEARCH_BRK | 256 | ** |
标记 ** 为旧版本不支持
这些标志位 可以 叠加 使用|
运算
Python>pattern = '55 8B EC'
addr = MinEA()
for x in range(0,5):
addr = idc.FindBinary(addr, SEARCH_DOWN, pattern);
if addr != idc.BADADDR:
print hex(addr), idc.GetDisasm(addr)
Python>
0x401000 push ebp
0x401000 push ebp
0x401000 push ebp
0x401000 push ebp
0x401000 push ebp
# 可见每次搜索都从指定地址开始, 查找下一个 标志则为 SEARCH_NEXT
Python>pattern = '55 8B EC'
addr = MinEA()
for x in range(0,5):
addr = idc.FindBinary(addr, SEARCH_DOWN|SEARCH_NEXT,
pattern);
if addr != idc.BADADDR:
print hex(addr), idc.GetDisasm(addr)
Python>
0x401040 push ebp
0x401070 push ebp
0x4010e0 push ebp
0x401150 push ebp
0x4011b0 push ebp
# 在设置Next标志位以后, 会自动顺延
字符串搜索
idc.FindText(ea, flag, y, x, searchstr)
查找字符串
Python>cur_addr = MinEA()
end = MaxEA()
while cur_addr < end:
cur_addr = idc.FindText(cur_addr, SEARCH_DOWN, 0, 0,
"Accept")
if cur_addr == idc.BADADDR:
break
else:
print hex(cur_addr), idc.GetDisasm(cur_addr)
cur_addr = idc.NextHead(cur_addr)
Python>
0x40da72 push offset aAcceptEncoding; "Accept-Encoding:\n"
0x40face push offset aHttp1_1Accept; " HTTP/1.1\r\nAccept: */*
\r\n "
0x40fadf push offset aAcceptLanguage; "Accept-Language: ru
\r\n"
...
0x423c00 db 'Accept',0
0x423c14 db 'Accept-Language',0
0x423c24 db 'Accept-Encoding',0
0x423ca4 db 'Accept-Ranges',0
地址类型判断
根据IDA的自动分析, 给每个地址作出标识
函数 | 功能 |
---|---|
idc.isCode(flag) |
返回True 如果IDA 自动分析, 判定地址为Code . |
idc.isData(flag) |
返回True 如果IDA 自动分析, 判定地址为Data . |
idc.isHead(flag) |
返回True 如果IDA 自动分析, 判定地址为Head(头部) . |
idc.isTail(flag) |
返回True 如果IDA 自动分析, 判定地址为Tail(尾部) . |
idc.isUnknown(flag) |
返回True 如果IDA 自动分析, 判定地址为Unknown , 此标记表示IDA 无法分析此地址是Code 还是Data . |
flag
通过idc.GetFlags(ea)
得到
获取选择目标的 开始和结束
idc.SelStart()
获得当前所选的开始地址idc.SelEnd()
获取当前所选的结束地址(选择结尾的下一条地址)
# .text:00408E46 push ebp
# .text:00408E47 mov ebp, esp
# .text:00408E49 mov al, byte ptr dword_42A508
# .text:00408E4E sub esp, 78h
# .text:00408E51 test al, 10h
# .text:00408E53 jz short loc_408E78
# .text:00408E55 lea eax, [ebp+Data]
Python>start = idc.SelStart()
Python>hex(start)
0x408e46
Python>end = idc.SelEnd()
Python>hex(end)
0x408e58
idaapi.read_selection()
获得选区, 返回一个元组, 其中包含 获得成功与否, 选择的开始地址和结束地址
Python>Worked, start, end = idaapi.read_selection()
Python>print Worked, hex(start), hex(end)
True 0x408e46 0x408e58
数据获取
函数 | 功能 |
---|---|
idc.Byte(ea) | 从指定地址, 获得一个Byte . |
idc.Word(ea) | 从指定地址, 获得一个Word . |
idc.Dword(ea) | 从指定地址, 获得一个Dword . |
idc.Qword(ea) | 从指定地址, 获得一个Qword . |
idc.GetFloat(ea) | 从指定地址, 获得一个Float . |
idc.GetDouble(ea) | 从指定地址, 获得一个Double . |
Python>print hex(ea), idc.GetDisasm(ea)
0xa14380 mov ecx, hHeap
Python>hex( idc.Byte(ea) )
0x8b
Python>hex( idc.Word(ea) )
0xd8b
Python>hex( idc.Dword(ea) )
0x6d0c0d8b
Python>hex( idc.Qword(ea) )
0x6a5000a26d0c0d8bL
Python>idc.GetFloat(ea) # Example not a float value
2.70901711372e+27
Python>idc.GetDouble(ea)
1.25430839165e+204
idc.GetManyBytes(ea, size, use_dbg=False)
从一个地址开始获取一个缓冲区
Python>for byte in idc.GetManyBytes(ea, 6):
print "0x%X" % ord(byte),
0x8B 0xD 0xC 0x6D 0xA2 0x0
Tips: idc.GetManyBytes(ea, size)
返回一个 字符序列, 并不像idc.Word(ea)
或idc.Qword(ea)
那样 返回一个整形
在IDB中修改字节码
函数 | 作用 |
---|---|
idc.PatchByte(ea, value) |
修改指定地址的一个字节 |
idc.PatchWord(ea, value) |
修改指定地址的一个字 |
idc.PatchDword(ea, value) |
修改指定地址的一个双字 |
# .data:1001ED3C aGcquEUdg_bUfuD db 'gcqu^E]~UDG_B[uFU^DC',0
# .data:1001ED51 align 8
# .data:1001ED58 aGcqs_cuufuD db 'gcqs\_CUuFU^D',0
# .data:1001ED66 align 4
# .data:1001ED68 aWud@uubQU db 'WUD@UUB^Q]U',0
# .data:1001ED74 align 8
# 100012A0 push esi
# 100012A1 mov esi, [esp+4+_size]
# 100012A5 xor eax, eax
# 100012A7 test esi, esi
# 100012A9 jle short _ret
# 100012AB mov dl, [esp+4+_key] ; assign key
# 100012AF mov ecx, [esp+4+_string]
# 100012B3 push ebx
# 100012B4
# 100012B4 _loop: ;
# 100012B4 mov bl, [eax+ecx]
# 100012B7 xor bl, dl ; data ^ key
# 100012B9 mov [eax+ecx], bl ; save off byte
# 100012BC inc eax ; index/count
# 100012BD cmp eax, esi
# 100012BF jl short _loop
# 100012C1 pop ebx
# 100012C2
# 100012C2 _ret: ;
# 100012C2 pop esi
# 100012C3 retn
Python>start = idc.SelStart()
Python>end = idc.SelEnd()
Python>print hex(start)
0x1001ed3c
Python>print hex(end)
0x1001ed50
Python>def xor(size, key, buff):
for index in range(0,size):
cur_addr = buff + index
temp = idc.Byte( cur_addr ) ^ key
idc.PatchByte(cur_addr, temp)
Python>
Python>xor(end - start, 0x30, start)
Python>idc.GetString(start)
WSAEnumNetworkEvents
IDA_Python中的文件输入输出
AskFile(forsave, mask, prompt)
# forsave: 值为0或1, 0为启动一个 "打开"对话框, 1为启动一个"保存"对话框
# mask: 字符串, 为对话框的文件过滤器 比如: 过滤".dll" 则传入过滤字符串"*.dll"
# prompt: 字符串, 为对话框的"Title"
import sys
import idaapi
class IO_DATA():
数据获取方式为在IDA中选中一段数据, 则自动获得 选择的起始地址和结束地址
作用有限, 需自定义Decode()函数
```
def __init__(self):
self.start = SelStart() # 所选区间开始
self.end = SelEnd() # 所选区间结尾
self.buffer = '' # 内置缓冲区
self.ogLen = None # 所选长度
self.status = True # 状态
self.run()
def checkBounds(self):
```
判断获得的选择区间是否为无效区间
```
if self.start is BADADDR or self.end is BADADDR:
self.status = False
def getData(self):
'''
把选择区间内的数据, 保存到类内置缓冲区
'''
self.ogLen = self.end - self.start
self.buffer = ''
try:
for byte in idc.GetManyBytes(self.start, self.ogLen):
self.buffer = self.buffer + byte
except:
self.status = False
return
def run(self):
'''
类的起始工作函数, 相当于Main()
'''
self.checkBounds()
if self.status == False:
sys.stdout.write('ERROR: Please select valid data\n')
return
self.getData()
def patch(self, temp = None):
'''
把缓冲区的数据, 替换掉IDB中的数据
'''
if temp != None:
self.buffer = temp
for index, byte in enumerate(self.buffer):
idc.PatchByte(self.start+index, ord(byte))
def importb(self):
'''
导入一个文件, 初始化内置缓冲区
'''
fileName = idc.AskFile(0, "*.*", 'Import File')
try:
self.buffer = open(fileName, 'rb').read()
except:
sys.stdout.write('ERROR: Cannot access file')
def export(self):
'''
保存选择的数据到一个文件
'''
exportFile = idc.AskFile(1, "*.*", 'Export Buffer')
f = open(exportFile, 'wb')
f.write(self.buffer)
f.close()
def stats(self):
'''
状态显示, 当前选择的起始地址和结束地址与长度
'''
print "start: %s" % hex(self.start)
print "end: %s" % hex(self.end)
print "len: %s" % hex(len(self.buffer))
def decode(self):
```
解密函数
```
pass
---
<a name="sn4glk"></a>
# 使用IDA生成一个程序的 `idb`和 `asm`文件
经测试我的`IDA7`版本的`idat.exe`程序`QT`框架上有些问题, 可使用`IDA68`版本的`idaw.exe`程序使用参数`-B`命令生成文件全文的`ASM`文件和`IDB`文件
```python
import os
import subprocess
import glob
paths = glob.glob("*")
ida_path = os.path.join(os.environ['PROGRAMFILES'], "IDA",
"idaw.exe")
for file_path in paths:
if file_path.endswith(".py"):
continue
subprocess.call([ida_path, "-B", file_path])
C:\injected>dir
0?/**/____ 09:30 AM <DIR> .
0?/**/____ 09:30 AM <DIR> ..
0?/**/____ 10:48 AM 167,936 bad_file.exe
0?/**/____ 09:29 AM 270 batch_analysis.py
0?/**/____ 06:55 PM 104,889 injected.dll
C:\injected>python batch_analysis.py
Thank you for using IDA. Have a nice day!
C:\injected>dir
0?/**/____ 09:30 AM <DIR> .
0?/**/____ 09:30 AM <DIR> ..
0?/**/____ 09:30 AM 506,142 bad_file.asm
0?/**/____ 10:48 AM 167,936 bad_file.exe
0?/**/____ 09:30 AM 1,884,601 bad_file.idb
0?/**/____ 09:29 AM 270 batch_analysis.py
0?/**/____ 09:30 AM 682,602 injected.asm
0?/**/____ 06:55 PM 104,889 injected.dll
0?/**/____ 09:30 AM 1,384,765 injected.idb
等待IDA
分析结束
idaapi.autoWait()
用于等待IDA
载入文件并自动分析全文结束
退出IDA
脚本
idaapi.qexit(0)
或 idc.Exit(0)
用于退出当前脚本, 会连同IDA一起退出sys.exit(0)
会连同IDA
程序一起退出
可使用 return
进行函数或脚本退出
自动分析
idaapi.auto_make_code(dwEA)
设置某个地址分析为代码
获取工作目录
idc.get_idb_path() # 获得当前IDB所在文件路径
idc.get_input_file_path() # 获得创建IDB时, 被分析的目标文件所在路径