hgame

FastAndFrustrating

aot 之前闻所未闻的东西

image-20250220171222036

运行 直接退出了 有检测

image-20250220171324491

只要的函数位置

image-20250220171350798

这里就是检测的 这个是检测系统语言的 很明显是有问题的 修改一下转跳

image-20250220171732516

这两段就是终端的回显

image-20250220171931625

这里获取输入

随便搞点输入

image-20250220184345360

报错了根据信息有个frombase64的解码

image-20250220184443331

跟进调试一手

image-20250220185026634

这里就是报错的地方 这里报错的原因就是

image-20250220185055501

这里是判断base后面的== 但是数据是不对的 毕竟fake就写在那

image-20250220185211613

只能去字符串里面搞

image-20250220185516255

可以看到这里是进行base以后还有个gzip和json反序列化 难绷

现在要去找正确的字符串进行base解码

image-20250220185936520

就这个像点

image-20250220190528724

1
{"mat_a": [[1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2, -1, 0, -2, 4, -12, 16, 2, -21, -29, 11, -37, 3, 104, 64, 192], [0, 1, 1, 0, 2, 1, 1, 1, -1, 3, -1, -1, -1, 0, -3, 0, -6, 18, 6, -23, -25, 3, -21, -25, 26, 156, -229], [0, -1, 0, 0, 0, -2, 0, 1, 2, 1, 0, 3, -1, -6, 3, -7, 30, -34, -7, 50, 99, -69, 147, -30, -241, -236, 188], [1, 1, 3, 1, 7, -1, 3, 4, 2, 10, -2, 6, -6, -8, -6, -1, 1, 35, 10, -34, 13, -65, 75, -98, -51, 197, 83], [0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 2, 0, -1, 4, 1, -1, 10, 0, 0, -7, 31, -56, 78, -58, -106, 53, -62], [-1, -1, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, -3, 3, -6, 20, -21, -1, 29, 53, -35, 79, -23, -162, -90, -142], [0, 0, -1, 0, -1, 0, 0, -1, -1, -4, -2, 0, 1, -3, -2, 5, -16, 1, -1, 5, -48, 84, -116, 86, 148, -25, -72], [0, 1, 1, 0, -1, 1, 1, -1, -4, 0, -7, -2, 2, -13, -6, 0, -24, 5, 4, 14, -86, 151, -207, 132, 230, -30, -241], [0, 0, -2, 0, -1, 2, -1, -1, 0, -6, 4, -3, 1, 16, 0, 12, -26, 27, 0, -55, -75, 31, -94, 11, 192, 226, -94], [-1, -1, 0, 0, -2, -1, -1, 0, 0, 1, 2, -1, 1, 1, 6, -8, 24, -22, -1, 24, 63, -66, 112, -50, -180, -111, 37], [0, 0, 1, 0, 3, -1, 1, 3, 2, 5, 2, 2, -3, 1, 1, -6, 25, 2, 5, -10, 69, -119, 169, -134, -240, 124, -169], [0, 0, -2, -1, -3, 2, -2, -2, -1, -5, 3, -4, 3, 14, 2, 6, -24, 23, 4, -52, -86, 36, -114, 10, 234, 189, 62], [-2, 0, -1, 0, -5, 1, -2, -3, -4, -2, 3, -9, 6, 12, 8, -6, 8, -16, -1, 3, -4, -6, -1, -6, -39, -24, -244], [0, 0, -1, 0, -2, 1, -2, -1, 1, -3, 6, -2, 1, 15, 3, 7, -16, 26, 4, -56, -54, -13, -39, -39, 133, 221, 37], [0, 0, 0, 0, 0, 0, -1, 0, 2, 0, 5, -2, 1, 11, 4, -2, 21, -17, -9, 6, 73, -100, 151, -79, -212, -50, 68], [0, 0, 0, 0, 1, -1, 1, 0, 1, 1, -1, 2, -1, -4, 0, -2, 13, -17, -5, 29, 49, -23, 64, 2, -116, -135, 68], [0, 0, -1, -1, -5, 1, -2, -3, -2, -5, 0, -4, 5, 2, 3, -2, -2, -24, -6, 25, -17, 54, -70, 70, 66, -152, 40], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 6, 1, 5, -19, 35, 9, -57, -66, 3, -64, -33, 180, 238, 106], [1, 0, 0, 0, 0, -1, 0, 0, 0, 1, -1, 1, 1, -2, -1, -2, -1, 2, 2, -7, -11, -2, -13, -11, 45, 21, 138], [-1, 0, -1, 0, -3, 1, -2, -2, -1, -1, 7, -6, 4, 22, 8, -3, 10, 3, 2, -41, 9, -97, 87, -113, -75, 172, -72], [0, 0, 0, 0, 1, 0, 0, 1, -1, 1, 1, -1, 0, 3, -1, 2, -9, 24, 10, -40, -44, -1, -37, -38, 77, 232, -226], [0, 1, 0, 0, 2, 2, 0, 1, 1, 0, 3, -3, -1, 13, -2, 5, -10, 23, -1, -43, -20, -30, 13, -51, 13, 207, -149], [0, 1, 1, 0, 2, 1, 0, 1, 0, 7, 5, -2, -1, 11, 3, -6, 18, 16, 8, -43, 41, -141, 159, -169, -169, 216, -12], [1, 0, -1, 0, -1, 1, -1, -2, 0, -4, 1, 0, 0, 2, -2, 7, -14, 1, -2, 1, -29, 49, -69, 63, 106, -36, 57], [1, 0, 0, 0, 4, 0, 0, 2, 4, 1, 6, 3, -4, 13, 1, 5, 10, 19, 0, -45, 50, -138, 166, -142, -139, 192, 198], [0, 1, 1, 0, 0, 1, 0, 0, -2, 3, 1, -3, 1, 6, 1, -3, -1, 18, 8, -35, -23, -29, 4, -61, 28, 173, -70], [1, 1, 0, 0, 1, 2, 0, -1, 0, -3, 1, -1, 0, 8, -4, 12, -33, 31, -1, -45, -83, 63, -129, 47, 244, 159, 77]], "vec_b": [31772, -16089, -5137, 19004, -11231, -30741, 1908, -13072, 12518, -15381, -28148, 26993, -37508, 20766, -10350, -4593, -2569, 33556, 17442, -11570, -9905, -5847, -5959, 13220, 23951, -670, 33570]}

