app逆向-平头哥框架ratel使用

一、前言

平头哥(ratel)是⼀个Android逆向分析⼯具套件,他提供⼀系列渐进式app逆向分析⼯具。同时平头哥也是⼀个app⼆次开发的沙箱环境,⽀持在免root环境下hook和重定义app功能。

项⽬地址: https://github.com/virjarRatel
在这里插入图片描述

二、初次体验

1、安装ratel手机端app

主要作用:可以方便查看app是否被感染成功

链接:https://pan.baidu.com/s/1eU2cEgW4pHOB08gcqDZDNQ 提取码:h7oo

安装效果图:
在这里插入图片描述

2、使⽤电脑端进⾏感染目标app

下载感染引擎:

链接:https://pan.baidu.com/s/13HqPPdqVL9LPrYFOHD-UBA 提取码:n3nj

⽬录结构

.
├── ratel.bat # windows上⽤来感染的脚本
├── ratel.sh # linux/mac 上⽤来感染的脚本
├── ratelConfig.properties
└── res
	├── build_timestamp.txt
	├── container-builder-repkg-2.0.0-SNAPSHOT-dex.jar
	├── container-builder-repkg-2.0.0-SNAPSHOT.jar
	├── hermes_bksv1_key
	├── hermes_key
	├── monthly_temp.txt
	└── ratel_version.txt

运⾏脚本进⾏感染

# liunx
./retal.sh 目标app的路径
# windows
./ratel.bat 目标app的路径

需要被感染的目标app下载

链接:https://pan.baidu.com/s/1412ZQWa4frCAeyM1tCiuKQ 提取码:c10k

运⾏完成之后, 会得到⼀个 com.example.myapplication_1.0_1_ratel.apk 这个就是感染好了的⽂件, 可以直接安装到⼿机, 确保之前的app已经被卸载了, 否则可能会安装失败, 如果是debug下并且开启了testOnly, 需要用 adb install -t xxx.apk 进⾏安装。

打开ratel查看是否感染成功
在这里插入图片描述

3、开发⼀个平头哥插件

新建⼀个普通的Android项⽬,用于插件的基本模板
在这里插入图片描述
添加相关依赖

android {
.............
    packagingOptions {
        exclude 'META-INF/INDEX.LIST'
        exclude 'META-INF/io.netty.versions.properties'
    }
}

第三方包

dependencies {

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    // ratel核⼼api
    compileOnly 'com.virjar:ratel-api:1.3.6'
    // ratel的扩展api,他⼀般是给逆向破解和爬⾍业务使⽤,如果您只是基于ratel做⼀个插件,那么⼤多数情况
    api 'com.virjar:ratel-extersion:1.0.6'
    // sekiro项⽬,他可以提供⻓链接RPC功能
    api 'com.virjar:sekiro-api:1.0.3'
}

在Android清单⽂件 AndroidManifest.xml 添加如下内容

    <application
    	.........
        <meta-data android:name="xposedminversion" android:value="54"/>
        <meta-data android:name="xposedmodule" android:value="true"/>
        <meta-data android:name="xposeddescription" android:value="这个描述可以随便写, 会展示在插件列"/>
    </application>

创建assets文件夹,在assets文件夹下添加文本xposed_init , 内容为hook的⼊⼝类的完整路径, 如果有多个,分到多⾏去写。

com.example.plugintest.HookEntry

#  如果有多个插件,分到多⾏去写
com.example.plugintest.HookEntry01
com.example.plugintest.HookEntry02

编写hook类

package com.example.plugintest;

import com.virjar.ratel.api.rposed.IRposedHookLoadPackage;
import com.virjar.ratel.api.rposed.callbacks.RC_LoadPackage;

public class HookEntry implements IRposedHookLoadPackage {
    @Override
    public void handleLoadPackage(RC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        System.out.println("包名是什么:" + lpparam.packageName);
    }
}

将编写好的插件运⾏到app, 然后开启插件
在这里插入图片描述
控制台打印效果图:
在这里插入图片描述

三、更多应用

com.example.myapplicationapp包增加java代码如下:

