ReactNative分析

1. 简介

React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的JS框架 React 在原生移动应用平台的衍生产物,支持iOS和安卓两大平台

2. 分析

核心代码为js编写,在安装包assest目录下存放index.android.bundle(有可能重命名,因为rn本身仅仅做了混淆,使用编辑器打开即可分析js代码。

注:部分APP可能会将index.android.bundle加密,运行时解密加载

2.1 数据解密

2.1.1 通过请求包关键字定位到加密点

2.1.2 新建js文件,复制strEnc、strDec方法和相关依赖方法,并使用node运行解密

2.1.3编写burp插件,java调用js加解密方法

TODO

2.2 bundle代码篡改

对于非对称加密需要将bundle中的公钥进行替换,所以需要对bundle进行篡改。
index.android.bundle中的js最终是需要被load到内存中,所以在某一时刻是可以获取,将load前的index.android.bundle进行篡改。

2.2.1 分析rn加载流程

com.facebook.react.ReactNativeHost.createReactInstanceManager方法

如上图 小1 由用户指定bundle路径,一般来说如果bundle加密了,解密后会将jSBundleFile设置为bundle解密后文件路径,由RN负责加载,此时可以HOOK该方法,进行解密后的bundle dump。

进入jSBundleFile方法

1
2
3
4
5
6
7
8
9
public ReactInstanceManagerBuilder setJSBundleFile(String str) {

if (!str.startsWith("assets://")) {
return setJSBundleLoader(JSBundleLoader.createFileLoader(str));
}
this.mJSBundleAssetUrl = str;
this.mJSBundleLoader = null;
return this;
}

解密后的文件路径固然不能是assets开头的,所以会走setJSBundleLoader流程

dump bundle脚本,获取到bundle文件后即可进行篡改

1
2
3
4
5
var ReactInstanceManagerBuilder = Java.use("com.facebook.react.ReactInstanceManagerBuilder");
ReactInstanceManagerBuilder.setJSBundleFile.overload('java.lang.String').implementation = function (path) {
console.log("bundle path is :",path);
return this.setJSBundleFile(path);
};

如上图 小2 如果用户未指定jSBundleFile,则默认调用setBundleAssetName方法,如下图会加载assets路径下的index.android.bundle(这也是为什么app资源路径下bundle默认名为index.android.bundle的原因)

2.2.2 篡改bundle

2.2.2.1 将index.android.bundle中的加密方法删除
2.2.2.2 push至手机sd卡下
1
adb push xxxx /sdcard
2.2.2.3 HOOK setBundleAssetName,load修改后bundle

因为setBundleAssetName方法会对当前入参路径拼接assets://,所以在该方法下不能简单的HOOK修改入参(bundle路径),故HOOK该方法,篡改代码逻辑,强制走上面分析中的小1流程

frida hook脚本如下

1
2
3
4
5
6
7
8
var ReactInstanceManagerBuilder = Java.use("com.facebook.react.ReactInstanceManagerBuilder");
var JSBundleLoader = Java.use("com.facebook.react.bridge.JSBundleLoader")
ReactInstanceManagerBuilder.setBundleAssetName.overload('java.lang.String').implementation = function (path) {

console.log("bundle path is :",path);
var newPath = "/storage/emulated/0/index.android.bundle";
return this.setJSBundleLoader(JSBundleLoader.$new().createFileLoader(newPath));
};

burp抓包未篡改js与篡改js后请求包对比

未篡改,数据已加密

篡改后,明文