首页
社区
课程
招聘
[原创]2026 年腾讯游戏安全初赛 Android方向
发表于: 4天前 2520

[原创]2026 年腾讯游戏安全初赛 Android方向

4天前
2520

注:本人草台班子出身,属于那种“能把效果整出来,但文章过程写得一坨”的类型。这篇题解也是靠 AI 帮忙润色过的。看了论坛里各位大佬的文章后,才发现自己还有不少明显的丢分点,只能说下次继续努力了。
   另外,本文仅代表个人解法,最终答案请以官方题解为准。


这题表面上是一个 Godot 小游戏,场景里有黄色方块和绿色方块。黄色方块更像是演示流程,车直接开过去就能触发;真正和计分相关的是绿色方块。

这题要求也不只是拿到绿色方块对应的 flag,而是还要:

所以这题本质上不是单纯“跑出一个结果”,而是要把整条链路都分析清楚。

我的做法分成两步:

最后可以确认,绿色 flag 的计算实际上被拆成了两层:

右上角显示的那串内容,本质上就是最终 8 字节结果转换成的大写十六进制字符串

题目左上角会显示一个随机 token。我这里注意到,token 对应的脚本会直接把内容打印到 Godot 日志里,所以最稳的方法其实是直接读 logcat:

所以当前这一局对应的 token 是:

后面的动态验证,我都以这个 token 作为主样本。

静态分析后可以确认,绿色方块的触发逻辑并不是在脚本里直接把 flag 算完,而是走到了一个原生扩展对象。

整个关键关系可以概括为:

最后界面显示的是:

这里有两个关键点:

所以分析重点自然就变成了:Process 到底是谁、怎么注册、具体做了什么。

这题是 Godot + GDExtension 结构。native 逻辑不是直接暴露在 Java 层,而是通过 Godot 的扩展接口在运行时注册进去的。

我的处理方式是用 Frida 去 hook 它的注册流程。做法比较简单粗暴:

最终抓到的 native 类名是:

父类是:

真正需要的 native 方法是:

动态抓到的关键参数如下:

这些值本身不是答案,但它们证明了一件事:Process 不是伪线索,它确实是运行时注册出来并被正常调用的 native 方法。

到这里,其实就已经可以跳过“碰到绿色方块”这件事,直接模拟绿色分支的调用过程了。

Process 的输入并不是原始 token,而是 xor_enc(token) 的结果。

这个预处理不复杂。输入是 token 的 8 个 ASCII 字节,处理规则如下:

如果把 token 记作 t0..t7,输出记作 x0..x7,那么它们之间的关系就是:

拿当前 token 37b8c7e2 去算,得到:

这里我也做了动态验证:在调用 Process 之前,把传进去的 8 字节打印出来,结果和脚本推导完全一致

有了 GameEx 的实例地址和 Process 的调用入口之后,就可以直接在 Frida 里构造 Godot 参数对象,然后原地调用 Process

对 token 37b8c7e2 的调用结果如下:

于是当前样本对应的绿色 flag 就直接出来了:

接下来我又喂了几组不同的 token 给同一个 native Process,拿到了下面这些样本:

这些样本放在一起看,规律其实很明显:native 并没有做什么复杂加密,而是对 xor_enc(token) 的每个字节又做了一次固定异或

把 key 反推出以后,得到:

所以 Process 的真实逻辑其实非常简单:

也就是说,Part1 的正向算法就是:

完整 flag 格式为:

既然正向算法已经拆成了两层,那么逆向时按相反顺序还原即可。

先把 flag 后缀的 16 个十六进制字符解成 8 个字节 y0..y7,然后计算:

这样就恢复出了 xor_enc(token) 的结果。

前面已经知道:

把这组关系整理一下,可以得到一组比较干净的恢复公式:

恢复出 8 个字节后,再检查它们是否都是合法的十六进制字符。如果是,就得到了原始 token。

拿当前样本验证:

结果与日志中的 token 完全吻合。

我把正向和逆向都写在了同一个 C++ 文件里:

主要支持两种用法:

其中:

这样题目要求的正向算法逆算法,都能用 C/C++ 方式完整跑通。

当前样本下,Part1 绿色方块对应的 flag 为:

对应的 token 为:

这题我最后的感觉是:表面上看是个小游戏,实际上核心在于把 Godot 脚本层和 native GDExtension 串起来看

真正有用的信息链路是:


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

最后于 4天前 被清野编辑 ,原因:
上传的附件:
收藏
免费 4
支持
分享
最新回复 (9)
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
xd你这没看Process的真实算法啊
4天前
0
雪    币: 1012
活跃值: (160)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
xxrinkoss xd你这没看Process的真实算法啊
不用看吧,只是没静态把 Process 一条条反编译完。已经定位到 Process,直接调它做了样本,最后把实际算法跑出来了。对交题来说已经够用了啊
4天前
0
雪    币: 1327
活跃值: (1991)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
你这是豆包生成的题解吗??我怎么记得算法是个chacha20呢
3天前
0
雪    币: 1012
活跃值: (160)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
周旋久 你这是豆包生成的题解吗??我怎么记得算法是个chacha20呢

底层是 chacha20-like,但是追根到底是 ChaCha20-like 生成的固定异或常量,因为这组固定异或字节来源于内部固定参数的 ChaCha20-like 流前 8 字节。

最后于 3天前 被清野编辑 ,原因:
3天前
0
雪    币: 104
活跃值: (8242)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
tql
3天前
0
雪    币: 28
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
有一个很诡异的点,我逆向到的native层计算chacha20的key是“Th1s ls n0t a rea1 key!!@sec2026”但这看起来像是作者在提示我找错了?
3天前
0
雪    币: 1012
活跃值: (160)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
Kevin· 有一个很诡异的点,我逆向到的native层计算chacha20的key是“Th1s ls n0t a rea1 key!!@sec2026”但这看起来像是作者在提示我找错了?

关键看它有没有跟 Process 的 runtime 行为对上吧,官方小彩蛋( )得分点也不看这个

最后于 2天前 被清野编辑 ,原因:
2天前
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
有官方的附件吗,比赛当时忘记下了
1天前
0
雪    币: 198
活跃值: (326)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
有官方的附件吗,比赛当时忘记下了
7小时前
0
游客
登录 | 注册 方可回帖
返回