public void MysteryBoxTest() throws Exception {
    MysteryBox mysteryBox_1 = new MysteryBox();
    mysteryBox_1.open();
    String content_1 = mysteryBox_1.getContent();

    MysteryBox mysteryBox_2 = new MysteryBox(10);
    mysteryBox_2.open();
    String content_2 = mysteryBox_2.getContent();

    MysteryBox mysteryBox_3 = new MysteryBox(10, "泡泡玛特");
    mysteryBox_3.open();
    String content_3 = mysteryBox_2.getContent();

    tvContent.setText("测试中.......");
    int price = mysteryBox_3.price;
    Field contentField = MysteryBox.class.getDeclaredField("brand");
    contentField.setAccessible(true);
    Object brand = contentField.get(mysteryBox_3);
    tvContent.setText(String.valueOf(price) + " " + brand);
}

打包好的案例app下载:

链接:https://pan.baidu.com/s/15_DlY8yfw8XXiMScJ65R7g 提取码:abph

1、hook构造函数

以下代码主要工作:打印了构造函数的参数长度,修改了参数内容,拿到构造函数的实例,构造函数执行后的返回值(null)

①hook 无参数的构造函数
Class<?> MysteryBoxClass = lpparam.classLoader.loadClass("com.example.myapplication.MysteryBox");
RposedHelpers.findAndHookConstructor(MysteryBoxClass, new RC_MethodHook() {
    // 调用构造方法之前
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        Object[] objects = param.args;
        System.out.println(TAG + "参数长度:" + objects.length);
        super.beforeHookedMethod(param);
    }

    // 调用构造方法之后
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
    }
});
②hook 1个参数的构造函数
RposedHelpers.findAndHookConstructor("com.example.myapplication.MysteryBox", lpparam.classLoader, int.class, new RC_MethodHook(){
    // 调用构造方法之前
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        Object[] objects = param.args;
        // 修改参数
        param.args[0] = 11111111;
        System.out.println(TAG + "参数长度:" + objects.length);
        super.beforeHookedMethod(param);
    }

    // 调用构造方法之后
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
    }
});
③hook 2个参数的构造函数
RposedHelpers.findAndHookConstructor("com.example.myapplication.MysteryBox", lpparam.classLoader, int.class, String.class, new RC_MethodHook(){
    // 调用构造方法之前
    @Override
    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
        Object[] objects = param.args;
        // 修改参数
        System.out.println(TAG + "原始参数1:" + param.args[0]);
        System.out.println(TAG + "原始参数2:" + param.args[1]);
        param.args[0] = 100;
        param.args[1] = "耐克";
        System.out.println(TAG + "参数长度:" + objects.length);
        super.beforeHookedMethod(param);
    }

    // 调用构造方法之后
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        super.afterHookedMethod(param);
        // 执行结束后拿到构造函数实例
        System.out.println(TAG + "构造函数实例:" + param.thisObject);
        // 执行结束后拿到构造函数返回值。为空
        System.out.println(TAG + "构造函数返回值:" + param.getResult());
    }
});

完整代码

package com.example.plugintest;

import com.virjar.ratel.api.rposed.IRposedHookLoadPackage;
import com.virjar.ratel.api.rposed.RC_MethodHook;
import com.virjar.ratel.api.rposed.RposedHelpers;
import com.virjar.ratel.api.rposed.callbacks.RC_LoadPackage;

public class HookEntry implements IRposedHookLoadPackage {
    public String TAG = "pluginTest";

    @Override
    public void handleLoadPackage(RC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        System.out.println(TAG + "包名是什么:" + lpparam.packageName);
        if (lpparam.packageName.equals("com.example.myapplication")){
            System.out.println(TAG + "确认hook的app是:" + lpparam.packageName);

            // hook 无参数的构造函数
            // 得到类定义
            Class<?> MysteryBoxClass = lpparam.classLoader.loadClass("com.example.myapplication.MysteryBox");
            RposedHelpers.findAndHookConstructor(MysteryBoxClass, new RC_MethodHook() {
                // 调用构造方法之前
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Object[] objects = param.args;
                    System.out.println(TAG + "参数长度:" + objects.length);
                    super.beforeHookedMethod(param);
                }

                // 调用构造方法之后
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                }
            });

