作为逆向工程练习的一部分,我尝试编写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。我如何更改脚本,以便我不必硬编码长度?我每次运行程序时如何生成不同的解决方案?
答案 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))))