def eval(self, op, a=None, b=None): concrete = True a_val = a if a is None else a.val b_val = b if b is None else b.val # determinate symbolic/concrete operation mode if a_val is not None and a_val.is_symbolic(): concrete = False if b_val is not None and b_val.is_symbolic(): concrete = False if concrete: a_reg = a if a is None else VM.Reg(a.size, a.get_val()) b_reg = b if b is None else VM.Reg(b.size, b.get_val()) # compute and return concrete value return Val(val=super(Math, self).eval(op, a_reg, b_reg)) else: assert a is not None assert op in [I_STR, I_NOT] or b is not None # get symbolic representation of the arguments a_sym = a if a is None else a.to_symbolic() b_sym = b if b is None else b.to_symbolic() # make a symbolic expression exp = a_sym if op == I_STR else SymExp(op, a_sym, b_sym) # return symbolic value return Val(exp=exp)
def keygen(kao_binary_path, kao_installation_ID): ''' Assembly code of serial number check from Kao's Toy Project binary, X and Y contains serial number that was entered by user. .text:004010EC check_serial proc near .text:004010EC .text:004010EC ciphered = byte ptr -21h .text:004010EC X = dword ptr 8 .text:004010EC Y = dword ptr 0Ch .text:004010EC .text:004010EC push ebp .text:004010ED mov ebp, esp .text:004010EF add esp, 0FFFFFFDCh .text:004010F2 mov ecx, 20h .text:004010F7 mov esi, offset installation_ID .text:004010FC lea edi, [ebp+text_ciphered] .text:004010FF mov edx, [ebp+X] .text:00401102 mov ebx, [ebp+Y] .text:00401105 .text:00401105 loc_401105: .text:00401105 lodsb .text:00401106 sub al, bl .text:00401108 xor al, dl .text:0040110A stosb .text:0040110B rol edx, 1 .text:0040110D rol ebx, 1 .text:0040110F loop loc_401105 .text:00401111 mov byte ptr [edi], 0 .text:00401114 push offset text_valid ; "0how4zdy81jpe5xfu92kar6cgiq3lst7" .text:00401119 lea eax, [ebp+text_ciphered] .text:0040111C push eax .text:0040111D call lstrcmpA .text:00401122 leave .text:00401123 retn 8 .text:00401123 check_serial endp ''' # address of the check_serial() function check_serial = 0x004010EC # address of the strcmp() call inside check_serial() stop_at = 0x0040111D # address of the global buffer with installation ID installation_ID = 0x004093A8 # load Kao's PE binary from pyopenreil.utils import bin_PE tr = CodeStorageTranslator(bin_PE.Reader(kao_binary_path)) # Construct DFG, run all available code optimizations # and update storage with new function code. dfg = DFGraphBuilder(tr).traverse(check_serial) dfg.optimize_all(tr.storage) print tr.get_func(check_serial) # create CPU and ABI cpu = Cpu(ARCH_X86) abi = VM.Abi(cpu, tr, no_reset=True) # hardcoded ciphered text constant from Kao's binary out_data = '0how4zdy81jpe5xfu92kar6cgiq3lst7' in_data = '' try: # convert installation ID into the binary form for s in kao_installation_ID.split('-'): in_data += struct.pack('L', int(s[:8], 16)) in_data += struct.pack('L', int(s[8:], 16)) assert len(in_data) == 32 except: raise Exception('Invalid instllation ID string') # copy installation ID into the emulator's memory for i in range(32): cpu.mem.store(installation_ID + i, U8, cpu.mem._Val(U8, 0, ord(in_data[i]))) ret, ebp = 0x41414141, 0x42424242 # create stack with symbolic arguments for check_serial() stack = abi.pushargs(( Val(exp = SymVal('ARG_0', U32)), \ Val(exp = SymVal('ARG_1', U32)) )) # dummy return address stack.push(Val(ret)) # initialize emulator's registers cpu.reg('ebp', Val(ebp)) cpu.reg('esp', Val(stack.top)) # run until stop try: cpu.run(tr, check_serial, stop_at=[stop_at]) except VM.CpuStop as e: print 'STOP at', hex(cpu.reg('eip').get_val()) # get Z3 expressions list for current CPU state state = cpu.to_z3() cpu.dump(show_all=True) # read symbolic expressions for contents of the output buffer addr = cpu.reg('eax').val data = cpu.mem.read(addr.val, 32) for i in range(32): print '*' + hex(addr.val + i), '=', data[i].exp # create SMT solver solver = z3.Solver() for i in range(32): # add constraint for each output byte solver.add( data[i].to_z3(state, U8) == z3.BitVecVal(ord(out_data[i]), 8)) # solve constraints solver.check() # get solution model = solver.model() # get and print serial number serial = map(lambda d: model[d].as_long(), model.decls()) serial[1] = serial[0] ^ serial[1] print '\nSerial number: %s\n' % '-'.join( ['%.8X' % serial[0], '%.8X' % serial[1]]) return serial assert False