python Z3库 以及之后ctf实战中遇到的进阶操作

python z3库

一、介绍

0

二、使用方法

1、设置变量

用Int型设置变量代表所有的解只能是整数,也可以用Ints同时设置多个变量
如a,s,d = Ints('a,s,d')
0
也可以设置具体值:
比如  BitVecVal(10,32) 可以创建一个32位的,值为10 的位向量

2、设置解方程的类Solver

设置完这个类,我们就能一个一个的添加约束项了
Solver()创造一个求解器,用于之后添加限制条件
0

3、添加约束项

add()进行添加限制条件

4、判断是否有解

check()用于判断是否有解,有解返回sat,无解返回unsat

5、返回解

model()在有解时返回解
 

三、实例

1、求解位向量问题

Z3库可以求解位向量,对RE来说极其友好
from z3 import *

a,b,c = BitVecs('a b c',10)  #这个10是在说明位数
x = Solver()
x.add(a ^ b & c == 12)
x.add(a & b >> 3 == 3)
x.add(b ^ c == 4)
print(x.check())
print(x.model())

 

 
0
 
 

2、用Z3库解实际ctf题目

CISCN 2021 baby_bc
import hashlib
from z3 import *

zy=[0x00, 0x00, 0x00, 0x01,0x01, 0x00, 0x00, 0x00,0x02, 0x00, 0x00, 0x01,0x00, 0x00, 0x00, 0x00,0x01, 0x00, 0x01, 0x00]
sx=[0x00, 0x00, 0x02, 0x00,0x02,0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x01, 0x00,0x00, 0x01, 0x00, 0x00, 0x01]
ts = Solver()
map = [BitVec('s%d' % i, 4) for i in range(25)]
ts.add(map[5*2+2] == 4)
ts.add(map[5*3+3] == 3)

for i in map:
    ts.add(i > 0)
    ts.add(i <= 5)
for a in range(5):
    ts.add(
    And(map[5 * a] != map[5 * a + 1],
        map[5 * a] != map[5 * a + 2],
        map[5 * a] != map[5 * a + 3],
        map[5 * a] != map[5 * a + 4],
        map[5 * a + 1] != map[5 * a + 2],
        map[5 * a + 1] != map[5 * a + 3],
        map[5 * a + 1] != map[5 * a + 4],
        map[5 * a + 2] != map[5 * a + 3],
        map[5 * a + 2] != map[5 * a + 4],
        map[5 * a + 3] != map[5 * a + 4]))
for b in range(5):
    ts.add(
    And(map[5 * 0 + b] != map[5 * 1 + b],
        map[5 * 0 + b] != map[5 * 2 + b],
        map[5 * 0 + b] != map[5 * 3 + b],
        map[5 * 0 + b] != map[5 * 4 + b],
        map[5 * 1 + b] != map[5 * 2 + b],
        map[5 * 1 + b] != map[5 * 3 + b],
        map[5 * 1 + b] != map[5 * 4 + b],
        map[5 * 2 + b] != map[5 * 3 + b],
        map[5 * 2 + b] != map[5 * 4 + b],
        map[5 * 3 + b] != map[5 * 4 + b]
        ))
for b in range(4):
 for y in range(5):
        ts.add(map[5 * b + y] != map[5 * (b + 1) + y])
for a in range(5):
 for x in range(4):
    if zy[4 * a + x]==1:
        ts.add(map[5 * a + x] > map[5 * a + x + 1])
    elif zy[4 * a + x] == 2:
        ts.add(map[5 * a + x] < map[5 * a + x + 1])
for b in range(4):
 for y in range(5):
    if sx[5 * b + y]==1:
        ts.add(map[5 * b + y] < map[5 * (b + 1) + y])
    elif sx[5 * b + y] == 2 :
        ts.add(map[5 * b + y] > map[5 * (b + 1) + y])
print()
while ts.check() == sat:
    answer = ts.model()
    condition = []
    p = []
    for i in map:
        p += [answer[i]]
        condition.append(i != answer[i])
    p[5 * 2 + 2] = 0
    p[5 * 3 + 3] = 0
    ts.add(Or(condition))

print(p)
#p=[1, 4, 2, 5, 3, 5, 3, 1, 4, 2, 3, 5, 0, 2, 1, 2, 1, 5, 0, 4, 4, 2, 3, 1, 5]
l=''
for i in p:
    l+=str(i)
md = hashlib.md5()
md.update(l.encode())
print('CISCN{'+md.hexdigest()+'}')
其中And语句与Or语句的作用参考:
 
一般来说,我们只要会 add()函数,会 创建符号向量就能解决大部分问题
但我在实际CTF中遇到了一些难以解决的问题,需要用到其内置的一些API函数
 

三、z3进阶之 使用Concat 与 Extract 函数实现 concatenate 和 separate

1、问题来源

在实际CTF中,我们经常会遇到字符数组的连接和拆分,比如把四个字符连接起来转4字节int类型数据,或者拆分回去
在处理字符数组的时候,我们经常使用一下方式来达到我们的预期效果:
连接:
arr[i] = ch[i+0] + (ch[i+1] << 8) + (ch[i+2] << 16) + (ch[i+3] << 24)
分隔:
ch[i] = arr[i] & 0xff
ch[i+1] = (arr[i] & 0xff00) >> 8
ch[i+2] = (arr[i] & 0xffff00) >> 16
ch[i+3] = (arr[i] & 0xffffff00) >> 24

但这在z3的符号向量里是行不通的

下面我们介绍Concat 与 Extract 函数

2、Concat 函数

Concat可以进行符号向量的连接

比如 定义四个符号向量,然后相连他们:

from z3 import *

xx = BitVec("xx",8)
yy = BitVec("yy",8)
zz = BitVec("zz",8)
pp = BitVec("pp",8)

v = Concat(xx,yy,zz,pp)
print(v.sort())     

最后会输出

BitVec(32)

3、Extract 函数

Extract  函数第一个参数代表了分隔的末位置,第二个参数代表分隔的起始位置,第三个参数代表要分割的符号向量

v = BitVec("v",32)
x = Extract(7,0,v) 
y = Extract(15,8,v)
z = Extract(23,16,v)
p = Extract(31,24,v)  
print(v.sort())

注意点

Concat 函数是不用考虑小端序的,他是直接连接,而 Extract函数需要注意到这点
# 0x12,0x34,0x56,0x78 => Concat => 0x12345678
# 0x12345678 => Extract(8*(i+1)-1,8*i) => 0x78,0x56,0x34,0x12

4、成功实现字符数组的相连与拆分

#相连:
for i in range(4):
    long_f1[i] = Concat(flag[4*i+3] , flag[4*i+2] , flag[4*i+1],  flag[4*i+0]) 
#拆分:
ver_f = [None] * 32
for i in range(4):
    ver_f[4*i + 0] = Extract(7,0,long_1[i])            # 好怪的函数
    ver_f[4*i + 1] = Extract(15,8,long_1[i])
    ver_f[4*i + 2] = Extract(23,16,long_1[i])
    ver_f[4*i + 3] = Extract(31,24,long_1[i])

问题解决

posted @ 2022-05-21 23:32  TLSN  阅读(916)  评论(0)    收藏  举报