nepctf_flutterpro

flutterpro

参考

https://github.com/worawit/blutter

Android-Flutter逆向 | LLeaves Blog

[原创]flutter逆向 ACTF native app-Android安全-看雪-安全社区|安全招聘|kanxue.com

吾爱破解安卓逆向入门教程《安卓逆向这档事》番外实战篇3-拨云见日之浅谈Flutter逆向_哔哩哔哩_bilibili

1
2
3
git clone https://github.com/worawit/blutter --depth=1
cd .\blutter\
python .\scripts\init_env_win.py

初始化一下

然后讲libapp和libflutter丢进新建的文件夹方便查找

1
python .\blutter.py ..\chall\lib\arm64-v8a\ .\output

image

最后会得到这些内容 其中的ida_script就可以用来恢复libapp的符号

image

js则是实例的frida模板

image

可以看到在没还原之前都是一坨 使用了脚本以后就好了很多

image

flutterpro

这个题就很逆天

image

blutter直接用不了 根据报错我们去看看extract_dart_info文件

image

炸掉是因为

image

section几乎都给抹除了 我们只能手动去算然后给程序填回去

ai分析以下这个代码是查找对应的sha256

image

直接搜字符串 跟过去

image

就找到了

image

image

image

image

我们也是一样的要去手算 当时这里我打晕了 我在app找了大半天才反应过来要去flutter里面找

image

1
3.8.1 (stable) (Wed May 28 00:47:25 2025 -0700) on "android_arm64"\x00

image

指定版本就行了上面的代码其实就是在拼接

image

image

使用ida的脚本文件恢复一下符号 ai分析一下

image

这里给了8*8的东西 修改一下数据类型

image

image

image

hook一下这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Java.perform(function () {
var so_module = Process.findModuleByName("libapp.so");
if (so_module === null) {
console.log("libapp.so not found!");
return;
}

var target = so_module.base.add(0x202D68);
console.log("[*] Hooking CMP W2, #0x80 at:", target);

Interceptor.attach(target, {
onEnter: function (args) {
var w2 = this.context.x2 & 0xFFFFFFFF;
console.log("[*] CMP W2, #0x80 about to execute");
console.log(" => W2 =", "0x" + w2.toString(16), "(", w2, ")");
}
});
});

image

正好两倍的关系

