Здесь есть несколько проблем, но наиболее важной из них является использование if-then-else
. Когда вы используете значение symboli c, вы не можете использовать Python if-then-else. Вместо этого вы должны использовать z3's If
construct.
В вашей программе ваши if-then-else точно оцениваются, и, таким образом, вы получаете в конце фиктивное утверждение. Вы можете проверить это, поставив print s.sexpr()
перед вызовом check
.
Начните с замены всех ваших if-then-else's
вызовами на функцию If
. И на каждом шаге посмотрите на s.sexpr()
(скажем, после каждого add
) и убедитесь, что он содержит правильные выражения. Это должно привести вас к правильному кодированию проблемы. Начните с чтения здесь: https://z3prover.github.io/api/html/namespacez3py.html#a782883a35d4c6a0be62cd5333645dbaf
Стиль кодирования z3
Ниже описано, как я могу написать вашу проблему в z3py. Обратите внимание, что я просто транслитерировал ваш код python, поэтому, если у вас есть какие-либо ошибки в вашем коде, они будут сохранены. Обратите внимание, что все вычисления Symboli c "if-then-else" выполняются отдельно и объединяются с помощью вызовов If
.
from z3 import *
size = 0x80
vec = BitVec("inf", size * 8)
s = Solver()
# Every byte in vec is either 0x30, 0x31 or 0x32
for i in range(0, size*8, 8):
b = Extract(i+7, i, vec)
s.add(Or(b == 0x30, b == 0x31, b == 0x32))
def setLastBit(v):
return Concat(Extract(63, 1, v), BitVecVal(1, 1))
def clearLastBit(v):
return Concat(Extract(63, 1, v), BitVecVal(0, 1));
def if30(inp, ecx):
inp = RotateLeft(inp, ecx)
inp = clearLastBit(inp)
inp = RotateRight(inp, ecx)
ecx = ecx - 1
return inp, ecx
def if31(inp, ecx):
ecx = ecx + 1
inp = RotateLeft(inp, ecx)
inp = clearLastBit(inp)
inp = RotateRight(inp, ecx)
ecx = ecx + 1
return inp, ecx
def if32(inp, ecx):
ecx = ecx + 1
inp = RotateLeft(inp, ecx)
inp = setLastBit(inp)
inp = RotateRight(inp, ecx)
ecx = ecx + 1
return inp, ecx
v1 = BitVecVal(0xDEADFACEDEADBEEF, 64)
ecx = BitVecVal(0x40, 64)
for i in range(0, size*8, 8):
val = Extract(i + 7, i, vec)
val30 = if30(v1, ecx)
val31 = if31(v1, ecx)
val32 = if32(v1, ecx)
v1 = If(val == 0x30, val30[0], If(val == 0x31, val31[0], val32[0]))
ecx = If(val == 0x30, val30[1], If(val == 0x31, val31[1], val32[1]))
s.add(v1 == 0x123456701234567)
print (s.sexpr())
print (s.check())
. Когда я запускаю это, к сожалению, z3 печатает программу, сгенерированную внутри. (Вы можете проверить это, чтобы получить представление о том, как все работает под капотом), но он не возвращается быстро, чтобы сказать sat
или unsat
. Причин может быть несколько:
Алгоритм, который вы закодировали, может быть не совсем правильным. Я бы порекомендовал изучить программу, как я ее написал, и убедиться, что она отражает то, что вы хотели. Посмотрите, можете ли вы следовать сгенерированным программам (вы можете добавить print (s.sexpr())
в Strategi c местах, чтобы увидеть, какой код генерируется на каждом шаге.
Если кодировка неверна, тогда надеюсь, вы исправите это в этом стиле, и z3 найдет ваше значение vec
. Если оно верное, но z3 не отвечает на ваш запрос в течение разумного промежутка времени, то это просто означает, что проблема слишком сложна для z3 для обработки. Я бы рекомендовал, чтобы ваш vec
был коротким: вместо текущего 64-байтового размера, начните с чего-то гораздо меньшего и посмотрите, сможет ли z3 справиться с этим (скажем, несколько байтов для начала.) Это также может включите дальнейшую отладку, если вы правильно поняли алгоритм.
Удачи!