            // hook 1个参数构造函数
            RposedHelpers.findAndHookConstructor("com.example.myapplication.MysteryBox", lpparam.classLoader, int.class, new RC_MethodHook(){
                // 调用构造方法之前
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Object[] objects = param.args;
                    // 修改参数
                    param.args[0] = 11111111;
                    System.out.println(TAG + "参数长度:" + objects.length);
                    super.beforeHookedMethod(param);
                }

                // 调用构造方法之后
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                }
            });

            // hook 2个参数构造函数
            RposedHelpers.findAndHookConstructor("com.example.myapplication.MysteryBox", lpparam.classLoader, int.class, String.class, new RC_MethodHook(){
                // 调用构造方法之前
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    Object[] objects = param.args;
                    // 修改参数
                    System.out.println(TAG + "原始参数1:" + param.args[0]);
                    System.out.println(TAG + "原始参数2:" + param.args[1]);
                    param.args[0] = 100;
                    param.args[1] = "耐克";
                    System.out.println(TAG + "参数长度:" + objects.length);
                    super.beforeHookedMethod(param);
                }

                // 调用构造方法之后
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    // 执行结束后拿到构造函数实例
                    System.out.println(TAG + "构造函数实例:" + param.thisObject);
                    // 执行结束后拿到构造函数返回值。为空
                    System.out.println(TAG + "构造函数返回值:" + param.getResult());
                }
            });
        }
    }
}
④打印效果:

在这里插入图片描述
app界面hook修改传参前
在这里插入图片描述
app界面hook修改传参后
在这里插入图片描述

2、hook属性

对于属性的hook可以用到如下方法:

属性值的获取实例属性的修改静态属性的修改
getObjectFieldsetObjectFieldsetStaticObjectField
getBooleanFieldsetBooleanFieldsetStaticBooleanField
getByteFieldsetByteFieldsetStaticByteField
getCharFieldsetCharFieldsetStaticCharField
getDoubleFieldsetDoubleFieldsetStaticDoubleField
getFloatFieldsetFloatFieldsetStaticFloatField
getIntFieldsetIntFieldsetStaticIntField
getLongFieldsetLongFieldsetStaticLongField
getShortFieldsetShortFieldsetStaticShortField

简单的测试了几个方法如下:

package com.example.plugintest;

import com.virjar.ratel.api.rposed.IRposedHookLoadPackage;
import com.virjar.ratel.api.rposed.RC_MethodHook;
import com.virjar.ratel.api.rposed.RposedHelpers;
import com.virjar.ratel.api.rposed.callbacks.RC_LoadPackage;

public class HookFieldsEntry implements IRposedHookLoadPackage {
    private static final String TAG= "pluginTest";
    public void handleLoadPackage(RC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        System.out.println(TAG + "包名是什么:" + lpparam.packageName);
        if (lpparam.packageName.equals("com.example.myapplication")){
            System.out.println(TAG + "hook成功:" + lpparam.packageName);
            RposedHelpers.findAndHookConstructor("com.example.myapplication.MysteryBox", lpparam.classLoader, new RC_MethodHook(){
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);

                    // 拿到构造函数实例
                    Object box = param.thisObject;
                    // 拿到实例属性
                    Object content = RposedHelpers.getObjectField(box, "content");
                    System.out.println(TAG + "content hook成功:" + content);

                    // 拿到静态属性
                    Object BASE_PRICE = RposedHelpers.getStaticObjectField(box.getClass(), "BASE_PRICE");
                    System.out.println(TAG + "BASE_PRICE hook成功:" + BASE_PRICE);

                    // 修改实例属性
                    RposedHelpers.setIntField(box, "price", 10000);
                    RposedHelpers.setObjectField(box, "content", "耐克");

                    // 修改静态属性
                    RposedHelpers.setStaticIntField(box.getClass(), "BASE_PRICE", 200);
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                }
            });
        }
    }
}

3、hook⼀般函数 静态方法/实例方法

package com.example.plugintest;

import com.virjar.ratel.api.rposed.IRposedHookLoadPackage;
import com.virjar.ratel.api.rposed.RC_MethodHook;
import com.virjar.ratel.api.rposed.RposedHelpers;
import com.virjar.ratel.api.rposed.callbacks.RC_LoadPackage;

public class HookMethodsEntry implements IRposedHookLoadPackage {
    private static final String TAG= "pluginTest";
    public void handleLoadPackage(RC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
        System.out.println(TAG + "包名是什么:" + lpparam.packageName);
        if (lpparam.packageName.equals("com.example.myapplication")){
            System.out.println(TAG + "hook成功:" + lpparam.packageName);

            // hook 静态方法/实例方法 methodName 就是要hook的方法名
            RposedHelpers.findAndHookMethod("com.example.myapplication.MysteryBox", lpparam.classLoader, "staticMethod", String.class, int.class, new RC_MethodHook(){
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    // 获取方法参数
                    System.out.println(TAG + "参数内容:" + param.args[0] + param.args[1]);

                    // 修改参数
                    param.args[0] = "小静被修改了";
                    param.args[1] = 10000;
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);

                    // 获取方法返回值
                    Object res = param.getResult();
                    System.out.println(TAG + "方法返回值:" + res);

                    // 修改方法返回值
                    param.setResult("返回值被修改了");
                }
            });

