首页
社区
课程
招聘
[原创]初识Frida--Android逆向之Java层hook (一)
发表于: 2018-6-5 17:35 39923

[原创]初识Frida--Android逆向之Java层hook (一)

2018-6-5 17:35
39923

博客同步:访问

Frida官网给我们了一个ctf的示例,就以此为例子,开始学习frida在android逆向的使用。
rps.apk 下载地址

使用genymotion等类似android模拟器安装好打开,发现这是一个石头剪刀布的游戏应用,简单的玩了一下,没什么特别的,直接分析代码吧,看看到底想干什么。

使用jadx-gui反编译,发现app没有加壳和混淆,当然一来就加壳和混淆的话对我们就太不友好了,接下分析就简单了,直接看java代码。当然也可以使用androidkiller,jeb等其他强大的反编译工具。

在MainActivity中找到OnCreate()方法,可以看到只是简单的声明了button控件以及对应的监听器。

继续查看button的onclick方法,可以看出cpu是通过随机数组出的,其判断输赢的方法在this.showMessageTask中。

跟进分析showMessageTask,可以看到如果赢了mainActivity.cnt会+1,但是一旦输了cnt就会置0,而获取flag的要求是我们得获胜1000次,...... :(

简单分析一下获取flag需要的条件,总结有3个办法:

分析calc()方法能算出答案,但这个方法在so中,得分析汇编代码才行,当然可以尝试使用ida pro,F5查看C代码分析,前提是算法不难。

获取calc函数的返回值,从而计算答案。

接下来就用frida,使用后两种思路来解这个简单的示例。但在这之前得先了解Frida自带的Messages机制,了解frida怎么从通过一个python脚本发送和接收message消息是一个提升理解frida的好方法。

先来看看一个Messages的模板,这里用到的语言分别是python和javascript,他们之间的关系是python作为载体,javascript作为在android中真正执行代码。

当然如果是对此简单的使用,只需要编写jscode,以及填写你要hook的应用完整包名就行了,不过如果单纯只会用可能在以后会被模板限制,所以一探究竟还是很有必要。
可以在cmd中,使用python终端的help()函数找到frida库的源代码的绝对路径。

接下来就来具体看看这几句代码做了什么事情。

首先使用了frida.get_usb_device(),返回了一个_get_device函数,跟进_get_device方法。

在_get_device中,通过get_device_manager()实例化DeviceManager类,并调用该类中的enumerate_devices()方法。

get_device_manager()代码

DeviceManager中enumerate_devices()方法,可以看到enumerate_devices()方法实际上是返回了一个Device()类的实例化对象List。

继续跟进Device类中的,就找到了attach()方法。在attach方法这是设置断点,看看传入的数据。

接下来提供的“应用完整名”是通过self._pid_of()函数去找到对应的进程号pid,然后将pid后通过Session类初始化。到此第一句代码过程就算是明白了,最终得到的是一个对应进程号pid的Session实例化对象process。

第二句,紧接着process.create_script(jscode),可以看到它返回一个Script类的实例化,参数不确定。

跟进Script类,可以找到on()方法,在on方法中可以设置自定义回调函数。


接下来调用load()方法,在服务端就启动javascript脚本了,至于在frida-server服务端怎么执行的,可逆向研究一下frida-server,它才是真正的核心。

现在就来使用frida实现刚刚试想的方法。

第一种思路就是直接获取calc的返回值,从native函数定义上知道它的返回值是int类型,当然直接获取calc函数的返回值是解出问题最简单的方法。

那怎么获取calc()函数的返回值呢,这个函数在MainActivity类中,直接引用该类下的calc()方法,不就ok了吗,原理是这样,下面就来构造一下Javascript代码。

JavaScript代码就是这样,如果不是很理解,学习一下JavaScript基础即可,下面看看完整的python脚本。

接下来运行一下,看看能否成功。

步骤如下:

因为hook的是应用的onCreate方法,执行python脚本的前提是应用首先启动,这样才能attach到该应用,所以还得返回模拟器桌面重新启动应用,这样它才会执行hook的onCreate()方法,结果如下。

第二种思路也比较简单,我们需要修改cnt的值,但如果直接修改cnt的初始值为1000的话,在游戏中可能存在不确定因素,比如输了会置0,赢了cnt值就变成1001了,所以还得控制一下输赢,而输赢的条件是电脑出什么,所以最终hook的方法就在onClick中。
从onClick()中可以知道,控制输赢的在于修改this.n 和 this.m的值,再来看看源代码。

来看JavaScript代码怎么写吧

完整python代码

执行python脚本,任意点击按钮,答案就出来了。

当然,如果so中的calc()函数算法不难的前提,直接使用ida pro或者radare2分析汇编代码也是可以的。这里给出用radare2反汇编出来的代码。可以看到,calc()函数就单纯的返回了int值7。

 
 
 
 
 
 
 
  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.P = (Button) findViewById(R.id.button);
        this.S = (Button) findViewById(R.id.button3);
        this.r = (Button) findViewById(R.id.buttonR);
        this.P.setOnClickListener(this);
        this.r.setOnClickListener(this);
        this.S.setOnClickListener(this);
        this.flag = 0;
    }

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-1-11 19:27 被kanxue编辑 ,原因:
收藏
免费 6
支持
分享
最新回复 (43)
雪    币: 19
活跃值: (1086)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
支持一下,最近也研究这个使用的方法,很好用的工具
2018-6-5 18:32
1
雪    币: 1385
活跃值: (5609)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
3
图片丢失了。
2018-6-6 09:20
0
雪    币: 930
活跃值: (731)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
4
supperlitt 图片丢失了。
手机端好像就显示不出图片,但是PC端就没有问题。
2018-6-6 09:31
0
雪    币: 6573
活跃值: (3893)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
5
两篇文章都有图片丢失,请仔细修正一下给精华
2018-6-6 10:17
0
雪    币: 930
活跃值: (731)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
LowRebSwrd 两篇文章都有图片丢失,请仔细修正一下给精华
恩,我看看哪里出问题了
2018-6-6 10:22
0
雪    币: 930
活跃值: (731)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
7
LowRebSwrd 两篇文章都有图片丢失,请仔细修正一下给精华
图片刚刚已经修复了....请审阅
2018-6-6 10:59
0
雪    币: 42
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
同样的代码执行到this.onClick(v);这句就报错了。
[*]  Hook  Start...
{u'columnNumber':  1,  u'description':  u"TypeError:  undefined  not  callable  (property  'art::mirror::Object::Clone'  of  [object  Object])",  u'fileName':  u'java.js',  u'lineNumber':  2725,  u'type':  u'error',  u'stack':  u"TypeError:  undefined  not  callable  (property  'art::mirror::Object::Clone'  of  [object  Object])\n        at  [anon]  (duk_js_call.c:2847)\n        at  E  (frida/node_modules/frida-java/lib/android.js:729)\n        at  resolveArtTargetMethodId  (frida/node_modules/frida-java/lib/class-factory.js:1621)\n        at  input:1\n        at  [anon]  (script1.js:6)\n        at  input:1"}
2018-6-6 15:49
1
雪    币: 930
活跃值: (731)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
9
xibijj 同样的代码执行到this.onClick(v);这句就报错了。 [*] Hook Start... {u'columnNumber': 1, u'description': u"Type ...

我刚刚在本地重新实验了一下,代码是没有问题的哈,可能是模拟器的原因,最好使用真机做实验,因为模拟器很多都是x86架构的,有的app对x86架构支持不是很好。

 

 

结果也能出来:

2018-6-6 16:07
1
雪    币: 1432
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
谢谢分享!!!!
2018-6-7 08:28
1
雪    币: 1705
活跃值: (676)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
老铁请问哪个模拟器不是x86架构的,因为我用逍遥模拟器也是完蛋,我需要一个能使用的模拟器,genymotion这个可以么
2018-6-7 10:44
1
雪    币: 1705
活跃值: (676)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
我买了个小米5x专门做调试用,结果很难root,而且转到开发板要绑定350小时,劝大家不要选小米5x调试
2018-6-7 10:47
1
雪    币: 930
活跃值: (731)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
13
看血大叔 老铁请问哪个模拟器不是x86架构的,因为我用逍遥模拟器也是完蛋,我需要一个能使用的模拟器,genymotion这个可以么
genymotion可以,genymotion  x86架构的支持的还可以,如果你下载6.0的镜像可以转成arm架构,但会出现一些奇怪的问题,我用的是小米3,刷的4.4.4版本,到目前还没有发现问题
2018-6-7 11:02
0
雪    币: 226
活跃值: (52)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
谢谢大佬分享
2018-6-22 14:36
0
雪    币: 208
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
大佬用过腾讯手游助手吗?用这个模拟器,刚开始就进行不下去了,frida  ps直接什么都不返回啊
2018-6-23 17:17
0
雪    币: 1
活跃值: (64)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
m
2018-6-26 16:28
0
雪    币: 201
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
方法一hook onCreate方法是不是有时机问题,我实验时无法成功。先运行程序app再hook,onCreate已经调用过了,没有结果。我把hook对象改成onClick方法,在自己点击时就有结果了。
2018-7-2 15:15
0
雪    币: 930
活跃值: (731)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
18
heeeeen 方法一hook onCreate方法是不是有时机问题,我实验时无法成功。先运行程序app再hook,onCreate已经调用过了,没有结果。我把hook对象改成onClick方法,在自己点击时就有结果 ...
其实在文章中已经写到了呢,“因为hook的是应用的onCreate方法,执行python脚本的前提是应用首先启动,这样才能attach到该应用,所以还得返回模拟器桌面重新点开应用,这样它才会执行hook的onCreate()方法”,你也可以在cmd上使用frida -U -f  应用名 ,这个时候会进入spawning状态, 随后启动python脚本, 使用 %resume,再让frida启动应用,这样也可以。
2018-7-2 16:31
0
雪    币: 222
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
楼主两个我都跑成功了,感谢分享。帖子写的很详细,对于我这种小白来讲是很不错的学习资料,虽然暂时不懂太多原理,慢慢再看。我也试了楼主讲的第一种方法IDA直接打开so 看到返回7。 希望楼主能够继续写下去!
2018-8-3 12:23
1
雪    币: 3517
活跃值: (4639)
能力值: ( LV13,RANK:437 )
在线值:
发帖
回帖
粉丝
20
初学frida,遇到两个解决不了问题,向楼主请教下:
1. Java.perform 里面写的 send("***"),写在外层js代码中,python端就能接收到。但是写在被hook的方法中,就接收不到
2. var currentApplication =Dalvik.use("android.app.ActivityThread").currentApplication(); 想通过这个方式获取Application,但是报错提示——identifier 'Dalvik' undefined"
2018-8-6 17:57
0
雪    币: 30
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
C:\Users\Administrator>python C:\Users\Administrator\Desktop\thj.py
Traceback (most recent call last):
  File "C:\Users\Administrator\Desktop\thj.py", line 24, in <module>
    session=rdev.attach("com.toocms.baihuisc")
  File "D:\Program Files\Python36\lib\site-packages\frida\core.py", line 110, in
 attach
    return Session(self._impl.attach(self._pid_of(target)))
frida.TransportError: the connection is closed

C:\Users\Administrator>

你好 请问这个是怎么回事呢 我明明链接了frida 程序也已经运行了 
2018-8-10 14:28
0
雪    币: 930
活跃值: (731)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
22
ctw爱情 C:\Users\Administrator>python C:\Users\Administrator\Desktop\thj.py Traceback (most recent call ...
这个很有可能是app做了防hook,你可以通过注入zygote来启动app 
使用命令: frida -U -f com.toocms.baihuisc  ,spawn成功之后,输入%resume,这个时候启动python hook脚本试试
2018-8-20 22:44
1
雪    币: 30
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
ghostmazeW 这个很有可能是app做了防hook,你可以通过注入zygote来启动app 使用命令: frida -U -f com.toocms.baihuisc ,spawn成功之后,输入%resume, ...
{'type': 'error', 'description': 'Error: expected a pointer', 'stack': 'Error: e
xpected a pointer\n    at frida/runtime/core.js:471\n    at script1.js:13', 'fil
eName': 'frida/runtime/core.js', 'lineNumber': 471, 'columnNumber': 1}
上面的问题解决了 现在这个 请问是什么原因?其他的so 可以 用来弄这个app 就不行了
2018-8-23 14:40
0
雪    币: 930
活跃值: (731)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
24
ctw爱情 {'type': 'error', 'description': 'Error: expected a pointer', 'stack': 'Error: e xpected a pointer\ ...
这个是类型错误吧,参数需要的是一个指针
2018-8-24 09:48
0
雪    币: 30
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
ghostmazeW 这个是类型错误吧,参数需要的是一个指针
Interceptor.attach(Module.findExportByName("libtiny.so","md5"), {
    onEnter: function(args) {
        ret=Memory.readUtf8String(args[1]);
        send("arg0:"+args[0]);
        send("arg1:"+ret);

    },
    onLeave:function(retval){
       
    }
});
我就是这样写的 来获取传递进来的参数 要是说是第一个是指针  用内存读取 应该是可以?
2018-8-24 11:04
0
游客
登录 | 注册 方可回帖
返回
//