Z3 方程求解器 - 位掩码操作
Z3 Equation Solver - Bitmask Operation
对程序进行逆向工程后,我发现了约束。
我必须找到两个无符号数,这样:
x + y = 0xC0ED91BD
和
x * y = Z
在原程序中,数字的乘法运算是使用imul指令进行的。
Z应该是这样的,当只检查Z的低32位时,它应该小于60。
Z & 0x00000000ffffffff < 60
然而,当我添加第二个方程作为约束时,z3 给我一个错误。
这是我的代码:
#! /usr/bin/python
from z3 import *
import sys
s = Solver()
result = int(sys.argv[1], 16)
x = Int('x')
y = Int('y')
s.add(x + y == result)
s.add(x > 0, y > 0)
s.add((x * y) & 0x00000000ffffffff < 60)
while s.check() == sat:
print s.model()
s.add(Or(x != s.model()[x], y != s.model()[y]))
更新:
这里是基于推荐方案的代码:
#! /usr/bin/python
from z3 import *
import sys
s = Solver()
x = BitVec('x', 32)
y = BitVec('y', 32)
result = BitVecVal(int(sys.argv[1], 16), 32)
s.add(x + y == result)
s.add(x > 0, y > 0)
s.add(x * y < 10)
print s.check()
print s.model()
二进制为 64 位。
但是,乘法运算是使用32位整数执行的,如下所示:
mov edx, [rbp+var_14]
mov eax, [rbp+var_10]
imul eax, edx
所以如果 eax = 0x425a95e5 和 edx = 0x7e92fbd8
然后使用imul指令进行乘法后,eax将存储:0x00000038。
EFLAGS 寄存器中的进位标志位和溢出标志位都将在其后设置。
这里的问题是您已将 x
和 y
声明为任意宽度的整数,而不是固定长度的位向量。只需更改您的声明以匹配基础位大小应该是什么。假设你希望你的算术以 32 位完成,你会说:
x = BitVec('x', 32)
y = BitVec('y', 32)
相反。您还应该类似地声明 result
:
result = BitVecVal(int(sys.argv[1], 16), 32)
完成这些更改后,您的程序应该可以正常工作。
请注意,在这种情况下,用 0x00000000ffffffff
屏蔽并不是真正必要的;因为数字已经是 32 位宽了。如果你的 x
和 y
较大,你只需要保留它;说 64 位。
通过上述更改,当我 运行 您的程序并使用 0xC0ED91BD
调用它时,我得到以下输出:
[y = 2123561944, x = 1113232869]
[y = 1440310864, x = 1796483949]
[y = 1171875408, x = 2064919405]
... many other lines ..
这可能看起来令人困惑,因为数字似乎比您认为的要大。但请记住,位向量的算术是对 2^n
取模,其中 n
是位大小,因此结果实际上是正确的:
>>> 2123561944 + 1113232869 % 2**32 == 0xC0ED91BD
True
>>> 2123561944 * 1113232869 % 2**32 < 60
True
等等
对程序进行逆向工程后,我发现了约束。
我必须找到两个无符号数,这样:
x + y = 0xC0ED91BD
和
x * y = Z
在原程序中,数字的乘法运算是使用imul指令进行的。
Z应该是这样的,当只检查Z的低32位时,它应该小于60。
Z & 0x00000000ffffffff < 60
然而,当我添加第二个方程作为约束时,z3 给我一个错误。
这是我的代码:
#! /usr/bin/python
from z3 import *
import sys
s = Solver()
result = int(sys.argv[1], 16)
x = Int('x')
y = Int('y')
s.add(x + y == result)
s.add(x > 0, y > 0)
s.add((x * y) & 0x00000000ffffffff < 60)
while s.check() == sat:
print s.model()
s.add(Or(x != s.model()[x], y != s.model()[y]))
更新:
这里是基于推荐方案的代码:
#! /usr/bin/python
from z3 import *
import sys
s = Solver()
x = BitVec('x', 32)
y = BitVec('y', 32)
result = BitVecVal(int(sys.argv[1], 16), 32)
s.add(x + y == result)
s.add(x > 0, y > 0)
s.add(x * y < 10)
print s.check()
print s.model()
二进制为 64 位。
但是,乘法运算是使用32位整数执行的,如下所示:
mov edx, [rbp+var_14]
mov eax, [rbp+var_10]
imul eax, edx
所以如果 eax = 0x425a95e5 和 edx = 0x7e92fbd8
然后使用imul指令进行乘法后,eax将存储:0x00000038。
EFLAGS 寄存器中的进位标志位和溢出标志位都将在其后设置。
这里的问题是您已将 x
和 y
声明为任意宽度的整数,而不是固定长度的位向量。只需更改您的声明以匹配基础位大小应该是什么。假设你希望你的算术以 32 位完成,你会说:
x = BitVec('x', 32)
y = BitVec('y', 32)
相反。您还应该类似地声明 result
:
result = BitVecVal(int(sys.argv[1], 16), 32)
完成这些更改后,您的程序应该可以正常工作。
请注意,在这种情况下,用 0x00000000ffffffff
屏蔽并不是真正必要的;因为数字已经是 32 位宽了。如果你的 x
和 y
较大,你只需要保留它;说 64 位。
通过上述更改,当我 运行 您的程序并使用 0xC0ED91BD
调用它时,我得到以下输出:
[y = 2123561944, x = 1113232869]
[y = 1440310864, x = 1796483949]
[y = 1171875408, x = 2064919405]
... many other lines ..
这可能看起来令人困惑,因为数字似乎比您认为的要大。但请记住,位向量的算术是对 2^n
取模,其中 n
是位大小,因此结果实际上是正确的:
>>> 2123561944 + 1113232869 % 2**32 == 0xC0ED91BD
True
>>> 2123561944 * 1113232869 % 2**32 < 60
True
等等