babyapk
首先分析了下java层的东西,然后发现和平常做的安卓不太一样,搜索后发现这是使用Flutter框架写的安卓apk,所以从网上找了下资料后发现可以使用blutter工具,具体的使用在此不再详说,网上有很多详细资料,在使用该工具初步解析apk后获得如下文件。


其中的main.dart可以说已经看清了该apk的主要逻辑。

该test函数可以轻易看到和验证有关的大量逻辑。
在下面发现最主要的是调用了 m3N4B5V6()函数进行判断。

右边的注释则说明了该函数所属的package。
进而找到simple.dart


接着跟进。

在这里我一度思路中断,因为我对Rust以及FFI调用的实现并不了解。
但是我注意到其中大量出现的API和Simple字样,于是在IDA中进行搜索发现该字符。

向上查看交叉引用发现了加密函数,
同时从加密函数这里继续向上查看引用多次最终索引到了这里。

这里是我之前搜索过m3n4b5v6分析过的函数,但是由于其中内部逻辑很多很乱,我实在没有分析下去,才转战dart文件去分析。除去前面这些过程实际上我还对native层的这些函数包括app.so内的一些和交互有关以及可疑的函数进行了多次fridaHOOK,但也成效甚微,不过还好总算找到加密逻辑处了。
然后这里也是因为之前HOOK时发现很多函数没反应于是猜测有长度检测,不断改变长度查看HOOK情况得到长度为0x2d,{}内为36位。

分析加密函数,倒着分析,得到该后半部分大致逻辑,判断为纯纯的z3.

用z3约束后发现约束出的数组都是可显字符,即32e750c8fb214562af22973fb5176b9c,猜测离flag很接近了。
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 | from z3 import *# 声明 v58 数组,每个变量为 16 位for j in range(4): v58 = [BitVec(f'v58[{i}]', 32) for i in range(8)] # 假设有8个变量 # 密文数组 cmp = [ 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() # 添加变量的范围限制 (0 <= num <= 65535) for i in range(8): s.add(v58[i] >= 0, v58[i] <= 0x10FFFF) # 添加约束条件 num2 = v58[2] num3 = v58[3] num0 = v58[0] num1 = v58[1] num4 = v58[4] num5 = v58[5] num6 = v58[6] num7 = v58[7] # 计算公式的约束条件 s.add(num7 + num1 * num3 * num5 - (num0 + num6 + num2 * num4) == cmp[0+j*8]) s.add(num3 - num4 - num0 * num5 + num7 * num1 + num2 + num6 == cmp[1+j*8]) s.add(num0 * num5 - (num4 + num7 * num1) + num2 + num6 * num3 == cmp[2+j*8]) s.add(num1 + num4 * num0 - (num7 + num2) + num6 * num5 * num3 == cmp[3+j*8]) s.add(num5 * num3 + num1 + num2 * num4 - (num6 + num7 * num0) == cmp[4+j*8]) s.add(num0 * num5 + num1 * num3 + num2 - (num6 + num4 * num7) == cmp[5+j*8]) s.add(num7 - num1 + num2 * num5 + num6 - num0 * num4 * num3 == cmp[6+j*8]) # 最后一轮的约束 s.add(num3 - num7 - (num1 + num5) + num4 * num0 + num6 * num2 == cmp[7+j*8]) # 求解 if s.check() == sat: model = s.model() v58_values = [model[v58[i]].as_long() for i in range(8)] print("数组解是:", v58_values) else: print("没有解。") |

这种逻辑的似乎涉及到编码转化,不影响flag的值。
这里发现了对-的约束,于是再根据很可显的字符串的长度为32,立马想到有四个-插在中间。