那么128的长度 外加下面的64的list 应该是进行了一些操作

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
while ( 1 )
{
v38 = *(v17 - 8);
*(v17 - 56) = n8_1;
if ( v30 <= *(*&v12 + 56LL) )
ArrayStub_32d270 = StackOverflowSharedWithoutFPURegsStub_32d378(
ArrayStub_32d270,
v23,
ArrayStub_32d270_2,
v38,
n8_1,
v26,
n8_2,
v28,
v29);
if ( n8_1 >= 8 )
break;
v26 = 8 * n8_1;
*(v17 - 48) = 8 * n8_1;
n8_2 = 0LL;
while ( 1 )
{
*(v17 - 24) = n8_2;
if ( v30 <= *(*&v12 + 56LL) )
StackOverflowSharedWithoutFPURegsStub_32d378(
ArrayStub_32d270,
v23,
ArrayStub_32d270_2,
v38,
n8_1,
v26,
n8_2,
v28,
v29);
if ( n8_2 >= 8 )
break;
v39 = *(ArrayStub_32d270_2 + 4 * n8_1 + 15) + (v14 << 32);
*(v17 - 40) = v39;
v40 = *(v38 + 19) + (v14 << 32);
MintSharedWithoutFPURegsStub_32d4f8 = 2 * (v26 + n8_2);
if ( v26 + n8_2 != MintSharedWithoutFPURegsStub_32d4f8 >> 1 )
{
MintSharedWithoutFPURegsStub_32d4f8 = AllocateMintSharedWithoutFPURegsStub_32d4f8(
ArrayStub_32d270_2,
v38,
n8_1,
v26,
n8_2,
v39,
v40);
*(MintSharedWithoutFPURegsStub_32d4f8 + 7) = v42;
}
*v30 = MintSharedWithoutFPURegsStub_32d4f8;
v30[1] = v40;
v43 = dart_core__StringBase::op_at_3090f4(MintSharedWithoutFPURegsStub_32d4f8, v23, ArrayStub_32d270_2, v38, n8_1);
Obj_Utf8Encoder@2a44c1_:____List(5)_[0__0x2__0__0x2__Null] = sub_7254EC6F98(
v43,
DartObjectPool->Obj_0x142d0,
v43,
DartObjectPool->Obj_0x14fd8,
v44,
v45,
v46,
v47);// Obj!Utf8Encoder@2a44c1 : {} List(5) [0, 0x2, 0, 0x2, Null]
if ( !(*(Obj_Utf8Encoder@2a44c1_:____List(5)_[0__0x2__0__0x2__Null] + 19) >> 1) )
{
v69 = RangeErrorSharedWithoutFPURegsStub_32d7c0(
0LL,
0LL,
Obj_Utf8Encoder@2a44c1_:____List(5)_[0__0x2__0__0x2__Null],
v49,
v50,
v51,
v52,
v53,
v54);
goto LABEL_46;
}
v56 = *(Obj_Utf8Encoder@2a44c1_:____List(5)_[0__0x2__0__0x2__Null] + 23);
v57 = *(v17 - 24);
v58 = 2 * v57;
if ( v57 != v58 >> 1 )
{
v58 = AllocateMintSharedWithoutFPURegsStub_32d4f8(v57, v56, v50, v51, v52, v53, v54);
*(v58 + 7) = v59;
}
v60 = 2 * v56;
v61 = *(v17 - 40);
v62 = *(v61 - 1) >> 12;
v55[1] = v58;
v55[2] = v61;
*v55 = v60;
(*(v10 + 8 * (v62 - 1377)))();
ArrayStub_32d270 = *(v17 - 24);
n8_2 = ArrayStub_32d270 + 1;
v38 = *(v17 - 8);
n8_1 = *(v17 - 56);
ArrayStub_32d270_2 = *(v17 - 32);
v26 = *(v17 - 48);
}
ArrayStub_32d270 = n8_1++;
ArrayStub_32d270_2 = *(v17 - 32);
}

这个也似乎也是一个8*8 应该是加载什么东西和我们的输入进行处理

image

这里v17-32应该就是我们8*8的东西 跟进去看看做了什么处理

image

