论坛首页 逆向工程技术区 阅读主题

从NCTF2026-NoMyBank!到Godot新特性下的游戏逆向分析破解

311 浏览 1 回复
#1 楼主 2026-06-01 21:08:54
前言
起因是笔者去年CISCN遇到godot游戏逆向题后,在小黑盒刷到一篇关于godot独立游戏作品保护的文章,文章里提到了godot支持pck加密机制,于是就想着找机会看看是怎么个事。这道题的最初思路就这么诞生了。但是详细了解pck加密机制后发现,godot平台提供的这一层保护还是太脆弱了,不够有挑战性,于是发动AI之力了解到了godot4.x的新特性:GDExtension系统。GDExtension系统可以将游戏扩展到其他语言生态,就有点像安卓native层的感觉。加上godot本身就是一个开源游戏引擎,源码是可获取的,且平台支持修改引擎并导出游戏,可以利用这点来增加一些游戏保护措施。于是最终笔者利用godot平台实现了三个挑战点:pck加密保护、dll解密加载、gdextension存放核心逻辑。(实际上pck加密保护属于弱挑战点,因为从解题角度来说没什么必要去攻克这点)
由于引擎的开源属性,godot游戏反逆向还是具有挑战性的,毕竟源码公开,要破解游戏也只是时间问题。抛开这点不谈,godot游戏反逆向还存在另一个挑战点:引擎中使用了大量ERR_系列宏,导致报错信息大部分是嵌入在程序中的,相关信息如函数名也会被转成字符串嵌在反编译代码中,以此为切入可以很方便地在IDA中找到想要分析的函数。本题就是利用了这一特性来找pck加密使用的密钥,此外笔者在实现dll动态解密时也故意去除了原代码中的ERR_宏使用以对抗分析。
WriteUp

Kruse几个月前入坑了BlueArchive,在了解泳装蒙面团的事迹之后,他灵机一动用开源引擎godot制作了一个迷宫小游戏”NoMyBank!“。游戏制作完成后,Kruse把demo发给了SydzI,让他帮忙测试测试。SydzI认为Kruse的游戏不安全,给它加上了一些保护措施,并声称在迷宫深处的宝箱中放入了一个神秘礼物,你能帮Kruse找到这个礼物吗?注:迷宫出口在右侧。附件解压路径请勿包含中文。

题目链接:NoMyBank!.zip - Google 云端硬盘
godot逆向题,利用了godot 4.x支持的pck加密和cpp extension机制,同时改了godot引擎的dll加载机制,考察了hook重定向和smc。以下为预期解:
获取基础信息
附件解压出来是一个exe和一个dll。分析发现游戏本体和dll都被处理过,DIE提示游戏本体被打包,而dll会被识别为未知二进制文件,进一步用010editor打开dll会发现整个dll都被加密了(完全看不到PE文件格式特征)
意味着如果要分析dll,首先要找到游戏本体加载dll时对dll进行了什么处理。
尝试解包
godot游戏实质上是由引擎和资源文件组合成的(即DIE提示的“打包”),解包游戏可以获得游戏开发时使用的代码和素材等资源文件,所以第一步可以先尝试解包游戏。用GDRETools解包exe会发现解包失败,提示需要设置密钥:

查找资料会发现godot4.x版本推出了PCK加密编译的机制,可以使用256位AES密钥加密PCK文件(即godot的资源文件)。对于查找PCK加密密钥的方法,网上已有现成的资料,可以参考BV14NtozWEFN
原理是godot内部有一个处理报错的宏定义,该宏会将报错的相关明文信息嵌入在程序中
用IDA打开游戏本体,待加载完毕后,打开字符串窗口,搜索”can't open encrypted pack directory“,跟进到字符串出现的函数,如下图

在两个匹配字符串中间可以看到一个for循环,其中循环读取的byte_144D85CD0[i]即为密钥:

提取出这串数字D34BFF62613FDD2861F6D5942C5E99A53EF3E90ADBE9091B4686859D5B7DAB22,在GDRETools中选中菜单栏的“RETools”,选择“Set encryption key”输入密钥即可解包游戏

解包出来的文件夹结构如下:

在Scripts文件夹内可以找到存放游戏逻辑的.gd文件,在WinPopupTreasury.gd里可以找到一些提示:
此处有一个叫做get_checker_from_loaded_dll_node的函数,在_on_buttun_pressed中这个函数被调用并返回了一个flag_checker,显而易见libextension.dll实现的应该就是类似flag检验的功能了。所以接下来转向分析dll
寻找dll解密逻辑
试着修改dll的名字,运行游戏可以发现会触发报错:

此处的报错信息显然经过特殊处理,可以尝试使用这个报错信息来定位游戏本体中的dll加载函数(前提是这段信息被硬编码在程序中,而非被实时解密)
在IDA字符串窗口,搜索“D11 f1l3 n0t f0und”,可以发现报错信息确实是硬编码的,跟进就可以找到dll加载函数

PS:审WP的时候发现大部分师傅都是分析调用模块直接找到解密后的dll的,这个方法更好,预期解有点偏门了()
分析dll加载函数
通过上述方法找到的dll加载函数如下:
__int64 __fastcall sub_140013FA0(__int64 a1, __int64 a2, HMODULE *a3, __int64 a4)
__int64 v4; // rax
__int64 v5; // rax
const char *v6; // rax
__int64 v8; // rax
__int64 v9; // rax
__int64 v10; // rax
__int64 v11; // rax
__int64 v12; // rax
__int64 v13; // rax
__int64 v14; // rax
const WCHAR *v15; // rax
__int64 v16; // rax
const WCHAR *v17; // rax
__int64 v18; // rax
int v19; // [rsp+20h] [rbp-478h]
int v20; // [rsp+20h] [rbp-478h]
CHAR v21; // [rsp+24h] [rbp-474h]
CHAR v22; // [rsp+25h] [rbp-473h]
char v23; // [rsp+27h] [rbp-471h]
int j; // [rsp+28h] [rbp-470h]
int v25; // [rsp+2Ch] [rbp-46Ch]
_BYTE v26[8]; // [rsp+30h] [rbp-468h] BYREF
int i; // [rsp+38h] [rbp-460h]
int k; // [rsp+3Ch] [rbp-45Ch]
int v29; // [rsp+40h] [rbp-458h]
_BYTE

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-290800.htm
#2 2026-06-01 21:08:54
tql

请登录后参与讨论

立即登录 注册账号