在前面的些文章里,我提到了怎么交叉编译Unicorn-engine,以及在windows上使用Unicorn python bindings进行分析程序。这一次我介绍下如何使用Unicorn-engine和Idaemu来解决一个ollvm混淆的android逆向,也就是Geekpwn SecretCode 150。
拿到题目,java的代码很简单,用户输入一个数字,程序调用native方法Java_net_bluelotus_tomorrow_easyandroid_MainActivity_stringFromJNI来进行验证。使用IDA打开so,发现代码经过了o-llvm混淆,控制流非常复杂。
这个时候如果直接逆的话,难度很大,所以我在这里借助了idaemu来对某些函数模拟执行,然后通过函数的输入和输出来猜测函数的功能。首先要知道的是,一个double类型的数据是要两个寄存器存储的,使用的是IEEE 754标准将数字存放到寄存器当中。直接对Java_net_bluelotus_tomorrow_easyandroid_MainActivity_stringFromJNI进行f5,可以看到里面除了复杂的控制流外,调用了几个别的函数,比如aeabi_dadd,fixdfsi,浏览函数列表的时候还发现了f0, f1, f2, f3函数,只从这几个函数名上就知道这是用户写的函数,并且在Java_net_bluelotus_tomorrow_easyandroid_MainActivity_stringFromJNI也发现调用了f1和f2,f2又调用了四次f0。
根据名字我大概觉得aeabi_dadd是浮点数的加法,我先google了aeabi_dadd 和fixdfsi,知道了fixdfsi是将浮点数转换为整数。我使用了idaemu模拟了几次aeabi_dadd,证实了自己的看法。用到的部分脚本如下:
a = Emu(UC_ARCH_ARM, UC_MODE_THUMB) #0xBFF0000000000000 #add -1 def aeabi_dadd(f): for i in f: p = struct.pack('>d',i) arg0 = int(binascii.hexlify(p[4:]),16) arg1 = int(binascii.hexlify(p[:4]),16) arg = [] arg.append(arg0) arg.append(arg1) arg.append(0) arg.append(0xBFF00000) r0 = a.eFunc(0x4188, None, arg) r1 = a.curUC.reg_read(UC_ARM_REG_R1) value = (r1<<32)|r0 print 'handling: '+ str(i)) result = hex(value)[2:-1].rjust(16,'0') print(result) result = binascii.unhexlify(result) print('final result: ' + str(struct.unpack('>d',result)[0])) aeabi_dadd([1,2,4,100])