2024 ByteCTF re wp
babyapk
jadx打开,我们可以发现是flutter逆向,然后打包出资源,用blutter来搞(因为reflutter和flutter逆向助手都已经停止更新),
可以直接从github上面git下来(代理环境下),windows或者linux都可以,但因为我的linux上面的g++版本小于13,所以我用的是windows,下面是项目源码
GitHub - worawit/blutter: Flutter Mobile Application Reverse Engineering Tool
然后在readme.md上面也说了怎么使用,这里我就只说一下一些可能遇到的报错,
-- Configuring incomplete, errors occurred!
Traceback (most recent call last):
File "D:\android\flutter\blutter\blutter.py", line 235, in <module>
main(args.indir, args.outdir, args.rebuild, args.vs_sln, args.no_analysis)
File "D:\android\flutter\blutter\blutter.py", line 217, in main
main2(libapp_file, libflutter_file, outdir, rebuild_blutter, create_vs_sln, no_analysis)
File "D:\android\flutter\blutter\blutter.py", line 208, in main2
build_and_run(input)
File "D:\android\flutter\blutter\blutter.py", line 193, in build_and_run
cmake_blutter(input)
File "D:\android\flutter\blutter\blutter.py", line 145, in cmake_blutter
subprocess.run([CMAKE_CMD, '-GNinja', f'-DCMAKE_MAKE_PROGRAM={NINJA_CMD}', '-B', builddir,
File "D:\python3.8\lib\subprocess.py", line 512, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['C:/Program Files/CMake/bin/cmake.exe', '-GNinja', '-DCMAKE_MAKE_PROGRAM=C:/Game/ninja.exe', '-B', 'D:\\android\\flutter\\blutter\\build\\blutter_dartvm3.5.0_android_arm64', '-DDARTLIB=dartvm3.5.0_android_arm64', '-DNAME_SUFFIX=', '-DCMAKE_BUILD_TYPE=Release', '--log-level=NOTICE', '-DHAS_RECORD_TYPE=1', '-DNO_METHOD_EXTRACTOR_STUB=1']' returned non-zero exit status 1.
这个报错是说cmake的命令的执行返回了非零状态码,也就是遇到了一些环境依赖问题
所以可以用vs2022的命令行来执行脚本,这样cmake和ninja就不会出现问题,
打开x64 Native Tools Command Prompt,直接搜索就行,

然后blutter.py运行后,会出现下图的文件

- asm文件夹里面存放dart文件的反编译结果
- ida_script里面存放着可以在ida使用的脚本,用来恢复so文件的符号表
- objs.txt和pp.txt有对象池的一些东西,逆向的时候作用不大
- frida脚本是工具自动编写的,可以用来hook so文件的一些函数(需要自己替换偏移)
然后先打开asm文件夹里面babyapk文件夹的main.dart,用vscord打开就行

首先就是审到这个,看到了用户输入后的逻辑,是先验证是否是’ByteCTF{’开头以及’}’结尾,继续审计代码可以发现字符串长度为43,并且通过frida hook几个地址时,会发现在m3N4B5V6这个函数这里有一些输出,
ida9(可以反汇编arm架构)打开libapp.so

运行重命名脚本后,恢复符号表,搜索m3N4B5V6

发现逻辑混乱,但还是出现了许多simple或者src的字符
于是回去看dart

然后会发现具体m3N4B5V6的实现需要在[package:babyapk/src/rust/api/simple.dart] ::m3N4B5V6这个里面去找,还是vscord打开simple.dart,

又发现提示这个dart文件,

这个dart主要实现一个与 Rust 库的交互接口,并且还有一些utf8编码解码函数,猜测加密会在flutter与rust交互的so里面,
也就是librust_lib_babyapk.so里面,于是ida打开,又出现了src/api/simple的字样,直接点进去


发现了一段数据,猜测密文,直接交叉引用,

果然是加密逻辑,审一审,先是一长串的判断’-’的位置是否在输入字符串的指定位置,然后是检查去掉了‘-’的字符串是否满足一系列条件,所以可以先z3解出未带’-’的字符串,然后再抄一下逻辑,爆破出‘-’的位置,反正只有4个‘-’,也许猜也可以,完整脚本如下:
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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | from z3 import *import itertoolschar=['']*4for j in range(4): flag = [BitVec(f'flag[{i}]',32)for i in range(8)] data = [0x0001EE59, 0x0000022A, 0x00001415, 0x00040714, 0x000013E0, 0x000008B8, 0xFFFDCEA0, 0x0000313B, 0x0003D798, 0xFFFFFE6B, 0x00000C4E, 0x00023884, 0x0000008D, 0x00001DB4, 0xFFFC1328, 0x00001EAC, 0x00043C64, 0x0000142B, 0xFFFFF622, 0x00023941, 0xFFFFEF6D, 0x0000120C, 0xFFFBD30F, 0x00001EBE, 0x00045158, 0xFFFFEF66, 0x00001D3F, 0x0004C46B, 0xFFFFF97A, 0x00001BFD, 0xFFFBA235, 0x00001ED2] s=Solver() for i in range(8): s.add(flag[i]>=0,flag[i]<=0x10FFFF) v45 = flag[2] v44 = flag[3] v46 = flag[0] v47 = flag[1] v48 = flag[4] v49 = flag[5] v50 = flag[6] v51 = flag[7] v52 = v46 * v49 v53 = v48 * v46 v54 = v44 - v51 - (v47 + v49) s.add(v51 + v47 * v44 * v49 - (v46 + v50 + v45 * v48) == data[0+j*8]) s.add(v44 - v48 - v46 * v49 + v51 * v47 + v45 + v50 == data[1+j*8]) s.add(v52 - (v48 + v51 * v47) + v45 + v50 * v44 == data[2+j*8]) s.add(v47 + v48 * v46 - (v51 + v45) + v50 * v49 * v44 ==data[3+j*8]) s.add(v49 * v44 + v47 + v45 * v48 - (v50 + v51 * v46) == data[4+j*8]) s.add(v52 + v47 * v44 + v45 - (v50 + v48 * v51) == data[5+j*8]) s.add(v51 - v47 + v45 * v49 + v50 - v53 * v44 == data[6+j*8]) s.add(v54 + v53 + v50 * v45 ==data[7+j*8]) if s.check()==sat: m=s.model() inp = [m.evaluate(flag[i]).as_long() for i in range(8)] char[j]= ''.join([chr(inp[i]) for i in range(8)]) # print(inp)byte_18E46 = [ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]def check(input_str): a1=[ord(i) for i in input_str] v2 = byte_18E46[a1[0]] if v2 == 36: return 0 v3 = byte_18E46[a1[v2]] + v2 if v3 == 36: return 0 v4 = v3 + byte_18E46[a1[v3]] if v4 == 36: return 0 v5 = v4 + byte_18E46[a1[v4]] if v5 == 36: return 0 v6 = v5 + byte_18E46[a1[v5]] if v6 == 36: return 0 v7 = v6 + byte_18E46[a1[v6]] if v7 == 36: return 0 v8 = v7 + byte_18E46[a1[v7]] if v8 == 36: return 0 v9 = v8 + byte_18E46[a1[v8]] if v9 == 36: return 0 v10 = a1[v9] if v10 != ord('-'): return 0 v12 = v9 + byte_18E46[a1[v9]] if v12 == 36: return 0 v13 = v12 + byte_18E46[a1[v12]] if v13 == 36: return 0 v14 = v13 + byte_18E46[a1[v13]] if v14 == 36: return 0 v15 = v14 + byte_18E46[a1[v14]] if v15 == 36: return 0 v16 = v15 + byte_18E46[a1[v15]] if v16 == 36: return 0 v18 = a1[v16] if v18 != ord('-'): return 0 v20 = v16 + byte_18E46[a1[v16]] if v20 == 36: return 0 v21 = v20 + byte_18E46[a1[v20]] if v21 == 36: return 0 v22 = v21 + byte_18E46[a1[v21]] if v22 == 36: return 0 v23 = v22 + byte_18E46[a1[v22]] if v23 == 36: return 0 v24 = v23 + byte_18E46[a1[v23]] if v24 == 36: return 0 v25 = a1[v24] if v25 != ord('-'): return 0 v27 = v24 + byte_18E46[a1[v24]] if v27 == 36: return 0 v28 = v27 + byte_18E46[a1[v27]] if v28 == 36: return 0 v29 = v28 + byte_18E46[a1[v28]] if v29 == 36: return 0 v30 = v29 + byte_18E46[a1[v29]] if v30 == 36: return 0 v31 = v30 + byte_18E46[a1[v30]] if v31 == 36: return 0 v32 = a1[v31] if v32 != ord('-'): return 0 return 1 str=char[0]+char[1]+char[2]+char[3]table = list(itertools.combinations(range(len(str)+1),4))c=0success=0for i in table: tmp = str for i,j in enumerate(i): tmp = tmp[:j+i]+'-' + tmp[j+i:] if check(tmp): print("ByteCTF{"+f"{tmp}"+"}") |