• idapython常用api记录7.0


    idapython常用api记录
    以下代码片段可以在ida的output窗口中测试用,需要引入相关的模块即可。

    import idaapi
    import idc
    import idautils

    后续需要使用的程序代码指令


    0017C24 CODE32
    LOAD:00017C24
    LOAD:00017C24 ; =============== S U B R O U T I N E =======================================
    LOAD:00017C24
    LOAD:00017C24 ; Attributes: thunk
    LOAD:00017C24
    LOAD:00017C24 ; int fstat(int fd, struct stat *buf)
    LOAD:00017C24 fstat ; CODE XREF: sub_136A44+64↓p
    LOAD:00017C24 ADRL R12, 0x1C1C2C
    LOAD:00017C2C LDR PC, [R12,#(off_1C2B20 - 0x1C1C2C)]! ; __imp_fstat
    LOAD:00017C2C ; End of function fstat
    LOAD:00017C2C
    ....

    0017C30
    LOAD:00017C30 ; =============== S U B R O U T I N E =======================================
    LOAD:00017C30
    LOAD:00017C30
    LOAD:00017C30 EXPORT start
    LOAD:00017C30 start ; DATA XREF: LOAD:00000018↑o
    LOAD:00017C30 ; LOAD:stru_66C↑o
    LOAD:00017C30 LDR R0, =(unk_1C3000 - 0x17C3C)
    LOAD:00017C34 ADD R0, PC, R0 ; unk_1C3000
    LOAD:00017C38 B __cxa_finalize
    LOAD:00017C38 ; End of function start
    LOAD:00017C38
    LOAD:00017C38 ; ---------------------------------------------------------------------------
    LOAD:00017C3C off_17C3C DCD unk_1C3000 - 0x17C3C
    LOAD:00017C3C ; DATA XREF: start↑r


    0017C3C ; DATA XREF: start↑r
    LOAD:00017C40 ; ---------------------------------------------------------------------------
    LOAD:00017C40
    LOAD:00017C40 loc_17C40 ; DATA XREF: LOAD:00017C5C↓o
    LOAD:00017C40 ; LOAD:off_17C68↓o
    LOAD:00017C40 CMP R0, #0
    LOAD:00017C44 BXEQ LR
    LOAD:00017C48 BX R0
    LOAD:00017C4C ; ---------------------------------------------------------------------------
    LOAD:00017C4C MOV R1, R0
    LOAD:00017C50 LDR R2, =(unk_1C3000 - 0x17C60)
    LOAD:00017C54 LDR R0, =(loc_17C40 - 0x17C64)
    LOAD:00017C58 ADD R2, PC, R2 ; unk_1C3000
    LOAD:00017C5C ADD R0, PC, R0 ; loc_17C40
    LOAD:00017C60 B __cxa_atexit
    LOAD:00017C60 ; ---------------------------------------------------------------------------
    LOAD:00017C64 off_17C64 DCD unk_1C3000 - 0x17C60
    LOAD:00017C64 ; DATA XREF: LOAD:00017C50↑r
    LOAD:00017C68 off_17C68 DCD loc_17C40 - 0x17C64 ; DATA XREF: LOAD:00017C54↑r
    LOAD:00017C6C CODE16
    LOAD:00017C6C
    LOAD:00017C6C ; =============== S U B R O U T I N E =======================================
    LOAD:00017C6C
    LOAD:00017C6C ; Attributes: bp-based frame
    LOAD:00017C6C
    LOAD:00017C6C sub_17C6C ; CODE XREF: sub_1BC30+8↓p
    LOAD:00017C6C ; LOAD:000303A6↓p ...
    LOAD:00017C6C PUSH {R7,LR}
    LOAD:00017C6E ADD R7, SP, #0
    LOAD:00017C70 BL sub_17580
    LOAD:00017C74 POP {R7,PC}
    LOAD:00017C74 ; End of function sub_17C6C
    LOAD:00017C74


    获取当前光标位置地址
    ea=here()
    ea=ScreenEA()

    遍历当前模块的segment
    import idautils
    import idc

    def loop_through_segments():
    '''
    遍历出所有的segment
    '''
    # ea=ScreenEA() ##获取当前光标指向的地址
    # print(hex(ea))
    for seg in idautils.Segments():
    print('segName:%s 0x%x-0x%x ' %(idc.SegName(seg),idc.SegStart(seg),idc.SegEnd(seg)))

    segmentName:idc.SegName(seg) ##段名称
    segmentStart:idc.SegStart(seg) ##段起始位置
    segmentEnd:idc.SegEnd(seg) ## 段结束位置


    获取段信息的其他api
    idc.NextSeg(ea) ##获取当前段的下一个段
    idc.SegByName(segname) ##根据名称获取段的地址,实际在测试的时候,调用这个函数只能返回的是segment的个数segment

    输出:
    Python>idc.SegByName('LOAD')
    2 ##表示有两个LOAD段


    获取当前模块的导出所有函数
    import idautils
    import idc

    def loop_module_funcs():
    for func in idautils.Functions(): ##获取所有的导出函数
    '''
    idautils.Functions列举出已知的函数,返回一个list对象,每个item是一个函数的首地址,
    通过idc.GetFunctionName(funcAddr)获取函数名称
    '''
    print(hex(func),idc.GetFunctionName(func))


    idautils.Functions():返回所有的导出函数的函数地址,可以通过for来循环迭代每个函数

    idautils.GetFuncntionName(ea):根据当前的函数地址,返回函数名称。


    获取函数的起始和结束地址
    有时候我们在读取一个函数的指令的时候,需要知道函数的起始地址和结束地址,使用idaapi.get_func(faddr)

    def get_func_boundaries(ea):
    func=idaapi.get_func(ea)
    start = func.start_ea
    end =func.end_ea
    print('start: 0x%x end:0x%x' %(start,end))

    def loop_module_funcs():
    for func in idautils.Functions():
    '''
    idautils.Functions列举出已知的函数,返回一个list对象,每个item是一个函数的首地址,
    通过idc.GetFunctionName(funcAddr)获取函数名称
    '''
    print(hex(func),idc.GetFunctionName(func))
    get_func_boundaries(func)
    loop_module_funcs()


    idaapi.get_func(ea):返回一个func_t对象,其中包含了函数的起始地址和结束地址


    使用dir函数查看func_t对象,如下
    Python>func = idaapi.get_func(0x17C30)
    Python>type(func)
    <class 'ida_funcs.func_t'>
    Python>dir(func)
    ['__class__', '__del__', '__delattr__',
    '__dict__', '__doc__', '__eq__', '__format__',
    '__getattribute__', '__gt__', '__hash__', '__init__',
    '__lt__', '__module__', '__ne__', '__new__', '__reduce__',
    '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
    '__str__', '__subclasshook__', '__swig_destroy__',
    '__weakref__', '_print', 'analyzed_sp', 'argsize',
    'clear', 'color', 'compare', 'contains', 'does_return',
    'empty', 'endEA', 'end_ea', 'extend', 'flags', 'fpd',
    'frame', 'frregs', 'frsize', 'intersect', 'is_far',
    'llabelqty', 'llabels', 'overlaps', 'owner', 'pntqty',
    'points', 'referers', 'refqty', 'regargqty', 'regargs',
    'regvarqty', 'regvars', 'size', 'startEA', 'start_ea',
    'tailqty', 'tails', 'this', 'thisown']


    其中的startEA,start_ea 和endEA ,end_ea表示函数的边界值

    在ida中执行上述脚本,输出如下:

    ('0x173c4L', 'strerror')
    start: 0x173c4 end:0x173d0
    ('0x173d0L', 'memcpy')
    start: 0x173d0 end:0x173dc
    ('0x173dcL', 'sub_173DC')
    start: 0x173dc end:0x173de


    列出指定地址范围内的所有函数
    有时候可能模块的很多区域的函数我们不需要,只需要指定一定范围内的并列举出该范围内的函数,如果全部列出可能会花费很大时间见,可以使用idautils.Functions(start_addr,end_addr)来读取

    def loop_module_funcs(start_addr,end_addr):
    for func in idautils.Functions(start_addr,end_addr):
    print(hex(func),idc.GetFunctionName(func))
    get_func_boundaries(func)

    loop_module_funcs(0x17514L,0x17560L)

    idc.GetFunctionName(func):获取函数地址处的函数名称

    上述脚本表述只列出了0x17514L~0x17560L之间的函数,如下

    ('0x17514L', '__aeabi_memset4')
    start: 0x17514 end:0x17520
    ('0x17520L', 'j_clock_gettime')
    start: 0x17520 end:0x17524
    ('0x17524L', 'clock_gettime')
    start: 0x17524 end:0x17530
    ('0x17530L', 'sub_17530')
    start: 0x17530 end:0x17532
    ('0x17534L', 'readlink')
    start: 0x17534 end:0x17540
    ('0x17540L', 'j_sscanf')
    start: 0x17540 end:0x17544
    ('0x17544L', 'sscanf')
    start: 0x17544 end:0x17550
    ('0x17550L', 'sub_17550')
    start: 0x17550 end:0x17552
    ('0x17554L', 'free')
    start: 0x17554 end:0x17560


    其他常用获取模块函数的api
    可以对应查看开始处的代码片段

    ##获取下一个函数
    idc.NextFunction(addr)

    nfc=idc.NextFunction(0x17C30)
    Python>idc.GetFunctionName(nfc)
    sub_17C6C

    ---------------------
    获取上一个函数
    idc.PrevFunction(addr)

    Python>pre = idc.PrevFunction(0x17C30)
    Python>idc.GetFunctionName(pre)
    fstat


    获取函数的指令
    读取函数的起始地址和结束地址
    读取函数内的指令,包括 汇编指令 操作数

    #coding:utf8

    import idaapi
    import idc
    import idautils


    def get_func_boundaries(ea):
    func=idaapi.get_func(ea)
    start = func.start_ea
    end =func.end_ea
    # print('start: 0x%x end:0x%x' %(start,end))
    return start,end

    def get_disassm(addr):

    '''
    这里读取start函数内的指令即可
    '''
    start,end = get_func_boundaries(addr)
    while True: ##
    print('start: 0x%x' %start)
    mnemonic=idc.GetMnem(start)##获取指令的助记符
    op1=idc.GetOpnd(start,0) ###获取指令的操作数1,
    op2 = idc.GetOpnd(start,1) ### 获取指令的操作数2
    # print('mnemonic:%s op1:%s op2:%s ' %(mnemonic,op1,op2))
    ##完整的一条指令
    print('disasm:')
    disasm = idc.GetDisasm(start) ###获取程序指令
    print(disasm)
    start +=4 ##每次地址递增4个字节
    if start>=end:
    break

    get_disassm(0x17C30)

    输出:

    start: 0x17c30
    disasm:
    LDR R0, =(unk_1C3000 - 0x17C3C)
    start: 0x17c34
    disasm:
    ADD R0, PC, R0; unk_1C3000
    start: 0x17c38
    disasm:
    B __cxa_finalize

    以上就将start出的函数所有指令都提取出来


    读取函数指令2
    在上面的程序中,利用现有的知识点来读取指定函数的指令,当然,ida还提供来另一种方式来读取指定函数地址出的指令,如下

    def get_disasm2(addr):
    '''
    读取指令的另一种方式
    '''
    start = idc.GetFunctionAttr(addr,FUNCATTR_START) ## 通过idc.GetFunctionAttr来获取函数的起始地址,起中第二个参数使用FUNCATTR_START表示起始
    end=idc.GetFunctionAttr(addr,FUNCATTR_END) ## 通过idc.GetFunctionAttr来获取函数的起始地址,起中第二个参数使用FUNCATTR_END表示结束
    cur_start=start
    print('start22: 0x%x end:0x%x' %(start,end))
    while cur_start<=end: ###结束条件为当前指令地址大于函数的结束地址
    print('addr2:0x%x'%cur_start)
    disasm = idc.GetDisasm(cur_start)
    print(disasm)
    cur_start=idc.NextHead(cur_start,end) ###读取下一个指令的地址,类似于我们的start+=4

    运行后,输出结果为:

    start22: 0x17c30 end:0x17c3c
    addr2:0x17c30
    LDR R0, =(unk_1C3000 - 0x17C3C)
    addr2:0x17c34
    ADD R0, PC, R0; unk_1C3000
    addr2:0x17c38
    B __cxa_finalize


    读取指令3
    使用idautils.FuncItems(addr)来获取函数的所有指令地址,这里比较好的是不用去判断某个指令地址大于函数的结束地址,如下指令


    def get_disasm33(addr):

    '''
    使用idc.FuncItems(addr)函数类读取一个函数的指令和边界值,idc.FuncItems(addr)返回一个可迭代对象
    将这个对象转为了list即可。这个list内部是一个顺序的地址值,从函数的起始地址到结束地址开始
    '''
    pass
    disasm_addrs = list(idautils.FuncItems(addr))
    for d in disasm_addrs:
    print(idc.GetDisasm(d))

    输出:
    LDR R0, =(unk_1C3000 - 0x17C3C)
    ADD R0, PC, R0; unk_1C3000
    B __cxa_finalize


    读取指令需要注意的问题
    有些地址不存在,需要处理,使用idaapi.BADADDR来做对比
    Python>if n != idaapi.BADADDR:print ('valid addr ')
    valid addr

    上述两个遍历指令的方式缺点为:
    1、只能读取包括在函数边界边内的,如果存在跳转指令,则有可能导致结束地址小于跳转指令,那么将会导致不能全部读取指令值。
    2、当出现跳转地址大于函数的边界值时,这种在代码混淆中常常存在。
    判断指令类型
    通常在读取指令的时候,可能需要判断一下指令的操作数类型,是否是寄存器还是常数函数指向内存的指针等

    idc.GetOpType(addr,index) 表示要获取的操作数类型,index表示第一个还是第二个
    常用的类型包括了

    o_void = ida_ua.o_void # No Operand ----------
    o_reg = ida_ua.o_reg # General Register (al,ax,es,ds...) reg
    o_mem = ida_ua.o_mem # Direct Memory Reference (DATA) addr
    o_phrase = ida_ua.o_phrase # Memory Ref [Base Reg + Index Reg] phrase
    o_displ = ida_ua.o_displ # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr
    o_imm = ida_ua.o_imm # Immediate Value value
    o_far = ida_ua.o_far # Immediate Far Address (CODE) addr
    o_near = ida_ua.o_near # Immediate Near Address (CODE) addr
    o_idpspec0 = ida_ua.o_idpspec0 # Processor specific type
    o_idpspec1 = ida_ua.o_idpspec1 # Processor specific type
    o_idpspec2 = ida_ua.o_idpspec2 # Processor specific type
    o_idpspec3 = ida_ua.o_idpspec3 # Processor specific type
    o_idpspec4 = ida_ua.o_idpspec4 # Processor specific type
    o_idpspec5 = ida_ua.o_idpspec5 # Processor specific type
    # There can be more processor specific types

    # x86
    o_trreg = ida_ua.o_idpspec0 # trace register
    o_dbreg = ida_ua.o_idpspec1 # debug register
    o_crreg = ida_ua.o_idpspec2 # control register
    o_fpreg = ida_ua.o_idpspec3 # floating point register
    o_mmxreg = ida_ua.o_idpspec4 # mmx register
    o_xmmreg = ida_ua.o_idpspec5 # xmm register

    # arm
    o_reglist = ida_ua.o_idpspec1 # Register list (for LDM/STM)
    o_creglist = ida_ua.o_idpspec2 # Coprocessor register list (for CDP)
    o_creg = ida_ua.o_idpspec3 # Coprocessor register (for LDC/STC)
    o_fpreglist = ida_ua.o_idpspec4 # Floating point register list
    o_text = ida_ua.o_idpspec5 # Arbitrary text stored in the operand
    o_cond = (ida_ua.o_idpspec5+1) # ARM condition as an operand

    # ppc
    o_spr = ida_ua.o_idpspec0 # Special purpose register
    o_twofpr = ida_ua.o_idpspec1 # Two FPRs
    o_shmbme = ida_ua.o_idpspec2 # SH & MB & ME
    o_crf = ida_ua.o_idpspec3 # crfield x.reg
    o_crb = ida_ua.o_idpspec4 # crbit x.reg
    o_dcr =

    如何获取当前指令的上一个指令和下一个指令
    有时候我们只有同一个地址值并且能读取到当前地址的指令,为了能获取到当前指令的上一个或者下一个指令,通过idc,PrevHead(addr)和idc.NextHead(addr)来
    获取。如下

    我们引用的是0x17C34处的地址,实际得到的是指令为

    ADD R0, PC, R0
    上一条指令为:
    Python>pre = idc.PrevHead(0x17C34 )
    Python>idc.GetDisasm(pre)
    LDR R0, =(unk_1C3000 - 0x17C3C)
    ------------------------------------------
    读取下一条指令为:
    Python>nt = idc.NextHead(0x17C34)
    Python>idc.GetDisasm(nt)
    B __cxa_finalize



    总结
    在ida的高版本中,6.95 -7.0以后,有一些api发生了变化。我们使用inspect查看函数
    如下

    Python>import inspect
    Python>inspect.getsource(SegByName)
    def SegByName(segname): return selector_by_name(segname)


    读取光标所在的位置:ScreenEA(),here()
    读取段:
    读取段名称:idc.SegName(addr)
    遍历段:idautils.Segments()返回一个可迭代对象,通过这个对象来获取模块的segment,
    获取段首地址:idc.SegStart(seg)
    获取段结束地址:idc.SegEnd(seg)
    读取下一个段:idc.NextSeg(seg)
    根据段名称获取段个数:idc.SegByName(segname)
    读取函数:
    获取所有导出的函数:idc.Functions()返回一个可迭代对象,利用for来迭代,每次返回一个函数地址func_addr

    获取指定返回的导出函数:idc.Functions(start,end) 会将start和end之间的函数迭代出来

    获取函数名称:idc.GetFunctionName(func_addr)

    获取函数的首地址和结束地址:

    func=idaapi.get_func(func_addr)

    这里的func是一个func_t对象,

    可以通过访问start_ea和end_ea来获取到函数的起始地址和结束地址
    start=func.start_ea
    end=func.end_ea

    获取下一个函数:idc.NextFunction(addr)

    获取上一个函数:idc.PrevFunction(addr)

    读取函数的起始地址:idc.GetFunctionAttr(addr,FUNCATTR_START)

    读取函数的结束地址:idc.GetFunctionAttr(addr,FUNCATTR_END)

    读取指令:
    读取助记符:idc.GetMnem(addr)
    读取操作数1:idc.GetOpnd(addr,0)
    读取操作数2:idc.GetOpnd(addr,1)
    读取操作数1的类型:idc.GetOpType(addr,0)
    读取操作数2的类型:idc.GetOpType(addr,1)
    读取汇编指令:idc.GetDisasm(addr)
    读取函数的所有指令地址:idautils.FuncItems(addr) 可以通过将得到的是强转为一个list对象,也可以直接迭代,推荐使用此方法来读取指令
    读取当前指令的上一条指令地址:idc.PrevHead(addr)
    读取当前指令的下一条指令地址:idc.NextHead(addr)
    未完…

  • 相关阅读:
    centos yum安装与配置vsFTPd FTP服务器(转)
    CentOS 6.9安装配置nmon
    Linux 中将用户添加到组的指令
    linux 设置用户组共享文件
    linux时间同步ntpdate
    java获取端口号,不用request
    centos6.5 yum安装redis
    Centos6 yum安装nginx
    Nginx 不支持WebSocket TCP
    django中的分页应用 django-pure-pagination
  • 原文地址:https://www.cnblogs.com/coffee520/p/14942258.html
Copyright © 2020-2023  润新知