利用Unicorn和Idaemu辅助解决Geekpwn SecretCode
在前面的些文章里,我提到了怎么交叉编译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,'')
print(result)
result = binascii.unhexlify(result)
print('final result: ' + str(struct.unpack('>d',result)[0]))
aeabi_dadd([1,2,4,100])
通过这段脚本的运行,我知道了j_j___aeabi_dadd(*(__int64 *)&in, 0xBFF0000000000000LL);就是将输入的浮点数进行减一操作。通过这个方法,我也知道了j_j___aeabi_dadd(v3, 0xC1D0000000000000LL);的作用,就是将输入的浮点数进行减去1073741824操作。
通过这几个函数的分析,我知道了用户输入的数据首先减去1然后减去四个1073741824,最后将其从浮点数转换成整数。转换成整数后,我看到这个整数传到了f2里面,因此,我现在要用Idaemu来模拟一下f2,用到的代码如下:
def f2_1(i):
arg = []
arg.append(i)
r0 = a.eFunc(0x1984, None, arg)
return r0 def walkf2(start, end):
i=start
while i<end:
print(str(i)+ ' '+ str(f2_1(i)))
i+=1
walkf2(0,200)
通过这段脚本的运行,我发现在0到200之间,只有5,11,101,191的返回结果是1,而其他的返回结果都是0,我就在google上搜索序列5,11,101,191发现这是四胞胎素数的序列,所以我就猜测f2则是判断数字是不是四胞胎素数。进入f2后,我发现了4处对f0的调用,因此我又对f0进行了模拟,发现f0则是判断输入的数据是不是素数,对f0的四次调用恰好印证了f2则是用来判断是不是四胞胎素数。用到的脚本:
def f0_1(i):
arg = []
arg.append(i)
r0 = a.eFunc(0x1430, None, arg)
return r0
def walkf0(start, end):
i=start
while i<end:
print(str(i)+ ' '+ str(f0_1(i)))
i+=1
walkf0(0,30)
我也同样的尝试去模拟f1,但是并没有发现规律。接下来,我开始动态地调试这个程序,发现虽说表面上看控制流很复杂,但是有相当大一部分是固定的跳转,而且Ida调试Android经常会遇到SIGILL,很不方便,我就想着如果把程序运行过程中的trace给log下来,然后进行静态的分析。用到的一些脚本如下:
a = Emu(UC_ARCH_ARM, UC_MODE_THUMB)
a.setTrace(TRACE_CODE)
a.setTrace(TRACE_FileLOG)
def StringFromJni(i):
print 'handling: '+str(i)
i += (1+1073741824*4)
p = struct.pack('>d',i)
print binascii.hexlify(p)
arg0 = int(binascii.hexlify(p[4:]),16)
arg1 = int(binascii.hexlify(p[:4]),16)
print 'arg0: '+hex(arg0)
print 'arg1: '+hex(arg1) arg = []
arg.append(0)
arg.append(0)
arg.append(arg0)
arg.append(arg1) r0 = a.eFunc(0x1C44, 0x1F7A, arg)
print('return: ' + hex(r0))
#StringFromJni(500227331)
StringFromJni(5)
脚本完成后,会生成tracelog文件,里面存放了所有的执行过程的指令。下一步我们就可以直接开始进行分析了,对着tracelog和IDA进行分析。因为很大一部分分支比较的代码是无用的,而且有一部分是已知函数的执行序列也是无用的,所以在看tracelog的时候把这些删除的话大概只剩下100多行,分析着还是蛮快的。无用的指令序列一般是下面这种形式的:
LDR R0, =0x61CB0C05 R0: 78d3a2ea;
CMP R1, R0 R1: 275f3da1; R0: 61cb0c05;
BGT loc_17D2
我初步在代码里看到的是:假设输入的是x,记subdone = x-1-4*1073741824,在代码分支里判断的有subdone是不是一个四胞胎素数,根据判断的结果将一个局部变量A置为0或1,以及subdone-1有没有大于500000000,根据判断的结果将一个局部变量B置为0xB29C1529(大于500000000)或者0x91CD6A9B(小于500000000),然后让i从1开始一次求i的平方知道i的平方大于subdone-1,当subdone-1存在平方根的时候,会用到局部变量B。我尝试通过hook的方式,在当要使用变量B的时候将变量B修改为0xB29C1529,则这个时候通过验证。
通过上面的推理与理解,我们可以得出:subdone是一个四胞胎素数,subdone要大于500000000,subdone-1要有平方根。根据此,我写了一个C语言的程序来爆破这个数字,顺利得到该数字,即512116901,所以输入为:512116901+1+1073741824*4=4807084198。Flag就是flag{hohay3f4nmop}。
其实我并没有很严格地逆清楚这个算法,但是通过Idaemu和Unicorn的帮助,我可以通过模拟运行产生tracelog的方式来进行分析,里面有些推测,但是算是合理的推测。