ok 那么这整个函数应该就是处理加校验的地方

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
  while ( 1 )
{
if ( n8_3 >= 8 )
{
v18 = n8_2++;
v31 = *(v15 - 8);
v36 = *(v15 - 16);
n8_1 = *(v15 - 64);
ArrayStub_32d270_2 = *(v15 - 32);
v34 = *(v15 - 72);
goto LABEL_18;
}
v38 = *(ArrayStub_32d270_2 + 4 * n8_1 + 15) + (v12 << 32);
*(v15 - 40) = v38;
v39 = *(v38 - 1) >> 12;
*v25 = MintSharedWithoutFPURegsStub_32d4f8_1;
v25[1] = v38;
v40 = (*(v8 + 8 * (v39 - 4090)))();
v48 = *(v15 - 72);
v49 = *(v15 - 64);
*(v15 - 80) = v40;
if ( v49 >= v48 )
break;
v50 = *(*(v15 - 8) + 4LL * *(v15 - 64) + 15) + (v12 << 32);
v51 = *(v50 - 1) >> 12;
*v47 = 2LL * *(v15 - 24);
v47[1] = v50;
v52 = (*(v8 + 8 * (v51 - 4090)))();
v59 = *(v15 - 16);
*(v15 - 88) = v52;
v60 = *(v59 + 11) >> 1;
v61 = *(v15 - 24);
if ( v61 >= v60 )
goto LABEL_44;
v62 = *(*(v59 + 15) + (v12 << 32) + 4LL * *(v15 - 24) + 0xF) + (v12 << 32);
v63 = *(v62 - 1) >> 12;
*v58 = *(v15 - 48);
v58[1] = v62;
v64 = (*(v8 + 8 * (v63 - 4090)))();
v71 = *(v15 - 88);
v72 = v71 >> 1;
if ( (v71 & 1) != 0 )
v72 = *(v71 + 7);
v73 = v64 >> 1;
if ( (v64 & 1) != 0 )
v73 = *(v64 + 7);
v74 = v72 * v73;
v75 = *(v15 - 80);
v76 = v75 >> 1;
if ( (v75 & 1) != 0 )
v76 = *(v75 + 7);
v77 = 2 * (v76 + v74);
if ( v76 + v74 != v77 >> 1 )
{
v77 = AllocateMintSharedWithoutFPURegsStub_32d4f8(v76, v76 + v74, v65, v66, v67, v68, v69);
*(v77 + 7) = v78;
}
v79 = v77;
v80 = *(v15 - 40);
v81 = *(v80 - 1) >> 12;
v70[1] = *(v15 - 48);
v70[2] = v80;
*v70 = v79;
MintSharedWithoutFPURegsStub_32d4f8 = (*(v8 + 8 * (v81 - 1377)))();
n8_3 = *(v15 - 24) + 1LL;
v31 = *(v15 - 8);
v36 = *(v15 - 16);
n8_1 = *(v15 - 64);
n8_2 = *(v15 - 56);
ArrayStub_32d270_2 = *(v15 - 32);
MintSharedWithoutFPURegsStub_32d4f8_1 = *(v15 - 48);
v34 = *(v15 - 72);
LABEL_25:
*(v15 - 24) = n8_3;
if ( v25 <= *(v10 + 56) )
goto LABEL_42;
}

又是一个8*8的东西 应该就是数据的处理

image

ai猛猛分析 调试速度太慢了 直接fridahook

image

查看一下偏移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Java.perform(function(){
var so_module = Process.findModuleByName("libapp.so");
if (so_module === null) {
console.log("libapp.so not found!");
return;
}

var target = so_module.base.add(0x203858);
console.log("[*] Disassembling at:", target);

try {
let pc = ptr(target);
for (let i = 0; i < 5; i++) {
const inst = Instruction.parse(pc);
console.log(inst.address + ":\t" + inst.mnemonic + "\t" + inst.opStr);
pc = inst.next;
}
} catch (e) {
console.log("Error parsing instructions:", e);
}
})

image

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
Java.perform(function(){
var so_module = Process.findModuleByName("libapp.so");
if (so_module === null) {
console.log("libapp.so not found!");
return;
}

var target = so_module.base.add(0x203858);
console.log("[*] Disassembling at:", target);

// try {
// let pc = ptr(target);
// for (let i = 0; i < 5; i++) {
// const inst = Instruction.parse(pc);
// console.log(inst.address + ":\t" + inst.mnemonic + "\t" + inst.opStr);
// pc = inst.next;
// }
// } catch (e) {
// console.log("Error parsing instructions:", e);
// }



Interceptor.attach(target, {
onEnter: function (args) {
console.log("=== onEnter ===");
console.log("x0: " + this.context.x0);

console.log("x1: " + this.context.x1);
console.log("x2: " + this.context.x2);
console.log("x29 (fp): " + this.context.x29);
console.log("================");
}
});


})


// Java.perform(function () {
// var so_module = Process.findModuleByName("libapp.so");
// if (so_module === null) {
// console.log("libapp.so not found!");
// return;
// }

// var target = so_module.base.add(0x202D68);
// console.log("[*] Hooking CMP W2, #0x80 at:", target);

// Interceptor.attach(target, {
// onEnter: function (args) {
// var w2 = this.context.x2 & 0xFFFFFFFF;
// console.log("[*] CMP W2, #0x80 about to execute");
// console.log(" => W2 =", "0x" + w2.toString(16), "(", w2, ")");
// }
// });
// });

image

image

难绷

