ANGR初识

首页: https://angr.io
项目存储库: GitHub - angr/angr: A powerful and user-friendly binary analysis platform!
文档: https://docs.angr.io
API 文档: angr documentation
练习项目: https://github.com/angr/angr-doc/tree/master
angr 是一款开源的python框架,是一个多架构开源二进制分析工具包,能够对二进制文件执行动态符号执行(如 Mayhem、KLEE 等)和各种静态分析。
直接 pip install angr就可以安装。

一、angr架构

CLE:
CLE是angr加载二进制文件的组件,在加载二进制文件时会分析并读取binary的信息,包括指令地址、shared library、arch information等;
import angr
b = angr.Project("./test")
VEX:
它会将指令转化为中间语言IR,分析IR并且模拟,搞清楚它是什么并且做了什么;
Claripy:
它是angr的求解引擎,根据程序所需要的输入设置符号变量以及收集限制式等等,在argr中多用于符号化。

二、核心概念

2.1、顶层接口

Project类是angr的主类,也是angr的开始,通过初始化该类的对象,可以将你想要分析的二进制文件加载进来,就像这样:
import angr
proj = angr.Project("/bin/true")
参数:
  • thing:待分析的文件路径,它是唯一必须传入的参数
  • auto_load_libs:是否用CLE自动解析共享库依赖关系,默认为on。
  • except_missing_libs:当二进制文件有无法解析的共享库依赖项时,将引发异常,默认为on。
  • force_load_libs:将字符串列表传递给force_load_libs,所列出的内容将作为未解析的共享库依赖项处理,
  • skip_libs:将字符串列表传递给skip_libs,以防止将该名称的任何库解析为依赖项。
  • main_opts是一个从选项名到选项值的映射
  • lib_opts是一个从库名到将选项名映射到选项值的字典的映射 例如angr.Project('examples/fauxware/fauxware', main_opts={'backend': 'blob', 'arch': 'i386'}, lib_opts={'libc.so.6': {'backend': 'elf'}}
任何附加的参数都会被传递到angr的加载器,即CLE.loader中(CLE 即 CLE Loads Everything的缩写)。
Project类中有许多方法和属性,例如架构、程序入口点、加载的文件名、大小端等等:
>>> print(proj.arch, hex(proj.entry), proj.filename, proj.arch.bits, proj.arch.memory_endness )
<Arch AMD64 (LE)> 0x4023c0 /bin/true 64 Iend_LE

2.2、Blocks

project.factory.block()用于 从给定的地址提取基本代码块。angr是以基本块为单位分析代码。
返回一个Block对象。
>>> block = proj.factory.block(proj.entry) # lift a block of code from the program's entry point
<Block for 0x401670, 42 bytes>>>> block.pp()       # 打印反汇编内容,地址显示16进制
4017b0  xor     ebp, ebp
4017b2  mov     r9, rdx
4017b5  pop     rsi
4017b6  mov     rdx, rsp
4017b9  and     rsp, 0xfffffffffffffff0
4017bd  push    rax
4017be  push    rsp
4017bf  lea     r8, [0x4049f0]
4017c6  lea     rcx, [0x404980]
4017cd  lea     rdi, [0x4016f0]
4017d4  call    qword ptr [0x606fd8]>>> block.instructions      # 有多少条指令
11
>>> block.instruction_addrs  # 指令的地址,返回10进制,若要返回16进制,在此之前加上 import monkeyhex # this will format numerical results in hexadecimal
(4200368, 4200370, 4200373, 4200374, 4200377, 4200381, 4200382, 4200383, 4200390, 4200397, 4200404)
此外,您可以使用 Block 对象来获取代码块的其他表示形式:
>>> block.capstone                   # capstone disassembly
<DisassemblerBlock for 0x4017b0>>>> block.vex                        # VEX IRSB (that's a Python internal address, not a program address)
IRSB <0x2a bytes, 11 ins., <Arch AMD64 (LE)>> at 0x4017b0

2.3、状态State

Project实际上只是将二进制文件加载进来了,要执行它,实际上是对SimState对象进行操作,它是程序的状态。用docker来比喻,Project相当于开发环境,State则是使用开发环境制作的镜像。

2.3.1、创建状态

要创建状态,需要使用Project对象中的factory,它还可以用于创建模拟管理器和基本块。
state = proj.factory.entry_state()
返回值:
    返回一个Simstate,SimState包含程序的内存、寄存器、文件系统、符号变量和约束内容等……任何可以通过执行更改的“实时数据”均在SimState。
预设状态有四种方式如下:   
  • entry_state():构造一个准备在主二进制文件的入口点执行的状态。
  • blank_state(addr=)构造了一个“空白石板”空白状态,其大部分数据未初始化,状态中下一条指令为addr处的指令当访问未初始化的数据时,将返回一个不受约束的符号值。
  • full_init_state()构造一个状态,该状态可以通过需要在主二进制的入口点之前运行的任何初始化程序执行,例如共享库构造函数或预初始化程序。当完成这些后,它将跳转到入口点。
  • call_state()构造准备执行给定函数的状态
entry_state和blank_state是常用的两种方式,后者通常用于跳过一些极大降低angr效率的指令,它们间的对比如下:
>>> state = p.factory.entry_state()
>>> print(state.regs.rax, state.regs.rip)  # state.regs.rip:get the current instruction pointer
<BV64 0x1c> <BV64 0x4023c0>>>> state = p.factory.blank_state(addr=0x4023c0)
>>> print(state.regs.rax, state.regs.rip)
<BV64 reg_rax_42_64{UNINITIALIZED}> <BV64 0x4023c0>
在blank_state方式中,我们仍将地址设定为程序的入口点,然而rax中的值由于没有初始化,它现在是一个名字,也即符号变量,这是符号执行的基础,后续在细说。
此外,可以看到寄存器中的数据类型并不是int,而是BV64,它是一个位向量(Bit Vector)。

2.3.2、BV与BVS

位向量(Bit Vector,BV)就是一串比特的序列,这于python中的int不同,例如python中的int提供了整数溢出上的包装。而位向量可以理解为CPU中使用的一串比特流,需要注意的是, angr封装的位向量有两个属性:值以及它的长度
以下是 如何从 Python 整数转换为 位向量 并再次转换回来每个位向量都有一个 .length 属性,描述其位宽
>>> 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
4660
位向量相互之间能够进行运算,但 参与运算的位向量的长度必须相同
>>> one = state.solver.BVV(1,64)
>>> one_hundred = state.solver.BVV(100,64)
>>> short_nine = state.solver.BVV(9,27)
>>> print(one,one_hundred,short_nine)
<BV64 0x1> <BV64 0x64> <BV27 0x9>>>> print(short_nine+1)
<BV27 0xa>
>>> print(one+one_hundred)
<BV64 0x65>
>>> print(one+short_nine)
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "/usr/local/lib/python3.6/dist-packages/claripy/operations.py", line 50, in _opraise ClaripyOperationError(msg)
claripy.errors.ClaripyOperationError: args' length must all be equal   # 当长度不一样时,claripy会提示“length must all be equal”,同时我们也得知,位向量运算的底层模块时claripy
如果一定要进行长度不相等位向量之间的运算,可以扩展位向量使用zero_extend会用零扩展高位,而sign_extend会在此基础上带符号地进行扩展
>>> print(one+short_nine.zero_extend(64-27))
<BV64 0xa>
接下来使用 BVS(Bit Vectort Symbol)创建一些符号变量:
>>> x = state.solver.BVS('x',64)   # BVS的参数分别是符号变量名和长度
>>> y = state.solver.BVS('y',64)
>>> z = state.solver.BVS('notz',64)
>>> print(x,y,z)
<BV64 x_42_64> <BV64 y_43_64> <BV64 notz_44_64>
此时对符号变量进行运算,做比较判断,都不会得到一个具体的值,而是将这些操作统统保存到符号变量中:
>>> print(x+1)
<BV64 x_42_64 + 0x1>

2.3.3、状态操作

状态包含了程序运行时的一切信息,寄存器、内存的值、文件系统以及符号变量等
寄存器访问:可以通过state.regs.寄存器名来访问和修改寄存器:
  • state.regs.rip  get the current instruction pointer
  • state.regs.rax
  • state.regs.rbp = state.regs.rsp # 将寄存器rsp的值给rbp
栈访问:栈访问涉及两个寄存器:ebp和esp,以及两个指令:push和pop,对于寄存器的访问与其他寄存器相同
  • state.stack_push(value)
  • state.stack_pop()
内存访问:使用以下两个指令对内存读写:
  • 读内存-state.memory.load(addr, size=None, condition=None, fallback=None, **kwargs) 程序所使用的大小端endness可以用proj.arch.memory_endness查询,因此在对默认值没有把握时,请让endness=p.arch.memory_endness。
  • 写内存-state.memory.store(addr, data, size=None, condition=None, **kwargs)
文件访问:angr提供SimFile类用来模拟文件,通过将SimFile对象插入到状态的文件系统中,在使用angr分析程序时就可以使用该文件。
    filename = 'test.txt'simfile = angr.storage.SimFile(name=filename, content=data, size=0x40)state.fs.insert(filename, simfile)
上述指令能创建一个SimFile对象,文件名为test.txt,内容为data,输入的内容长度为0x40,单位为字节。之后,使用state.fs.insert方法,将SimFile对象插入到状态的文件系统中,在模拟运行程序时就可以使用这个文件了。

2.4、符号约束与求解

2.4.1、符号约束

每个符号本质上可以看做是一颗抽象语法树(AST), x = state.solver.BVS( ' x ' ,64 )生成的符号变量<BV64 x_42_64>可以看作是只有一层的AST,对它进行操作实际上是在扩展AST,这样的AST的构造规则如下:
  • 如果AST只有根节点的话,name它必定是符号变量BVS或位向量BV
  • 如果AST有多层,那么叶子节点为符号变量和位向量,其他节点为运算符
其中一个节点的左右孩子可以使用args来访问,节点本身存放的信息则使用op来访问。可以通过下面的例子来理解:
接下来对符号变量进行 比较判断:
结果不是一个位向量,而是一个符号化的布尔类型。
这些布尔类型的值可以通过is_true和is_false来判断,但对于上述有符号变量参与的布尔类型,它永远为false
此外需要注意的是,直接使用比较符号比较两个位向量,通常是默认不带符号的,例子如下:
符号约束与状态相关,或者说一个state除了包含内存、寄存器中的值这些信息外,还包含了符号约束(也就是要到达当前状态符号变量所必须满足的条件)。
除了运行程序,SM根据分支搜集起来的符号约束之外,用户 可以自动手动添加约束
此时,x必须满足大于5小于8,而y必须满足小于x。

2.4.2、符号求解

可以使用 state.solver.eval(x)来求解当前状态(即state)中的符号约束下x的值
此外,很明显能够看到,x应该是有多个值的,可以solver中的其他方法取出来:
  • solver.eval(x):给出表达式的一个可能解
  • sovler.eval_one(x):给出表达式的解,如果有多个解,将抛出错误
  • solver.eval_upto(x,n) 给出表达式的至多n个解
  • sovler.eval_taleast(x,n):给出表达式的n个解,如果解的数量少于n,则抛出错误
  • solver.eval_exact(x,n):给出表达式的n个解,如果解的个数不为n,则抛出错误
  • sovler.min(x) : 给出表达式的最小解
  • sovler.max(x) : 给出表达式的最大解
这些方法还有两个可省略的 参数
  • extra_constraints:可以作为约束进行求解,但不会被添加到当前状态
  • cast_to:将传递结果转换成指定数据类型, 目前只能是int和bytes ,例如state.solver.eval(state.solver.BVV(0x41424344, 32), cast_to=bytes) 将返回b'ABCD'
此外,如果将两个互相矛盾的约束加入到一个state当中,那么这个state就会被放到unsat这个stash里面,对这样的state进行求解会导致异常,可以使用 state.satisfiable()来检查是否有解。

2.5、模拟管理器(Simulation Manager)

proj.factory.entry_state()只是预设了程序分析开始时的状态,要分析程序就必须要让它到达下一个状态,这就需要模拟管理器的帮助(简称SM)。
使用以下指令能创建一个SM,它需要传入一个state或者state的列表作为参数
simgr = proj.factory.simulation_manager(state
SM中有许多列表,这些列表被称为stash它保存了处于某种状态的state,stash有如下几种:
  • active:此存储区包含默认情况下将逐步执行的状态,除非指定了备用存储区;
  • deadended:当一个状态由于某种原因不能继续执行时,例如没有合法指令,或者有非法指针,它就会进入死区隐藏;
  • pruned:与solve的策略有关,当发现一个不可解的节点后,其后面所有的节点都优化掉放在pruned里;
  • unconstrained:如果创建SM时启用了save_unconstrained,则被认定为不受约束的state会放在这,不受约束的state是指由用户数据或符号控制的指令指针(例如eip)
  • unsat:如果创建SM时启用了save_unsat,则被认为不可满足(即,它们有相互矛盾的约束,比如输入必须同时为“AAAA”和“BBBB”)的state会放在这里。
默认情况下,state会被存放在active中
stash中的state可以通过move()方法来转移,将fulter_func筛选出来的state从from_stash转移到to_stash:
simgr.move(from_stash='deadended', to_stash='more_then_50', filter_func=lambda s: '100' in s.posix.dumps(1))
stash是一个列表,可以使用python支持的方式去遍历其中的元素,也可以使用常见的列表操作。但angr提供了一种更高级的方式,在stash名字前加上one_,可以得到stash中的第一个状态,加上mp_,可以得到一个mulpyplexed版本的stash。
解释一下上面代码中的 posix.dumps
  • state.posix.dumps(0):表示到达当前状态所对应的程序输入
  • state.posix.dumps(1): 表示到达当前状态所对应的程序输出
上述代码就是将deadended中输出的字符串包含'100'的state转移到more_then_50这个stash中。
可以通过 step()方法来让处于active的state执行一个基本块, 这种操作不会改变state本身:
>>> state = p.factory.entry_state()
>>> simgr = p.factory.simgr(state)
>>> print(state.regs.rax, state.regs.rip)
<BV64 0x1c>  <BV64 0x4023c0>>>> print(simgr.one_active)
<SimState @ 0x4023c0>>>> simgr.step()
<SimulationManager with 1 active>>>> print(simgr.one_active)
<SimState @ 0x529240>
>>> print(state.regs.rax, state.regs.rip)
<BV64 0x1c>  <BV64 0x4023c0>

2.6、Analyses

angr 预先打包了几个内置分析: Analyses - angr documentation (docs-angr-io.translate.goog)
>>> proj .analyses .         # Press TAB here in ipython to get an autocomplete-listing of everything:
作为一个非常简短的示例:以下是构建和使用快速控制流图的方法:
# 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 0x7f03988ec7b8># 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 0x7f0398e7d6d8>
>>> len(cfg.graph.nodes())
1094# 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)))
1

2.7、探索技术(explorer techniques)

Simulation Managers - angr documentation (docs-angr-io.translate.goog)
可以 使用 explorer() 方法去执行某个状态,直到找到目标指令或者active中没有状态为止,它有如下 参数
  • find:传入目标指令的 地址或地址列表,或者一个用于判断的函数,函数以state为形参,返回布尔值
  • avoid:传入要避免的指令的地址或地址列表,或者一个用于判断的函数,用于减少路径
此外还有一些搜索策略,之后会集中讲解, 默认使用DFS(深度优先搜索)
explorer找到的符合find的状态会被保存在 simgr.found 这个列表当中,可以遍历其中元素获取状态。

2.7.1、传入一个用于判断的函数

看一个简单的crackme示例: https://github.com/angr/angr-doc/tree/master/examples/CSCI-4968-MBE/challenges/crackme0x00a
# 1、首先,我们加载二进制文件
>>> proj = angr.Project('examples/CSCI-4968-MBE/challenges/crackme0x00a/crackme0x00a')# 2、接下来,我们创建一个SimulationManager
>>> simgr = proj.factory.simgr()# 3、现在,符号执行直到找到与我们的条件匹配的state(即“win”条件)
>>> simgr.explore(find=lambda s: b"Congrats" in s.posix.dumps(1))  # 传入一个用于判断的函数
<SimulationManager with 1 active, 1 found># 4、现在,我们可以将flag从该state中取出!
>>> s = simgr.found[0]
>>> print(s.posix.dumps(1))
b'Enter password: Congrats!\n'
>>> print(s.posix.dumps(1).decode())   # bytes转成str
Enter password: Congrats!>>> flag = s.posix.dumps(0)
>>> print(flag)
g00dJ0B!

2.7.2、传入目标指令的地址

https://github.com/angr/angr-doc/blob/master/examples/CSCI-4968-MBE/challenges/crackme0x00a/solve.py
#!/usr/bin/env python3# Author: David Manouchehri <manouchehri@protonmail.com>
# Modern Binary Exploitation
# http://security.cs.rpi.edu/courses/binexp-spring2015/import angrFIND_ADDR = 0x08048533 # mov dword [esp], str.Congrats_ ; [0x8048654:4]=0x676e6f43 LEA str.Congrats_ ; "Congrats!" @ 0x8048654
AVOID_ADDR = 0x08048554 # mov dword [esp], str.Wrong_ ; [0x804865e:4]=0x6e6f7257 LEA str.Wrong_ ; "Wrong!" @ 0x804865edef main():proj = angr.Project('crackme0x00a', load_options={"auto_load_libs": False})sm = proj.factory.simulation_manager()sm.explore(find=FIND_ADDR, avoid=AVOID_ADDR)  return sm.found[0].posix.dumps(0).split(b'\0')[0] # stdindef test():assert main() == b'g00dJ0B!'if __name__ == '__main__':print(main())
​

2.8、符号执行

angr通常作为符号执行工具使用。
符号执行就是给程序传递一个符号而不是具体值,让这个符号伴随程序执行,当碰见分支时,符号会全部进入各个分支。angr会保存所有分支以及分支后的所有分支,并且在分支时,保存进入该分支时的判断条件,通常这些判断条件是对符号的约束。
angr运行到目标状态时,就可以调用求解器对一路上搜集到的约束进行求解,最终得到某个符号能到达当前状态的输入值。
例如,程序接收一个int类型的输入,当这个输入大于0小于5时,就会执行某条保存在该程序中,我们希望执行的指令(例如一个后门函数backdoor),具体而言如下图所示

angr会沿着分支按照某种策略(默认DFS)进行状态搜索,当达到目标状态(也就是backdoor能够执行的状态),此时angr已经收集了两个约束(x>0 以及x<=5),那么angr就通过这两个约束对x进行求解,解出来的x值就是能够让程序执行backdoor的输入。

三、官方示例

利用angr分析程序时有个一般的流程:
  1. 导入angr
  2. 导入二进制文件,创建Project
  3. 预设状态state
  4. 定义符号变量bvs并与二进制文件相联系
  5. 建立simgr,用于管理state
  6. 运行,探索满足条件的路径
  7. 约束求解获取执行结果
直接用了 https://github.com/angr/angr-doc/tree/master/examples/sym-write 里面提供的例子
1、issue.c
#include <stdio.h>char u=0;
int main(void)
{int i, bits[2]={0,0};for (i=0; i<8; i++) {bits[(u&(1<<i))!=0]++;}if (bits[0]==bits[1]) {printf("you win!");}else {printf("you lose!");}return 0;
}
2、编译: gcc issue.c -o issue
3、编写python脚本
# -*- coding: utf-8 -*- 
import angr
import claripydef main():proj = angr.Project('./issue',load_options={"auto_load_libs":False}) # 创建一个工程并导入二进制文件——issue,选择不自动加载依赖项(可选)#以下是对二进制文件的一些基本操作(可选)print(proj.arch)                # 架构 <Arch X86 (LE)>#proj.arch.memory_endess        # 大小端#proj.entry                     # 二进制程序入口点 134513520#proj.filename                  # 程序名称以及位置 './issue'#proj.loader                    # 是通过CLE模块将二进制对象加载并映射带单个内存空间  <Loaded issue, maps [0x8048000:0x8407fff]>#proj.loader.min_addr           # proj.loader 的低位地址 134512640#proj.loader.max_addr           # proj.loader 的高位地址 138444799#proj.loader.all_objects        # CLE加载的对象的完整列表#proj.loader.shared_objects     # 这是一个从共享对象名称到对象的字典映射#proj.loader.all_elf_objects    # 这是从ELF文件中加载的所有对象#proj.loader.all_pe_objects     # 加载一个windows程序#proj.loader.main_object             # 加载main对象#proj.loader.main_object.execstack   # 这个二进制文件是否有可执行堆栈#proj.loader.main_object.pic         # 这个二进制位置是否独立#proj.loader.extern_object      # 这是“externs对象”,我们使用它来为未解析的导入和angr内部提供地址#proj.loader.kernel_object      # 此对象用于为模拟的系统调用提供地址#proj.loader.find_object_containing(0x400000) # 获得对给定地址的对象的引用#以下是对确定的对象进行基本操作(可选)obj = proj.loader.main_object  # 指定main对象print(obj.entry)      # 获取地址#obj.min_addr, obj.max_addr # 地址的地位和高位#obj.segments#检索该对象的段#obj.sections#检索该对象的节#obj.find_segment_containing(obj.entry) # 通过地址获得单独的段#obj.find_section_containing(obj.entry)# 通过地址获得单独的节#addr = obj.plt['abort'] # 通过符号获取地址#obj.reverse_plt[addr]   # 通过地址获取符号#obj.linked_base#obj.mapped_base # 显示对象的预链接基以及CLE实际映射到内存中的位置state = proj.factory.entry_state(add_options={angr.options.SYMBOLIC_WRITE_ADDRESSES})# 返回一个simstate,SimState包含程序的内存、寄存器、文件系统数据以及符号变量等……任何可以通过执行更改的“实时数据”均在SimState。#.entry_state的替换:# .entry_state()构造一个准备在主二进制文件的入口点执行的状态。#.blank_state()构造了一个“空白石板”空白状态,其大部分数据未初始化。当访问未初始化的数据时,将返回一个不受约束的符号值。#.full_init_state()构造一个状态,该状态可以通过需要在主二进制的入口点之前运行的任何初始化程序执行,例如共享库构造函数或预初始化程序。当完成这些后,它将跳转到入口点。#.call_state()构造准备执行给定函数的状态。#通过state来访问一些寄存器的数值(可选)#state.regs.rip#state.regs.rax#state.regs.rbp = state.regs.rsp # 将寄存器rsp的值给rbp#注意:这儿采用的bitvectors,并不是python值,后面会说明python和bitvectors的转换u = claripy.BVS("u",8)#建立一个名称为u,8位宽的符号变量#claripy.BVS和state.solver.BVS有什么区别还不清楚,需要验证#可以通过.eval(A)的方法将A(bitvectors)转化位python int型#a = state.solver.FPV(3.2, state.solver.fp.FSORT_DOUBLE)#通过FPV来创建浮点型向量#raw_to_bv和raw_to_fp方法将位向量解释为浮点数,反之亦然:state.memory.store(0x601041,u) # 使用.memory.store(addr,val)方法将数据val保存在地址位addr的内存中,0x601041代表的是二进制文件中的某个变量的地址simgr = proj.factory.simulation_manager(state) # 使用的模拟管理器来管理状态或状态列表。state被组织成stash,可以forward, filter, merge, and move 。#simgr.active # 存储操作#simgr.step() # 执行一个基本块的符号执行,即就是所有状态向前推进一个基本块(类似单步操作,这儿是单块操作)#simgr.active # 以列表的形式更新存储#simgr.run() # .run()方法直接执行程序,直到一切结束,运行simgr会查看返回deadended数目while len(simgr.active)!=2:simgr.step()#循环运行直到通过.active来判断是否进入了分支,这是因为angr在遇到分支时,会将每个分支作为一个状态来保存。return simgr.active[0].state.se.eval(u) # 返回结果为win的u值,要是想返回lose的u值,将active[0]中0变为1即可if __name__ == "__main__":print(repr(main()))  # repr() 函数将对象转化为供解释器读取的形式。
​
4、solve.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Author: xoreaxeaxeax
Modified by David Manouchehri <manouchehri@protonmail.com>
Original at https://lists.cs.ucsb.edu/pipermail/angr/2016-August/000167.html
The purpose of this example is to show how to use symbolic write addresses.
"""
import angr
import claripydef main():p = angr.Project('./issue', load_options={"auto_load_libs": False})# By default, all symbolic write indices are concretized.state = p.factory.entry_state(add_options={angr.options.SYMBOLIC_WRITE_ADDRESSES})u = claripy.BVS("u", 8)state.memory.store(0x804a021, u)sm = p.factory.simulation_manager(state)def correct(state):try:return b'win' in state.posix.dumps(1)  # state.posix.dumps(1):表示到达当前状态所对应的程序输出except:return Falsedef wrong(state):try:return b'lose' in state.posix.dumps(1)except:return Falsesm.explore(find=correct, avoid=wrong)  # 探索# Alternatively, you can hardcode the addresses.# sm.explore(find=0x80484e3, avoid=0x80484f5)return sm.found[0].solver.eval_upto(u, 256)def test():good = set()for u in range(256):bits = [0, 0]for i in range(8):bits[u&(1<<i)!=0] += 1if bits[0] == bits[1]:good.add(u)res = main()assert set(res) == goodif __name__ == '__main__':print(repr(main()))

四、参考

angr_ctf——从0学习angr(一):angr简介与核心概念 - Uiharu - 博客园 (cnblogs.com)

angr_ctf——从0学习angr(二):状态操作和约束求解 - Uiharu - 博客园 (cnblogs.com)

angr_ctf——从0学习angr(三):Hook与路径爆炸 - Uiharu - 博客园 (cnblogs.com)

angr_ctf——从0学习angr(四):库操作和溢出漏洞利用 - Uiharu - 博客园 (cnblogs.c

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/178246.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MSQL系列(十一) Mysql实战-Inner Join算法底层原理及驱动表选择

Mysql实战-Inner Join算法驱动表选择 前面我们讲解了BTree的索引结构&#xff0c;及Mysql的存储引擎MyISAM和InnoDB,也详细讲解下 left Join的底层驱动表 选择, 并且初步了解 Inner join是Mysql 主动选择优化的驱动表&#xff0c;知道索引要建立在被驱动表上 那么对于Inner j…

“排队领奖,购物狂欢!开启全新商业模式

欢迎来到这个充满惊喜的商业模式——工会排队奖励模式&#xff01;在这个时代&#xff0c;你是否感到购物和消费的乐趣被平淡无奇的模式所限制&#xff1f;那么&#xff0c;这个全新的商业模式将带你进入一个充满刺激和惊喜的世界&#xff01; 想象一下&#xff0c;当你购物时&…

AutoX.js - openCV多分辨率找图

AutoX.js - openCV多分辨率找图 一、起因 AutoXjs 中有两个找图相关的方法 findImage 和 matchTemplate&#xff0c;之前一直没发现什么问题&#xff0c;但最近在一次测试找图时&#xff0c;明明大图和模板图的轮廓都清晰&#xff0c;却怎么也找不到图&#xff0c;降低阈值参…

C语言 每日一题 11

1.使用函数求素数和 本题要求实现一个判断素数的简单函数、以及利用该函数计算给定区间内素数和的函数。 素数就是只能被1和自身整除的正整数。注意&#xff1a;1不是素数&#xff0c;2是素数。 函数接口定义&#xff1a; int prime(int p); int PrimeSum(int m, int n); 其中…

云原生环境下JAVA应用容器JVM内存如何配置?—— 筑梦之路

Docker环境下的JVM参数非定值配置 —— 筑梦之路_docker jvm设置-CSDN博客 之前简单地记录过一篇&#xff0c;这里在之前的基础上更加细化一下。 场景说明 使用Java开发且设置的JVM堆空间过小时&#xff0c;程序会出现系统内存不足OOM&#xff08;Out of Memory&#xff09;的…

Java实验二类编程实验

1.编写一个代表三角形的类&#xff08;Triangle.java&#xff09;。 其中&#xff0c;三条边a,b,c&#xff08;数据类型为double类型&#xff09;为三角形的属性&#xff0c;该类封装有求三角形的面积和周长的方法。分别针对三条边为3、4、5和7、8、9的两个三角形进行测试&…

【精】UML及软件管理工具汇总

目录 1 老七工具&#xff08;规划质量&#xff09; 1.1 因果图&#xff08;鱼骨图、石川图&#xff09; 1.2 控制图 1.3 流程图:也称过程图 1.4 核查表:又称计数表 1.5 直方图 1.6 帕累托图 1.7 散点图&#xf…

通过USM(U盘魔术大师)在PE环境下使用分区助手拷贝磁盘——无损升级硬盘

这里写自定义目录标题 背景本次使用技术步骤1、添加新硬盘2、添加PE3、开机进入BIOS&#xff0c;进入PE4、开始拷贝磁盘5、调整分区5.1 删除系统盘前的所有分区5.2 修改硬盘分区表格式为GUID5.3 新建引导分区 6、修复引导7、大功告成 背景 由于硬盘空间不够的时候就需要更换硬盘…

CCF_A 计算机视觉顶会CVPR2024投稿指南以及论文模板

目录 CVPR2024官网&#xff1a; CVPR2024投稿链接&#xff1a; CVPR2024 重要时间节点&#xff1a; CVPR2024投稿模板: WORD: LATEX : CVPR2024_AuthorGuidelines CVPR2024投稿Topics&#xff1a; CVPR2024官网&#xff1a; https://cvpr.thecvf.com/Conferences/2024CV…

【设计模式】第7节:创建型模式之“建造者模式”

Builder模式&#xff0c;中文翻译为建造者模式或者构建者模式&#xff0c;也有人叫它生成器模式。 在创建对象时&#xff0c;一般可以通过构造函数、set()方法等设置初始化参数&#xff0c;但当参数比较多&#xff0c;或者参数之间有依赖关系&#xff0c;需要进行复杂校验时&a…

Linux进程概念(2)

Linux进程概念(2) &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解了进程的概念&#xff0c;PCB&am…

【数据结构】树形结构所有路径复原为链表

目录 1. 树形结构可视化 2. 树形结构转为链表 此目标是要还原树形结构的所有路径。树形结构是一种常见的数据结构&#xff0c;它表示元素之间层次关系。在树形结构中&#xff0c;每个节点可能拥有一个或多个子节点&#xff0c;形成了一个分层的结构。为了还原树形结构的路径&…

OpenCV官方教程中文版 —— 图像去噪

OpenCV官方教程中文版 —— 图像去噪 前言一、原理二、OpenCV 中的图像去噪1.cv2.fastNlMeansDenoisingColored()2.cv2.fastNlMeansDenoisingMulti() 前言 目标 • 学习使用非局部平均值去噪算法去除图像中的噪音 • 学习函数 cv2.fastNlMeansDenoising()&#xff0c;cv2.fa…

贝锐向日葵亮相阿里云“云栖大会”:独创专利算法赋能全新云桌面

2023年10月31日-11月2日&#xff0c;一年一度的云栖大会如期举办&#xff0c;国产远程连接服务创领者贝锐受邀参与。活动现场&#xff0c;贝锐CTO张小峰进行了分享&#xff0c;宣布贝锐旗下国民级远程控制品牌“贝锐向日葵”与无影展开合作&#xff0c;同时全新的“云桌面”将于…

后台界面设计都有哪些关键的技巧

在大数据时代&#xff0c;越来越多的设计师接触到背景界面设计。网站的背景是网站数据库和文件的快速操作和管理系统&#xff0c;以便及时更新和调整前台内容。和大多数UI设计一样&#xff0c;背景界面设计也有自己的设计元素和规范。本文将分享和总结背景界面设计的五个关键设…

Lightdb23.4 Client 包含ecpg可执行程序及相关库文件

功能介绍 部分客户在使用Lightdb client绿色包时需要ecpg程序和ecpg相关的头文件和库文件&#xff0c;所以在Lightdb 23.4版本client绿色包中新增了ecpg的程序和相关头文件和库文件&#xff0c;以方便用户的使用。 Client包目录结构 bin目录是可执行程序和脚本&#xff0c;i…

微信聚合聊天系统的便捷功能:自动发圈,跟圈

快到双十一咯&#xff0c;很多商家和自媒体、运营人都在发圈做运营&#xff0c;所以现在发圈的频率也会比以往的多一些&#xff0c;但事情一多就会担心今天的朋友圈忘记发、漏发或者错过发圈的时间导致错过私域里的好友、客户会错过活动时间。 其实这些都是可以不用担心&#…

无需服务器内网穿透Windows下快速搭建个人WEB项目

&#x1f4d1;前言 本文主要是windows下内网穿透文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ 参考自&#xff1a;Windows搭建web站点&#xff1a;免费内网穿透发布至公网 &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首…

day47

今日内容详细 overflow溢出属性 visible 默认值&#xff0c;内容不会被修剪&#xff0c;会呈现在元素框之外 hidden 内容会被修剪&#xff0c;并且其余内容是不可见的 scroll 内容会被修剪&#xff0c;但是浏览器会显示滚动条以便查看其余内容 auto 如果内容被修剪&#xff0c…

python之pip常用指令

文章目录 pip show xxx 查看是否安装该 module