mgaic

爱错


  • 首页

  • 标签

  • 分类

  • 归档

某企业加固应用脱壳、ollvm去混淆、算法分析记录

发表于 2026-04-29

应用

某咖啡

抓包

新买的pixel 6, 用公司网络, 设置代理后,charles 没有任务反应, 就好像代理每设置成功一样。 但是用自己的另外一个手机开热点,可以抓到请求.
问题已解决: 在连接wifi 的时候设置使用设备 MAC, 不要随机mac 就可以使用公司网络进行抓包了.

反编译.

打开 发现用了 某数字厂商的壳. 于是尝试用 frida 脱壳. 结果发现这个apk 有anti-frida. 然后 hluda-server, Strong-frida 等都过不了.

脱壳

https://github.com/LLeavesG/eBPFDexDumper
我是用的这个基于 ebpf 的 dexDumper. 对内核有一定的要求, 本人亲测 pixel 6, 官方 rom, android 14. 可正常使用并完成脱壳.

1
./eBPFDexDumper dump -n com.example.app -o /sdcard/dex_out

脱壳后拖入 jadx, 发现有部分代码已经可以正常显示了. 全局搜索 sign, 定位几处可疑的地方。想要使用 frida, 但是有双进程保护,注入的时候找不到进程.
spawn 模式注入也会崩溃. 本人使用的是内核模块过 frida 检测. 但spawn 模式注入 不能先 注入 Java.perform。 要先加载脚本,等稳定后再把注入代码粘贴到hook 脚本中。否则一样闪退.
本人猜测是 init_array, 或者 jni_onload 中有 crc 检测. 但线程不但轮询检测中没有 crc 检测. 当然只能猜测.

本人使用 frida 环境
frida-server https://github.com/ultrafunkamsterdam/undetected-frida undetected_f1783
frida==17.8.3
frida-tools==14.8.1

frida hook String.getBytes 方法

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
55
56
57
58
59
60

console.log("Script loaded");

function showStacks() {
// return
Java.perform(function() {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
});
}

Java.perform(function() {
var StringClass = Java.use("java.lang.String");

StringClass.getBytes.overload('java.nio.charset.Charset').implementation = function (charset) {
var result = this.getBytes(charset);
var str = this.toString();

console.log(" === getBytes(Charset) ===");
console.log("Charset:", charset.toString());
console.log("String:", str);

// if (str.indexOf("mobile") !== -1 || str.indexOf("latitude") !== -1) {
// printStack("getBytes(Charset)");
// }
showStacks()
return result;
};

StringClass.getBytes.overload('java.lang.String').implementation = function (charset) {
var result = this.getBytes(charset);
var str = this.toString();

console.log(" === getBytes(charset) ===");
console.log("Charset:", charset);
console.log("String:", str);

// if (str.indexOf("mobile") !== -1 || str.indexOf("latitude") !== -1) {
// printStack("getBytes(charset)");
// }
showStacks()
return result;
};


StringClass.getBytes.overload().implementation = function () {
var result = this.getBytes();
var str = this.toString();

console.log(" === getBytes() ===");
console.log("String:", str);
showStacks()
// 过滤你关心的字段(避免刷屏)
// if (str.indexOf("mobile") !== -1 || str.indexOf("latitude") !== -1) {
// printStack("getBytes()");
// }

return result;
};
})

根据堆栈,定位到 md5_crypt 函数. frida 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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

console.log("Script loaded");


Java.perform(function() {
let CryptoHelper = Java.use("com.xxxxx.safeboxlib.CryptoHelper");
let StringCls = Java.use("java.lang.String");

function bytesToString(bytes) {
try {
return StringCls.$new(bytes);
} catch (e) {
return "[decode error]";
}
}
function bytesToHex(bytes) {
let result = "";
for (let i = 0; i < bytes.length; i++) {
let b = (bytes[i] & 0xff).toString(16);
if (b.length == 1) b = "0" + b;
result += b;
}
return result;
}

// CryptoHelper["localAESWork4Api"].implementation = function (bArr, i2) {
// console.log(`CryptoHelper.localAESWork4Api is called: bArr=${bArr}, i2=${i2}`);
// console.log("localAESWork4Api input(str):", bytesToString(bArr)); console.log("localAESWork4Api input(hex):", bytesToHex(bArr));
// let result = this["localAESWork4Api"](bArr, i2);
// console.log(`CryptoHelper.localAESWork4Api result=${result}`);
// console.log("localAESWork4Api output(str):", bytesToString(result)); console.log("localAESWork4Api output(hex):", bytesToHex(result));
// return result;
// };

// let CryptoHelper = Java.use("com.xxxxx.safeboxlib.CryptoHelper");
CryptoHelper["localAESWork"].implementation = function (bArr, i2, bArr2) {
// console.log(`CryptoHelper.localAESWork is called: bArr=${bArr}, i2=${i2}, bArr2=${bArr2}`);
console.log(`CryptoHelper.localAESWork is called: i2=${i2}, `);
console.log("localAESWork bytesToString(bArr) :", bytesToString(bArr)); //console.log("localAESWork input(hex):", bytesToHex(bArr));
console.log("localAESWork bytesToHex(bArr) :", bytesToHex(bArr)); //console.log("localAESWork input(hex):", bytesToHex(bArr));
console.log("localAESWork bytesToString(bArr2) :", bytesToString(bArr2)); //console.log("localAESWork input(hex):", bytesToHex(bArr));
console.log("localAESWork bytesToHex(bArr2) :", bytesToHex(bArr2)); //console.log("localAESWork input(hex):", bytesToHex(bArr));

let result = this["localAESWork"](bArr, i2, bArr2);
// console.log(`CryptoHelper.localAESWork result=${result}`);
console.log("localAESWork output(str):", bytesToString(result));
console.log("localAESWork output(hex):", bytesToHex(result));
return result;
};


// let CryptoHelper = Java.use("com.xxxxx.safeboxlib.CryptoHelper");
// CryptoHelper["c"].implementation = function (str) {
// console.log(`CryptoHelper.c is called: str=${str}`);
// let result = this["c"](str);
// console.log(`CryptoHelper.c result=${result}`);
// return result;
// };
//
// let StubApp = Java.use("com.stub.StubApp");
// var res = StubApp.getString2("21888")
// console.log("StubApp res is ", res);


// let CryptoHelper = Java.use("com.xxxxx.safeboxlib.CryptoHelper");
CryptoHelper["md5_crypt"].implementation = function (bArr, i2, bArr2) {
console.log(`CryptoHelper.md5_crypt is called: i2=${i2}, `);
console.log("md5_crypt bytesToString(bArr) :", bytesToString(bArr)); //console.log("localAESWork input(hex):", bytesToHex(bArr));
console.log("md5_crypt bytesToHex(bArr) :", bytesToHex(bArr)); //console.log("localAESWork input(hex):", bytesToHex(bArr));
console.log("md5_crypt bytesToString(bArr2) :", bytesToString(bArr2)); //console.log("localAESWork input(hex):", bytesToHex(bArr));
console.log("md5_crypt bytesToHex(bArr2) :", bytesToHex(bArr2)); //console.log("localAESWork input(hex):", bytesToHex(bArr));
let result = this["md5_crypt"](bArr, i2, bArr2);
console.log("md5_crypt output(str):", bytesToString(result));
console.log("md5_crypt output(hex):", bytesToHex(result));
return result;
};

})