1
PS F:\frida-for-windows\frida-agent-example\android\nepctf> frida -U -f com.example.flutterpro -l .\flutter.js >data.xtx
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
Java.perform(function(){
var so_module = Process.findModuleByName("libapp.so");
if (so_module === null) {
console.log("libapp.so not found!");
return;
}

var target = so_module.base.add(0x203858);
console.log("[*] Disassembling at:", target);

// try {
// let pc = ptr(target);
// for (let i = 0; i < 5; i++) {
// const inst = Instruction.parse(pc);
// console.log(inst.address + ":\t" + inst.mnemonic + "\t" + inst.opStr);
// pc = inst.next;
// }
// } catch (e) {
// console.log("Error parsing instructions:", e);
// }



Interceptor.attach(target, {
onEnter: function (args) {
// console.log((this.context.x0&0xff)+"*"+this.context.x2);
console.log(this.context.x0&0xff+",");
}

});
})


// Java.perform(function () {
// var so_module = Process.findModuleByName("libapp.so");
// if (so_module === null) {
// console.log("libapp.so not found!");
// return;
// }

// var target = so_module.base.add(0x202D68);
// console.log("[*] Hooking CMP W2, #0x80 at:", target);

// Interceptor.attach(target, {
// onEnter: function (args) {
// var w2 = this.context.x2 & 0xFFFFFFFF;
// console.log("[*] CMP W2, #0x80 about to execute");
// console.log(" => W2 =", "0x" + w2.toString(16), "(", w2, ")");
// }
// });
// });

长度是512

