├── .gitattributes ├── .gitignore ├── 10_交叉引用.py ├── 11_搜索.py ├── 12_数据选取.py ├── 13_注释和重命名.py ├── 14_访问原始机器码.py ├── 15_补丁.py ├── 16_输入与输出.py ├── 17_英特尔动态插桩记录器.py ├── 18_批量解析文件.py ├── 19_执行脚本.py ├── 5_基本操作.py ├── 6_区段.py ├── 7_函数.py ├── 8_指令.py ├── 9_操作数.py ├── IDAPython-Book.pdf ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *.cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # Jupyter Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # SageMath parsed files 79 | *.sage.py 80 | 81 | # Environments 82 | .env 83 | .venv 84 | env/ 85 | venv/ 86 | ENV/ 87 | 88 | # Spyder project settings 89 | .spyderproject 90 | .spyproject 91 | 92 | # Rope project settings 93 | .ropeproject 94 | 95 | # mkdocs documentation 96 | /site 97 | 98 | # mypy 99 | .mypy_cache/ 100 | -------------------------------------------------------------------------------- /10_交叉引用.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idc 4 | import idaapi 5 | import idautils 6 | 7 | #获取对指定API函数的所有交叉引用处 8 | writefile_addr = idc.LocByName("__imp_iswalpha") #获取API函数的地址 9 | print hex(writefile_addr), idc.GetDisasm(writefile_addr) 10 | for addr in idautils.CodeRefsTo(writefile_addr, 0): #循环遍历该API函数的所有交叉引用 11 | print hex(addr), idc.GetDisasm(addr) 12 | 13 | #获取所有API函数和被重命名函数的相关信息 14 | for x in Names(): 15 | print hex(x[0]), x[1] 16 | 17 | #获取指定地址所引用的代码 18 | #0x100001dcaL call cs:__imp_iswalpha 19 | #0x100001278L extrn __imp_iswalpha:qword 20 | ea = here() 21 | print hex(ea),idc.GetDisasm(ea) 22 | for addr in idautils.CodeRefsFrom(ea, 0): 23 | print hex(addr),idc.GetDisasm(addr) 24 | 25 | ea = 0x100001CD4 26 | print idc.MakeName(ea, "RtlCompareMemory") #将指定地址重命名 27 | for addr in idautils.CodeRefsTo(ea, 0): 28 | print hex(addr), idc.GetDisasm(addr) 29 | 30 | #查询所有对指定地址处数据的交叉引用 31 | #0x100001378L text "UTF-16LE", '\UNC\',0 32 | #0x100001723L lea r11, aUnc; "\\UNC\\" 33 | ea = here() 34 | print hex(ea), idc.GetDisasm(ea) 35 | for addr in idautils.DataRefsTo(ea):print hex(addr), idc.GetDisasm(addr) 36 | 37 | #查询该地址所引用的所有数据地址 38 | #0x100001723L lea r11, aUnc; "\\UNC\\" 39 | #0x100001378L text "UTF-16LE", '\UNC\',0 40 | ea = here() 41 | print hex(ea), idc.GetDisasm(ea) 42 | for addr in idautils.DataRefsFrom(ea):print hex(addr), idc.GetDisasm(addr) 43 | 44 | # 交叉引用的类型 45 | #0 = 'Data_Unknown' 46 | #1 = 'Data_Offset' 47 | #2 = 'Data_Write' 48 | #3 = 'Data_Read' 49 | #4 = 'Data_Text' 50 | #5 = 'Data_Informational' 51 | #16 = 'Code_Far_Call' 52 | #17 = 'Code_Near_Call' 53 | #18 = 'Code_Far_Jump' 54 | #19 = 'Code_Near_Jump' 55 | #20 = 'Code_User' 56 | #21 = 'Ordinary_Flow' 57 | 58 | # 通用查找交叉引用的方式 59 | #0x100001410L text "UTF-16LE", '\\?\Volume',0 60 | #1 Data_Offset 0x100002462L 0x100001410L 0 lea rbx, aVolume; "\\\\?\\Volume" 61 | ea = here() 62 | print hex(ea), idc.GetDisasm(ea) 63 | for xref in idautils.XrefsTo(ea, 1): # idautils.XrefsTo 第二个参数为1表示略过正常顺序指令流程造成的交叉引用 64 | print xref.type, idautils.XrefTypeName(xref.type), hex(xref.frm), hex(xref.to),xref.iscode,idc.GetDisasm(xref.frm) 65 | 66 | #True 67 | #17 Code_Near_Call 0x1000023ffL 0x100001cd4L 1 call RtlCompareMemory 68 | #1 Data_Offset 0x100007054L 0x100001cd4L 0 RUNTIME_FUNCTION 0x20: 74 | return 75 | 76 | func_call = 0 77 | instr_cmp = 0 78 | op = None 79 | op_addr = None 80 | op_type = None 81 | 82 | #遍历函数中的每条指令 83 | for ea in dism_addr: 84 | m = idc.GetMnem(ea) 85 | if m == 'call' or m == 'jmp': 86 | if m == 'jmp': 87 | temp = idc.GetOperandValue(ea, 0) 88 | # 忽略函数边界内的跳转 89 | if temp in dism_addr: 90 | continue 91 | func_call += 1 92 | #封装函数内不会包含多个函数调用 93 | if func_call == 2: 94 | return 95 | op_addr = idc.GetOperandValue(ea, 0) 96 | op_type = idc.GetOpType(ea, 0) 97 | elif m == 'cmp' or m == 'test': 98 | # 封装函数内不应该包含太多的逻辑运算 99 | instr_cmp += 1 100 | if instr_cmp == 3: 101 | return 102 | else: 103 | continue 104 | 105 | # 所有函数内的指令都被分析过了 106 | if op_addr == None: 107 | return 108 | 109 | name = idc.Name(op_addr) 110 | #跳过名称粉碎的函数名称 111 | if "[" in name or "$" in name or "?" in name or "@" in name or name == "": 112 | return 113 | name = "w_" + name 114 | if op_type == o_near: 115 | if idc.GetFunctionFlags(op_addr) & FUNC_THUNK: 116 | rename_wrapper(name, func) 117 | return 118 | if op_type == o_mem or op_type == o_far: 119 | rename_wrapper(name, func) 120 | return 121 | 122 | for func in idautils.Functions(): 123 | check_for_wrapper(func) 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /14_访问原始机器码.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idc 4 | import idaapi 5 | import idautils 6 | 7 | idc.Byte(ea) #获取单字节 8 | idc.Word(ea) #获取单字 9 | idc.Dword(ea) #获取双字 10 | idc.Qword(ea) #获取四字 11 | idc.GetFloat(ea) #获取单精度浮点数 12 | idc.GetDouble(ea) #获取双精度浮点数 13 | 14 | #0x100003b2fL mov rcx, cs:__imp__wcmdln 15 | #0x48 16 | #0x8b48L 17 | #0xa0d8b48L 18 | #0x48ffffd70a0d8b48L 19 | #6.81509894557e-33 20 | #4.46006192587e+43 21 | ea = here() 22 | print hex(ea), idc.GetDisasm(ea) 23 | print hex(idc.Byte(ea)) 24 | print hex(idc.Word(ea)) 25 | print hex(idc.Dword(ea)) 26 | print hex(idc.Qword(ea)) 27 | print float(idc.GetFloat(ea)) 28 | print float(idc.GetDouble(ea)) 29 | 30 | # 利用idc.GetManyBytes(ea, size) 获取指定地址开始的多个字节码 该函数返回的是字节的字符形式 31 | ea = here() 32 | for byte in idc.GetManyBytes(ea, 20): 33 | print "0x%X" % ord(byte) 34 | 35 | -------------------------------------------------------------------------------- /15_补丁.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idc 4 | import idaapi 5 | import idautils 6 | 7 | idc.PatchByte(ea, value) #修改字节 8 | idc.PatchWord(ea, value) #修改字 9 | idc.PatchDword(ea, value) #修改双字 10 | 11 | # 利用异或解密算法 解密选中的加密字符串 12 | start = idc.SelStart() 13 | end = idc.SelEnd() 14 | print hex(start) 15 | print hex(end) 16 | 17 | def xor(size, key, buff): 18 | for index in range(0, size): 19 | cur_addr = buff + index 20 | temp = idc.Byte(cur_addr) ^ key 21 | idc.PatchByte(cur_addr, temp) 22 | 23 | xor(end - start, 0x30, start) 24 | print idc.GetString(start) 25 | 26 | 27 | -------------------------------------------------------------------------------- /16_输入与输出.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import sys 4 | import idc 5 | import idaapi 6 | import idautils 7 | 8 | class IO_DATA(): 9 | def __init__(self): 10 | self.start = idc.SelStart() 11 | self.end = idc.SelEnd() 12 | self.buffer = '' 13 | self.ogLen = None 14 | self.status = True 15 | self.run() 16 | 17 | def checkBounds(self): 18 | if self.start is idc.BADADDR or self.end is idc.BADADDR: 19 | self.status = False 20 | 21 | def getData(self): 22 | #获取起始地址和结束地址之间的数据,并将它们存入object.buffer中 23 | self.ogLen = self.end - self.start 24 | self.buffer = '' 25 | try: 26 | for byte in idc.GetManyBytes(self.start, self.ogLen): 27 | self.buffer = self.buffer + byte 28 | except: 29 | self.start = False 30 | return 31 | 32 | def run(self): 33 | #主要功能 34 | self.checkBounds() 35 | if self.status == False: 36 | sys.stdout.write('ERROR:Please select valid data\n') 37 | return 38 | self.getData() 39 | 40 | def patch(self, temp = None): 41 | #用object.buffer中的数据给idb打补丁 42 | if temp != None: 43 | self.buffer = temp 44 | for index,byte in enumerate(self.buffer): 45 | idc.PatchByte(self.start + index, ord(byte)) 46 | 47 | def importb(self): 48 | #将文件中的内容导入到buffer中 49 | fileName = idc.AskFile(0, "*.*", 'Import File') 50 | try: 51 | self.buffer = open(fileName, 'rb').read() 52 | except: 53 | sys.stdout.write('ERROR:Cannot access file') 54 | 55 | def export(self): 56 | #将所选择的buffer保存到文件 57 | exportFile = idc.AskFile(1, "*.*", "Export Buffer") 58 | f = open(exportFile, 'wb') 59 | f.write(self.buffer) 60 | f.close() 61 | 62 | def stats(self): 63 | print "start: %s" % hex(self.start) 64 | print "end: %s" % hex(self.end) 65 | print "len: %s" % hex(len(self.buffer)) 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /17_英特尔动态插桩记录器.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import sys 4 | import idc 5 | import idaapi 6 | import idautils 7 | 8 | #对pintools执行完毕生成的文件,用IDAPython脚本来遍历其中的地址并添加注释 9 | f = open('itrace.out', 'r') 10 | lines = f.readlines() 11 | for y in lines: 12 | y = int(y, 16) 13 | idc.SetColor(y, CIC_ITEM, 0xfffff) 14 | com = idc.GetCommentEx(y, 0) 15 | if com == None or 'count' not in com: 16 | idc.MakeComm(y, 'count:1') 17 | else: 18 | try: 19 | count = int(com.split(':')[1], 16) 20 | except: 21 | print hex(y) 22 | tmp = "count:0x%x" % (count + 1) 23 | idc.MakeComm(y, tmp) 24 | 25 | f.close() 26 | -------------------------------------------------------------------------------- /18_批量解析文件.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import os 4 | import subprocess 5 | import glob 6 | 7 | paths = glob.glob("*") 8 | ida_path = os.path.join(os.environ['PROGRAMFILES'], "IDA", "idaw.exe") 9 | for file_path in paths: 10 | if file_path.endswith(".py"): 11 | continue 12 | subprocess.call([ida_path, "-B", file_path]) 13 | -------------------------------------------------------------------------------- /19_执行脚本.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idc 4 | import idaapi 5 | import idautils 6 | 7 | idaapi.autoWait() #等待IDA的分析完成 8 | 9 | # 统计idb文件中所有指令的总数 10 | # "D:\software\IDA 7.0\idat64.exe" -A -Scountrecord.py rundll32.idb 11 | 12 | count = 0 13 | for func in idautils.Functions(): 14 | #忽略库函数 15 | flags = idc.GetFunctionFlags(func) 16 | if flags & FUNC_LIB: 17 | continue 18 | for instru in idautils.FuncItems(func): 19 | count += 1 20 | 21 | f = open("instru_count.txt", "w") 22 | print_me = "Instruction Count is %d" % (count) 23 | f.write(print_me) 24 | f.close() 25 | 26 | idc.Exit(0) #停止执行脚本 并关闭idb数据库文件 27 | -------------------------------------------------------------------------------- /5_基本操作.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idc 4 | import idaapi 5 | 6 | #获取当前光标的地址 7 | ea = idc.ScreenEA() 8 | print "0x%x %s" % (ea, ea) 9 | 10 | #获取当前光标的地址 11 | ea = here() 12 | print "0x%x %s" % (ea, ea) 13 | 14 | #获取当前IDB中最小地址 15 | print hex(MinEA()) 16 | 17 | #获取当前IDB中最大地址 18 | print hex(MaxEA()) 19 | 20 | ea = here() 21 | 22 | #获取指定地址区段名称 23 | print idc.SegName(ea) 24 | 25 | #获取指定地址反汇编代码 26 | print idc.GetDisasm(ea) 27 | 28 | #获取指定地址助记符 29 | print idc.GetMnem(ea) 30 | 31 | #获取指定地址第一个操作数 32 | print idc.GetOpnd(ea, 0) 33 | 34 | #获取指定地址第二个操作数 35 | print idc.GetOpnd(ea, 1) 36 | 37 | #标识无效地址 38 | print hex(idaapi.BADADDR) 39 | 40 | if idaapi.BADADDR != here() : print "valid address" 41 | 42 | 43 | -------------------------------------------------------------------------------- /6_区段.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idautils 4 | import idc 5 | 6 | #遍历区段 7 | for seg in idautils.Segments(): 8 | print idc.SegName(seg), hex(idc.SegStart(seg)), hex(idc.SegEnd(seg)) 9 | 10 | #获取当前地址所在段的下一个段的起始地址 11 | ea = here() 12 | print hex(idc.NextSeg(ea)) 13 | 14 | #通过名称获取一个区段的起始地址 ?? 15 | print hex(idc.SegByName('.data')) 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /7_函数.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idautils 4 | import idaapi 5 | import idc 6 | 7 | #遍历所有区段中的函数 8 | for func in idautils.Functions(): 9 | print hex(func), idc.GetFunctionName(func) 10 | 11 | #查找指定起始地址,结束地址之间的所有函数 12 | funcs = idautils.Functions(0x1000491D0, 0x10004932A) 13 | for func in funcs: 14 | print hex(func), idc.GetFunctionName(func) 15 | 16 | #通过某个地址获取函数名称 17 | print idc.GetFunctionName(0x10000646D) 18 | 19 | #获取指定地址所在函数的起始地址和结束地址 方式1 20 | func = idaapi.get_func(0x10000646D) 21 | 22 | print "FuncName:%s,Start:0x%x,End:0x%x" % (idc.GetFunctionName(func.startEA),func.startEA, func.endEA) 23 | 24 | #获取指定地址所在函数的起始地址和结束地址 方式2 25 | print "Start:0x%x,End:0x%x" % (idc.GetFunctionAttr(0x10003F3BD, FUNCATTR_START), idc.GetFunctionAttr(0x10003F3BD, FUNCATTR_END)) 26 | 27 | #查看类有哪些属性 28 | dir(func) 29 | 30 | #获取类型 31 | type(func) 32 | 33 | #获取指定地址所在函数的前一个函数的起始地址 34 | func = idc.PrevFunction(0x10000646D) 35 | print idc.GetFunctionName(func), hex(func) 36 | 37 | #获取指定地址所在函数的后一个函数的起始地址 38 | func = idc.NextFunction(0x10000646D) 39 | print idc.GetFunctionName(func), hex(func) 40 | 41 | #获取下一条指令的地址 42 | idc.NextHead() 43 | 44 | #遍历某个地址所在函数的所有指令 45 | ea = here() 46 | start = idc.GetFunctionAttr(ea, FUNCATTR_START) 47 | end = idc.GetFunctionAttr(ea, FUNCATTR_END) 48 | 49 | cur_addr = start 50 | 51 | while cur_addr < end: 52 | print hex(cur_addr), idc.GetDisasm(cur_addr) 53 | cur_addr = idc.NextHead(cur_addr, end) 54 | 55 | #检索关于函数的信息 56 | 57 | for func in idautils.Functions(): 58 | flags = idc.GetFunctionFlags(func) 59 | if flags & FUNC_NORET: #FUNC_NORET:1 判断某个函数是否有返回值 (也就是说函数最后有没有ret或者leave指令) 60 | print idc.GetFunctionName(func),hex(func),"FUNC_NORET" 61 | if flags & FUNC_FAR: #FUNC_FAR:2 标识程序是否使用分段内存 62 | print idc.GetFunctionName(func),hex(func),"FUNC_FAR" 63 | if flags & FUNC_LIB: #FUNC_LIB:4 判断是否为库函数 64 | print idc.GetFunctionName(func),hex(func),"FUNC_LIB" 65 | if flags & FUNC_STATIC: #判断某个函数是否为静态函数,静态函数只能为本文件中的函数访问 66 | print idc.GetFunctionName(func),hex(func),"FUNC_STATIC" 67 | if flags & FUNC_FRAME: #判断某个函数是否使用了ebp寄存器(帧指针),使用ebp寄存器的函数通常会保存栈帧 68 | print idc.GetFunctionName(func),hex(func),"FUNC_FRAME" 69 | if flags & FUNC_USERFAR: #FUNC_USERFAR:32 用的很少 70 | print idc.GetFunctionName(func),hex(func),"FUNC_USERFAR" 71 | if flags & FUNC_HIDDEN: #带有FUNC_HIDDEN标记的函数意味着它们是隐藏的,这个函数需要展开才能查看 72 | print idc.GetFunctionName(func),hex(func),"FUNC_HIDDEN" 73 | if flags & FUNC_THUNK: #判断该函数是否为一个thunk函数,thunk函数表示的是一个简单的跳转函数 74 | print idc.GetFunctionName(func),hex(func),"FUNC_THUNK" 75 | if flags & FUNC_BOTTOMBP: #用于跟踪帧指针(ebp),它的作用是识别函数中帧指针是否等于堆栈指针(esp) 76 | print idc.GetFunctionName(func),hex(func),"FUNC_BOTTOMBP" 77 | -------------------------------------------------------------------------------- /8_指令.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idautils 4 | import idc 5 | import idaapi 6 | 7 | #获取指定函数中所有指令地址的集合,FuncItems返回的是迭代器,可以强制转换为list 8 | dism_addr = list(idautils.FuncItems(here())) 9 | print type(dism_addr) 10 | 11 | print dism_addr 12 | 13 | for line in dism_addr: 14 | print hex(line), idc.GetDisasm(line) 15 | 16 | #获取下一个指令的地址 17 | idc.NextHead(ea) 18 | 19 | #获取上一条指令的地址 20 | idc.PrevHead(ea) 21 | 22 | #获取下一个地址 23 | idc.NextAddr(ea) 24 | 25 | #获取上一个地址 26 | idc.PrevAddr(ea) 27 | 28 | #遍历所有的动态调用 29 | for func in idautils.Functions(): 30 | flags = idc.GetFunctionFlags(func) 31 | if flags & FUNC_LIB or flags & FUNC_THUNK: 32 | continue 33 | dism_addr = list(idautils.FuncItems(func)) 34 | for line in dism_addr: 35 | m = idc.GetMnem(line) 36 | if m == 'call' or m == 'jmp': 37 | op = idc.GetOpType(line, 0) 38 | if op == o_reg: 39 | print "0x%x %s" % (line, idc.GetDisasm(line)) 40 | 41 | ea = here() 42 | print hex(ea), idc.GetDisasm(ea) 43 | next_instr = idc.NextHead(ea) 44 | print hex(next_instr), idc.GetDisasm(next_instr) 45 | prev_instr = idc.PrevAddr(ea) 46 | print hex(prev_instr), idc.GetDisasm(prev_instr) 47 | print hex(idc.NextAddr(ea)) 48 | print hex(idc.PrevAddr(ea)) 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /9_操作数.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | 3 | import idaapi 4 | import idc 5 | import idautils 6 | 7 | # o_void值为0 表示指令没有任何操作数 8 | # 1000029A9 retn 9 | ea = here() 10 | print hex(ea), idc.GetDisasm(ea) 11 | print idc.GetOpType(ea, 0) 12 | 13 | # o_reg值为1 表示指令的操作数是寄存器 14 | # 0x100002779L mov rax, cs:__security_cookie 15 | ea = here() 16 | print hex(ea), idc.GetDisasm(ea) 17 | print idc.GetOpType(ea, 0) 18 | 19 | # o_mem值为2 表示指令的操作数是直接寻址的内存 这种类型对寻找数据的引用非常有帮助 20 | # 0x100002779L mov rax, cs:__security_cookie 21 | ea = here() 22 | print hex(ea), idc.GetDisasm(ea) 23 | print idc.GetOpType(ea, 1) 24 | 25 | # o_phrase值为3 表示指令的操作数采用的是基址寄存器和变址寄存器的寻址方式 26 | # 1000022B4 lea rdx, [rsi+rsi] ; uBytes 27 | ea = here() 28 | print hex(ea), idc.GetDisasm(ea) 29 | print idc.GetOpType(ea, 1) 30 | 31 | # o_displ的值为4 表示指令的操作数采用寄存器加偏移的寻址方式 这种类型在获取结构体中的某个数据的时候非常常见 32 | # 100002396 lea r9, [rsp+288h+var_268] ; unsigned __int64 * 33 | ea = here() 34 | print hex(ea), idc.GetDisasm(ea) 35 | print idc.GetOpType(ea, 1) 36 | 37 | # o_imm的值为5 表示指令的操作数是一个确定的值 38 | # 1000022B8 mov ecx, 40h ; uFlags 39 | ea = here() 40 | print hex(ea), idc.GetDisasm(ea) 41 | print idc.GetOpType(ea, 1) 42 | 43 | # o_far的值为6 用来判断直接访问远端地址的操作数 x86 x64逆向用的很少 44 | ea = here() 45 | print hex(ea), idc.GetDisasm(ea) 46 | print idc.GetOpType(ea, 1) 47 | 48 | # o_near的值为7 用来判断直接访问近端地址的操作数 49 | # 1000027E2 jz short loc_100002835 50 | ea = here() 51 | print hex(ea), idc.GetDisasm(ea) 52 | print idc.GetOpType(ea, 0) 53 | 54 | # 例子1 将o_displ类型的指令 偏移 + 指令首地址 构成字典 便于查询 55 | displace = {} 56 | #遍历所有已知的函数 57 | for func in idautils.Functions(): 58 | flags = idc.GetFunctionFlags(func) 59 | #跳过库函数和简单的跳转函数 60 | if flags & FUNC_LIB or flags & FUNC_THUNK: 61 | continue 62 | dism_addr = list(idautils.FuncItems(func)) 63 | for curr_addr in dism_addr: 64 | op = None 65 | index = None 66 | #另一种访问类型的方式,跟idc.GetOpType类似 67 | idaapi.decode_insn(curr_addr) 68 | if idaapi.cmd.Op1.type == idaapi.o_displ: 69 | op = 1 70 | if idaapi.cmd.Op2.type == idaapi.o_displ: 71 | op = 2 72 | if op == None: 73 | continue 74 | if "bp" in idaapi.tag_remove(idaapi.ua_outop2(curr_addr, 0)) or "bp" in idaapi.tag_remove(idaapi.ua_outop2(curr_addr, 1)): 75 | # bp/ebp/rbp将返回一个负数 76 | if op == 1: 77 | index = (~(int(idaapi.cmd.Op1.addr) - 1) & 0xFFFFFFFF) 78 | else: 79 | index = (~(int(idaapi.cmd.Op2.addr) - 1) & 0xFFFFFFFF) 80 | else: 81 | if op == 1: 82 | index = int(idaapi.cmd.Op1.addr) 83 | else: 84 | index = int(idaapi.cmd.Op2.addr) 85 | if index: 86 | if displace.has_key(index) == False: 87 | displace[index] = [] 88 | displace[index].append(curr_addr) 89 | 90 | for x in displace[0x130]: print hex(x), idc.GetDisasm(x) 91 | 92 | #遍历所有函数,尝试将带有立即数寻址方式的指令中立即数转化为对数据的偏移 93 | 94 | min = MinEA() 95 | max = MaxEA() 96 | #遍历所有已知的函数 97 | for func in idautils.Functions(): 98 | flags = idc.GetFunctionFlags(func) 99 | #跳过库函数和简单的跳转函数 100 | if flags & FUNC_LIB or flags & FUNC_THUNK: 101 | continue 102 | dism_addr = list(idautils.FuncItems(func)) 103 | for curr_addr in dism_addr: 104 | if idc.GetOpType(curr_addr, 0) == o_imm and (min < idc.GetOperandValue(curr_addr, 0) < max): 105 | idc.OpOff(curr_addr, 0, 0) #将操作数转换为一个偏移 106 | if idc.GetOpType(curr_addr, 1) == o_imm and (min < idc.GetOperandValue(curr_addr, 1) < max): 107 | idc.OpOff(curr_addr, 1, 0) #将操作数转换为一个偏移 108 | -------------------------------------------------------------------------------- /IDAPython-Book.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExpLife0011/IDAPython_Note/1f0e03a19716dab16a81997ffe1726a5073e072a/IDAPython-Book.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 ExpLife 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IDAPython_Note 2 | --------------------------------------------------------------------------------