0x01 基本用法
求解器
在使用 z3 进行约束求解之前我们首先需要获得一个 求解器 类实例,本质上其实就是一组约束的集合:
1 | s = z3.Solver() |
变量
再创建用于解方程的变量
1 | import z3; |
整型与实数类型变量之间可以互相进行转换:
1 | z3.ToReal(x) |
还能创建常量
1 | z3.IntVal(val = 114514) #int类型常量 |
添加约束
用add()方法为指定求解器添加约束,条件为初始化中变量组成的式子;
1 | s.add(x + 5 == 111) |
bool类型还可逻辑运算,暂且不表;
约束求解
使用check()方法寻找是否有解
1 | s.check() |
若有解则可以通过model()方法获取一组解;
1 | >>> if s.check() == z3.sat: |
0x02 for CTF
初始化
不用写z3.前缀;
1 | from z3 import * |
用循环创建变量
1 | v = [Int(f'v{i}') for i in range(0, 16)] #f'{}'用来格式化字符串,传入后面的i |
求解
model()方法会返回一个列表,比如
1 | [i11i1Iii1I1[14] = 49, |
接下来要做的是将解转化为字符,但由于该列表中的元素是z3中的特殊类型,需要先转换为python中的整数类型才能使用chr()函数转为对应字符;
但列表中解不是按未知参数或数组大小排序的,解决办法是循环访问列表中的值,将其作为索引去访问ans列表,即此处的【ans[i]】,然后使用as_long()函数将解的类型转为python中的int类型,最后使用chr()函数转为对应字符;
1 | if solver.check() == sat: #check()方法用来判断是否有解,sat(即satisify)表示满足有解 |
0x03 板子
原文链接:https://blog.csdn.net/liKeQing1027520/article/details/138047537
板子作者:CSDN-晴友读钟
预处理字符串
1 | import re |
(ida) 将整串条件复制过来放进s1中之后,把多余的换行和空格删除掉*(shift+tab删除缩进)*,形成一连串的由关系运算符连接的条件;
接着你根据条件中具体的关系运算符,到底是”&&”还是”||”来使用split()函数将每个方程分隔开形成列表
在这里你需要仔细注意一下方程中的”||”中间有没有空格,如果有那你用的split()函数也得加上空格,即s1.split(‘| |’),因为你要让split()函数正确地找到分隔符
然后打印res就可以输出分割好的方程列表
求解
1 | from z3 import * |
把这一整个列表复制下来,赋值给下面这个脚本的fc列表,直接运行就能出结果,这样脚本的通用性和便捷性大大提升了。