• app逆向(8)|app的加固+脱壳和frida+rpc介绍


    一、frida和frida-rpc

    1.简单介绍

    • frida是一款轻量级逆向HOOK框架,可用于多平台上,例如android、windows、ios等。
    • frida分为两部分,服务端运行在目标机上,通过注入进程的方式来实现劫持应用函数,另一部分运行在系统机器上。
    • frida上层接口支持js、python、c等
    • frida官方github地址为:https://github.com/frida

    Frida 常用模块API:

    • Java 模块:Hook Java 层的类 方法 相关
    • Process 模块:处理当前线程相关
    • Interceptor 模块:操作指针相关,多用来Hook Native 相关
    • Memory 模块:内存操作相关
    • Module 模块:处理so相关

    2.安装frida

    1. 安装python3.7以上版本,并安装frida和frida-tools。

    pip install frida
    pip install frida-tools
    
    • 1
    • 2

    2. 在手机上下载frida-sever端,官方下载地址:https://github.com/frida/frida/releases,下载时要选择对应的版本下载,例如我的机器为arm64位架构,就选择frida-server-15.1.11-android-arm64.xz下载

    # 查看手机架构
    adb shell 
    su
    getprop ro.product.cpu.abi
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    3. 将第四步下载好的文件解压,名字修改为frida-server,然后通过命令adb push 电脑存放位置 /data/local/tmp将文件传输到手机中,然后通过adb shell进入手机端,给文件赋权777,并于root权限启动。

    在这里插入图片描述

    # 然后进入手机
    adb shell
    su 
    cd /data/local/tmp
    chmod 777 frida-server
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4. 启动frida,执行未输出任何东西,表示执行成功

    ./fridaserver1280_32
    ./fridaserver1280_32&   (以后台模式运行)
    
    • 1
    • 2

    5. 启动frida-server之后, 再打开一个cmd窗口,通过命令转发tcp端口 (端口转发, 将设备信息端口转发至PC端)

    adb forward tcp:27043 tcp:27043
    adb forward tcp:27042 tcp:27042
    
    • 1
    • 2

    6.执行frida-ps -U
    在这里插入图片描述
    在这里插入图片描述

    二、了解app的hook

    1.hook能干嘛

    功能:不改变代码功能的前提下,捕获要用的代码,获取要用的信息。hook一般hook两层:

    • Java层
    • Native层(so层),汇编代码,难度较大

    2.frida中使用implementation进行hook

    # -*- coding: utf-8 -*-
    import sys
    import frida
    
    
    def on_message(message, data):
        if message["type"] == "send":  # 当通过send函数发送时,会打印至控制台
            print(u"[*] {0}".format(message["payload"]))
        else:
            print(message)
    
    jsCode = """
    Java.perform(
                function(){
                    java.use("com.me.world").check.implentation = function (v1,v2){
                    	return False;
                    	}
                    }
                )   
    """
    
    process = frida.get_remote_device().attach("com.taobao.taobao")  # 标准端口 使用包名 该包名通过frida-ps -U 获取
    
    script = process.create_script(jsCode)  # 识别JS字符串
    script.on("message", on_message)  # 输出 打印
    script.load()  # 加载  注入
    sys.stdin.read()  # 程序等待, 防止程序结束
    # -------------------------------------------------------------------------------
    # 如果我们想要在app启动的时候就想hook到某个函数,将上述的代码改成如下
    # 前提也需要将APP启动,只不过后面有函数会让app重启
    device = frida.get_remote_device()
    pid = device.spawn("com.yaotong.crackme") # 获取进程id
    process = device.attach(pid)
    
    script = process.create_script(jsCode)
    script.on("message", on_message)
    script.load()
    device.resume(pid)   表示app重启
    sys.stdin.read()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    其中jsCode中的函数有一些是固定写法,分别代表

    Java.perform(匿名函数)
    var MainActivity=Java.use(app类名)
    MainActivity.方法名.implementation = function(){}   hook这个类中的函数
    
    • 1
    • 2
    • 3

    由于在JAVA中有函数重载,即函数名相同,传入参数类型不同或者数量不同,执行的函数也不同,因此在面对这种情况,hook的时候需要找到自己究竟要hook哪个函数

    例如Overloading.java 有两个test函数

    public class Overloading {
        public int test(){
            System.out.println("test1");
            return 1;
        }
     
        public void test(int a){
            System.out.println("test2");
        }   
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果直接调用会报错
    在这里插入图片描述

    这种情况hook就需要指定是哪一个函数,在overload里传参数代表hook哪一个

    jsCode = """
    	Java.perfom(
    	     function(){
    	     	// 无参数的test
    	        java.use("Overloading").test.overload().implentation = function (){};
    	        
    	        // 有参数的test
    			java.use("Overloading").test.overload(a).implentation = function (a){};
    	           }
    	       )   
    """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.hook分析加密值的注意事项

    正常分析app加密值的逻辑

    • 反编译app(加固需要脱壳)
    • 通过 关键字/其他手段 定位到加密值的地方
    • 分析如何加密

    反向分析app加密值的逻辑

    • 无论加密值怎么变化,通常是调用常见的加密算法(md5,rsa,base64等等)

    • 那么我们直接hook底层加密算法,并在hook的时候进行堆栈打印,这样就可以知道哪个方法调用了加密操作,然后找到该方法

      // 打印调用栈
      function print_stack(){
          	   send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Excepetion").$new()));
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5

    进行hook操作需要注意

    • 尽量不要改写原来的方法流程逻辑,执行完自己的操作以后,别忘了调用本身

      this.function()
      
      • 1

    4.使用implementation进行hook的案例

    安装该app到手机:http://www.downcc.com/soft/276877.html
    安装app后进入app,会提示输入手机号,然后输入一个手机号,点击下一步,进行抓包

    在这里插入图片描述
    抓包后,我们看一下参数

    {"phone":"15811223344","sign":"BE1B05B2ED7689457F9DCE74E4F8C743","currTime":"20220818161311","type":"1"}
    
    • 1

    看到里边生成了一个sign,然后我们用jadx反编译一下该app,该app是无壳的,然后我们搜一下getSmscode

    在这里插入图片描述

    进入代码后看到
    在这里插入图片描述
    sign值是

    HttpUtils.getStringMD5toUpperCase(yyyyMMddHHmmss + i + str + str2);
    而四个值分别是:  日期格式化 + type + str + 手机号
    看样子是进行拼接后,然后好像进行md5
    
    • 1
    • 2
    • 3

    str是传入的值,因此我们需要知道str是什么,这里使用frida抓一下

    打开cmd窗口开启frida-server
    在这里插入图片描述
    再卡开另一个cmd,进行转发
    在这里插入图片描述
    然后构造python代码

    # -*- coding: utf-8 -*-
    import sys
    import frida
    
    
    def on_message(message, data):
        if message["type"] == "send":  # 当通过send函数发送时,会打印至控制台
            print(u"[*] {0}".format(message["payload"]))
        else:
            print(message)
    
    
    jsCode = """
    Java.perform(
        function () {
            var MainActivity = Java.use('com.jx885.library.http.CommAction');
            MainActivity.getSmscode.implementation = function (arg1,arg2,arg3) {
                console.log(arg1,arg2,arg3);
                return this.getSmscode(arg1,arg2,arg3);
            }      
        });
    """
    
    process = frida.get_remote_device().attach("驾培创业教练")  # 标准端口 使用包名 该包名通过frida-ps -U 获取
    script = process.create_script(jsCode)  # 识别JS字符串
    script.on("message", on_message)  # 输出 打印
    script.load()  # 加载  注入
    sys.stdin.read()  # 程序等待, 防止程序结束
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    重启app,运行代码,输入手机号,点击下一步,我们看到刚才的str串结果是wocaonima,然后我们将刚才的值拼接一下

    日期格式化 + type + str + 手机号
    202208181613111wocaonima15811223344
    
    • 1
    • 2

    找个网站md5一下,发现和刚开始的值吻合
    在这里插入图片描述
    这里我们有两种方式得出结果

    1. 自己拼接,然后python进行md5加密
    2. 使用frida-rpc进行自动调取手机app中的md5

    5.这里简单使用一下frida-rpc

    我们不通过app触发得到结果,我们主动调用的方式一般就是frida-rpc解决。

    进入该方法
    在这里插入图片描述

    然后修改代码,变为主动调用app里的md5方法

    # -*- coding: utf-8 -*-
    import sys
    import frida
    
    
    def on_message(message, data):
        if message["type"] == "send":  # 当通过send函数发送时,会打印至控制台
            print(u"[*] {0}".format(message["payload"]))
        else:
            print(message)
    
    
    jsCode = """
    var sign = function (s) {
        var result = '';
        Java.perform(function () {
            result = Java.use('com.jx885.library.http.network.HttpUtils').getStringMD5toUpperCase(s);
        });
        return result;
    };
    
    rpc.exports = {
        getsign: sign
    };
    """
    
    process = frida.get_remote_device().attach("驾培创业教练")  # 标准端口 使用包名 该包名通过frida-ps -U 获取
    script = process.create_script(jsCode)  # 识别JS字符串
    script.on("message", on_message)  # 输出 打印
    script.load()  # 加载  注入
    
    yyyyMMddHHmmss = '20220818161311'
    i = '1'
    str_1 = 'wocaonima'
    str_2 = '15811223344'
    s = yyyyMMddHHmmss + i + str_1 + str_2
    sign = script.exports.getsign(s)
    print(sign)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    运行
    在这里插入图片描述

  • 相关阅读:
    iOS——Autoreleasepool底层原理
    Web3.0与机器学习
    1-2 暴力破解-模拟
    java的amazonaws接口出现无法执行http请求:管道中断
    J2L3x,实现企业团队协作的完美工具!
    string 类以及模拟实现
    Leetcode81. Search in Rotated Sorted Array II
    [RoarCTF 2019]Easy Calc
    软件工程经济学期末复习
    SpringBoot+Mybaits搭建通用管理系统实例十:基础增删改查功能实现下
  • 原文地址:https://blog.csdn.net/qq_40558166/article/details/125880807