技术标签: java android studio app逆向随笔
平头哥(ratel)是⼀个Android逆向分析⼯具套件,他提供⼀系列渐进式app逆向分析⼯具。同时平头哥也是⼀个app⼆次开发的沙箱环境,⽀持在免root环境下hook和重定义app功能。
项⽬地址: https://github.com/virjarRatel
主要作用:可以方便查看app是否被感染成功
链接:https://pan.baidu.com/s/1eU2cEgW4pHOB08gcqDZDNQ 提取码:h7oo
安装效果图:
下载感染引擎:
链接: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查看是否感染成功
新建⼀个普通的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.myapplication
app包增加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
以下代码主要工作:打印了构造函数的参数长度,修改了参数内容,拿到构造函数的实例,构造函数执行后的返回值(null)
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);
}
});
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);
}
});
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修改传参后
对于属性的hook可以用到如下方法:
属性值的获取 | 实例属性的修改 | 静态属性的修改 |
getObjectField | setObjectField | setStaticObjectField |
getBooleanField | setBooleanField | setStaticBooleanField |
getByteField | setByteField | setStaticByteField |
getCharField | setCharField | setStaticCharField |
getDoubleField | setDoubleField | setStaticDoubleField |
getFloatField | setFloatField | setStaticFloatField |
getIntField | setIntField | setStaticIntField |
getLongField | setLongField | setStaticLongField |
getShortField | setShortField | setStaticShortField |
简单的测试了几个方法如下:
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);
}
});
}
}
}
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("返回值被修改了");
}
});
}
}
}
文章浏览阅读220次。定理:把n+1个物体放进n个盒子中,至少有一个盒子中含有两个物体理解:ai为第i天下的总棋盘数,显然an为递增序列,对an做部分和序列:如上图所示,上面77项,下面77项,共154项,153个盒子,所有存在aj+21 = ai,所以21 = aj - ai = bi + bi+1 + … + bj相当于19个物体,18个盒子五个点,四个三角形反证:Li <..._鸽巢原理的三个公式
文章浏览阅读6.6w次,点赞20次,收藏194次。欢迎技术交流和帮助,提供所有IT相关的服务,有需要请联系博主QQ: 21497936,若该文为原创文章,未经允许不得转载原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/77847820目录效果 Demo下载地址QCustom..._qcustomplot编译
文章浏览阅读1k次。<text wx:if="{{item.data.status=='待打印'}}" style="color:red">{{item.data.status}}</text><text wx:if="{{item.data.status=='已打印'}}" style="color:green">{{item.data.status}}</text>_小程序 color if
文章浏览阅读210次。转载:http://www.bo56.com/%E7%BA%BF%E4%B8%8Aphp%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E6%80%9D%E8%B7%AF%E4%B8%8E%E5%AE%9E%E8%B7%B5/前几天,在一淘网,腾讯网媒和微博商业技术联合组织的技术分享大会上,我分享了《在线PHP问题排查思路与实践》。此博文除了对PPT..._在php开发过程中,线上代码怎么查哪段代码有问题,且不影响线上运行
文章浏览阅读841次,点赞28次,收藏9次。centos 7.x 升级内核 3.x 至 5.x
文章浏览阅读922次。利用JavaParser去除java文件中的注释个人博客:记录一下在项目实施过程中的一些点情景回顾之前项目有个需求,就是去掉.java文件中的所有注释,常用的方法是用正则匹配。然而在网络上查找到的正则或多或少都有一些问题,无法匹配到所有的情况。或者说,由于写.java文件的人的不规范(各种奇葩的问题),导致正则覆盖不全。所以正则方法不靠谱,或者说,存在一定的限制。新的想法后来想到利用AST来去除注..._在线java代码去除注释工具
文章浏览阅读4.2k次,点赞10次,收藏25次。构造函数、初始化列表、析构函数_构造函数和析构函数
文章浏览阅读281次。1.问题 1、何为分布式何为微服务? 2、为什么需要分布式? 3、分布式核心理论基础,节点、网络、时间、顺序,一致性? 4、分布式是系统有哪些设计模式? 5、分布式有哪些类型? 6、如何实现分布式? 2.关键词节点,时间,一致性,CAP,ACID,BASE,P2P,机器伸缩,网络变更,负载均衡,限流,鉴权,服务发现,服务编排,降级,熔断,幂等,分库分表,分片分区,自动运维,容错处理,全栈监控,故障恢复,性能调优3.全文概要随着移动互联网_分布式架构知识体系
文章浏览阅读1.5k次,点赞6次,收藏13次。深信服防火墙配置SSL VN_深信服ssl配置教程
文章浏览阅读768次。一、安装erlang:1、先下载rpm包:wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm2、rpm包:rpm -Uvh erlang-solutions-1.0-1.noarch.rpm可能会有以下问题:解决办法:(执行以下命令后,在执行上一条命令)yum..._rabbitmq linux安装
文章浏览阅读781次。docker安装官方文档:Install Docker Engine on CentOS2、安装提供了工具3、通过添加docker repository如果出现上面的错误提示,可通阿里源进行添加4、安装docker4.1、直接安装最新版本这步完成后可直接跳至启动docker4.2、或者安装指定版本按版本号倒序列出可安装版本列表安装指定版本例如安装20.10.9版本5、启动docker通过进行启动设置docker服务开机启动6、测试7、卸载docker下的_centos7安装最新版dockers
文章浏览阅读429次。package aaa.bbb.demo;import java.util.ArrayList;import java.util.List;public class RecognitionDemo { public static void main(String[] args) { String str1="SB哈NM哈哈哈WBDhdsada"; String str_敏感文本识别算法