hook 结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
localAESWork bytesToString(bArr2) : ��o�_��ug�� ��ŖI    �P�Wbr�l|a�4;
localAESWork bytesToHex(bArr2) : fdc66fb15f838677abfc20c8d5c5964909fa50da57621072a76c7c61ae343b
localAESWork output(str): {"lsopName":"xxxxxxx","mobile":"","deptId":"","appversion":"5395","packageName":"com.lucky.luckyclient","version":"5.3.95","deviceId":"xxxxxxx-b7a5-4a7f-xxxx-xxxxxxxxx","userId":"","platform":"android"}
localAESWork output(hex): 7b226c736f704e616d652235636b79636c69656e74616e64726f6964222c226d6f62696c65223a22222c22646570744964223a22222c2261707076657273696f6e223a2235333935222c227061636b6167654e616d65223a22636f6d2e6c75636b792e6c75636b79636c69656e74222c2276657273696f6e223a22352e332e3935222c226465766963654964223a2264623565346262352d623761352d346137662d626361302d316630383130663566346462222c22757365724964223a22222c22706c6174666f726d223a22616e64726f6964227d
CryptoHelper.localAESWork is called: i2=2,
localAESWork bytesToString(bArr) : {"deptId":"","positionCode":"F101","appversion":"5395","cityId":"0"}
localAESWork bytesToHex(bArr) : 7b22646570744964223a222f736974696f6e436f6465223a2246313031222c2261707076657273696f6e223a2235333935222c22636974794964223a2230227d
localAESWork bytesToString(bArr2) : ��o�_��ug�� ��ŖI �P�Wbr�l|a�4;
localAESWork bytesToHex(bArr2) : fdc66fb15f83867567abfc20c8d5c5964909fa50da57621072a76c7c61ae343b
localAESWork output(str): >�uA8�wq�f6�c�OU��p���X8���B�Y0�}1��4�8��`��o���ߴ:ݠ�<* Zˠ�j�]+:z���$�� MOv
localAESWork output(hex): 3ec8754138b17771a866369d63e04f55b1dc70bc9c9b5838ba8ad242e05930ca7d31d8e0349438ff916015f69f6ffec8c7dfb43adda0f2b83c172a205acba0e46a965d2b3a7af9b9cf24a4e1204d4f76
CryptoHelper.md5_crypt is called: i2=1,
md5_crypt bytesToString(bArr) : cid=210101;q=Psh1QTixd3GoZjadY-
md5_crypt bytesToHex(bArr) : 6369643d3231303130313b713d5073683151546978476f5a6a6164592d425056624863634c79636d316734756f72535175425a4d4d70394d646a674e4a51345f35466746666166625f374978392d304f7432673872673846796f6757737567354771575853733665766d357a79536b3453424e5433593d3b743d313737373337303232333938323b7569643d32396464363634352d626230362d346133382d396665302d32653433326264313066396231373737333536363235343439
md5_crypt bytesToString(bArr2) : ��o�_��ug�� ��ŖI �P�Wbr�l|a�4;
md5_crypt bytesToHex(bArr2) : fdc66fb15f83867567abfc20c5964909fa50da57621072a76c7c61ae343b
md5_crypt output(str): 921726219197044498301375182129635621
md5_crypt output(hex): 393231373236323139313937303434343936333031333735313832313239363335363231

可以看到 先 localAESWork 再 md5_crypt, localAESWork 的结果会参数到 md5_crypt 的计算.
CryptoHelper.md5_crypt is called: i2=1 可以看到 i2 = 1 这点跟 localAESWork 的 2 是不一样的.

ida 打开. 进入 jni_onload 函数。
img_11

进入 off_4BCE0, 可以看到是个结构体, 里面存放的是 java函数名, 方法签名, native层绑定的 jni 函数.

img_11

进入 android_native_md5 函数看看,可以看到, 有大面积的 ollvm .

img_11

将整个函数丢给 chatgpt 和 gemini,这两个我喜欢混着用。 但是最近我发现 claude code 真的非常强大. 例如分析某个函数时, chatgpt 和 gemini 还在用非常含糊的语言表达时.
claude code 会用非常肯定语气告诉你. 并且十分靠谱, 这一点是我觉得 cc 远比 gpt 和 gemini 好用的地方

放个 cc 的回答.
img_11

AI 告诉我们

rock5b frida 使用记录

发表于 2026-03-23

环境准备
frida 16.1.4
frida-tools 12.3.0
objection 1.11.0
jnitrace 3.3.1

低版本 frida-server 14.2.18 亲测会报错 类似于注入错误. 16.1.4 这个版本可以实现在 redroid 安卓容器中的注入
github 下载 frida-server 16.1.4 以及 hluda-server 16.1.4 push /data/local/tmp/

1
2
3
./h1614   #  frida -U 微博
./h1614 -l 0.0.0.0:6666 # frida -H 172.31.102.97:6666 微博

基于rock5b ebpf 脱壳记录

发表于 2026-03-20
介绍

记录如何使用 ebpf 脱壳

过程

最近分析一款app, 某啡最新版. 本来以为很简单, 没想到踩了很多坑.

首先 jadx 打开 发现 com.stub.StubApp. 这里就猜到是 数字壳, 尝试用 frida 脱壳看看, 结果一 hook 就崩溃. 并且崩溃后必须重启, 否则即使不挂frida 这个app都无法正常打开.
我们看看是哪个so 导致的崩溃

1
2
3
4
5
6
7
8
9
10
11
12
13
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
if(android_dlopen_ext != null){
Interceptor.attach(android_dlopen_ext,{
onEnter: function(args){
var soName = args[0].readCString();
console.log(soName);
},
onLeave: function(retval){
Thread.sleep(3);
}
});
}

img_11
结果崩溃在 libjgdtc.so, 并不是 libmsaoaid.so. ida 打开 libjgdtc.so, 也被混淆了, 无法查看内容.

怎么办呢, 想到了 blackDex, 之前用过, 有的时候还是很有效的, 结果试了发现不行.

于是就想到了fart. 但是我的测试机有各种环境,到时候再装环境太麻烦了。

正好一顿搜索看到了一个开源项目, https://github.com/LLeavesG/eBPFDexDumper
这个项目是基于ebpf 完成脱壳。 之前用过 基于 ebpf 的 stackplz, 非常好用, 内核插桩,一行指令hook libart 下的各种函数. 非常方便.
于是我看了下自己的测试机, 是 pixel 4, 内核为 4.14.150-gf3a84757f21f-ab6216664, 不支持.

于是我想到了我手里还有一台rock5b+. 看能否试试看.

于是装上 radxa 官方提供的镜像. 因为我加了一个固态硬盘, 数据都放在固态硬盘, 每次启动需要将固态挂在到目录下.

sudo mount /dev/nvme0n1p1 /media/ssd

我自己的数据都在 /media/ssd/ubuntu_data/mt 下

然后 通过 redroid 启动一个android 容器. 指定各种参数. 并且这个镜像还支持lsposed + justTrustme 本人亲测可用.

1
docker run -d -p 5557:5555 -v /media/chilly/c5ab23a8-48d8-4d3b-98e7-692b498e1a98/ubuntu_data/android_2:/data --restart unless-stopped --name android_2 --privileged cnflysky/redroid-rk3588:lineage-20 androidboot.redroid_height=1920 androidboot.redroid_width=1080 androidboot.redroid_magisk=1 ro.ril.oem.imei=861503068361145 ro.product.manufacturer=OPPO ro.product.locale=zh-CN ro.product.model=OPPO A83js ro.product.brand=OPPO ro.product.name=A83js ro.product.device=M6763C ro.product.board=full_oppo6763_17101 ro.build.product=oppo6763_17101 androidboot.redroid_fake_wifi=1

然后本机

adb -s 172.31.xxx.xx:5557 shell
uname -r
5.10.0-1012-rockchip

可以看到是 手机显示的 5.10 的内核.
于是我们下载一个 eBPFDexDumper, 然后 adb -s ip:port push /data/local/tmp/

1
2
3
chmox +x eBPFDexDumper

./eBPFDexDumper dump --name com.luxxxcky.xxxxxx /apex/com.android.art/lib64/libart.so 0 0 0>

img_11

然后整个 pull 出来, jadx 打开. 发现成功脱壳

img_11

某站点wasm 逆向分析

发表于 2026-03-17

背景

某站点响应被加密, 需要对数据进行解密.

过反调试

进入到详情页面,发现F12 无效, 无法调试. 右键也无法进入开发者调试界面
img.png

鼠标移动到 url 栏, 按 F12 即可过掉这个反调试.

现在很顺利的打开了调试界面, 但我并没有下断点, 竟然自己断在了这里.

img.png

很明显,这也是反调试, 当上一行代码与下一行代码间隔时间大于 500ms,就重定向到主页。
总结: 此处也可以将这片代码 交给 AI, AI 基本也能分析个八九不离十

ok 我们直接 patch js. 我习惯使用 charles.
用 charles 的 map local 功能

img.png

然后 将 js 替换为本地的 min_book.txt

min_book.txt 的内容也很简单, 把这两行注释掉就可以了,不过最好还是直接删掉. 避免出麻烦.

img.png

然后 将 js 替换为本地的 min_book.txt

img.png

然后F5刷新, 发现没有反调试了.

后面我试了另一种方式. 也是可行的。 那就是禁用断点, 一律不在此处暂停.

img.png

关键函数定位

ok 反调试过了, 直接搜索关键字 html5_pages

搜索结果有几十处,其中有一处
img.png

这里比较可疑, 是将数据转为 json 的地方, 我们打上断点.

刷新后发现在此处断下. 然后一路调试到了这里

img.png

这里 b 的值就是加密的内容.

继续单步走.
发现 z 就是 解密后的内容, 那看来解密函数就是 Module._DeString(p)

img.png

我们进入 _DeString 函数看看.

img.png

根据上下文猜测是 wasm 代码保护.

断点打在 asm[name].apply(null, arguments), 发现成功断下,F11 直接步进,进入函数内部, 发现跳转到 wat代码 (wasm 文本可读格式).

img.png

补 WebAssembly 环境

试试用 node 补环境.

问问 gpt

img.png

补环境,以下代码来自 chatgpt

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
WebAssembly.instantiate(wasmBytes, {})
.then(obj => {
// 1 写入字符串
var b = "123"
const encoder = new TextEncoder()
const bytes = encoder.encode(b)

const ptr = obj.instance.exports.malloc(bytes.length + 1)

HEAPU8.set(bytes, ptr)
HEAPU8[ptr + bytes.length] = 0

// 2 调用 wasm
// const retPtr = obj.instance.exports.DeString(ptr)
const retPtr = obj.instance.exports.EnString(ptr)

// 3 读取返回字符串
let end = retPtr
while(HEAPU8[end] !== 0) end++

var result = new TextDecoder().decode(
HEAPU8.slice(retPtr, end)
)

console.log("result ", result)
})

运行后报错

1
2
3
4
5
6
7
node:internal/process/promises:288
triggerUncaughtException(err, true /* fromPromise */);
^

[TypeError: WebAssembly.instantiate(): Import #0 module="env" error: module is not an object or function]

Node.js v18.20.8

大概是env 的问题, 谷歌搜索了一下,回答是 wasm 还依赖env 下的一些函数. 缺少 imports. 我们在 DeString.js 里面搜索一些 env.

img.png

img.png

补上 wasmImports 后的代码如下

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
const fs = require("fs")
const assert = require('assert');

const wasmBytes = fs.readFileSync("yunzhanwang_bytes.wasm")


function _emscripten_run_script(ptr) {
console.log("_emscripten_run_script called !!!")
eval(UTF8ToString(ptr));
}


function _emscripten_resize_heap(requestedSize) {
var oldSize = HEAPU8.length;
requestedSize = requestedSize >>> 0;
assert(requestedSize > oldSize);
var maxHeapSize = getHeapMax();
if (requestedSize > maxHeapSize) {
err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + maxHeapSize + ' bytes!');
return false;
}
let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
var replacement = emscripten_realloc_buffer(newSize);
if (replacement) {
return true;
}
}
err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!');
return false;
}
function _emscripten_memcpy_big(dest, src, num) {
console.log("_emscripten_memcpy_big called !!!")
HEAPU8.copyWithin(dest, src, src + num);
}
function _fd_write(fd, iov, iovcnt, pnum) {
var num = 0;
for (var i = 0; i < iovcnt; i++) {
var ptr = HEAPU32[((iov) >> 2)];
var len = HEAPU32[(((iov) + (4)) >> 2)];
iov += 8;
for (var j = 0; j < len; j++) {
printChar(fd, HEAPU8[ptr + j]);
}
num += len;
}
HEAPU32[((pnum) >> 2)] = num;
console.log(1111)
return 0;
}

var wasmImports = {
"emscripten_memcpy_big": _emscripten_memcpy_big,
"emscripten_resize_heap": _emscripten_resize_heap,
"emscripten_run_script": _emscripten_run_script,
"fd_write": _fd_write
};

var imports = {
'env': wasmImports,
'wasi_snapshot_preview1': wasmImports,
};




WebAssembly.instantiate(wasmBytes, imports)
.then(obj => {
// 1 写入字符串
var b = "123"
const encoder = new TextEncoder()
const bytes = encoder.encode(b)

const ptr = obj.instance.exports.malloc(bytes.length + 1)

HEAPU8.set(bytes, ptr)
HEAPU8[ptr + bytes.length] = 0

// 2 调用 wasm
// const retPtr = obj.instance.exports.DeString(ptr)
const retPtr = obj.instance.exports.EnString(ptr)

// 3 读取返回字符串
let end = retPtr
while(HEAPU8[end] !== 0) end++

var result = new TextDecoder().decode(
HEAPU8.slice(retPtr, end)
)

console.log("result ", result)
})

注意. _emscripten_run_script, _emscripten_resize_heap, _emscripten_memcpy_big 这些函数都是从 DeString.js 抠出来的.

继续运行。 报错如下

1
2
3
4
HEAPU8.set(bytes, ptr)
^

ReferenceError: HEAPU8 is not defined

交给 gpt 帮忙修复. 修复后的代码如下

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
const fs = require("fs")
const assert = require('assert');

const wasmBytes = fs.readFileSync("yunzhanwang_bytes.wasm")


function _emscripten_run_script(ptr) {
console.log("_emscripten_run_script called !!!")
eval(UTF8ToString(ptr));
}


function _emscripten_resize_heap(requestedSize) {
var oldSize = HEAPU8.length;
requestedSize = requestedSize >>> 0;
assert(requestedSize > oldSize);
var maxHeapSize = getHeapMax();
if (requestedSize > maxHeapSize) {
err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + maxHeapSize + ' bytes!');
return false;
}
let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
var replacement = emscripten_realloc_buffer(newSize);
if (replacement) {
return true;
}
}
err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!');
return false;
}
function _emscripten_memcpy_big(dest, src, num) {
console.log("_emscripten_memcpy_big called !!!")
HEAPU8.copyWithin(dest, src, src + num);
}
function _fd_write(fd, iov, iovcnt, pnum) {
var num = 0;
for (var i = 0; i < iovcnt; i++) {
var ptr = HEAPU32[((iov) >> 2)];
var len = HEAPU32[(((iov) + (4)) >> 2)];
iov += 8;
for (var j = 0; j < len; j++) {
printChar(fd, HEAPU8[ptr + j]);
}
num += len;
}
HEAPU32[((pnum) >> 2)] = num;
console.log(1111)
return 0;
}

var wasmImports = {
"emscripten_memcpy_big": _emscripten_memcpy_big,
"emscripten_resize_heap": _emscripten_resize_heap,
"emscripten_run_script": _emscripten_run_script,
"fd_write": _fd_write
};

var imports = {
'env': wasmImports,
'wasi_snapshot_preview1': wasmImports,
};




WebAssembly.instantiate(wasmBytes, imports)
.then(obj => {
// 1 写入字符串
var b = "123"
const encoder = new TextEncoder()
const bytes = encoder.encode(b)

const ptr = obj.instance.exports.malloc(bytes.length + 1)

const memory = obj.instance.exports.memory
HEAPU8 = new Uint8Array(memory.buffer)
HEAPU32 = new Uint32Array(memory.buffer)

HEAPU8.set(bytes, ptr)
HEAPU8[ptr + bytes.length] = 0

// 2 调用 wasm
// const retPtr = obj.instance.exports.DeString(ptr)
const retPtr = obj.instance.exports.EnString(ptr)

// 3 读取返回字符串
let end = retPtr
while(HEAPU8[end] !== 0) end++

var result = new TextDecoder().decode(
HEAPU8.slice(retPtr, end)
)

console.log("result ", result)
})

继续运行, 报错如下

img.png

继续补 printChar. 把DeString.js 中的函数抠出来

1
2
3
4
5
6
7
8
9
10
function printChar(stream, curr) {
var buffer = printCharBuffers[stream];
assert(buffer);
if (curr === 0 || curr === 10) {
// (stream === 1 ? out : err)(UTF8ArrayToString(buffer, 0));
buffer.length = 0;
} else {
buffer.push(curr);
}
}

补上还报错, 如下

img.png

运行后, 发现解密成功.
img.png

下面给出完整 node 补 wasm 运行环境代码.
以下代码在 Node v18.20.8 下运行通过

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
const fs = require("fs")
const assert = require('assert');

const wasmBytes = fs.readFileSync("yunzhanwang_bytes.wasm")

var printCharBuffers = [null,[],[]];
function printChar(stream, curr) {
var buffer = printCharBuffers[stream];
assert(buffer);
if (curr === 0 || curr === 10) {
// (stream === 1 ? out : err)(UTF8ArrayToString(buffer, 0));
buffer.length = 0;
} else {
buffer.push(curr);
}
}



function _emscripten_run_script(ptr) {
console.log("_emscripten_run_script called !!!")
eval(UTF8ToString(ptr));
}


function _emscripten_resize_heap(requestedSize) {
var oldSize = HEAPU8.length;
requestedSize = requestedSize >>> 0;
assert(requestedSize > oldSize);
var maxHeapSize = getHeapMax();
if (requestedSize > maxHeapSize) {
err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + maxHeapSize + ' bytes!');
return false;
}
let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
var replacement = emscripten_realloc_buffer(newSize);
if (replacement) {
return true;
}
}
err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!');
return false;
}
function _emscripten_memcpy_big(dest, src, num) {
console.log("_emscripten_memcpy_big called !!!")
HEAPU8.copyWithin(dest, src, src + num);
}
function _fd_write(fd, iov, iovcnt, pnum) {
var num = 0;
for (var i = 0; i < iovcnt; i++) {
var ptr = HEAPU32[((iov) >> 2)];
var len = HEAPU32[(((iov) + (4)) >> 2)];
iov += 8;
for (var j = 0; j < len; j++) {
printChar(fd, HEAPU8[ptr + j]);
}
num += len;
}
HEAPU32[((pnum) >> 2)] = num;
return 0;
}

var wasmImports = {
"emscripten_memcpy_big": _emscripten_memcpy_big,
"emscripten_resize_heap": _emscripten_resize_heap,
"emscripten_run_script": _emscripten_run_script,
"fd_write": _fd_write
};

var imports = {
'env': wasmImports,
'wasi_snapshot_preview1': wasmImports,
};




WebAssembly.instantiate(wasmBytes, imports)
.then(obj => {
// 1 写入字符串
// var b = "123"
var b = "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"
const encoder = new TextEncoder()
const bytes = encoder.encode(b)

const ptr = obj.instance.exports.malloc(bytes.length + 1)

const memory = obj.instance.exports.memory
HEAPU8 = new Uint8Array(memory.buffer)
HEAPU32 = new Uint32Array(memory.buffer)

HEAPU8.set(bytes, ptr)
HEAPU8[ptr + bytes.length] = 0

// 2 调用 wasm
const retPtr = obj.instance.exports.DeString(ptr)
// const retPtr = obj.instance.exports.EnString(ptr)

// 3 读取返回字符串
let end = retPtr
while(HEAPU8[end] !== 0) end++

var result = new TextDecoder().decode(
HEAPU8.slice(retPtr, end)
)

console.log("result ", result)
})

zip 解密分析

发现解密后的响应中的 zip 文件无法解压.

解密后的 json 数据中有图片缩略图地址 和 *.zip。 这个 *.zip 是无法解压的. 猜测这个 zip 做了手脚.
抓包发现 有 很多这种 blob 请求

img.png

全局搜索 blob. 都打上断点, 发现在此处断下.

img.png

然后将这个函数贴给 AI

img.png

然后让 AI python 还原, 代码如下

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
def decrypt_pdf_with_password(input_path, output_path):
with open(input_path, 'rb') as f:
data = f.read()

# --- 1. 提取密码 (Password Extraction) ---
# JS: h = response.slice(1080, 1083)
part_h = data[1080:1083].decode('utf-8', errors='ignore')

# JS: k = response.slice(response.size - 1003, response.size - 1000)
# 注意:JS 的 1E3 是 1000
file_size = len(data)
part_k = data[file_size - 1003: file_size - 1000].decode('utf-8', errors='ignore')

password = part_h + part_k

# --- 2. 还原文件内容 (File Decryption) ---
# JS: f = response.slice(1083, response.size - 1003)
body = data[1083:-1003]
content = bytearray(body)

# 核心解密:反转前 4000 个字节
for i in range(min(4000, len(content))):
content[i] = 255 - content[i]

# --- 3. 保存与输出 ---
with open(output_path, 'wb') as f_out:
f_out.write(content)

print("-" * 30)
print(f"✅ 处理完成!")
print(f"🔑 该 PDF 的可能密码为: {password}")
print(f"📂 还原后的文件已保存至: {output_path}")
print("-" * 30)

decrypt_pdf_with_password('267f31b1ec79c8cb70f23bf33a518918.zip', 'restored_document.pdf')

运行后, zip 转为 restored_document.pdf. 用浏览器打开, 输入密码, 即可看到高清大图.

chomper 还原 ios 某社区app 算法

发表于 2026-02-25

春节回来,发现我的 iphone 6plus 关机了, 我的ios 系统是 15.8.5, 采用的是 dopamine 越狱, 属于无根越狱, 每次重启就需要重新越狱。所以特别坑。

当我充好电,打开手机,点击 dopamine 发现弹出 dopamine 不可用, 并且我手机桌面上的 sileo 也不见了. sileo 是dopamine 越狱后的一个包管理平台.

然后我用爱思助手重新越狱,发现失败了,跟之前是一个情况, 于是我想到之前我的手机里装了巨魔, 我直接通过巨魔来安装 dopamine.ipa. 于是打开巨魔,选择 install from url,
输入 https://github.com/opa334/Dopamine/releases/download/2.4.7/Dopamine.ipa.
这个安装包在 https://github.com/opa334/Dopamine/releases/tag/2.4.7

安装好后,打开 dopamine, 点击越狱, 过程全自动, 等待一段时间后,会自动重启, 重启后桌面出现了 sileo 和 dopamine, 并且进入 sileo 后, 之前装的 ssh 还有各种插件都还可以正常使用. 所以这里记录一下

当手机意外重启后,或者没电重启后, 可以直接通过巨魔来安装 dopamine.ipa. 并且之前的所以数据都还在, 并且还不用重装.

或者也可以在windows 上把dopamine.ipa 下载好, 然后打开爱思助手,将ipa 拖到这个手机目录下

img.png

然后手机上装个 filza app,在 /var/mobile/Media/Downloads 目录下就可以找到从爱思助手上拖入的文件.

于是抓包. 结果如下, 主要就是这个 -96参数

img.png

因为之前还原过安卓端的算法, 知道这是一个魔改的白盒 AES 的算法. 并且结果是标准的base64. 所以我们直接 hook base64 看看

1
2
3
/var/jb/usr/sbin/frida-server -l 0.0.0.0:6666  # 启动 frida-server 监听 6666 端口
/home/chilly/xxx/ios_frida_env/bin/frida-trace -H 172.31.101.83:6666 7885 -m "-[NSData base64EncodedStringWithOptions:]"

7885 是pid,
然后将这段代码贴进 handles 中,因为结果特别多,所以我们只过滤需要的信息. 并且打印堆栈.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
onEnter(log, args, state) {
this.self = args[0];
},
onLeave(log, retval, state) {
var before = ObjC.classes.NSString.alloc().initWithData_encoding_(this.self, 4);
var after = new ObjC.Object(retval);

if(after.toString().indexOf("Wrsw9oPOU3ScR35Ma5")>=0){
log(`-[NSData base64EncodedStringWithOptions:]before=${before}=`);
log(`-[NSData base64EncodedStringWithOptions:]after=${after}=`);
log(Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join('\n'));
}
// if(after.toString().length>=64 && after.toString().length <= 67 ){
// console.log(Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join('\n'));
// }
}
}

然后继续 hook

1
/home/chilly/xxxx/ios_frida_env/bin/frida-trace -H 172.31.101.83:6666 2092 -m "-[NSData base64EncodedStringWithOptions:]"

结果如下
img.png

可以看到调用堆栈, 上层调用了 encryptDataBase64String 函数, 我们用 frida hook 一下 encryptDataBase64String 这个函数. 如下给出 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
55
56
57
58
59
60
61
62
63
64
function hook() {
if (!ObjC.available) {
console.log("ObjC not available");
return;
}

var cls = ObjC.classes.ZHWhiteBoxEncryptTool;
if (!cls) {
console.log("ZHWhiteBoxEncryptTool not found");
return;
}

var method = cls["+ encryptDataBase64String:"];

Interceptor.attach(method.implementation, {
onEnter: function (args) {
this.self = new ObjC.Object(args[0]);
// console.log("cmd:", ObjC.selectorAsString(args[1]));

this.arg = new ObjC.Object(args[2]);

console.log("\n========== encryptDataBase64String ENTER ==========");
console.log("self:", this.self.toString());

try {
console.log("arg:", this.arg.toString());
} catch (e) {
console.log("arg raw:", args[2]);
}

try {
console.log("arg class:", this.arg.$className);
if (this.arg.$className === "NSData") {
var bytes = Memory.readByteArray(this.arg.bytes(), this.arg.length());
console.log("arg bytes:", hexdump(bytes, { length: 64 }));
}
} catch (e) {}
},

onLeave: function (retval) {
console.log("---------- encryptDataBase64String LEAVE ----------");

try {
var ret = new ObjC.Object(retval);
console.log("ret:", ret.toString());
console.log("ret class:", ret.$className);

if (ret.$className === "NSData") {
var bytes = Memory.readByteArray(ret.bytes(), ret.length());
console.log("ret bytes:", hexdump(bytes, { length: 64 }));
}
} catch (e) {
console.log("ret raw:", retval);
}

console.log("=================================================\n");
}
});

console.log("[+] Hooked +[ZHWhiteBoxEncryptTool encryptDataBase64String:]");
}

setImmediate(hook);

1
/home/chilly/zhipu/ios_frida_env/bin/frida -H 172.31.101.83:6666 -n osxxxunixxxxxRelexxx -l hook_encryptDataBase64String.js

结果如下
img.png

可以看到入参是 32 字节, 这让我想到了安卓, 入参也是 32 字节。我验证了一下, 跟android 一样, 这个入参就是url, headers 中几个字段拼接起来做标准md5 生成的.

要注意 0x64626137, 转成hex 是 dba7 也就是md5 的32字符的前4个字符.

那主动rpc call 调用一下算法看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (ObjC.available) {

var md5 = "dba7f8100a5ef95d623ec360e8415ddd";

// 1. JS -> NSString
var nsstr = ObjC.classes.NSString.stringWithString_(md5);

// 2. NSString -> NSData (UTF8 = 4)
var data = nsstr.dataUsingEncoding_(4);

console.log("[*] input:", md5);
console.log("[*] data len:", data.length());

// 3. call 类名已脱敏
var cls = ObjC.classes.XXXXXXXEncryptTool;
var ret = cls.encryptDataBase64String_(data);

// 4. result
console.log("[+] output:", ret.toString());
}

结果如下
img.png

可以看到 当入参是 md5, -96的结果已经出来了. 可以 rpc 调用算法了.

我们这里试试看 chomper 还原该算法. 这里我直接给出代码, 部分已脱敏

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
import os

from chomper import Chomper
from chomper.const import ARCH_ARM64, OS_IOS
from chomper.objc import ObjcRuntime

base_path = os.path.abspath(os.path.dirname(__file__))

rootfs_path = os.path.join(base_path, "../../rootfs/ios")
module_path = os.path.join(base_path, "../../examples/binaries/ios/ios_10_86_0/xxxxxxxxxx")


def main():
if not os.path.exists(module_path):
print(
"Binary doesn't exist, please download "
"from 'https://sourceforge.net/projects/chomper-emu/files/'"
)
return

emu = Chomper(
arch=ARCH_ARM64,
os_type=OS_IOS,
rootfs_path=rootfs_path,
)
objc = ObjcRuntime(emu)

emu.load_module(module_path)

white_box_encrypt_tool_class = objc.find_class("XXXXXXEncryptTool")

with objc.autorelease_pool():
data = objc.create_ns_data(b"dba7f8100a5ef95d623ec360e8415ddd")
result = white_box_encrypt_tool_class.call_method("encryptDataBase64String:", data)
result_str = emu.read_string(objc.msg_send(result, "UTF8String"))
emu.logger.info("+[XXXXXXEncryptTool encryptDataBase64String:] result: %s", result_str)

if __name__ == "__main__":
main()

看看 chomper 跑出的结果

img.png

跟抓包结果完全一致。 这是最理想的, 因为当输入固定,输出也是固定的,算法内部没有时间戳,随机数参与计算. 这样就很好验证算法结果。

某投屏软件去除强制更新

发表于 2026-02-24

2026 春节回老家了一趟, 节前跟高中同学在一张床上深入交流了一下, 还跟另外一个在非洲肯尼亚的同学打了个视频, 他们老板在那边装了星lian, 按之前的网速是没法打微信视频的. 他也算搭上老板的顺风车了, 并且还各种摸鱼,
北京时间是晚上十点, 他们那边大概是下午两点的样子, 边上班边跟我们视频,他做的是桥梁设计,他开了 chatgpt pro 的会员,一个月大概1000多,让gpt 生成一个 50多页的pdf, 大概已完成了 60%-80%,然后再反复迭代优化提示词,听他说能否节约一半的工作时间.

好了说正事, 就是这个深入交流的同学, 他家新盖了房子, 买了新的电视, 需要投屏. 有一款app 强制更新,让我帮忙看看, 于是有了这篇文章.

打开app, 申请完权限后, 直接进入到了自动更新.

img_2.png

我们jadx 打开app, 全局搜索 “更新”

img_2.png

此处比较可疑,我们frida hook 看看

1
2
3
4
5
6
7
8
9
10
11
12
Java.perform(function() {
let MainActivity = Java.use("com.cctv.tv.mvp.ui.activity.MainActivity");
MainActivity["a"].overload('boolean', 'boolean').implementation = function (z, z2) {
console.log(`MainActivity.a is called: z=${z}, z2=${z2}`);
this["a"](z, z2);
// this["a"](false, false);
// return this["a"](true, false);
console.log(111111)
// return this["a"](false, true);
// return this["a"](false, false);
};
});

结果是 MainActivity.a is called: z=true, z2=true
我们使用 frida 改改参数看看能否绕过更新, 亲测不管怎么组合, 都不能绕过更新。

于是问 chatgpt 如何绕过强制更新, gpt 说可以通过拦截网络请求来实现绕过, 于是试试看 charles 抓包
看 charles 能否 patch 掉自动更新.

img.png

直接 block List, 直接禁用该请求, 发现app 强制更新不弹出了. 直接成功.
还有一个办法, compose 这个请求,将返回值中的 versionCode 和 versionName 置为空 也可以跳过强制更新.

到此处已经有可用方案了, 就是通过 charles patch response. 但我同学不懂技术,他要装charles, 并且还要设置证书, 我想着有没有什么apk, 可以拦截 url, 于是尝试了 netguard 工具, 好像无法像charles 一样直接拦截, 我想如果有的话,应该就是小黄鸟. 或者如果设备够新的话,支持ebpf 特性,应该可以实现.

这里我没有试小黄鸟了. 我想重打包一下 apk, 这样,我这个不懂技术但深入交流过的同学就可以傻瓜式的使用了.

于是打开 AndroidManifest.xml, 找到 启动 activity.

img.png

大致看一下整个MainActivity, 有几处更新字眼, 大概率是有更新相关的逻辑的, 然后将整个 MainActivity 的代码 copy 给 chatgpt, 让它帮我们分析一下, 更新的逻辑大致在哪里.

gpt 回答说是在 onResume 里, jadx 查看 onResume

img.png

发现并没有反编译完全, 这里不想去用 android killer 等其他工具了, 直接看 smali 代码吧, 之前帮另一个同学重打包过一个应用, 也是改的 smali 代码, 不过那个时候是 2022年, 还没有 gpt 这么强大的工具, 需要自己学习,硬改smali 代码, 添加寄存器,用前还要申请, 一不小心就崩溃了.

这里我们让gpt 帮我们修改.

img.png

大致是patch, 将检测的结果颠倒黑白, 即可.

于是我们试试将源代码转化为 smali 代码.

1
java -jar apktool_3.0.1.jar d   video.apk -o app_src

然后按照gpt 的方法, 将 sget-boolean v0, Lc/e/c/l/a/h;->c:Z 改为 const/4 v0, 0x1. 让后续的条件永远不会满足,这样也不会走强制更新的逻辑.

然后将 smali 转为 java 代码.

1
java -jar apktool_3.0.1.jar b app_src -o unsigned_video.apk

然后这个时候还需要对 apk 进行签名. 否则
adb install unsigned_video.apk
Performing Streamed Install
adb: failed to install yangshi.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES: Failed collecting certificates for /data/app/vmdl1002557303.tmp/base.apk: Failed to collect certificates from /data/app/vmdl1002557303.tmp/base.apk: Attempt to get length of null array]

签名

1
git clone https://github.com/techexpertize/SignApk.git
1
java -jar signapk/signapk.jar SignApk/certificate.pem signapk/testkey.pk8 unsigned_video.apk signed_video.apk

然后安装

1
adb install signed_video.apk

打开后发现,app正常使用,不会强制更新了.

总结:

  1. 这个apk 33M, 比较小, 强制更新的逻辑在 MainActivity, 将这个类的代码直接扔给gpt, 直接给出了结果,运气比较好.
  2. 巩固了如何对 apk 进行反编译, 回编, 签名.
  3. 修改 smali 的代码是 gpt 帮我们生成的. 如果自己改, 可能会面临闪退, 并且你不知道是不是由于签名验证造成的。 如果想验证是不是smali 语法导致的闪退也很简单, 添加一个无关紧要的 smali 代码,例如打个日志,print hello 等,就是特别简单, 不会出错的代码, 然后再重打包,如果崩溃了就是有apk签名检测. 如果没有崩,说明就是smali 语法问题. 寄存器用前没有申请等等.

编写magisk 模块修改机型

发表于 2025-10-11

修改机型记录

1.Magisk 模板下载
1
git clone https://github.com/Petit-Abba/Magisk-Modules-Template-ge20.4.git
2.修改 system.prop 文件
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
ro.product.brand=google
ro.product.device=husky
ro.product.manufacturer=Google
ro.product.model=Pixel 9 Pro
ro.product.name=husky

# 以下针对分区/多产品命名空间,尽量统一
ro.product.system.brand=google
ro.product.system.device=husky
ro.product.system.manufacturer=Google
ro.product.system.model=Pixel 8 Pro
ro.product.system.name=husky

ro.product.system_ext.brand=google
ro.product.system_ext.device=husky
ro.product.system_ext.manufacturer=Google
ro.product.system_ext.model=Pixel 9 Pro
ro.product.system_ext.name=husky

ro.product.vendor.brand=google
ro.product.vendor.device=husky
ro.product.vendor.manufacturer=Google
ro.product.vendor.model=Pixel 9 Pro
ro.product.vendor.name=husky

ro.product.odm.brand=google
ro.product.odm.device=husky
ro.product.odm.manufacturer=Google
ro.product.odm.model=Pixel 9 Pro
ro.product.odm.name=husky

# 可选:指纹与描述(部分应用校验)
ro.build.fingerprint=google/husky/husky:14/UQ1A.240705.004/1234567:user/release-keys
ro.build.description=husky-user 14 UQ1A.240705.004 1234567 release-keys
修改模块名,版本等信息. 编辑 module.prop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# id 只能填 字母 数字 半角符号
#id=Module-Template
#name=模块模板
#version=v1
#versionCode=1
#author=Petit Abba
#description=一个简短的描述


# id 只能填 字母 数字 半角符号
id=buildprop_modify
name=buildprop_modify by chill wei
version=v4
versionCode=1
author=chill wei
description=build prop modify

然后在项目根目录下, 选中所有文件, 压缩成 zip文件, 不可以在文件夹外部,压缩。否则安装该模块的时候会报错 unzip error. 别问我怎么知道的.

没错就是这么简单

img_11

然后安装. 重启后打开手机查看器。发现机型都变成了 Pixel 9 Pro

img_11

下面给出手机查看器 apk.
点我下载 手机查看器.apk

还有另外一个软件 AIDA64. 看看生效没

img_11

可以看到也是生效的.

给出 aida64 的下载地址
aida64-v211.apk

测试另外一个 xposed 模块, 看是否可行

试试另外一个xposed 模块 -> Guise. 看看效果如何
点击下载 Guise_1.1.2.apk

一键随机

img_11

然后打开app, 抓包看看是否生效.

img_11

可以看到机型修改已经生效

magisk 的 resetprop 也可以实现类似的功能

参考 https://yydsxx.com/blog/change%20device%20model/

1
2
3
4
5
6
7
resetprop ro.product.manufacturer Xiaomi
resetprop ro.product.brand Redmi
resetprop ro.product.model 22127RK46C
resetprop ro.product.device socrates
resetprop ro.build.product socrates

stop;start; #一定要通过该方式重启

打开 AIDA64, 发现成功了

img_11

rock5b plus 折腾记录

发表于 2025-09-01

从淘宝上了个 rock5b+ 的板子, 16G内存, 买了七彩虹的固态 256G, 129 RMB.

踩坑一:

镜像无法从U盘刷, 以前windows 我都是直接通过 软碟通把系统镜像直接刷入u盘, 但rock5b+ 貌似不支持这么干. 无奈我买了个读卡器加SD卡, 我的板子到了 这个读卡器和SD卡都还没到, 又需要等两天.

tips: 貌似固态也是可以用来刷写镜像的, 但是需要硬盘盒这种连接设备

装备都到了

ok 今天装备都齐了, 一个 sd卡, 一个读卡器, 这两个用来装系统, 一个固态硬盘,一个风扇, 一个 rock5b+板子.

如图

img_11

下载系统镜像.

从 第三方下载 ubuntu 镜像.

1
https://joshua-riek.github.io/ubuntu-rockchip-download/boards/rock-5b-plus.html

我选择的是这个镜像.

img_11

开工把, 刷系统.

  1. 按照 官方文档 下载 SPL Loader, SPI Image. 还有 balenaEtcher-Setup-1.18.11.exe

  2. 打开 balendEtcher, 选择ubuntu 镜像文件, 然后我们的 SD卡, 然后点击烧录,显示正在烧录中, 界面如下:

img_11

等了大概7,8分钟, 显示如下界面:

img_11

看来烧录镜像估计要 10分钟左右, 我的机器是 windows 11, 32G内存, 512G rom, 处理器是 intel Ultra5 125H, 这颗U 相当于 i5-13500H 的性能, 这个配置下, 烧录系统镜像需要10分钟.

img_11

ok, fine, 太好了, 烧录好了.

自我怀疑

按开机键发现没有任务反应, 风扇也不转. 我甚至想退货了, 买到了坏的板子.
然后还是按照官方的文档, 发现没有插sd卡到主板上, 插上sd卡后,发现主板的等从绿色变成了蓝色. 然后再按开机键,过了几秒,指示灯从蓝灯变成了蓝绿交替, 进入系统了, 然后进入了熟悉的图形界面 Ubuntu 的界面,简单设置了语言, 时区, 账密后,进入了系统。

参考 https://docs.radxa.com/rock5/rock5b/getting-started/interface-usage/fan
后面问客服了解到需要温度达到60度风扇才转. 好吧 再忍一忍,起码线上能进入系统了, 说明1000大洋没买废铁。

踩坑二:

我简单安装了 zsh, vim 等工具后, 就去吃饭了, 也正常关机了。 但是第二次开机, 就有了如下报错, 进入不到系统了。
显示如下

img_11

下载官方镜像

https://docs.radxa.com/rock5/rock5b/download

ROCK 5B+ 系统镜像: rock-5b-plus_bookworm_kde_b2

然后正常玩了一个下午 开启了 openssh 可以远程连接。 发现又突然黑屏了。然后启动就启动不了了, 并且期间还重启了一次。坑爹啊。

下载armbian 试试。

https://www.armbian.com/rock-5b-plus/
https://www.armbian.com/rock-5b/

重装了一下,是个server版系统, 用了一下,还不错,好像还挺稳定的。开启了 ssh-server, 远程连接。 就是感觉cpu 和主板 有点发烫.

然后我按照 radxa 官方的教程 执行语句将风扇调至最高档

https://docs.radxa.com/rock5/rock5b/getting-started/interface-usage/fan

1
sudo cp /sys/class/thermal/cooling_device5/max_state /sys/class/thermal/cooling_device5/cur_state

但是只转了两三秒就停了。

于是问了下 chatgpt, 应该是控温策略导致的。温度还没有达到60度。

但是我还是觉得有点烫。于是写了个bash 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# 临时全速风扇脚本
# 持续将风扇设置为最大状态,直到手动停止
# 适用于 /sys/class/thermal/cooling_device4

# 获取最大风扇状态
MAX_STATE=$(cat /sys/class/thermal/cooling_device5/max_state)

echo "最大风扇状态: $MAX_STATE"

# 持续循环设置风扇
while true; do
# 写入当前状态
echo $MAX_STATE | sudo tee /sys/class/thermal/cooling_device5/cur_state > /dev/null

# 可选:打印当前 CPU 温度
TEMP=$(cat /sys/class/thermal/thermal_zone0/temp)
echo "CPU 温度: $((TEMP/1000))°C | 风扇状态: $MAX_STATE"

# 每秒刷新一次
sleep 1
done

img_11

可以看到 温度确实降下来了, 于是我关闭了 bash 脚本, 风扇依然再转。 很奇怪. 转吧 总比不转好.

ok 看看系统使用

1
df -lh

img_11

20250928
烧录系统后,SD卡内存变小的解决
https://blog.csdn.net/u010994456/article/details/117119317?spm=1001.2101.3001.6650.15&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-15-117119317-blog-145263778.235%5Ev43%5Epc_blog_bottom_relevance_base5&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-15-117119317-blog-145263778.235%5Ev43%5Epc_blog_bottom_relevance_base5&utm_relevant_index=22

20250929
通过ssh 远程链接, 刷的radxa 的官方镜像, 系统长时间不用
会返回
Broadcast message from gdm@rockpi-4cplus on tty1 (Sun 2025-01-19 10:19:10 UTC):
The system will suspend now!

20260323 更新
我用一根其他的type c 的线插上 rock5b+, 发现只亮绿灯, 换上小米线后亮蓝色灯。 看来还是要充电头和充电线过关才行.

给出目前我在用的 rock5b+ 让风扇转起来脚本

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
55
56
57
58
59
60
61
62
63
64
65
66
#!/bin/bash
# smart_fan_control.sh

TEMP_THRESHOLD=30000 # 30度(注意:通常是毫摄氏度)
FAN_ON_STATE=4
FAN_OFF_STATE=0
CHECK_INTERVAL=1

echo "智能风扇温度控制启动"
echo "温度阈值: 30°C"
echo "检查间隔: ${CHECK_INTERVAL}秒"
echo "按 Ctrl+C 停止"

while true; do
# 获取当前温度(尝试不同的温度传感器)
CURRENT_TEMP=""

# 尝试常见的温度传感器路径
for temp_file in /sys/class/thermal/thermal_zone*/temp; do
if [ -f "$temp_file" ]; then
temp=$(cat "$temp_file")
if [ ! -z "$temp" ] && [ "$temp" -gt 0 ]; then
CURRENT_TEMP=$temp
break
fi
fi
done

# 如果没找到温度文件,使用 sensors 命令
if [ -z "$CURRENT_TEMP" ]; then
CURRENT_TEMP=$(sensors 2>/dev/null | grep -E "Core 0|Package id 0|temp1" | head -1 | awk '{print $3}' | sed 's/[+°C]//g' | awk -F. '{print $1}')
# 转换为毫摄氏度
if [ ! -z "$CURRENT_TEMP" ]; then
CURRENT_TEMP=$((CURRENT_TEMP * 1000))
fi
fi

# 转换为摄氏度显示
if [ ! -z "$CURRENT_TEMP" ] && [ "$CURRENT_TEMP" -gt 1000 ]; then
TEMP_C=$((CURRENT_TEMP / 1000))
else
TEMP_C=$CURRENT_TEMP
fi

# 温度控制逻辑
if [ ! -z "$CURRENT_TEMP" ] && [ "$CURRENT_TEMP" -gt $TEMP_THRESHOLD ]; then
# 温度超过阈值,开启风扇
echo $FAN_ON_STATE | sudo tee /sys/class/thermal/cooling_device4/cur_state > /dev/null
FAN_STATE="开启"
else
# 温度低于阈值,关闭风扇
echo $FAN_OFF_STATE | sudo tee /sys/class/thermal/cooling_device4/cur_state > /dev/null
FAN_STATE="关闭"
fi

# 显示状态
clear
echo "=== 智能风扇控制 ==="
echo "当前温度: ${TEMP_C}°C"
echo "风扇状态: ${FAN_STATE}"
echo "阈值: 30°C"
echo "下次检查: ${CHECK_INTERVAL}秒后"
echo "按 Ctrl+C 停止"

sleep $CHECK_INTERVAL
done

ubuntu 20.04 redroid 踩坑日记

发表于 2025-07-02 | 分类于 逆向

我有一台 2核2G 的腾讯云机器, 想使用这台机器测试一下, 看能不能跑起来redroid

1
2
3
4
5
6
7
8
sudo docker run -itd --rm --memory-swappiness=0 \
--privileged --pull always \
-v /data:/data \
-p 5555:5555 \
docker-0.unsee.tech/redroid/redroid:11.0.0-latest \
androidboot.hardware=mt6891 ro.secure=0 ro.boot.hwc=GLOBAL ro.ril.oem.imei=861503068361145 ro.ril.oem.imei1=861503068361145 ro.ril.oem.imei2=861503068361148 ro.ril.miui.imei0=861503068361148 ro.product.manufacturer=Xiaomi ro.build.product=chopin \
redroid.width=720 redroid.height=1280 \
redroid.gpu.mode=guest

启动完之后, 执行 adb connect 127.0.0.1:5555 发现是可以正常连接的. 可以进入到 手机的 shell 终端.

然后我在自己的电脑上 执行 adb connect xx.xx.xxx.xxx:5555 卡了几秒钟, 然后显示 offline. 在这里踩坑踩了两天.
然后我又在另外两台 ubuntu 主机上 安装 adb 1.0.39, 发现也是可以正常进入 手机shell 终端的. 于是我只能怀疑是自己本地的 adb 版本原因。
找到各种方法, 下载 adb 1.0.39 发现还是同样的问题. 并且 执行 adb shell 程序会一直卡住, 没有任务输出 也没有结束。 并且 我发现我的C盘。只剩下 15G了, 之前还有200G,

于是我问了 deepseek, 它让我执行 kill server, 结果 kill server 也卡住, 我又继续问,他是这么回答的
img_11

1
2
3
sudo pkill -9 adb         # 强制结束ADB客户端
sudo pkill -9 adb_server # 结束ADB服务进程
sudo pkill -9 adbd # 结束设备端守护进程(如有)

然后我执行了这三行, 确实, 我的c盘的空间没有持续的往下降. 基本上1分钟不到就几百M 没了.

然后我按照提示查看了一下 /tmp/adb.1000.log 文件, 发现这个文件 208G
tail -f /tmp/adb.1000.log

显示 “adb : sysdeps_unix.cpp:125 network_peek error: Invalid argument”

我拿这个问题问 deepseek, 它的回答是网络原因, 我突然想到本地似乎开启了魔法, 我关掉魔法试试。 果然可以了.

执行 scrcpy.exe 发现也可以直接显示 android 内容了

scrcpy 下载地址

img_11

由于我部署 redroid 的机器配置很低, 所以只显示了一个界面, 其他的一些app 没有加载, 更不要谈安装app,进行测试了。
不过整体上算是体验了一下 redroid 部署云手机. 算是初体验, 算比较成功, 后面打算玩一下开发板(rock5b, 香橙派), 看能否过风控, 正常刷xhs, dy.

哈哈哈哈哈哈 被我找到了根本原因, 为何其他服务器上就可以 正常 adb connect , 本地却不行, 并不是魔法的原因, 也不是adb 版本39和 41 的差别,
而是公司网络的原因, 我自己用手机给电脑开了个热点, 手机使用移动数据流量上网. 手机就可以正常 connect remote_ip:5555 了.

无语子啊。。。。。。

贴下一些工具的链接以及参考帖子

1
2
# https://github.com/barry-ran/QtScrcpy/releases/tag/v3.2.0
# https://zhaoyang.xlog.app/redroidmd?locale=zh

某app rsa 算法逆向踩坑记录

发表于 2025-06-26 | 分类于 逆向
抓包

img_11

利用 charles 的 compose 功能 修改一个字符, 发现 403. 但是可以repeat, 但几分钟后 repeat 照样 403, 说明后台校验时间

jadx 全局搜索

img_11

进入 this.b.a 看看

img_11

是个接口, 查看交叉引用.
img_11

第一个很可疑, 我们进入看看

img_11

可以看到, 这个方法就是具体实现.

简单分析了一下, 其中 bytes 就是 时间 + url 路径 + app_type + version
关键函数是 e71.a.a, 我们进入这个函数看看.

img_11

frida 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
55
56
57
58
59
60
function getJavaClassName(obj) {
return Java.cast(obj, Java.use("java.lang.Object")).getClass().getName();
}


Java.perform(function () {
var Base64 = Java.use("android.util.Base64");

var TargetClass = Java.use("e71");

TargetClass.a.overload("java.security.PrivateKey", "[B").implementation = function (key22, data) {
console.log("=== Hooked method a(PrivateKey, byte[]) ===");

// 打印 data
var dataHex = hexdump(data);
var dataBase64 = Base64.encodeToString(data, 0);

var StringClass = Java.use("java.lang.String");
var dataStr = StringClass.$new(data, "UTF-8");

console.log("[*] Data (hex):", dataHex);
console.log("[*] Data (base64):", dataBase64);
console.log(111)
console.log("[*] Data (string):", dataStr.toString());
console.log(111)

// 打印 key 信息
console.log("[*] PrivateKey class:", getJavaClassName(key22));

try {
var RSAPrivateKey = Java.use("java.security.interfaces.RSAPrivateKey");
if (RSAPrivateKey.class.isInstance(key22)) {
var castKey = Java.cast(key22, RSAPrivateKey);
var encoded = castKey.getEncoded();
var keyBase64 = Base64.encodeToString(encoded, 0);
console.log("[+] PrivateKey (Base64):", keyBase64);
} else {
console.log("[-] Not an RSAPrivateKey instance.");
}
} catch (e) {
console.log("[-] Exception extracting key:", e);
}

// 调用原函数
var result = this.a(key22, data);

// 打印签名结果
var resultBase64 = Base64.encodeToString(result, 0);
console.log("[+] Signature (base64):", resultBase64);
console.log("=========================================");

return result;
};

function hexdump(bytes) {
return Array.prototype.map.call(Java.array('byte', bytes), function (b) {
return ('00' + (b & 0xff).toString(16)).slice(-2);
}).join(' ');
}
});

注意这里有两个坑, 一个是如何打印 privatekey 的问题, 另外一个是查看类型的问题, 总是 not a function, 我记得之前frida 还可以用

obj.getClass().getName() 来查看一个对象的类型的, 但是这个样本就是 not a function, 然后我降frida-server版本, 从 frida-server 16.6.6,
降为 frida-server 14.2.18, 还是 not a function, 我问了下chatgpt 和 deepseek 是这么解答的

img_11

我们再次打印 privatekey 的类型

PrivateKey class: com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey

然后交给chatgpt 问gpt 这个类型要怎么打印私钥.
结合 gpt 给出的答案, 我们整合一下代码, 最终的代码如下

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
55
56
57
58
59
function getJavaClassName(obj) {
return Java.cast(obj, Java.use("java.lang.Object")).getClass().getName();
}


Java.perform(function () {
var Base64 = Java.use("android.util.Base64");
console.log(1222)

// 替换成你的实际类名,比如 com.example.MyClass
var TargetClass = Java.use("e71");

// Hook public final byte[] a(PrivateKey key, byte[] data)
TargetClass.a.overload("java.security.PrivateKey", "[B").implementation = function (key22, data) {
console.log("=== Hooked method a(PrivateKey, byte[]) ===");

// 打印 data
var dataHex = hexdump(data);
var dataBase64 = Base64.encodeToString(data, 0);

var StringClass = Java.use("java.lang.String");
var dataStr = StringClass.$new(data, "UTF-8");

console.log("[*] Data (hex):", dataHex);
console.log("[*] Data (base64):", dataBase64);
console.log(111)
console.log("[*] Data (string):", dataStr.toString());
console.log(111)

// 打印 key 信息
console.log("[*] PrivateKey class:", getJavaClassName(key22));

try {
const Base64 = Java.use("android.util.Base64");
const encoded = Java.cast(key22, Java.use("java.security.Key")).getEncoded();
const keyBase64 = Base64.encodeToString(encoded, 0);
console.log("[+] PrivateKey PKCS#8 (Base64):");
console.log(keyBase64);
} catch (e) {
console.log("[-] Exception dumping key:", e);
}

// 调用原函数
var result = this.a(key22, data);

// 打印签名结果
var resultBase64 = Base64.encodeToString(result, 0);
console.log("[+] Signature (base64):", resultBase64);
console.log("=========================================");

return result;
};

function hexdump(bytes) {
return Array.prototype.map.call(Java.array('byte', bytes), function (b) {
return ('00' + (b & 0xff).toString(16)).slice(-2);
}).join(' ');
}
});

我们再次 frida hook 一下,结果如下
img_11

可以看到 私钥已经出来了, 剩下的就是如何 使用私钥进行 rsa sha256签名了, 下面给出 Java 代码

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
55
56
57
58
59
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;


class MyClass {
public static void main(String[] args) throws Exception {
// 假设你已经有 PrivateKey 对象
PrivateKey privateKey = loadPrivateKey(); // 你需要从文件或 Base64 解析

//String data = "hello world";
String data = "1750927494\n/graphql/v2\nXXX-xxxxxxx\n11.31.0\n";
byte[] dataBytes = data.getBytes("UTF-8");

// 创建 SHA256withRSA 签名对象
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(dataBytes);
byte[] signed = signature.sign();

// 输出 Base64 签名结果
String signatureBase64 = Base64.getEncoder().encodeToString(signed);
System.out.println("Signature (Base64): " + signatureBase64);
}

// 示例:从 PKCS#8 Base64 字符串中加载私钥
public static PrivateKey loadPrivateKey() throws Exception {
String base64Key =
"MIIEvAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxx==";

// 用 MIME 解码器自动忽略换行
byte[] keyBytes = Base64.getMimeDecoder().decode(base64Key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
return KeyFactory.getInstance("RSA").generatePrivate(keySpec);
}
}

然后运行 结果如下

img_11

然后用 java 生成的结果, 替换 charles 中的请求的加密参数. 发现可以成功获取到数据, 到此基本就成功了.

如何用 python 还原一份呢, 下面给出代码. 已下代码经过验证, 可成功通过校验.

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
55
56
57
58
59
60
61
62
63
64
65
66
67
import base64
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend


def load_private_key():
base64_key = """
MIIEvXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXX=="""

# 移除空白和换行
base64_key = "".join(base64_key.split())

# 解码Base64并加载私钥
key_bytes = base64.b64decode(base64_key)
private_key = serialization.load_der_private_key(
key_bytes,
password=None,
backend=default_backend()
)
return private_key


def main():
# 加载私钥
private_key = load_private_key()

# 准备要签名的数据
data = "1750929449\n/graphql/v2\nXXXX-XXXXX\n11.31.0\n"
data_bytes = data.encode('utf-8')

# 使用SHA256withRSA进行签名
signature = private_key.sign(
data_bytes,
padding.PKCS1v15(),
hashes.SHA256()
)

# 输出Base64编码的签名
signature_base64 = base64.b64encode(signature).decode('utf-8')
print("Signature (Base64):", signature_base64)


if __name__ == "__main__":
main()

python 需要安装 cryptography

1
$ python3 -m pip install cryptography -i https://pypi.tuna.tsinghua.edu.cn/simple

通过私钥 进行签名, 使用的是 SHA256withRSA

改为 python 后,同样也可以生成加密结果 并且可以通过校验.

总结
  • 遇到的核心问题, getClass().getName() 会报错 not a function, 可能是由于android 高版本的优化问题. 并不是 frida-server 和 frida 以及 frida-tools 的问题.
  • privateKey 如何打印的问题, 上面已经给出答案. 还有些是通过 keyStore 这种, 这种导出就很麻烦.
  • python3.8 安装 frida 14.2.18 会遇到 frida-14.2.18-py3.8-linux-x86_64.egg 问题, 直接下载 放到指定位置就好.
  • 关于 RSA private, 或者 public key 也可以考虑 hook base64 的 decode 方法, 一般公钥要base64 解码后然后加载字节数据.
收获

在分析这个样本的过程中, 想借助一些文章, 发现了一些站点, 貌似可以低成本下载文档。

1
2
http://toolman.dedyn.io:9192/#/main/csdnPaper
https://github.com/bigintpro/csdn_downloader

充值了一块钱, 结果是个垃圾文章, 骗加公众号的, 无语子.

另外记录一下本人使用的 frida稳定的版本

1
2
3
4
5
6
7
8
9
10
11
12
pip install frida==14.2.18
pip install frida-tools==9.2.5
pip install objection==1.11.0

# 下面是本人使用到的 objection 的脚本, 这里记录一下
objection -g com.xxxxxxx.android explore -P ~/.objection/plugins
plugin wallbreaker objectsearch com.xxxxxxx.android.internal.auth.signing.util.RSASigner
plugin wallbreaker objectdump 0x4142 --fullname


# http://littleshark.space/2024/08/25/Frida%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/Frida%E4%BD%BF%E7%94%A8%E5%A4%A7%E5%85%A8/
# https://bbs.kanxue.com/thread-277929.htm
123>

27 日志
2 分类
RSS
© 2026 chilly
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.3