ok啊 一个矩阵

z3解出正确的key

1
CompressedEmbeddedResources

image-20250224005442466

创建了一个aes对象

image-20250224005515821

派生key 长度为48

image-20250224005552351

image-20250224005616478

获取到密钥

image-20250224005928781

解出flag

更新

还有另一个说法 这是问出题人去了

image-20250228213215297我们可以手动找到正确的base 但是为什么不会去加载正确的base 而是加载错的

image-20250228210334083

搜索字符串也是可以找到这个东西 但是你找不到调用 启动调试以后调用的地方也不是预想的东西 况且程序明显就是一个输入key自解密的流程 静态调试纯坐牢 于是有了这次更新

image-20250228210721473

set ip直接过掉检测

image-20250228210848557

输入

image-20250228211039201

调试 到了这里就是加载对应资源名称的地方

ResourceManager.GetResourceFileName(CultureInfo) 方法 (System.Resources) | Microsoft Learn

阅读一下官方文档

image-20250228211239339

可以看到加载的资源名称 这里就是为什么有些情况下手动修了正确的base但是还是会报错 因为后面的派生密钥也是在这资源中 手动修了

image-20250228212018564

直接启动 当然前提是你main打了断点

image-20250228212131363

这次就没有报错

image-20250228212415996

尊嘟假嘟

image-20250222012312404

这里的逻辑很简单就是拼接字符串

image-20250222012501703

settext方法这里就开始有问题了 有个dexcall 动态加载dex无疑了

image-20250222012828640 还有个native 先去检查native

image-20250222013029634

image-20250222013048510

rc4 没魔改的

再去搞dex

WrBug/dumpDex: 💯一款Android脱壳工具,需要xposed支持, 易开发已集成该项目。

GuoQiang1993/Frida-Apk-Unpack

不上frida的话就是用mt管理器 删掉delete

image-20250222021654305

再去资源文件找dex

image-20250222021821292

主要是换表的base 还有个异或 加密逻辑就是先走这个dex的再进行rc4 但是这东西只能爆破拼接的字符串作为key

image-20250222023804210

密文 搓个脚本就行

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
import re
import binascii

# 自定义编码表
CUSTOM_ALPHABET = (
"3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5"
)

# 替换规则
REPLACE_RULE = {'0': "0.o", '1': "o.0"}