思考后感觉z3不好写而且情况也不多,于是直接写了穷举的爆破脚本。
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 | from itertools import combinations# 原始字符串original_string = "32e750c8fb214562af22973fb5176b9c"# 定义用于验证的 byte 数组(byte_18E46)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, 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 validate_hyphen_positions(input_str): byte = byte_18E46 input_bytes = [ord(c) for c in input_str] # 模拟你提供的验证逻辑 v2 = byte[input_bytes[0]] if v2 == 36: return False v3 = byte[input_bytes[v2]] + v2 if v3 == 36: return False v4 = v3 + byte[input_bytes[v3]] if v4 == 36: return False v5 = v4 + byte[input_bytes[v4]] if v5 == 36: return False v6 = v5 + byte[input_bytes[v5]] if v6 == 36: return False v7 = v6 + byte[input_bytes[v6]] if v7 == 36: return False v8 = v7 + byte[input_bytes[v7]] if v8 == 36: return False v9 = v8 + byte[input_bytes[v8]] if v9 == 36: return False v10 = input_bytes[v9] if v10 != ord('-'): return False v12 = v9 + byte[input_bytes[v9]] if v12 == 36: return False v13 = v12 + byte[input_bytes[v12]] if v13 == 36: return False v14 = v13 + byte[input_bytes[v13]] if v14 == 36: return False v15 = v14 + byte[input_bytes[v14]] if v15 == 36: return False v16 = v15 + byte[input_bytes[v15]] if v16 == 36: return False v18 = input_bytes[v16] if v18 != ord('-'): return False v20 = v16 + byte[input_bytes[v16]] if v20 == 36: return False v21 = v20 + byte[input_bytes[v20]] if v21 == 36: return False v22 = v21 + byte[input_bytes[v21]] if v22 == 36: return False v23 = v22 + byte[input_bytes[v22]] if v23 == 36: return False v24 = v23 + byte[input_bytes[v23]] if v24 == 36: return False v25 = input_bytes[v24] if v25 != ord('-'): return False v27 = v24 + byte[input_bytes[v24]] if v27 == 36: return False v28 = v27 + byte[input_bytes[v27]] if v28 == 36: return False v29 = v28 + byte[input_bytes[v28]] if v29 == 36: return False v30 = v29 + byte[input_bytes[v29]] if v30 == 36: return False v31 = v30 + byte[input_bytes[v30]] if v31 == 36: return False v32 = input_bytes[v31] if v32 != ord('-'): return False return True# 生成插入 '-' 的位置的组合positions = list(combinations(range(len(original_string) + 1), 4)) # 选择 4 个插入位置# 计数器count = 0valid_count = 0 # 成功验证的组合计数器# 遍历所有组合for pos in positions: temp_str = original_string # 插入时要注意位置的偏移,每次插入后,字符串长度增加 for i, p in enumerate(pos): temp_str = temp_str[:p + i] + '-' + temp_str[p + i:] # 插入 '-' 并调整位置索引 # 验证插入的 '-' 是否符合条件 if validate_hyphen_positions(temp_str): print(f"Valid combination: {temp_str}") valid_count += 1 # 计数通过验证的组合 # 计数 count += 1# 打印总次数print(f"Total combinations: {count}")print(f"Total valid combinations: {valid_count}") |
最终Flag:ByteCTF{32e750c8-fb21-4562-af22-973fb5176b9c}
ByteBuffer
根据题目提示了解了下flatbuffer,大致明白就是把数据以某种形式序列化那种?转化为一维的数组这样子。
然后用010打开。
发现有很多的Edge,Dot字样

所以大致能猜到这些线和点能画出来Flag。
于是将dot和Edge的数据分别提取一份喂给Gpt,然后它成功猜测到可能的数据结构:进而提取了所有的数据

