React App逆向入门

在逆向某易新闻时,发现该App是个React App,请求参数生成逻辑似乎是在js层处理的。故此进行React Native逆向的学习。

React App js层

React Native是一个流行的跨平台移动应用开发框架,它允许开发者使用JavaScriptReact 来构建应用。
使用 React Native 打包的应用,应用的一部分或全部界面和逻辑是用 JavaScript 实现的,而JavaScript 代码和资源会被打包成 main.jsbundle 文件,也可能通过https://github.com/facebook/hermes压缩成`Hermes`字节码文件(`.hbc`)。最终生成的文件的路径在asset目录下。

以某易新闻为例,asset目录下仅有一个basics.android.hbc文件,查看该文件信息:

1
2
$ file basics.android.hbc
basics.android.hbc: Hermes JavaScript bytecode, version 89

确认是Hermes JavaScript bytecode后,使用hermes-dec或者hbctool工具反编译出js文件(注意反编译工具支持得版本信息要对得上)

1
2
3
4
5
6
7
8
9
10
D:\CTFTools\hermes-dec>python hbc_file_parser.py basics.android.hbc

D:\CTFTools\hermes-dec>python hbc_disassembler.py basics.android.hbc newsreader.hasm

[+] Disassembly output wrote to "newsreader.hasm"


D:\CTFTools\hermes-dec>python hbc_decompiler.py basics.android.hbc newsreader.js

[+] Decompiled output wrote to "newsreader.js"

然后看了一眼反编译出的js文件,发现进行了vmp保护!

对于js层的逆向,如果没有jsvmp的保护,可以在目标函数出添加自己的逻辑,打印日志,重新打包成bundle文件添加到App中

React App java层

React Native 加载 Bundle 的核心类是 CatalystInstanceImplJSBundleLoader。我们可以 Hook 它们的构造函数或加载方法。

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function findRNBundlePath() {
Java.perform(function() {
console.log("开始寻找 React Native Bundle 路径...");

// 1. Hook JSBundleLoader (最通用)
// 它的 createAssetLoader, createFileLoader 等方法会暴露路径
try {
var JSBundleLoader = Java.use("com.facebook.react.bridge.JSBundleLoader");

// 如果是从 Assets 加载
JSBundleLoader.createAssetLoader.implementation = function(context, assetUrl, syncFallback) {
console.log("################ createAssetLoader Found Bundle (Assets) ################");
console.log("Asset URL: " + assetUrl); // 这里的 assetUrl 就是 assets 下的文件名!
return this.createAssetLoader(context, assetUrl, syncFallback);
};

// 如果是从文件系统加载 (动态下发)
JSBundleLoader.createFileLoader.overload('java.lang.String', 'java.lang.String', 'boolean').implementation = function(fileName, assetUrl, syncFallback) {
console.log("################ createFileLoader Found Bundle (File) ################");
console.log("File Path: " + fileName); // 这里的 fileName 就是手机里的绝对路径
return this.createFileLoader(fileName, assetUrl, syncFallback);
};

JSBundleLoader.createFileLoader.overload('java.lang.String').implementation = function(fileName) {
console.log("################ createFileLoader Found Bundle (File) ################");
console.log("File Path: " + fileName); // 这里的 fileName 就是手机里的绝对路径
return this.createFileLoader(fileName);
};

// 某些版本的 RN 还有 createCachedBundleFromNetworkLoader 等
} catch(e) {
console.log("JSBundleLoader hook failed: " + e);
}

// 2. Hook ReactInstanceManagerBuilder (构建时指定 bundle)
try {
var ReactInstanceManagerBuilder = Java.use("com.facebook.react.ReactInstanceManagerBuilder");

ReactInstanceManagerBuilder.setBundleAssetName.implementation = function(name) {
console.log("################ setBundleAssetName Bundle Name Set ################");
console.log("Name: " + name); // assets 下的名字
return this.setBundleAssetName(name);
};

ReactInstanceManagerBuilder.setJSBundleFile.implementation = function(path) {
console.log("################ setJSBundleFile Bundle File Set ################");
console.log("Path: " + path);
return this.setJSBundleFile(path);
};
} catch(e) {
// 忽略
}
});
}

使用spawn模式,打印出它到底加载了哪个文件作为 Bundle

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
[Pixel XL::com.netease.newsreader.activity ]-> 开始寻找 React Native Bundle 路径...
################ setJSBundleFile Bundle File Set ################
Path: assets://basics.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
################ createAssetLoader Found Bundle (Assets) ################
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basics.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basics.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basics.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basics.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basics.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basics.android.hbc
################ setJSBundleFile Bundle File Set ################
Path: assets://basic_3.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basic_3.android.hbc
################ setJSBundleFile Bundle File Set ################
Path: assets://basics.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basics.android.hbc
################ setJSBundleFile Bundle File Set ################
Path: assets://basic_3.android.hbc
################ createAssetLoader Found Bundle (Assets) ################
Asset URL: assets://basic_3.android.hbc

还额外加载了basic_3.android.hbc,但是在asset目录下找不到!

另外React Native开发的App通过LoadScript加载js脚本,也可以hook该函数获取相关信息。


参考:

https://github.com/bongtrop/hbctool
https://github.com/P1sec/hermes-dec

React应用逆向工程:深入解析与反编译JS文件技巧 - 云原生实践

从去哪儿看React Native安卓App逆向 - 吾爱破解 - 52pojie.cn

React Native Hermes 逆向实践-Android安全-看雪安全社区|专业技术交流与安全研究论坛

和原生端通信 · React Native 中文网

https://fuping.site/2023/11/23/ios-reverse-reactnative-case/

https://cloud.tencent.com/developer/article/1593007

https://reactnative.dev/docs/handling-touches


React App逆向入门
http://example.com/2025/12/25/逆向实战/React App逆向入门/
作者
gla2xy
发布于
2025年12月25日
许可协议