sbox = [i for i in range(256)]

def encode(input_bytes):
if not input_bytes:
return None
# 对输入数据进行异或操作
tempInput = [b ^ i for i, b in enumerate(input_bytes)]
# 编码后的长度
input_len = len(tempInput)
output_len = ((input_len + 2) // 3) * 4
output = []
input_index = 0
while input_index < input_len:
b0 = tempInput[input_index] if input_index < input_len else 0
b1 = tempInput[input_index + 1] if input_index + 1 < input_len else 0
b2 = tempInput[input_index + 2] if input_index + 2 < input_len else 0
group = (b0 << 16) | (b1 << 8) | b2
# 获取每个6位分组
output.append(CUSTOM_ALPHABET[(group >> 18) & 0x3F])
output.append(CUSTOM_ALPHABET[(group >> 12) & 0x3F])
output.append(CUSTOM_ALPHABET[(group >> 6) & 0x3F])
output.append(CUSTOM_ALPHABET[group & 0x3F])
input_index += 3
# 填充空格
return ''.join(output).encode()

def swap(a, b):
return b, a

def init_sbox(key):
global sbox
sbox = [i for i in range(256)]
key_len = len(key)
Ttable = [key[i % key_len] for i in range(256)]
j = 0
for i in range(256):
j = (j + sbox[i] + Ttable[i]) % 256
sbox[i], sbox[j] = swap(sbox[i], sbox[j])

def RC4(data, key):
global sbox
init_sbox(key)
data = list(data)
i = j = 0
for h in range(len(data)):
i = (i + 1) % 256
j = (j + sbox[i]) % 256
sbox[i], sbox[j] = swap(sbox[i], sbox[j])
t = (sbox[i] + sbox[j]) % 256
k = sbox[t]
data[h] ^= k
return bytes(data)

def binary_to_str(num_bits, max_num):
replaced_str = []
for i in range(max_num):
binary = bin(i)[2:].zfill(num_bits)
current_str = ''.join([REPLACE_RULE[c] for c in binary])
replaced_str.append(current_str)
return replaced_str

def main():
data = bytes([
0x7A, 0xC7, 0xC7, 0x94, 0x51, 0x82, 0xF5, 0x99, 0x0C, 0x30,
0xC8, 0xCD, 0x97, 0xFE, 0x3D, 0xD2, 0xAE, 0x0E, 0xBA, 0x83,
0x59, 0x87, 0xBB, 0xC6, 0x35, 0xE1, 0x8C, 0x59, 0xEF, 0xAD,
0xFA, 0x94, 0x74, 0xD3, 0x42, 0x27, 0x98, 0x77, 0x54, 0x3B,
0x46, 0x5E, 0x95
])

# 遍历1到12位的二进制字符串
for num_bits in range(1, 13):
max_num = 1 << num_bits
replaced_str_list = binary_to_str(num_bits, max_num)
for replaced_str in replaced_str_list:
key = encode(replaced_str.encode())
tmp = bytearray(data)
decrypted_data = RC4(tmp, key)
if decrypted_data.startswith(b"hgame"):
print(f"key: {replaced_str}")
print(f"flag: {decrypted_data.decode()}")
break

if __name__ == "__main__":
main()

脚本搓的时间比分析还久

Delta Erro0000ors

阴间东西

简单说一下逻辑 有一个补丁出题人修改了补丁的校验hsah值 但是出题人给了我们回填校验hsah的机会 最简单的办法就是直接动态调试找到校验的地方 要么抹除校验 要么把真的hash搞到回填 最后这题也是有类似的题目也可以上脚本一把梭

image-20250222170218274

简单修一下 有两次校验 第一次无脑F9就行

image-20250222170405667

这里要改一下避免程序获取不到异常导致炸缸 无脑F9

image-20250222170529594

现在给了回填的机会随便填 因为我们的目的就是找又不是真的指望通过校验

image-20250222170701910

回填了

image-20250222170725294

添加一个硬件断点一会好找

image-20250222170803613

到了这里 f9注意一下内容

image-20250222170834098

左边就是正确的校验hash 右边是我们输入的

image-20250222170933580

1
44D292FFE2E91730AE69EB50AE11D04A

重新启动程序

image-20250222171027698

其他的就不用打断点了直接打一个就行

image-20250222171216633

异或的东西就出来了 干掉校验也简单 已经找到了校验附近的地方手动处理一下就行