使用Frida给apk脱壳并穿透加固Hook函数
2020-05-06 08:46:01 Author: xz.aliyun.com(查看原文) 阅读量:410 收藏

前言

今天拿到了新玩具JEB 3.17.1,想测试一下,顺便学习学习Android逆向,于是找了一个apk准备试试水,看看能不能搞到VIP。

初步分析

拖入jeb查看

嗯。。google一下

几维安全的壳,虚拟化很烦,也没什么好的脱壳工具,于是切换思路

从本质上来说,虚拟化就是自己实现了一套基本的cpu指令,通过自己的解释器解释给机器。因此想要在虚拟化之后仍然能让机器运行,当然还得还原代码给机器,只不过可能在内存中释放,加大了静态分析的难度。

那么直接让apk运行起来,我们去dump虚拟机自解密出来的dex不就好了么。

frida dump dex

frida 是一款基于 python+javascript 的 hook 框架,可运行在 android、ios、linux、win等各个平台,主要使用的动态二进制插桩技术。

总之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脚本

这里使用了FRIDA-DEXDump https://github.com/hluwa/FRIDA-DEXDump

其原理就是在内存中检索dex035头并获取dex长度,然后提取出来。当然,这样做会将内存中所有的dex包都提取出来,具体哪个才是我们需要的得根据包名判断并静态分析查看。

这里我成功提取到了无壳dex,包名都比较清晰

抓包分析

既然壳不好脱而且脱下来的又不容易修复,就考虑先看看封包里有没有VIP数据

使用HttpCanary对apk进行抓包

抓到了一个登陆验证包

但响应里没有我们想要的信息,只是一个随时变动的值而已

看来抓包这条路走不通了,我们接下来只能分析拿到的dex。

JEB静态分析

我们使用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;
}

编写frida脚本穿透加固 Hook Java层函数

没有加固的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 Hook脚本

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

这里我使用命令行方式(这里有个坑,必须按我给出的顺序,不然会报错无法连接)

先连接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就行。

参考

https://bbs.pediy.com/thread-246767.htm

https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=2ahUKEwih5Ja1rv7oAhW0IaYKHegbDKkQrAIoADAAegQIARAI&url=https%3A%2F%2Fbbs.pediy.com%2Fthread-249602.htm&usg=AOvVaw1NsItIh36jELfizdNiiAdL


文章来源: http://xz.aliyun.com/t/7670
如有侵权请联系:admin#unsafe.sh