re1-babyharmony
找到的工具:HapViewer 发行版 - Gitee.com
完全不知道鸿蒙os如何逆向QAQ
那就按安卓的方法来逆但是没有工具!!!
.apk其实可以按zip的格式打开看见拥有源码的.dex文件,那么.hap是不是也可以这样!
百度一些.abc文件发现啥也没有资料QAQ,直接用txt打开发现居然有源码在里面!!
发现需要用utf-8可以解决部分中文乱码!
提取出主要的代码:
constructor(parent, params, __localStorage, elmtId = -1) {
super(parent, __localStorage, elmtId);
this.context = getContext(this);
this.__message = new ObservedPropertySimplePU('请输入flag', this, "message");
this.__button_name = new ObservedPropertySimplePU('提交', this, "button_name");
this.__flag = new ObservedPropertySimplePU('', this, "flag");
this.__result = new ObservedPropertySimplePU('', this, "result");
this.dialogController = new CustomDialogController({
builder: () => {
let jsDialog = new CustomDialogExample(this, {
textValue: this.__result,
});
jsDialog.setController(this.dialogController);
ViewPU.create(jsDialog);
}
}, this);
this.setInitiallyProvidedValue(params);
}
这段代码初始化了一个flag提交框!!!
this.observeComponentCreation((elmtId, isInitialRender) => {
ViewStackProcessor.StartGetAccessRecordingFor(elmtId);
Button.createWithLabel(this.button_name);
Button.onClick(() => {
this.context.resourceManager.getRawFileContent("bin").then((value) => {
var c = testNapi.check(this.flag, value);
if ((c & 0b100) === 0b100) {
this.result = '系统环境异常';
}
else if ((c & 0b10) === 0b10) {
this.result = 'flag格式错误';
}
else if ((c & 0b1) === 0b1) {
this.result = 'flag错误或系统环境异常';
}
else {
this.result = 'flag正确';
}
this.dialogController.open();
});
});
if (!isInitialRender) {
Button.pop();
}
ViewStackProcessor.StopGetAccessRecording();
});
在txt里面找到了判断flag的按钮!!var c = testNapi.check(this.flag, value);
发现这里就有check函数可以判断flag!
但是找不到testNapi.check方法百度一下!
发现testNapi其实就类似于安卓的Native方法:16.7:NAPI 加载原理(上) | 《ArkUI实战》
百度查一下发现方法是写在libentry.so文件里!
拖入ida直接搜索字符串找到了方法!!!
发现这个check方法是在so文件里的!
找到check方法!!
发现这个调用的原理是使用使用ArkTs调用so方法QAQ,我去问chatgpt他说是js调用so方法差点肝死我了!
js调用so方法:node-ffi-napi/node-ffi-napi:用于 Node.js N-API 样式的外部函数接口 (FFI)
// example.js
const ffi = require('ffi-napi'); // 使用 ffi-napi 模块来加载 SO 文件
// 加载 example.so 文件
const example = ffi.Library('./libentry.so', {
'add': ['int', ['int', 'int']] // 定义 SO 文件中的 add 函数
});
// 暴露一个函数给 JavaScript 使用
function add(a, b) {
return example.add(a, b);
}
module.exports = { add };
// main.js
const { add } = require('./example');
// 调用封装的 add 函数
const result = add(2, 3);
console.log(result); // 输出 5
去配了js的的ffi-napi库再去调用这个so文件的check方法发现报错:
然后继续百度才发现它用的是ArkTs调用so方法!!!
那继续肝,去下载一个鸿蒙开发环境:
- DevEco Studio-HarmonyOS SDK下载和升级-华为开发者联盟 (huawei.com)
- 华为官方:手把手教你使用鸿蒙 HarmonyOS 本地模拟器 - IT之家 (ithome.com)
- 鸿蒙手机版JNI实战(JNI开发、SO库生成、SO库使用) - 齐行超 - 博客园 (cnblogs.com)
成功了!!!
打开模拟器!成功剩下的就是分析so文件的具体调用了!!!
知识链接:
DevEco Studio-HarmonyOS SDK下载和升级-华为开发者联盟 (huawei.com)
华为官方:手把手教你使用鸿蒙 HarmonyOS 本地模拟器 - IT之家 (ithome.com)
手把手教你使用HarmonyOS本地模拟器 (qq.com)手把手教你使用HarmonyOS本地模拟器_harmonyos怎么本地模拟器-CSDN博客
鸿蒙 hap apk,逆向分析第一个鸿蒙OS应用-CSDN博客
华为hap安装包逆向记录 - LY 的博客 (young-lord.github.io)
[下载][原创]鸿蒙APP逆向分析-HarmonyOS-看雪-安全社区|安全招聘|kanxue.com
硬核教程:OpenHarmony和鸿蒙hap包逆向解析应用名称~_哔哩哔哩_bilibili
hap查看器的实现原理以及逆向解析应用名的初步方案 - 文章 OpenHarmony开发者论坛
安装js的ffi-napi库在kali上根本装不了一点!!!
nodejs动态调试:
re4-easy-wasm
提示:
找到注册的加密函数->主动调用->逐字节爆破密文
这道题题的分析过程:
先把网站映射到本地端口:
python -m http.server 8888
这样就可以用浏览器来进行调试了!
浏览器访问:127.0.0.1:8888 就可以访问这个页面并且进行调试了!
成功获得flag:
当然这样是不够的要去看代码QAQ
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<script src="static/wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("static/main.wasm"), go.importObject)
.then((result) => go.run(result.instance));
function check_flag() {
var flag = document.getElementById("flag").value;
console.log("你输入的 flag 是:");
console.log(flag);
if (document.getElementById("flag").value === "flag{this_1s_fake_f_l_A__g}") {
console.log("I have a gift for you!");
console.log(console.gift("ABCCDDEE", "AABBCCDDEE"));
alert("恭喜你,答对了!我想你应该知道 flag 是什么了 !");
} else {
alert("答错了,再想想吧!");
}
}
</script>
<body>
<input id="flag" type="text" />
<button id="btn" onclick="check_flag();" >Click</button>
</body>
</html>
分析发现这里的check_flag是假的,flag不在这里!!
继续分析发现了:
const go = new Go();
WebAssembly.instantiateStreaming(fetch("static/main.wasm"), go.importObject)
.then((result) => go.run(result.instance));
解释一下代码:
fetch("static/main.wasm")
fetch
函数从指定的 URL ("static/main.wasm"
) 获取 WebAssembly 文件
fetch
返回一个Promise
,它解析为响应对象(Response
)。
WebAssembly.instantiateStreaming(fetch("static/main.wasm"), go.importObject)
WebAssembly.instantiateStreaming
是一个高效的加载和编译 WebAssembly 模块的方法。- 它接收两个参数:
- 第一个参数是
Response
对象,这里通过fetch("static/main.wasm")
获得。 - 第二个参数是导入对象(
go.importObject
),它包含 WebAssembly 实例需要的导入值。
- 第一个参数是
instantiateStreaming
返回一个Promise
,解析为一个包含已编译 WebAssembly 模块的对象。
.then((result) => go.run(result.instance));
then
方法注册一个回调函数,该函数在Promise
解析时执行。- 回调函数接收一个
result
对象,该对象包含已实例化的 WebAssembly 模块实例(result.instance
)。 - 调用
go.run(result.instance)
运行 WebAssembly 模块。
然后就可以去浏览器看看具体的wasm代码了!按f12
调试的时候会发现存在无限debugger QAQ
我绕不过去!!!