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