首页
社区
课程
招聘
[原创]第八题:亥子合辰·塔影迷楼 Writeup
发表于: 2026-8-21 12:24 20

[原创]第八题:亥子合辰·塔影迷楼 Writeup

2026-8-21 12:24
20

第八题:亥子合辰·塔影迷楼

基本信息

附件中的程序是 64 位 Windows PE,SHA-256 为:

b0dae7a21b059805a35fc5490f84a607d00afb28ad6b5b9f9ebc31574c382ea1

程序只接受 16 字节输入。导入表很小,文件读写、进程退出和时间查询均通过解析 ntdll 中的系统调用号后直接执行 syscall。

两层代码解密

入口首先读取 .tgt 中的偏移和长度,得到第一层区域:

RVA  = 0x1800
size = 0x510

程序将该区域改成可写权限,每个字节异或 0x5A,刷新指令缓存后进入 0x1400018D0。

第一层代码对自身计算两组 FNV 风格的 64 位哈希。两个初值分别为 0xCBF29CE484222325 和 0x9E3779B97F4A7C15,乘数均为 0x100000001B3,最终结果为:

h0 = 0x73FB4F498AAB364F
h1 = 0xB157C7E044B966DF

随后解密第二层区域:

RVA  = 0x1D10
size = 0x4962

标量路径可以写成:

MASK = (1 << 64) - 1
G = 0x9E3779B97F4A7C15
M = 0xFF51AFD7ED558CCD

for i in range(0x4962):
    t = h0 ^ h1 ^ ((G * i) & MASK)
    t ^= t >> 33
    key = ((M * t) & MASK) >> 56
    code[i] ^= key

程序还包含向量化实现,两条路径生成的密钥流相同。解密后,核心校验函数位于 0x140004380。

反调试和上下文生成

核心函数先检查以下状态:

  • PEB 的 BeingDebugged 和 NtGlobalFlag;
  • Dr0 至 Dr3、Dr7 硬件断点寄存器;
  • ProcessDebugPort 与 ProcessDebugObjectHandle;
  • 扫描代码段前后的 RDTSC 差值。

这些状态合并成一个掩码。正常运行时掩码为 0。核心代码再次对已解密的第二层区域计算哈希,得到:

hash_golden = 0x4AEEE52B5738EB8F
hash_fnv    = 0x553D3C5EF6EE11FF

两个哈希与反调试掩码进入 SplitMix64 风格的生成器,循环 43 次,产生 86 个 64 位字。后续数据全部来自这组确定性上下文:

  • 第 0 至 9 个字组成五个素域多项式系数;
  • 第 10、11 个字组成轮函数乘数;
  • 第 12 至 43 个字组成 256 字节替换表;
  • 第 44 至 83 个字组成两组各 20 个轮密钥;
  • 最后两个字用于解开目标值和最终哈希。

素域与输入编码

所有 128 位运算都在以下素域中进行:

p = 2^127 - 39
  = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9

输入首先满足字节和检查:

sum(input[0:16]) = 0x500

随后把可打印字符按 94 进制编码:

x = 0
for ch in input_bytes:
    x = (x * 94 + ch - 33) % p

字符范围为 0x21 至 0x7E,所以每一位正好落在 0 至 93。94^16 小于 p,最终可以直接用 94 进制无歧义还原。

五个上下文字段记作 c0 至 c4。核心函数用 Horner 形式计算:

y = (((((x + c0)·x + c1)·x + c2)·x + c3)·x + c4) mod p

简化 20 轮变换

反编译结果将 128 位乘法和模约减完全展开,主体超过两千条指令。把重复片段合并后,每轮是两次 Feistel 更新。

设 C 为上下文生成的 128 位乘数,S 为逐字节替换表,定义:

t = (((A << 64) | k) · C) mod p
z = low64(t) XOR k XOR ROR64(high64(t), 47)
F(A, k) = S(z) XOR ROR64(z, 51)

单轮正向运算为:

A' = B XOR F(A, k)
B' = A XOR F(A', k XOR 0x9E3779B97F4A7C15)

因此可以直接逆运算:

A = B' XOR F(A', k XOR 0x9E3779B97F4A7C15)
B = A' XOR F(A, k)

两组 20 轮使用不同轮密钥和不同交替哈希,初始输入都是多项式结果 y。解开上下文掩码后的两个目标分别为:

target1 = 0x0C14DB1C20DD97A8B8FD0694401D3D03
target2 = 0x9A2789B6DE31C2DCACA5240A53FB78A6

分别逆转两组 20 轮,独立得到相同结果:

y = 0x4BE831B0AD3A2D361489375BBA3FB8DE

五次多项式求根

将 Horner 表达式展开后得到有限域上的五次多项式:

f(X) = X^5 + c0·X^4 + c1·X^3 + c2·X^2 + c3·X + c4 - y

先计算:

gcd(f(X), X^p - X)

这样可以保留 F_p 中的一次因子,再用 Cantor-Zassenhaus 方法确定性拆分。多项式只有一个域内根:

x = 0x174A5E1D4CF4F146E72F70092AC

把 x 连续除以 94,取 16 个余数并各加 33,得到:

kanxue@2o26o8!@#

该字符串满足全部条件:字节和为 0x500,多项式结果正确,两组 20 轮输出正确,两组最终 FNV 校验正确。原程序输出 correct。

Flag

kanxue@2o26o8!@#

传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

上传的附件:
收藏
点赞 ・0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回