Search code examples
z3smtz3py

Howt to use properly ZeroExt(n,a) in a Z3py formula?


I am trying to find out the password of a keygen algorithm hidden in a binary. So, I extracted the formula from the assembly and translated (correctly, hopefully) in a small Python script to solve it:

#!/usr/bin/env python
from z3 import *

# Password initialization
pwd = BitVecs('pwd0 pwd1 pwd2 pwd3 pwd4 pwd5', 8)

# Internal states
state = BitVecs('state0 state1 state2 state3 state4 state5 state6', 32)

# Building the formula
state[0] = (pwd[3] ^ 0x1337) + 0x5eeded
for i in range(6):
    state[i+1] = (ZeroExt(24, pwd[i]) ^ state[i]) % 0xcafe

# Solving the formula under constraint
solve(state[6] == 0xbad1dea)

Unfortunately, the ZeroExt(n,a) seems to produce the following error message:

Traceback (most recent call last):
  File "./alt.py", line 13, in <module>
    state[i+1] = (ZeroExt(24, pwd[i]) ^ state[i]) % 0xcafe
  File "/usr/lib/python2.7/dist-packages/z3.py", line 3115, in __xor__
    return BitVecRef(Z3_mk_bvxor(self.ctx_ref(), a.as_ast(), b.as_ast()), self.ctx)
  File "/usr/lib/python2.7/dist-packages/z3core.py", line 1743, in Z3_mk_bvxor
    raise Z3Exception(lib().Z3_get_error_msg_ex(a0, err))
z3types.Z3Exception: Argument (bvadd (bvxor pwd3 #x37) #xed) at position 1 does not match declaration (declare-fun bvxor ((_ BitVec 32) (_ BitVec 32)) (_ BitVec 32))

What did I do wrong and how to workaround this problem ?

NOTE: I changed the constants of the challenge to avoid to be easily found by searching for it (no cheating!). So, this problem might have no satisfiable solution...


Solution

  • It doesn't matter that you initialize the state vector to be 32-bits Z3 expressions. Once you overwrite state[0] to be the expression you supply, it is not 32 bits. It is instead just 8 bits. Also your bit-vector constants are truncated to 8 bits because of the bit-width of pwd[3].

    So, the effect of:

         state[0] = (pwd[3] ^ 0x1337) + 0x5eeded
    

    is that state[0] contains a bit-vector that has size 8.

    Then when you take the xor of state[0] and (ZeroExt(24, pwd[0]) you get the type mismatch.

    A fix is to zero-extend pwd[3] in the first occurrence.