z3学习笔记
这HGAME的re真让我长见识了,逆着逆着还出来个线性方程组。。
即刻学习z3!
安装
上次安的virtualenvwrapper真的太好用辣
有了上次angr的配置前提,这次直接source ~/.bashrc
然后mkvirtualenv --python=$(which python3) z3 && pip install z3-solver
,就在名为z3的虚拟环境内安装好z3-solver辣
(直接pip install的话大概率会和angr冲突,所以建议在虚拟环境下安装)
简单的例子
比如说下面这个东西
from z3 import *
x = Int('x')
y = Int('y')
solve(x + y == 4)
输出了[y = 0, x = 4],显然,这是在x和y均为整数的情况下,\(x+y=4\)的一组解
如果我们想要在y = 3的情况下的解呢?
from z3 import *
x = Int('x')
y = Int('y')
solve(y == 3, x + y == 4)
输出了[x = 1, y = 3]
如果条件比较多的话,可以考虑下面这种写法
from z3 import *
x = Int('x')
y = Int('y')
solver = Solver() # 建立约束器
solver.add(x > 3) # 添加约束条件
solver.add(y < 5)
solver.add(x + y == 4)
if solver.check()==sat: # 判断是否有解
print (solver.model())
else:
print ("OOps!")
另外我们注意到,即使是存在多解的情况,z3也只会给出其中一种解
z3的用法实在是太多了,那就就遇到一种用法写一种在这吧,以后自己也好翻回来复习
求解矩阵乘法
会了矩阵乘法就相当于会了线性方程组的解法,线性代数不能白学(
摸一道例题吧,看dalao博客是whctf的一个题
其中convert()将flag赋值给一个6x6的矩阵a,Transposition()将a的转置矩阵赋值给b,Multi()将a*b赋值给c,d就是我们的c矩阵的目标状态
from z3 import *
# 建立约束器
solver = Solver()
# flag长度先设置为36,包括尾部的9个1
flag = [Int('flag%d'%i) for i in range(36)]
# 保存flag的矩阵
a = [i for i in flag]
# 保存flag的转置矩阵
b = [i for i in range(36)]
# 保存a * b的矩阵
c = [0 for i in range(36)]
# 正确的flag的运算结果
d = [0x12027, 0x0F296, 0x0BF0E, 0x0D84C, 0x91D8, 0x297,
0x0F296, 0x0D830, 0x0A326, 0x0B010, 0x7627, 0x230,
0x0BF0E, 0x0A326, 0x8FEB, 0x879D, 0x70C3, 0x1BD,
0x0D84C, 0x0B010, 0x879D, 0x0B00D, 0x6E4F, 0x1F7,
0x91D8, 0x7627, 0x70C3, 0x6E4F, 0x9BDC, 0x15C,
0x297, 0x230, 0x1BD, 0x1F7, 0x15C, 0x6]
# 获得a的转置矩阵
for i in range(6):
for j in range(6):
b[6 * j + i] = a[6 * i + j]
# 运算a * b
for i in range(6):
for j in range(6):
for k in range(6):
c[6 * i + j] = c[6 * i + j] + a[6 * i + k] * b[6 * k + j]
# 添加约束,正确flag的运算结果
solver.add(c[6 * i + j] == d[6 * i + j])
# 添加约束,除了尾部,flag的字符一定在可见字符范围内
for i in range(6,36 - 10):
solver.add(flag[i] >= 32)
solver.add(flag[i] <= 127)
# 添加约束,由于flag有格式,前6位一定为whctf{
for i in range(6):
solver.add(flag[i] == ord('whctf{'[i]))
# 添加约束,flag的尾部为9个1
for i in range(36 - 9,36):
solver.add(flag[i] == 0x1)
# 添加约束,flag的最后一个肯定是}
solver.add(flag[-10] == ord('}'))
# 添加约束,A*A的转置结果矩阵中A(i,i)一定是平方和
# 这里一定要有,不check的话会报错
if solver.check() == sat:
m = solver.model()
s = []
# 获得结果
for i in range(36):
s.append(m[flag[i]].as_long())
# 输出flag
print(bytes(s))
else:
print('OOps!')
这exp还差个约束没补齐,下次补一下