Esempio n. 1
0
    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)
Esempio n. 2
0
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