• angr学习


    0、资料

    几个主要的网站

    angr的github:https://github.com/angr

    angr的document:https://docs.angr.io/

    angr的api:https://angr.io/api-doc/

    1、angr安装

    我的实验环境是Ubuntu14.04,显示安装依赖:

    sudo apt-get install python-dev libffi-dev build-essential virtualenv

    然后新建一个python虚拟环境,进入angr环境

    virtualenv angr
    source angr/bin/activate

    安装angr

    sudo pip install angr

    2、angr中的基本概念

    Project

    Project是angr中的基本概念,通过下面的简单两行代码可以新建一个Project变量

    import angr
    p = angr.Project('/bin/sh')

    project中有一些基本属性,然后打印他们,包括arch中的很多属性

    print(p.arch)
    print(p.arch.bits)
    print(p.arch.name)
    print(p.arch.bytes)
    print(p.arch.memory_endness)
    print(hex(p.entry))
    print(p.filename)

    结果

    <Arch AMD64 (LE)>
    64
    AMD64
    8
    Iend_LE
    0x404e32
    /bin/sh

    loader

    loader是表示可执行文件加载到内存之中的变量,同样先来看一些基本的属性,打印他们

    print(p.loader)#主程序对象,下面的打印结果显示程序的名字是dash
    print(p.loader.shared_objects)#动态库对象,结果包含了动态连接器、库以及主程序
    print(p.loader.min_addr)
    print(p.loader.max_addr)
    print(p.loader.main_object)#主对象
    print(p.loader.main_object.execstack)#是否有可执行栈,即是否开启了nx
    print(p.loader.main_object.pic)#是否是地址无关代码

    结果如下:

    <Loaded dash, maps [0x400000:0x5008000]>
    OrderedDict([('dash', <ELF Object dash, maps [0x400000:0x61fde7]>), (u'libc.so.6', <ELF Object libc-2.19.so, maps [0x1000000:0x13c82bf]>), (u'ld-linux-x86-64.so.2', <ELF Object ld-2.19.so, maps [0x2000000:0x22241c7]>)])
    4194304
    83918848
    <ELF Object dash, maps [0x400000:0x61fde7]>
    False
    True

    factory

    可以使用project构造一系列对象

    Blocks

    angr可以从基本块的角度来分析程序,block代表基本块,给project.factory.block()函数传递一个地址,则会返回一个block对象

    看block中有哪些对象,将p.entry传递给block函数

    block = p.factory.block(p.entry)
    print(block)#基本块信息
    print(block.pp())#打印出汇编指令
    print(block.instructions)#打印出指令数目
    print(block.instruction_addrs)#打印出每条指令的地址

    结果:

    <Block for 0x404e32, 41 bytes>
    0x404e32:    xor    ebp, ebp
    0x404e34:    mov    r9, rdx
    0x404e37:    pop    rsi
    0x404e38:    mov    rdx, rsp
    0x404e3b:    and    rsp, 0xfffffffffffffff0
    0x404e3f:    push    rax
    0x404e40:    push    rsp
    0x404e41:    lea    r8, qword ptr [rip + 0x10c88]
    0x404e48:    lea    rcx, qword ptr [rip + 0x10c11]
    0x404e4f:    lea    rdi, qword ptr [rip - 0x1f6]
    0x404e56:    call    0x404900
    None
    11
    [4214322L, 4214324L, 4214327L, 4214328L, 4214331L, 4214335L, 4214336L, 4214337L, 4214344L, 4214351L, 4214358L]

    同时,可以使用block来获得其他的对象

    print(block.capstone)
    print(block.vex)

    States

    在angr中,project代表一个可执行文件的映像,如果要模拟执行程序,则需要angr中的SimState的对象states来表示程序状态

    state = p.factory.entry_state()

    看里面的一些属性

    print(state.regs.rip)#rip的值
    print(state.regs.rax)#rax的值
    print(state.mem[p.entry].int.resolved)#以int的格式打印出p.entry处的值

    结果,因为是初始状态,所以初始的rip指向的是p.entry的值

    <BV64 0x404e32>
    <BV64 0x1c>
    <BV32 0x8949ed31>

    上面这些都是不python中int值的含义,BV指的Bitvector,位向量。

    这样来进行位向量和int值的转换

    >>> bv = state.solver.BVV(0x1234, 32)       # create a 32-bit-wide bitvector with value 0x1234
    <BV32 0x1234>                               # BVV stands for bitvector value
    >>> state.solver.eval(bv)                # convert to python int
    0x1234
    >>> state.regs.rsi = state.solver.BVV(3, 64)
    >>> state.regs.rsi
    <BV64 0x3>

    然后看mem接口

    >>> state.regs.rsi = state.solver.BVV(3, 64)
    >>> state.regs.rsi
    <BV64 0x3>
    
    >>> state.mem[0x1000].long = 4
    >>> state.mem[0x1000].long.resolved
    <BV64 0x4>

    使用数组[索引]符号指定地址

    使用.<type>指定内存应该解释为<type>(常见值:char、short、int、long、size_t、uint8_t、uint16_t…)

    从那里,你可以:

    为它存储一个值,可以是位向量,也可以是python int

    使用.resolve获取作为位向量的值

    使用.concrete获取作为python int的值

    >>> state.regs.rdi
    <BV64 reg_48_11_64{UNINITIALIZED}>

    这仍然是一个64位位向量,但它不包含数值。相反,它有一个名字!这被称为符号变量,它是符号执行的基础。

    Simulation Managers

    模拟管理器,管理了程序在执行过程之中的各种接口,看看新建一个模拟管理器,使用statue

    simgr = proj.factory.simulation_manager(state)

    往下执行一个基本快

    simgr.step()

    我们可以看看simgr.active[0]来查看我们当前的statue,simgr.active[0].regs.rip则会打印寄存器的RIP,可以发现它和初始化simgr的statue已经不同了

    Analyses

    project中定义了许多的analyses

    proj.analyses.BackwardSlic
    proj.analyses.CongruencyCheck
    proj.analyses.reload_analyses
    proj.analyses.BinaryOptimizer
    proj.analyses.DDG
    proj.analyses.StaticHooker
    proj.analyses.BinDiff
    proj.analyses.DFG
    proj.analyses.VariableRecovery
    proj.analyses.BoyScout
    proj.analyses.Disassembly
    proj.analyses.VariableRecoveryFast
    proj.analyses.CDG
    proj.analyses.GirlScout
    proj.analyses.Veritesting
    proj.analyses.CFG
    proj.analyses.Identifier
    proj.analyses.VFG
    proj.analyses.CFGEmulated
    proj.analyses.LoopFinder
    proj.analyses.VSA_DDG
    proj.analyses.CFGFast
    proj.analyses.Reassembler
     
    看下面简单的CFG的例子来了解analyses的简单用法
    # Originally, when we loaded this binary it also loaded all its dependencies into the same virtual address  space
    # This is undesirable for most analysis.
    >>> proj = angr.Project('/bin/true', auto_load_libs=False)
    >>> cfg = proj.analyses.CFGFast()
    <CFGFast Analysis Result at 0x2d85130>
    
    # cfg.graph is a networkx DiGraph full of CFGNode instances
    # You should go look up the networkx APIs to learn how to use this!
    >>> cfg.graph
    <networkx.classes.digraph.DiGraph at 0x2da43a0>
    >>> len(cfg.graph.nodes())
    951
    
    # To get the CFGNode for a given address, use cfg.get_any_node
    >>> entry_node = cfg.get_any_node(proj.entry)
    >>> len(list(cfg.graph.successors(entry_node)))
    2
  • 相关阅读:
    (6)Lua 模块与包
    (3)Lua 迭代器与迭代函数
    (二)miller指导查看主控板寄存器操作
    (一)mtg3000常见操作
    (三)NAND flash和NOR flash的区别详解
    (八)shell中的循环结构
    (七)shell编程学习
    (六)动手写第一个shell
    (五)uboot移植补基础之shell
    (四)ubuntu学习前传—uboot中对Flash和DDR的管理
  • 原文地址:https://www.cnblogs.com/likaiming/p/10732650.html
Copyright © 2020-2023  润新知