            // 内部类的处理 就多了一个$+内部类名称符号
            RposedHelpers.findAndHookMethod("com.example.myapplication.MysteryBox$InnerClass", lpparam.classLoader, "innerClassMethod", String.class, int.class, new RC_MethodHook(){
                @Override
                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                    super.beforeHookedMethod(param);
                    // 获取方法参数
                    System.out.println(TAG + "参数内容:" + param.args[0] + param.args[1]);

                    // 修改参数
                    param.args[0] = "内部类修改了";
                    param.args[1] = 10000;
                }

                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);

                    // 获取方法返回值
                    Object res = param.getResult();
                    System.out.println(TAG + "方法返回值:" + res);

                    // 修改方法返回值
                    param.setResult("返回值被修改了");
                }
            });
        }
    }
}

4、hook Java层JNI函数

参考:app逆向-Java层JNI函数

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Ratel平头哥是一款用于Android系统的hook工具。它可以实现对Android应用程序的动态调试和修改。 这款工具可以在不修改应用程序源代码的情况下,对应用程序进行hook操作。具体来说,Ratel平头哥可以用来修改应用程序中的参数、方法和对象等。同时,它还支持一些高级的hook技术,如Inline Hook和Xposed Hook。 除了hook功能外,Ratel平头哥还具有一些实用的辅助功能,如应用程序稳定性监测、Crash日志收集等。这些功能可以帮助开发者更好地了解应用程序的运行状况,更快地排查和修复bug。 需要注意的是,使用Ratel平头哥进行hook操作需要一定的专业知识和技能。此外,它仅适用于Android系统,对于iOS系统的应用程序无法使用。因此,在使用该工具时,需要谨慎、理性地进行操作,以免影响应用程序的正常运行。 ### 回答2: Ratel平头哥是一款针对Android系统的hook工具,可以帮助开发者在不修改应用程序源代码的情况下,对应用程序进行二次开发和定制化。Ratel平头哥采用了一种名为“沙箱”技术的方式,从而实现了对应用程序的hook。沙箱是指在操作系统中运行的一种隔离环境,它可以模拟硬件环境、网络环境等,从而确保应用程序在沙箱环境中运行时不会影响到操作系统的正常运行。这种技术不仅保护了操作系统的安全性,同时也提高了应用程序的运行效率和稳定性。 Ratel平头哥可以对应用程序的各种相关操作进行hook,例如调用系统API、读取文件、访问网络等等。通过hook这些操作,开发者可以实现对应用程序的加密、优化、广告屏蔽等功能,并抵御恶意攻击、防止反编译等。同时,Ratel平头哥还支持插件化开发,用户可以自己编写插件来完成特定的任务。由于Ratel平头哥具有较强的兼容性,用户无需担心修改后的应用程序会出现各种奇怪的问题。 总之,Ratel平头哥是一款很实用的hook工具,为安卓系统提供了更多的二次开发空间,可以助力开发者快速定制化自己的应用程序。它不仅具有强大的功能,而且还很容易上手,是一款非常值得尝试的工具。 ### 回答3: Ratel平头哥是一种流行的Android Hook工具,它能够助力在Android应用中实现不同的挂钩操作。它支持多种应用中检测活动的方法,如onCreate、onStart、onResume和onPause等。这些都可以被编程人员作为钩子使用,以便更好地分析内存和线程操作,并跟踪应用的运行情况。 Ratel平头哥还支持沙箱技术,并能够用于修改应用程序的原始代码。这些代码可以用于修复应用程序的漏洞,或者用于帮助应用程序中的其他开发人员进行测量和调试操作。平头哥工具旨在为开发人员提供一种简单的方法,以便轻松地重载不同的类,添加自定义函数,或者随时监视应用程序中发生的任何事件。 总的来说,Ratel平头哥是一个功能丰富且易于使用Android Hook工具,它为开发人员提供了许多有用的功能,并且可以用于监视应用程序的运行和调试过程。使用该工具还可以加速开发过程,提高开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是花臂不花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值