如何在Z3Py中循环遍历数组

时间:2014-05-19 02:05:28

标签: z3 z3py

作为逆向工程练习的一部分,我尝试编写Z3求解器来查找满足以下程序的用户名和密码。这尤其困难,因为每个人都提到的z3py教程(rise4fun)都已关闭。

#include <iostream>
#include <string>

using namespace std;

int main() {
    string name, pass;
    cout << "Name: ";
    cin >> name;

    cout << "Pass: ";
    cin >> pass;

    int sum = 0;
    for (size_t i = 0; i < name.size(); i++) {
        char c = name[i];
        if (c < 'A') {
            cout << "Lose: char is less than A" << endl;
            return 1;
        }
        if (c > 'Z') {
            sum += c - 32;
        } else {
            sum += c;
        }
    }
    int r1 = 0x5678 ^ sum;

    int r2 = 0;
    for (size_t i = 0; i < pass.size(); i++) {
        char c = pass[i];
        c -= 48;
        r2 *= 10;
        r2 += c;
    }
    r2 ^= 0x1234;

    cout << "r1: " << r1 << endl;
    cout << "r2: " << r2 << endl;
    if (r1 == r2) {
        cout << "Win" << endl;
    } else {
        cout << "Lose: r1 and r2 don't match" << endl;
    }
}

我从二进制文件的集合中得到了代码,虽然它可能是错的但我想专注于编写求解器。我从第一部分开始,只计算r1,这就是我所拥有的:

from z3 import *

s = Solver()
sum = Int('sum')
name = Array('name', IntSort(), IntSort())
for c in name:
    s.add(c < 65)
    if c > 90:
        sum += c - 32
    else:
        sum += c
r1 = Xor(sum, 0x5678)
print s.check()
print s.model()

我所声称的是,没有任何字母少于&#39; A&#39;在数组中,所以我希望得到一个数字大于65的任何大小的数组。

显然这是完全错误的,主要是因为它无限循环。此外,我不确定我是否正确计算总和,因为我不知道它是否已初始化为0.有人可以帮助弄清楚如何使第一个循环工作吗? / p>

编辑:我能够获得一个接近上面显示的C ++代码的z3脚本:

from z3 import *

s = Solver()
sum = 0
name = Array('name', BitVecSort(32), BitVecSort(32))
i = Int('i')

for i in xrange(0, 1):
    s.add(name[i] >= 65)
    s.add(name[i] < 127)
    if name[i] > 90:
        sum += name[i] - 32
    else:
        sum += name[i]
r1 = sum ^ 0x5678

passwd = Array('passwd', BitVecSort(32), BitVecSort(32))
r2 = 0
for i in xrange(0, 5):
    s.add(passwd[i] < 127)
    s.add(passwd[i] >= 48)
    c = passwd[i] - 48
    r2 *= 10
    r2 += c
r2 ^= 0x1234

s.add(r1 == r2)

print s.check()
print s.model()

此代码能够为我提供正确的用户名和密码。但是,我硬编码用户名的长度为1,密码为5。我如何更改脚本,以便我不必硬编码长度?我每次运行程序时如何生成不同的解决方案?

2 个答案:

答案 0 :(得分:2)

Z3中的数组不一定有任何界限。在这种情况下,index-sort是Int,这意味着无界整数(不是机器整数)。因此,for c in name将永久运行,因为它枚举了name[0], name[1], name[2], ...

看起来你实际上在原始程序(name.size())中有一个绑定,所以只需枚举那个限制即可。否则,您可能需要一个量词,例如Int sort的\ forall x。 name [x]&lt; 65.当然,这带有关于量词的所有警告(例如,见Z3 Guide

答案 1 :(得分:2)

假设要确定长度。以下是我认为你可以做的事情:

length = Int('length')
x = Int('x')
s.add(ForAll(x,Implies(And(x>=0,x<length),And(passwd[x] < 127,passwd[x] >=48))))