c语言的源代码:http://files.cnblogs.com/files/wangaohui/secretcode.zip
idaemu:https://github.com/36hours/idaemu 我在其基础上进行了些修改,使其能将指令序列记录到文件中,并且以一种友好的方式记录寄存器的值
利用Unicorn和Idaemu辅助解决Geekpwn SecretCode的更多相关文章
- 利用Python的三元表达式解决Odoo中工资条中城镇、农村保险的问题
Python中没有像C#中有三元表达式 A?B:C 但在python中可以通过 A if condition else B 的方式来达到同样的效果. 例如 : 1 if True else 0 输出 ...
- C#下利用封包、拆包原理解决Socket粘包、半包问题(新手篇)
介于网络上充斥着大量的含糊其辞的Socket初级教程,扰乱着新手的学习方向,我来扼要的教一下新手应该怎么合理的处理Socket这个玩意儿. 一般来说,教你C#下Socket编程的老师,很少会教你如何解 ...
- 利用nginx做反向代理解决前端跨域问题
最近朋友再群里提了一个问题,他们公司给他提供了一个获取数据的接口,在浏览器访问这个接口能获取到json数据,但是放在项目里使用ajax就产生了跨域问题,一般这个需要提供接口的后台方面需要做跨域处理,但 ...
- GIS技术在医疗行业的应用:利用切片地图发布技术解决dmetrix数字病理切片在线浏览
最近一直在研究切片地图发布技术,解决各种矢量和栅格数据的切片地图制作和发布问题.这块的技术在土地评估和调查类公司中应用较多,因为他们经常需要使用各地地图,传统的文件管理方式很难适应工作现状,如果将各种 ...
- 利用Spring AOP自定义注解解决日志和签名校验
转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...
- 利用Ihttpmodel实现网站缓存,解决Server.Transfer 直接输出HTML源代码的问题
今天在用.NET利用IHttpModel实现网站静态缓存的时候,不知道最后为什么用 Server.Transfer(html)的时候结果输出的是HTML的源代码. 贴上源代码 using System ...
- 利用Azure嵌套虚拟化,解决公有云上机器不能启动的问题
很多时候我们都会碰到因为意外重启,机器硬盘被损坏导致无法启动,或者是因为各种原因Windows上的RDP服务启动不了,Linux上的SSH无法链接等等问题.碰到这种问题基本上很难解决以前都是将VHD下 ...
- linux 中的进程wait()和waitpid函数,僵尸进程详解,以及利用这两个函数解决进程同步问题
转载自:http://blog.sina.com.cn/s/blog_7776b9d3010144f9.html 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / wait ...
- (转)利用Spring AOP自定义注解解决日志和签名校验
一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...
随机推荐
- linux 服务器更主板后无法识别网卡处理过程
linux 服务器更主板后无法识别网卡处理过程 服务器故障报修,主板坏,更换主板后无法识别网卡,ifconfig 查看只显示:lo loopback 127.0.0.1. 系统加载网卡驱动后会去读 ...
- KVO详解
NSKeyValueObserving非正式协议定义了一种机制,它允许对象去监听其它对象的某个属性的修改. 我们可以监听一个对象的属性,包括简单属性,一对一的关系,和一对多的关系.一对多关系的监听者会 ...
- Linux的启动流程
1.首先是bios加电自检.初始化,这个过程会检测相关硬件(cpu.内存.硬盘等),然后会读取硬盘中的MBR:2.加载内核,读取/boot里边的配置文件:3.启动初始化进程,开始运行/sbin/ini ...
- javascriptt切换组件MyTab.js封装
之前做的大多数是jquery的插件,就优雅性来说,我觉得还是原生的代码,写起来更舒服一点,虽然麻烦很多. 之前写了一个利用完美运动框架的轮播效果,因为使用的是原生的代码,因为不懂原生对象封装的原因一直 ...
- ssh maven 搭建
数据库建表脚本不带,是很简单的一个表,把数据库环境搭建起来即可. 1.项目结构(Eclipse) 2.pom.xml <project xmlns="http://maven.apac ...
- 一个很简单的jQuery插件实例教程(菜鸟级)
很多公司的前端设计开发人员都是女孩子,而这些女孩子很多JavaScript技能都不是很好.而前端开发过程中,JavaScript技能又是必不可少的.所以,如果前端小MM正在为某个JavaScript效 ...
- 新浪短链接API接口示例
<?php /** * URL地址长短切换,由sina新浪短链接API生成 * User: chenqt * Date: 2016/8/23 * Time: 18:45 */ class Url ...
- php 实时推送代码
网站质量不错的网站可以在百度站长平台/数据提交/sitemap栏目下看到实时推送的功能, 目前这个工具是邀请开放, 百度的实时推送的api接口可以实时推送我们新发布的文章, 保证百度在第一时间收录. ...
- 解决ligerUI服务器分页Total不起作用的问题
Js代码: $('#userTable').ligerGrid({ width:'100%', height:'100%', title:'用户列表', //url:'', dataAction: ...
- select p.id, name,ROW_NUMBER() over(PARTITION by name order by p.id) names from person p
select p.id, name,ROW_NUMBER() over(PARTITION by name order by p.id) names from person p