一开始Edge的分析成了两个坐标,后来才发现它的分析的起始坐标很有规律,于是猜到了是代表的下面的点的序号及之间的连接。
遂训练AI写出脚本解出。
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 | import matplotlib.pyplot as plt# 点的坐标数据dot_coordinates = [ (75, 75),(25, 75),(75, 25),(25, 25),(25, 125),(75, 125),(100, 75),(100, 25),(150, 25),(150, 75), (100, 125),(150, 125),(175, 75),(175, 25),(225, 25),(225, 75),(225, 125),(250, 75),(250, 25),(300, 25), (300, 75),(250, 125),(300, 125),(325, 75),(325, 25),(375, 75),(375, 25),(375, 125),(400, 75),(400, 25), (450, 25),(450, 75),(400, 125),(450, 125),(475, 75),(475, 25),(475, 125),(525, 75),(550, 75),(550, 25), (600, 25),(600, 75),(550, 125),(600, 125),(625, 75),(625, 25),(675, 25),(675, 75),(625, 125),(675, 125), (700, 75),(700, 25),(750, 25),(750, 75),(750, 125),(700, 125),(775, 75),(775, 25),(825, 25),(825, 75), (775, 125),(825, 125),(850, 75),(850, 25),(900, 25),(900, 75),(850, 125),(900, 125),(925, 75),(925, 25), (975, 25),(975, 75),(925, 125),(975, 125),(1000, 75),(1000, 25),(1050, 25),(1050, 75),(1000, 125),(1050, 125), (1075, 75),(1075, 25),(1125, 25),(1125, 75),(1125, 125),(1075, 125),(1150, 75),(1150, 25),(1200, 25),(1200, 75), (1200, 125),(1225, 75),(1225, 25),(1225, 125),(1275, 75),(1300, 75),(1300, 25),(1350, 25),(1350, 75),(1300, 125), (1350, 125),(1375, 75),(1375, 25),(1425, 25),(1425, 75),(1375, 125),(1425, 125),(1450, 75),(1450, 25),(1500, 25), (1500, 75),(1450, 125),(1500, 125),(1525, 75),(1525, 25),(1575, 25),(1575, 75),(1525, 125),(1575, 125),(1600, 75)]# 边的连接关系 (基于点的序号,序号从0开始)edges = [ (119, 117), (119, 118), (117, 114), (116, 115), (115, 114), (113, 111), (113, 112), (112, 108), (111, 108), (110, 109), (109, 108), (107, 105), (107, 106), (106, 102), (105, 102), (105, 104), (104, 103), (103, 102), (101, 99), (101, 100), (99, 96), (98, 97), (97, 96), (94, 92), (93, 92), (91, 90), (90, 89), (89, 88), (86, 81), (86, 85), (85, 84), (84, 83), (83, 82), (82, 81), (80, 78), (80, 79), (78, 75), (78, 77), (77, 76), (76, 75), (74, 73), (73, 69), (72, 69), (72, 71), (71, 70), (68, 66), (68, 67), (66, 63), (66, 65), (65, 64), (64, 63), (62, 60), (62, 61), (61, 57), (60, 57), (59, 58), (58, 57), (56, 51), (56, 55), (55, 54), (54, 53), (53, 52), (52, 51), (50, 48), (50, 49), (48, 45), (47, 46), (46, 45), (44, 42), (44, 43), (43, 39), (42, 39), (42, 41), (41, 40), (40, 39), (37, 35), (36, 35), (34, 33), (33, 29), (32, 29), (32, 31), (31, 30), (28, 26), (27, 26), (26, 24), (25, 24), (23, 21), (23, 22), (21, 18), (20, 19), (19, 18), (17, 16), (16, 15), (15, 14), (12, 11), (11, 7), (10, 7), (10, 9), (9, 8), (6, 1), (6, 5), (4, 3), (3, 1), (2, 1)]# 创建图形plt.figure(figsize=(12, 12))# 绘制点for i, (x, y) in enumerate(dot_coordinates): plt.scatter(x, y, c='blue', zorder=2) plt.text(x, y, f"{i+1}", fontsize=8, ha='right', zorder=3)# 绘制连接关系for start, end in edges: x_values = [dot_coordinates[start-1][0], dot_coordinates[end-1][0]] y_values = [dot_coordinates[start-1][1], dot_coordinates[end-1][1]] plt.plot(x_values, y_values, 'k-', zorder=1)# 优化显示plt.title("Optimized Dot and Edge Connections")plt.xlabel("X Coordinate")plt.ylabel("Y Coordinate")plt.grid(True)plt.axis('equal') # 保持比例相同plt.show() |

发现图还有点问题,第三个一看就很有特点,是7,于是镜像翻转

flag:ByteCTF{327542185069230715865}