Tags: re idapython emulation bruteforce ida 

Rating:

The binary reads the flag, then checks that f[flag[i]](flag[i+1]) == enc_flag[i], where enc_flag is an array of integers and f is an array of 256 encrypted functions.

It is not a good idea to solve it with angr, so we decided to write an IDAPython script to solve it in static, with the help of Unicorn Engine:

import struct
import string

from unicorn import *
from unicorn.x86_const import *

def check_ea(ea):
    if ea is None:
        return ScreenEA()
    return ea

def decr(ea=None):
    ea = check_ea(ea)
    enc_addr = Dword(ea)
    size = Dword(ea + 4)
    key = Qword(ea + 8)
    for i in range(size):
        enc = Byte(enc_addr + i)
        PatchByte(enc_addr + i, (enc ^ (key >> ((i & 3) * 8))) & 0xFF)
    MakeCode(enc_addr)
    MakeFunction(enc_addr)

def decr_all(ea, n):
    for i in range(n):
        decr(ea + i * 16)

def emul(ea, size, arg):
    stack = 0x7F000000
    mu = Uc(UC_ARCH_X86, UC_MODE_32)
    mu.mem_map(ea & 0xFFFFF000, 0x2000)
    mu.mem_map(stack - 0x1000, 0x1000)
    mu.mem_write(ea, GetManyBytes(ea, size - 1))
    mu.mem_write(stack - 4, struct.pack('<I', arg)) 
    mu.reg_write(UC_X86_REG_ESP, stack - 8)
    mu.emu_start(ea, ea + size - 1)
    return mu.reg_read(UC_X86_REG_EAX)

def solve():
    checkers_addr = 0x0804C140
    decr_all(checkers_addr, 256)
    checkers = [(Dword(checkers_addr + i * 16), Dword(checkers_addr + i * 16 + 4)) for i in range(256)]
    consts = 'CB00000000808B003B3D0000A8E50B002EDA000098010000C0830A00121C0E003D00000000698A0000AF89009D3A00004FFFFFFFDE000000701B00001EE70C008420000080F48A005301000002B80F00E6090000750E000054FFFFFFF41D0000E0430600FC09000063220000FC03F1FF005AFFFF3EEFFFFFDE0000004C2F0000920100003DD84E00720D00003C610000691D00009E0000001CD41000F30800001D1A5500370000004CFFFFFF0537000022371F00FD5B5B00E609000005070000B56F000099720000'.decode('hex')
    consts = [struct.unpack('<I', consts[i:i + 4])[0] for i in range(0, len(consts), 4)]
    alph = string.printable
    for first_char in alph:
        prev = ord(first_char)
        ans = [prev]
        for const in consts:
            t = len(ans)
            for c in alph:
                if emul(checkers[ans[-1]][0], checkers[ans[-1]][1], ord(c)) == const:
                    ans.append(ord(c))
                    break
            if len(ans) == t:   # letter not decrypted
                break
        if len(ans) > 1:
            print '[*] ' + ''.join(map(chr, ans))


if __name__ == '__main__':
    solve()

What's happening is decrypting all checkers (from f array), bruteforcing the first character and trying to decrypt all (by bruteforcing the character feeded to the checker, that is emulated). When executed the script gives the following output:

[*] 8t
[*] nT
[*] you are looking for this EKO{4ngr_d1dn't_like_th1s}
[*] Gg