Z3基础使用

目录

Z3求解约束器

所求结果的几种数据类型

基本语法使用

求解的步骤

useZ3

参考资料


Z3求解约束器

windows安装
python -m pip install z3-solver

kali
pip install z3-solver

所求结果的几种数据类型

int

bool(布尔型)

Array(数组)

BitVec('a',8)(char型)

Real(实数)

其中BitVec可以是特定大小的数据类型,不一定是8,例如C语言中的int型可以用BitVec('a',32)表示

y = Real('y')#实数
z = BitVec('z',8)#char型
w = BitVec('w',32) #int型
p = Bool('p') #定义布尔型

基本语法使用

Solver()

创建一个求解器,在里面添加约束条件进行下一步的求解

add()

通常在solver()命令之后,用来添加约束条件,通常添加的约束条件是一个等式

check()

判断是否添加的约束条件是否有解,有解返回sat,无解返回unsat

model()

在有解的情况下,求解的交集再输出

求解的步骤

创建求解约束器

solver = Solver

添加约束条件

solver.add()

判断解是否存在

 if solver.check()==sat

求解

print solver.model()

useZ3

先查壳发现没有壳,发现是64位的文件

拖到ida里查看主函数(关键代码)

分析代码,一个for循环得到两个ptr和v7

__int64 __fastcall sub_40094C(const char *a1)
{
  unsigned __int8 v2; // [rsp+13h] [rbp-2Dh]
  signed int i; // [rsp+14h] [rbp-2Ch]
  signed int j; // [rsp+18h] [rbp-28h]
  signed int v5; // [rsp+1Ch] [rbp-24h]
  _DWORD *ptr; // [rsp+20h] [rbp-20h]
  _DWORD *v7; // [rsp+28h] [rbp-18h]
  _DWORD *v8; // [rsp+30h] [rbp-10h]
  _DWORD *v9; // [rsp+38h] [rbp-8h]


  v2 = 1;
  v5 = strlen(a1);
  if ( v5 > 37 ) #a1长度为36
    return 0LL;
  ptr = (_DWORD *)sub_400736(36LL);
  v7 = (_DWORD *)sub_400736(36LL);
  for ( i = 0; i < v5; ++i )
  {
    ptr[i] = (char)(a1[i] >> 4);   #等价于除以16
    v7[i] = a1[i] & 15;   #a1[i]和15相与
  }#得到两个数组ptr和v7
  v8 = (_DWORD *)sub_40078E(ptr, &unk_602080, 6LL);
  v9 = (_DWORD *)sub_400892(v7, &unk_602080, 6LL); #两个函数和两个数据得到v8和v9
  for ( j = 0; j <= 35; ++j )
  {
    if ( v8[j] != dword_602120[j] || v9[j] != dword_6021C0[j] )
      v2 = 0;
  }#将v8[j]和v9[j]与两个数据进行比较
  free(ptr);
  free(v7);
  free(v8);
  free(v9);
  return v2;
}

分析sub_40078E函数

__int64 __fastcall sub_40078E(__int64 a1, __int64 a2, unsigned int a3)
{
  int v4; // [rsp+Ch] [rbp-34h]
  int i; // [rsp+2Ch] [rbp-14h]
  int j; // [rsp+30h] [rbp-10h]
  int k; // [rsp+34h] [rbp-Ch]
  __int64 v8; // [rsp+38h] [rbp-8h]


  v4 = a3;
  v8 = sub_400736(a3);   #传进两个数组,值赋给v4和v8
  for ( i = 0; i < v4; ++i )
  {
    for ( j = 0; j < v4; ++j )
    {
      for ( k = 0; k < v4; ++k )
        *(_DWORD *)(v8 + 4LL * (v4 * i + j)) = *(_DWORD *)(4LL * (v4 * i + j) + v8)
                                             + *(_DWORD *)(4LL * (v4 * i + k) + a1)
                                             * *(_DWORD *)(4LL * (v4 * k + j) + a2);
    }# 三个for循环,对传进的两个数组进行了相乘运算,4LL就是长长整型的4,LL代表long long int
  }
  return v8;
}

分析sub_400892函数

__int64 __fastcall sub_400892(__int64 a1, __int64 a2, unsigned int a3)
{
  int v4; // [rsp+Ch] [rbp-24h]
  int i; // [rsp+20h] [rbp-10h]
  int j; // [rsp+24h] [rbp-Ch]
  __int64 v7; // [rsp+28h] [rbp-8h]


  v4 = a3;
  v7 = sub_400736(a3);
  for ( i = 0; i < v4; ++i )
  {
    for ( j = 0; j < v4; ++j )
      *(_DWORD *)(v7 + 4LL * (v4 * i + j)) = *(_DWORD *)(4LL * (v4 * i + j) + a1) + *(_DWORD *)(4LL * (v4 * i + j) + a2);
  }
  return v7;
}#数组进行相加运算