1
key = [0x4, 0x6, 0x6, 0x7, 0x7, 0x6, 0x4, 0x4, 0xe, 0xf, 0x1, 0x5, 0x6, 0x5, 0x1, 0x3, 0x6, 0x5, 0x4, 0x7, 0x6, 0x7, 0x6, 0x7, 0x5, 0x3, 0x9, 0x4, 0x9, 0x5, 0xc, 0x5, 0x7, 0x6, 0x7, 0x6, 0x6, 0x7, 0x7, 0x7, 0x5, 0x1, 0x3, 0x5, 0xc, 0x2, 0x3, 0x4, 0x7, 0x6, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x2, 0xd, 0x3, 0x5, 0xe, 0xf, 0xf, 0x5, 0x4, 0x6, 0x6, 0x7, 0x7, 0x6, 0x4, 0x4, 0xe, 0xf, 0x1, 0x5, 0x6, 0x5, 0x1, 0x3, 0x6, 0x5, 0x4, 0x7, 0x6, 0x7, 0x6, 0x7, 0x5, 0x3, 0x9, 0x4, 0x9, 0x5, 0xc, 0x5, 0x7, 0x6, 0x7, 0x6, 0x6, 0x7, 0x7, 0x7, 0x5, 0x1, 0x3, 0x5, 0xc, 0x2, 0x3, 0x4, 0x7, 0x6, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x2, 0xd, 0x3, 0x5, 0xe, 0xf, 0xf, 0x5, 0x4, 0x6, 0x6, 0x7, 0x7, 0x6, 0x4, 0x4, 0xe, 0xf, 0x1, 0x5, 0x6, 0x5, 0x1, 0x3, 0x6, 0x5, 0x4, 0x7, 0x6, 0x7, 0x6, 0x7, 0x5, 0x3, 0x9, 0x4, 0x9, 0x5, 0xc, 0x5, 0x7, 0x6, 0x7, 0x6, 0x6, 0x7, 0x7, 0x7, 0x5, 0x1, 0x3, 0x5, 0xc, 0x2, 0x3, 0x4, 0x7, 0x6, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x2, 0xd, 0x3, 0x5, 0xe, 0xf, 0xf, 0x5, 0x4, 0x6, 0x6, 0x7, 0x7, 0x6, 0x4, 0x4, 0xe, 0xf, 0x1, 0x5, 0x6, 0x5, 0x1, 0x3, 0x6, 0x5, 0x4, 0x7, 0x6, 0x7, 0x6, 0x7, 0x5, 0x3, 0x9, 0x4, 0x9, 0x5, 0xc, 0x5, 0x7, 0x6, 0x7, 0x6, 0x6, 0x7, 0x7, 0x7, 0x5, 0x1, 0x3, 0x5, 0xc, 0x2, 0x3, 0x4, 0x7, 0x6, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x2, 0xd, 0x3, 0x5, 0xe, 0xf, 0xf, 0x5, 0x4, 0x6, 0x6, 0x7, 0x7, 0x6, 0x4, 0x4, 0xe, 0xf, 0x1, 0x5, 0x6, 0x5, 0x1, 0x3, 0x6, 0x5, 0x4, 0x7, 0x6, 0x7, 0x6, 0x7, 0x5, 0x3, 0x9, 0x4, 0x9, 0x5, 0xc, 0x5, 0x7, 0x6, 0x7, 0x6, 0x6, 0x7, 0x7, 0x7, 0x5, 0x1, 0x3, 0x5, 0xc, 0x2, 0x3, 0x4, 0x7, 0x6, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x2, 0xd, 0x3, 0x5, 0xe, 0xf, 0xf, 0x5, 0x4, 0x6, 0x6, 0x7, 0x7, 0x6, 0x4, 0x4, 0xe, 0xf, 0x1, 0x5, 0x6, 0x5, 0x1, 0x3, 0x6, 0x5, 0x4, 0x7, 0x6, 0x7, 0x6, 0x7, 0x5, 0x3, 0x9, 0x4, 0x9, 0x5, 0xc, 0x5, 0x7, 0x6, 0x7, 0x6, 0x6, 0x7, 0x7, 0x7, 0x5, 0x1, 0x3, 0x5, 0xc, 0x2, 0x3, 0x4, 0x7, 0x6, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x2, 0xd, 0x3, 0x5, 0xe, 0xf, 0xf, 0x5, 0x4, 0x6, 0x6, 0x7, 0x7, 0x6, 0x4, 0x4, 0xe, 0xf, 0x1, 0x5, 0x6, 0x5, 0x1, 0x3, 0x6, 0x5, 0x4, 0x7, 0x6, 0x7, 0x6, 0x7, 0x5, 0x3, 0x9, 0x4, 0x9, 0x5, 0xc, 0x5, 0x7, 0x6, 0x7, 0x6, 0x6, 0x7, 0x7, 0x7, 0x5, 0x1, 0x3, 0x5, 0xc, 0x2, 0x3, 0x4, 0x7, 0x6, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x2, 0xd, 0x3, 0x5, 0xe, 0xf, 0xf, 0x5, 0x4, 0x6, 0x6, 0x7, 0x7, 0x6, 0x4, 0x4, 0xe, 0xf, 0x1, 0x5, 0x6, 0x5, 0x1, 0x3, 0x6, 0x5, 0x4, 0x7, 0x6, 0x7, 0x6, 0x7, 0x5, 0x3, 0x9, 0x4, 0x9, 0x5, 0xc, 0x5, 0x7, 0x6, 0x7, 0x6, 0x6, 0x7, 0x7, 0x7, 0x5, 0x1, 0x3, 0x5, 0xc, 0x2, 0x3, 0x4, 0x7, 0x6, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x2, 0xd, 0x3, 0x5, 0xe, 0xf, 0xf, 0x5]

那么密文就是我们之前看到的那一坨rcnb解码一下

1
[3879, 4271, 4182, 4951, 4753, 2999, 3842, 6611, 4718, 5457, 5122, 5534, 5695, 3657, 4630, 7665, 4624, 4843, 4866, 5493, 5393, 3633, 4286, 7709, 4483, 5040, 4992, 5293, 5501, 3293, 4495, 7342, 4251, 5003, 4743, 5202, 5345, 3154, 4404, 7079, 3835, 4503, 4051, 4247, 4534, 2815, 3648, 5681, 4601, 5432, 5132, 5434, 5554, 3802, 4573, 7904, 4752, 5223, 5307, 5762, 5829, 3838, 4728, 7723]

最后z3解出flag