转载:使用Frida给apk脱壳并穿透加固Hook函数:https://xz.aliyun.com/t/7670
[推荐] 『Android安全』版2018年优秀和精华帖分类索引:https://bbs.pediy.com/thread-249602.htm
今天拿到了新玩具 JEB 3.17.1,想测试一下,顺便学习学习 Android 逆向,于是找了一个 apk 准备试试水,看看能不能搞到VIP。
拖入jeb查看
google一下
几维安全的壳,虚拟化很烦,也没什么好的脱壳工具,于是切换思路
从本质上来说,虚拟化就是自己实现了一套基本的cpu指令,通过自己的解释器解释给机器。因此想要在虚拟化之后仍然能让机器运行,当然还得还原代码给机器,只不过可能在内存中释放,加大了静态分析的难度。
那么直接让apk运行起来,我们去dump虚拟机自解密出来的dex不就好了么。
frida 是一款基于 python+javascript 的 hook 框架,可运行在 android、ios、linux、win等各个平台,主要使用的动态二进制插桩技术。
总之 frida 是非常强大的,可以实现很多奇妙操作。
pip3 install frida
frida-server 下载地址:https://github.com/frida/frida/releases
到上面链接里找到对应手机架构,与 frida 版本相同的 frida-server
移动 frida-server 到安卓的 /data/local/tmp 目录
./adb push frida-server /data/local/tmp
./adb kill-server && ./adb server && ./adb shell # 这里我用了mumu模拟器,其他虚拟机连接adb方法请自行查询
cd /data/local/tmp
chmod 777 frida-server
./frida-server #开始你的炸弹秀
这里使用了 FRIDA-DEXDump:https://github.com/hluwa/FRIDA-DEXDump
其原理就是在内存中检索dex035头并获取dex长度,然后提取出来。当然,这样做会将内存中所有的dex包都提取出来,具体哪个才是我们需要的得根据包名判断并静态分析查看。
python3 ./main.py
这里我成功提取到了无壳 dex,包名都比较清晰
既然壳不好脱而且脱下来的又不容易修复,就考虑先看看封包里有没有VIP数据
使用HttpCanary对apk进行抓包
抓到了一个登陆验证包
但响应里没有我们想要的信息,只是一个随时变动的值而已
看来抓包这条路走不通了,我们接下来只能分析拿到的 dex。
我们使用 JEB 来分析我们拿到的 dex,查看包的层级数,定位到目标 apk 的包名,这里的命名都很清晰,直接按单词分析即可。
我这次用来当例子的是一个类似抖音快手的app,有视频和直播两个Activity,视频每天只能看十个(最坑的是重复点十次也算),然后就要求充值VIP,用户进入后可以不登录,会自动生成一个ID,且读取系统信息作为认证,所以重复的卸载安装当然是绕不过次数限制的。
所以我们的目标就是通过frida hook函数使我们绕过限制,成为VIP。
查看原apk文件的Manifest
这个权限它就离谱。。。
我们来看Activity的启动顺序
先来了一个开屏广告SplashActivity,然后加载Main和Live顺便走一遍登录注册。
一般判断用户是否是VIP,可能存在多处判断,这样的话我们hook的点会量很大,而且可能存在漏掉的情况,因此去找变量最初赋值的位置来hook是从源头上控制了数据,而且前面封包分析发现用户数据请求发送后给我们的响应不包含VIP确认数据,因此可以说是万无一失。
回到层级目录分析,我们发现video/bean这个包里有我们感兴趣的东西,应该是包含了短视频相关数据。
查看TouseinfoBean这个类
我们发现这里应该包含了用户数据,修改此处就可以了。
但事情没有那么简单,通过交叉引用我们发现这个类根本没有被实例化(可能是写着写着忘了又重新写了一个用户管理模块???)
搜索字符串后并没有什么有用的发现,分析良久才想到从包层级列表搜索方法,豁然开朗(还是太菜)。
嗯。。原来把直播和视频的vip管理合并到一个包了。
com.xxx.bean下有二十多个类,只能一个一个分析了,最后发现了几个有用的类
其中UserBean用来管理用户信息,评论,VIP相关等等,UserLevelBean管理用户经验之类的信息。
UserBean类中以下三个方法是我们的Hook点
@JSONField(name = "vvLevel")
public String getVVLevel() {
return this.vvLevel;
}
@JSONField(name = "isVV")
public boolean isVV() {
return this.isVV;
}
public int getLevel() {
if(this.level == 0) {
this.level = 1;
}
return this.level;
}
没有加固的 apk,一般来说直接改 smali 重新打包就行,而像我们现在遇到的壳,修复 dex 打包是一件很费力的事情,在这里frida 的强大就体现出来了。
使用frida来hook加固的Android应用的java层 的原理可以看这里,简单来说就是拿到加载应用本身 dex 的 classloader,通过这个classloader 去找到被加固的类,通过这个类去 Hook 需要 Hook的方法。
因此要穿透加固 Hook Java 层函数的 jscode 模版如下:
if(Java.available) {
Java.perform(function(){
var application = Java.use("android.app.Application");
application.attach.overload('android.content.Context').implementation = function(context) {
var result = this.attach(context); // 先执行原来的attach方法
var classloader = context.getClassLoader(); // 获取classloader
Java.classFactory.loader = classloader;
var Hook_class = Java.classFactory.use("com.xxx.类名");
console.log("Hook_class: " + Hook_class);
// 下面代码和写正常的hook一样
Hook_class.方法名.implementation = function() // 有参数填参数
{
//要执行的操作
}
return result;
}
});
}
根据上面对 Hook 点的分析,我们可以写出以下 jscode
if(Java.available) {
console.log('ok111');
Java.perform(function(){
var application = Java.use("android.app.Application");
console.log('ok222');
application.attach.overload('android.content.Context').implementation = function(context) {
console.log('ok333');
var result = this.attach(context); // 先执行原来的attach方法
var classloader = context.getClassLoader(); // 获取classloader
Java.classFactory.loader = classloader;
console.log('ok444');
var userinfo = Java.classFactory.use("com.xxx.bean.UserBean");
console.log("user: " + userinfo);
userinfo.getLevel.implementation = function(){
return 10;
}
userinfo.isVV.implementation = function(){
return true;
}
userinfo.getVVLevel.implementation = function(){
return "9";
}
return result;
}
});
}
frida 注入脚本有两种方式,使用 python 作为载体,直接运行脚本即可。
import frida, sys
# hook代码,采用javascript编写
jscode = """
//javascript代码
"""
# 自定义回调函数
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
process = frida.get_usb_device().attach('应用完整包名')
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()
或者使用命令行方式,当然了,还需要安装 frida-tools
pip3 install frida-tools
这里我使用命令行方式(这里有个坑,必须按我给出的顺序,不然会报错无法连接)
先连接 adb
./adb kill-server && ./adb server && ./adb shell // mumu模拟器连接方式,其他模拟器自行查询
新开一个 shell,打开 tcp 转发,默认为 27042 端口,但是有些 app 会检测这个端口,因此我们来自定义一个
./adb forward tcp:1234 tcp:1234
回到第一个 shell,我们已经连接到了 adb,直接输入
./data/local/tmp/frida-server -l 0.0.0.0:1234
在第二个 shell 中执行注入命令
frida -H 127.0.0.1:1234 -f com.xxx -l hook.js
成功连接后命令行有如下回显
输入 %resume 对应的 apk 自启,没有报错则成功注入
我这里还加了一些流程和类名的输出
测试 apk,已经可以了,其他功能思路差不多,Hook 就行。
使用 frida 来 hook 加固的 Android 应用的 java 层:https://bbs.pediy.com/thread-246767.htm
『Android安全』版2018年优秀和精华帖分类索引:https://bbs.pediy.com/thread-249602.htm