3&5
十进制3转为二进制的3:0000 0011
十进制5转为二进制的5:0000 0101
------------------------结果:0000 0001 ->转为十进制:1

用idapython对相应数据进行提取

addr1 = 0x602120
addr2 = 0x6021C0
addr3 = 0x602080
v8 = []
v9 = []
v10 = []
for i in range(36):
v8.append(idc.get_wide_byte(addr1+4*i))
v9.append(idc.get_wide_byte(addr2+4*i))
v10.append(idc.get_wide_byte(addr3+4*i))
print(v8)
print(v9)
print(v10)

提取之后的数据

v8=[122, 207, 140, 149, 142, 168, 95, 201, 122, 145, 136, 167, 112, 192, 127, 137, 134, 147, 95, 207, 110, 134, 133, 173, 136, 212, 160, 162, 152, 179, 121, 193, 126, 126, 119, 147]


v9=[16, 8, 8, 14, 6, 11, 5, 23, 5, 10, 12, 23, 14, 23, 19, 7, 8, 10, 4, 13, 22, 17, 11, 22, 6, 14, 2, 11, 18, 9, 5, 8, 8, 10, 16, 13]


v10=[8, 1, 7, 1, 1, 0, 4, 8, 1, 2, 3, 9, 3, 8, 6, 6, 4, 8, 3, 5, 7, 8, 8, 7, 0, 9, 0, 2, 3, 4, 2, 3, 2, 5, 4, 0]

菜鸡找的脚本(偷偷做了解释嘿嘿)

from z3 import *       #若导入了模块但没有使用则是这种灰色
arr1 = [0X7A,0XCF,0X8C,0X95,0X8E,0XA8,0X5F,0XC9,0X7A,0X91,0X88,0XA7,0X70,0XC0,0X7F,0X89,0X86,0X93,0X5F,0XCF,0X6E,0X86,
        0X85,0XAD,0X88,0XD4,0XA0,0XA2,0X98,0XB3,0X79,0XC1,0X7E,0X7E,0X77,0X93]
arr2 = [0x10,0x08,0X08,0x0E,0X06,0X0B,0X5,0X17,0X05,0X0A,0X0C,0X17,0X0E,0X17,0X13,0X07,0X08,0X0A,0X04,0X0D,0X16,0X11,0X0B,
        0X16,0X06,0X0E,0X02,0X0B,0X12,0X09,0X05,0X08,0X08,0X0A,0X10,0X0D]
arr3 = [8,1,7,1,1,0,4,8,1,2,3,9,3,8,6,6,4,8,3,5,7,8,8,7,0,9,0,2,3,4,2,3,2,5,4,0]
#学会了idapython将其提取出来,arr1对应v8,arr2对应v9,arr3对应unk_602080也就是v10
temp = [BitVec('%d' % i, 8) for i in range(36)]  #初始化序列
s = Solver()     #创建约束求解器
for i in range(36):
    s.add(temp[i] <127)   #添加约束条件①
    s.add(temp[i] >=32)
#接下来还原代码
ptr = [0]*36
v7 = [0]*36   #最开始的两个变换之后的数组
one = [0]*36
two = [0]*36    #这两个用来存放对应的两个函数的结果
for i in range(36):
    ptr[i] = temp[i] >> 4
    v7[i] = temp[i] & 15
for i in range(6):
    for j in range(6):
        for k in range(6):
            one[6*i+j] += ptr[6*i + k] * arr3[6*k+j]
 
for i in range(6):
    for j in range(6):
        two[6*i+j] = v7[6*i+j] + arr3[6*i+j]
#代码还原结束
for i in range(36):          #添加约束条件②
    s.add(one[i] == arr1[i])
    s.add(two[i] == arr2[i])
flag = []
strflag = ''
if s.check() == sat:     #检测是否有解
    result = s.model()
    for i in temp:       #因为最后得出的是等式,先遍历temp,把temp的每个依次赋给i
        flag.append(result[i])    #然后找到每个temp对应的解,附加到空列表的后面
    print(flag)          #这里先打印出来,然后后面重新赋一个序列
else:
    print('wujie') #因为是用kali运行的,不识别中文所以改了一下,下面的result就是打印出来的
 
result = [104, 103, 97, 109, 101, 123, 49, 95, 116, 104, 105, 110, 107, 95, 77, 97, 116, 114, 49, 120, 95, 105, 115, 95, 118, 101, 114, 121, 95, 117, 115, 101, 102, 53, 108, 125]
for i in range(36):
    strflag += chr(result[i])
print(strflag)
 

 hgame{1_think_Matr1x_is_very_usef5l}

参考资料

逆向z3求解约束器_syj-re的博客-CSDN博客

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值