作为逆向工程练习的一部分,我正在尝试编写 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()
我要断言的是数组中没有小于“A”的字母,所以我希望得到一个数字大于 65 的任意大小的数组。
显然这是完全错误的,主要是因为它无限循环。另外,我不确定我是否正确计算总和,因为我不知道它是否已初始化为 0。有人可以帮助弄清楚如何让第一个循环工作吗?
编辑:我能够得到一个接近上面显示的 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。我将如何更改脚本,这样我就不必对长度进行硬编码?每次运行程序时如何生成不同的解决方案?