基于京华杯和阿里云ctf|alictf逆向中pixelflow对Unity引擎技术深入研究并进行逆向学习
什么是Unity?
unity是一款3D游戏开发引擎,市面上很多知名游戏都有其身影,如王者农药,lol等等,同时还应用于很多3D视频,电影,产品的构建,是及其强大的工具,unity引擎具备以下主要特点和功能:
物理引擎
unity具备真实的物理引擎,可以进行物理层面的真实模拟,可以使操作与画面更加逼真呈现
动画引擎
用于打造各种动作特效,如切枪,发刀,下包等等,提供真实动作指引
声音引擎
为游戏的动作、背景等等提供音乐特效,增添氛围感
脚本引擎
脚本引擎是最为重要的部分,也是我们逆向的主要部分,通过函数分析来解析游戏逻辑,从而实现逆向分析
Unity编译逻辑
unity以c#作为编译语言,早期采用mono运行时构建,将c#编译为IL(中间语言,易被逆向),然后通过JIT编译来运行代码,后期改为用IL2CPP运行时,将IL转换为c++代码,再通过AOT编译来运行c++代码,更难被逆向,这也是主流的逆向题目所采用的运行时,我们主要针对这一块展开
为了进一步了解unity,我们对其中的文件进行一波阐述,我们通过两道题目,对mono运行时和IL2CPP运行时进行区分
mono运行时
例题:25年京华杯binary-unity

打开文件我们发现有明显的Mono字样
然后我呢对每个文件进行一个详细介绍
simu.exe
肯定是我们游戏的运行程序,双击直接运行
Managed 文件夹:核心中的核心,位于 Simu_Data/Managed,
这是 Mono 架构与 IL2CPP 最大的区别所在。所有的 C# 代码都在这里,而且是分门别类放好的 DLL 文件。

内部的Assembly-CSharp.dll (最重要):这是开发者的代码仓库。游戏里写的逻辑、角色控制、Flag 校验算法、加密解密函数,99% 都在这个文件里。
MonoBleedingEdge 文件夹:虚拟机的“引擎室”
名字由来:"Bleeding Edge" 意味着这是 Unity 官方维护的一个最新版/激进版的 Mono 运行时环境。
作用:它相当于在这个游戏文件夹里内置了一个微型的 .NET 环境。因为 Mono 采用的是 JIT (Just-In-Time) 编译模式。游戏运行时,这个文件夹里的程序负责读取 Managed 里的 DLL 文件,把它们实时翻译成 CPU 能懂的机器码。内部存在两个文件夹:
EmbedRuntime:存放 Mono 虚拟机本身的 DLL。
etc:存放 Mono 的配置文件(比如时区设置、映射配置)。
资源与素材文件

(1)level0:
身份: 场景文件 (Scene)。细节: level0 通常是游戏的第一个场景(Start Menu 或 Main Scene)。它定义了物体树(Hierarchy)结构。
(2)sharedassets0.assets, resources.assets:
身份: 资产包。细节: 这里面塞满了 纹理(Texture)、3D模型(Mesh)、音频(Audio) 和 文本(TextAsset)。
(3).resS 文件 (如 sharedassets0.assets.resS)
身份: 流式资源 (Streamed Resource)。细节: 这种文件通常很大,存的是体积巨大的数据,比如背景音乐或高清贴图。它从主 .assets 文件中分离出来是为了加快加载速度。
(4)globalgamemanagers
身份: 全局设置。细节: 存储了项目的设置,比如 Tag 定义、Layer 定义、物理设置、构建版本号等。
(5)boot.config
身份: 启动参数。细节: 一个简单的文本文件,配置了引擎启动时的参数(例如是否开启调试器、图形API版本等)
UnityPlayer.dll
身份: Unity 引擎本体。细节: 负责渲染、物理计算、输入处理。
了解完mono运行时的内容,我们再来看看IL2CPP运行时
IL2CPP运行时s
例题:26年alictf-pixelflow


在data中明显看得到IL2CPP字样其中文件类型与上述mono的文件类型大同小异,我们不做阐述,仅对重要文件进行说明比较
il2cpp_data/Metadata/global-metadata.dat
- 身份: 密码本 (Rosetta Stone)。
- 细节: 虽然代码在
GameAssembly.dll里,但这文件记录了所有的字符串信息(类名、函数名、变量名)用于恢复符号表(很关键)
| 特征 | Mono | IL2CPP |
| 核心代码位置 | Project_Data/Managed/Assembly-CSharp.dll | GameAssembly.dll (根目录) |
| 代码格式 | .NET IL (中间语言) | Native x86/x64 (机器码) |
| 关键文件夹 | MonoBleedingEdge | il2cpp_data |
| 逆向难度 | 简单 (★) | 困难 (★★★★) |
| 主要工具 | dnSpy (直接改代码) | Il2CppDumper + IDA Pro |
| 能否还原源码 | 能还原出几乎 100% 的 C# 源码 | 只能看到汇编,需要结合伪代码猜逻辑 |
了解完了我们的unity引擎逻辑便可以通过工具对程序进行逆向解密了,我们先从简单的看起
例题一:25年京华杯binary-unity
工具链接:
dnSpy/dnSpy: .NET debugger and assembly editor
通过AssetRipper加载游戏,通过上述我们提到的图片资源在sharedassets0.assets,resources.assets文件中,我们对这两个文件进行处理在resourse中我们找到如图所示的内容,点开便是flag

找完flag2我们再去找其他的,用dnspy,可以将IL中间语言完全转变为源代码,因此可以真正实现对源码的操作,这也是mono简单的原因,不必对机器码死磕,我们前面提到代码都存在Assembly_CSharp中,我们将该文件拖入dnspy可以发现我们得到了程序的全逻辑,同时我们发现了定义的许多类,如door1,door2

很快我们便能定位到函数关键逻辑点,通过适当修改就可以得到flag1和3了,这里不再阐述,直为讲解工具使用,详细解题方案可以关注这条视频,讲解很清楚【CTF】GeekGame5 Unity逆向题 视频writeup_哔哩哔哩_bilibili
例题二:26年aliCTF-pixelflow
这道题就是前面说的另一种运行时,是纯粹的c++逆向,不过我们也可以通过工具去进行初步逆向,接下来将进行详细讲解,先附上参考文献Unity 游戏逆向:使用 Il2CppDumper 还原 C# 符号表,修改 DLL 实现“无敌模式”-CSDN博客
我们主要攻击两个目录,GameAssembly.dll : 存放逻辑代码,但直接IDA逆向看不到符号表。global-metadata.dat: 存放字符串、类定义、方法签名,用于恢复符号表。
对于IL2CPP我们有一个强大的工具Il2CppDumper(提取地址映射来恢复符号表),工具链接:Releases · Perfare/Il2CppDumper
使用方法非常简单,运行 Il2CppDumper.exe,按顺序选择 GameAssembly.dll ,然后再选择 global-metadata.dat。会生成一个内含大量DLL文件的DummyDll文件夹,这个文件夹里面定义了许多的类,类似于先前Mono下的文件夹Managed,但是DummyDll没有具体代码,仅仅是一个空壳,此外会额外生成文件ida_with_struct_py3.py、script.json 、 il2cpp.h: 用于在 IDA 中导入符号
此时我们有了Assembly-CSharp文件,使用 DnSpy 打开它,虽然看不到具体代码实现,但是可以看到类结构的地址以方便定位在ida的哪个位置,我们可以清晰地看到有k0、k1这些字眼,我们用ida去查看函数

用 IDA 打开原始的 GameAssembly.dll,然后点击File -> Script file -> 选择 Dumper 生成的 ida_with_struct_py3.py,并加载 script.json,此时便会发现符号表被恢复了,为了方便定位到底哪个函数才是关键函数,我们先将类文件拖入ida中查看函数名,其中最显眼的莫过于123的check,我们在主程序文件中去看具体逻辑

函数很多,但在 IDA 里真正需要看的部分是ComputeShader 本体(K0/K1/K2 的 DXBC),主要函数逻辑如下所述:
Controller__Check_d__18__MoveNext
这是整条校验流水线的“调度器”:按顺序 await 哪些步骤、跑几次、失败走哪条分支。
从这里能确认:b__18_2 被调用了 3 次(三轮变换),最后才跑 b__18_3 做检查。
Controller__Check_b__18_0_d__MoveNext
解析输入:前后缀、Substring、长度=16、ASCII.GetBytes。
Controller__Check_b__18_1_d__MoveNext
把 16 个 byte 写成 Texture2D(16×1) 的 Color32,再 CopyTexture 到 TexF。输入进入 GPU。
Controller__Check_b__18_2_d__MoveNextComputeShader.Dispatch(Shader0, K0, ...)加密/变换核是K0。
Controller__Check_b__18_3_d__MoveNext
清 Buffer0,然后 Dispatch(Shader0, K1, ...)
校验核K1以及判错标志在Buffer/SharedState
这题的逻辑也变的清晰了,严格说这题是 IDA + shader dump 的组合:
IDA 负责把“流程”拆清楚:输入→纹理→K0×3→K1→显示shader dump 负责给出“数学逻辑”:K0 做了什么、K1怎么比,所以接下来我们要用新的工具去看GPU做了什么
我们用到前面提到的一个工具:AssetRipper,通过ida分析我们知道关键点在computershader中,于是打开sharedassets0文件,找到shader并查看Json代码,我们可以看到一坨数据,里面用base64对K0、K1、K2进行加密,我们只需要解密便可得到相应二进制处理逻辑,同时我们可以看到相关数据调用,如cotex、worktex等等,我们直接终端命令保存一份dxbc文件,虽然不可读,但是可以通过工具进行反汇编
{
"m_CompilationContext": {
"m_BuildTarget": {
"m_ExtendedPlatform": 0,
"m_IsEditor": 0,
"m_Platform": 0,
"m_SubTarget": 0
},
"m_CompilationFlags": 0,
"m_IncludeHash0": 0,
"m_IncludeHash1": 0,
"m_IncludeHash2": 0,
"m_IncludeHash3": 0,
"m_KernelMacros": [],
"m_Kernels": [],
"m_NeverUseDxcAPIs": 0,
"m_PlatformGroup": 0,
"m_Source": "",
"m_SourceFile": "",
"m_SourceFileName": "",
"m_SupportedAPIs": 0,
"m_UseDxcAPIs": 0
},
"m_CorrespondingSourceObject": { "m_FileID": 0, "m_PathID": 0 },
"m_Errors": [],
"m_HideFlags": 0,
"m_Name": "Shader",
"m_PrefabAsset": { "m_FileID": 0, "m_PathID": 0 },
"m_PrefabInstance": { "m_FileID": 0, "m_PathID": 0 },
"m_Variants": [
{
"m_CompilerPlatform": 0,
"m_ConstantBuffers": [
{
"m_ByteSize": 32,
"m_Name": "Params",
"m_Params": [
{
"m_ArraySize": 0,
"m_ColCount": 2,
"m_Name": "ScrollSpeed",
"m_Offset": 0,
"m_RowCount": 1,
"m_Type": 0
},
{
"m_ArraySize": 0,
"m_ColCount": 2,
"m_Name": "TileScale",
"m_Offset": 8,
"m_RowCount": 1,
"m_Type": 0
},
{
"m_ArraySize": 0,
"m_ColCount": 1,
"m_Name": "RotationRad",
"m_Offset": 16,
"m_RowCount": 1,
"m_Type": 0
},
{
"m_ArraySize": 0,
"m_ColCount": 1,
"m_Name": "TimeValue",
"m_Offset": 20,
"m_RowCount": 1,
"m_Type": 0
}
]
}
],
"m_KernelParents": [
{
"m_DynamicKeywords": [],
"m_GlobalKeywords": [],
"m_LocalKeywords": [],
"m_Name": "K0",
"m_UniqueVariants": [
{
"m_BuiltinSamplers": [],
"m_Cbs": [],
"m_CbVariantIndices": [],
"m_Code": "RFhCQ+aJbqNjWgR7GoPngPtMbogBAAAALBgAAAQAAAAwAAAAQAAAAFAAAAAcGAAASVNHTggAAAAAAAAACAAAAE9TR04IAAAAAAAAAAgAAABTSEVYxBcAAFAABQDxBQAAaggAAVgYAAQAcBAAAAAAAFVVAACcGAAEAOARAAAAAABVVQAAaAAAAgUAAABpAAAEAAAAABAAAAAEAAAAaQAABAEAAAAgAAAABAAAAJsAAAQBAAAAAQAAAAEAAAA2AAAGEjAgAAEAAAAAAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAABAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAACAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAADAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAEAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAFAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAGAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAHAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAIAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAJAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAKAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAALAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAMAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAANAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAOAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAPAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAQAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAARAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAASAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAATAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAUAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAVAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAWAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAXAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAYAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAZAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAaAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAbAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAcAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAdAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAeAAAAAUAAAAAAAAA2AAAGEjAgAAEAAAAfAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAAAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAABAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAACAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAADAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAEAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAFAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAGAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAHAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAIAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAJAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAKAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAALAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAMAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAANAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAOAAAAAUAAAAAAAAA2AAAGEjAgAAAAAAAPAAAAAUAAAAAAAAA9EACJwgAAgENVFQASABAAAAAAAAFAAAAAAAAARn4QAAAAAAA2AAAI4gAQAAEAAAACQAAAAAAAAAAAAAAAAAAAAAAAADYAAAhiABAAAgAAAAJAAAAAAAAAAAAAAP////8AAAAANgAACFIAEAADAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAA2AAAIYgAQAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAADAAAAFQAAAHggAQAAAAAAAqABAAAAAAAAFAAAAABAAAAwAEAzoAEAAAAAAAUAAAB4IAEAAAAAAACgAQAAMAAAAKABAAAAAAADwAAAeCABAAAAAAADoAEAAAAAAAKgAQAAMAAAAfAAQDOgAQAAAAAAACAAABFQAAATYAAAUSABAAAgAAAAoAEAADAAAALQAAicIAAIBDVRUA8gAQAAQAAABGBRAAAgAAAEZ+EAAAAAAAOAAACvIAEAAEAAAARg4QAAQAAAACQAAAAAB/QwAAf0MAAH9DAAB/QxwAAAXyABAABAAAAEYOEAAEAAAATAAAAwoAEAAEAAAABgAAAwFAAAAAAAAANgAABxIwIAQBAAAAGgAQAAQAAAA6ABAABAAAAB4AAAcSABAAAwAAAAoAEAADAAAAAUAAAAEAAAACAAABBgAAAwFAAAABAAAANgAAB4IAEAAAAAAACjAgBAEAAAAqABAABAAAAAEAAAcSABAAAQAAADoAEAAAAAAAAUAAAA8AAACjAACJwgAAgENVFQCCABAAAAAAAEYOEAABAAAAluMRAAAAAAA4AAAHggAQAAAAAAA6ABAAAAAAAAFAAAAAAH9DQAAABYIAEAAAAAAAOgAQAAAAAAAcAAAFggAQAAAAAAA6ABAAAAAAAAEAAAeCABAAAAAAADoAEAAAAAAAAUAAAP8AAAA2AAAHEjAgBAEAAAAaABAABAAAADoAEAAAAAAAHgAABxIAEAADAAAACgAQAAMAAAABQAAAAQAAAAIAAAEGAAADAUAAAAIAAAA2AAAHggAQAAAAAAAKMCAEAQAAABoAEAAEAAAANgAABxIAEAABAAAACjAgBAEAAAAqABAABAAAAFcAAAeCABAAAAAAADoAEAAAAAAACgAQAAEAAAABAAAHggAQAAAAAAA6ABAAAAAAAAFAAAD/AAAANgAABxIwIAQBAAAAGgAQAAQAAAA6ABAAAAAAAB4AAAcSABAAAwAAAAoAEAADAAAAAUAAAAEAAAACAAABBgAAAwFAAAADAAAANgAAB4IAEAAAAAAACjAgBAEAAAAaABAABAAAADYAAAcSABAAAQAAAAowIAQBAAAAKgAQAAQAAAABAAAHEgAQAAEAAAAKABAAAQAAAAFAAAAHAAAAAQAAB4IAEAACAAAAOgAQAAAAAAABQAAA/wAAAIwAAAuCABAAAAAAAAFAAAAIAAAACgAQAAEAAAA6ABAAAAAAAAFAAAAAAAAAHgAACBIAEAABAAAACgAQgEEAAAABAAAAAUAAAAgAAABVAAAHEgAQAAEAAAA6ABAAAgAAAAoAEAABAAAAPAAAB4IAEAAAAAAAOgAQAAAAAAAKABAAAQAAAAEAAAeCABAAAAAAADoAEAAAAAAAAUAAAP8AAAA2AAAHEjAgBAEAAAAaABAABAAAADoAEAAAAAAAHgAABxIAEAADAAAACgAQAAMAAAABQAAAAQAAAAIAAAEGAAADAUAAAAQAAAA2AAAHggAQAAAAAAAKMCAEAQAAACoAEAAEAAAAAQAABxIAEAABAAAAOgAQAAQAAAABQAAA/wAAACYAAAgA0AAAggAQAAAAAAA6ABAAAAAAAAoAEAABAAAAAQAAB4IAEAAAAAAAOgAQAAAAAAABQAAA/wAAADYAAAcSMCAEAQAAABoAEAAEAAAAOgAQAAAAAAAeAAAHEgAQAAMAAAAKABAAAwAAAAFAAAABAAAAAgAAAQYAAAMBQAAABQAAADYAAAeCABAAAAAAAAowIAQBAAAAKgAQAAQAAAABAAAHEgAQAAEAAAA6ABAABAAAAAFAAAD/AAAAHgAAB4IAEAAAAAAAOgAQAAAAAAAKABAAAQAAAAEAAAeCABAAAAAAADoAEAAAAAAAAUAAAP8AAAA2AAAHEjAgBAEAAAAaABAABAAAADoAEAAAAAAAHgAABxIAEAADAAAACgAQAAMAAAABQAAAAQAAAAIAAAEGAAADAUAAAAYAAAA2AAAHggAQAAAAAAAKMCAEAQAAABoAEAAEAAAANgAABxIAEAABAAAACjAgBAEAAAAqABAABAAAAB4AAAeCABAAAAAAADoAEAAAAAAACgAQAAEAAAABAAAHggAQAAAAAAA6ABAAAAAAAAFAAAD/AAAANgAABxIwIAQBAAAAGgAQAAQAAAA6ABAAAAAAAB4AAAcSABAAAwAAAAoAEAADAAAAAUAAAAEAAAACAAABBgAAAwFAAAAHAAAANgAAB4IAEAAAAAAACjAgBAEAAAAaABAABAAAAAEAAAeCABAAAAAAADoAEAAAAAAAAUAAAA8AAAA2AAAHEgAQAAEAAAAKMCAEAQAAACoAEAAEAAAAAQAABxIAEAABAAAACgAQAAEAAAABQAAA/wAAADYAAAcSMCAEAAAAADoAEAAAAAAACgAQAAEAAAAeAAAHEgAQAAMAAAAKABAAAwAAAAFAAAABAAAAAgAAAQYAAAMBQAAACAAAADYAAAeCABAAAAAAAAowIAQBAAAAGgAQAAQAAAABAAAHEgAQAAEAAAA6ABAABAAAAAFAAAD/AAAATwAAByIAEAAAAAAAOgAQAAAAAAAKABAAAQAAAB4AAAcSABAAAwAAAAoAEAADAAAAAUAAAAEAAAACAAABBgAAAwFAAAAJAAAAAQAAB4IAEAAAAAAAOgAQAAQAAAABQAAAgAAAAB4AAAcSABAAAQAAADoAEAAEAAAAAUAAAAD///83AAAJggAQAAAAAAA6ABAAAAAAAAoAEAABAAAAOgAQAAQAAAAeAAAHIgAQAAMAAAA6ABAAAAAAAAoAEAADAAAAIgAAB4IAEAAAAAAAGgAQAAMAAAABQAAAAAAAACEAAAcSABAAAQAAABoAEAADAAAACgAQAAAAAAA8AAAHggAQAAAAAAA6ABAAAAAAAAoAEAABAAAANwAACZIAEAACAAAA9g8QAAAAAAAGCBAAAgAAAFYJEAADAAAAHgAABxIAEAADAAAACgAQAAMAAAABQAAAAQAAADcAAAlSABAAAwAAAFYFEAAAAAAABgMQAAIAAAAGAhAAAwAAAAIAAAEKAAABNgAABUIAEAADAAAAAUAAAP////8CAAABFwAAAR4AAAdCABAAAAAAACoAEAAAAAAAAUAAAAEAAAAWAAABNgAABhIAEAAAAAAACjAgAAAAAAAAAAAANgAABiIAEAAAAAAACjAgAAAAAAABAAAANgAABkIAEAAAAAAACjAgAAAAAAACAAAANgAABoIAEAAAAAAACjAgAAAAAAADAAAANgAABhIAEAABAAAACjAgAAAAAAAEAAAANgAABiIAEAABAAAACjAgAAAAAAAFAAAANgAABkIAEAABAAAACjAgAAAAAAAGAAAANgAABoIAEAABAAAACjAgAAAAAAAHAAAANgAABhIAEAACAAAACjAgAAAAAAAIAAAANgAABiIAEAACAAAACjAgAAAAAAAJAAAANgAABkIAEAACAAAACjAgAAAAAAAKAAAANgAABoIAEAACAAAACjAgAAAAAAALAAAANgAABhIAEAADAAAACjAgAAAAAAAMAAAANgAABiIAEAADAAAACjAgAAAAAAANAAAANgAABkIAEAADAAAACjAgAAAAAAAOAAAANgAABoIAEAADAAAACjAgAAAAAAAPAAAAVgAABRIAEAAAAAAACgAQAAAAAAA4AAAHEgAQAAQAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAEAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAEYOEAAEAAAAVgAABRIAEAAAAAAAGgAQAAAAAAA4AAAHEgAQAAQAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAEAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAAAQAAAAAAAAAAAAAAAAAAAEYOEAAEAAAAVgAABRIAEAAAAAAAKgAQAAAAAAA4AAAHEgAQAAQAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAEAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAAAgAAAAAAAAAAAAAAAAAAAEYOEAAEAAAAVgAABRIAEAAAAAAAOgAQAAAAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAAAwAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAACgAQAAEAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAABAAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAGgAQAAEAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAABQAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAKgAQAAEAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAABgAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAOgAQAAEAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAABwAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAACgAQAAIAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAACAAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAGgAQAAIAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAACQAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAKgAQAAIAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAACgAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAOgAQAAIAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAACwAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAACgAQAAMAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAADAAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAGgAQAAMAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAADQAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAKgAQAAMAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAADgAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAVgAABRIAEAAAAAAAOgAQAAMAAAA4AAAHEgAQAAAAAAAKABAAAAAAAAFAAACBgIA7NgAACOIAEAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD+kAAAK8uARAAAAAAACQAAADwAAAAAAAAAAAAAAAAAAAEYOEAAAAAAAPgAAAVNGSTAIAAAAAAgAAAAAAAA=",
"m_InBuffers": [],
"m_IsCompiled": false,
"m_Keywords": [],
"m_OutBuffers": [
{
"m_BindPoint": 0,
"m_GeneratedName": "",
"m_Name": "WorkTex",
"m_SamplerBindPoint": -1,
"m_TexDimension": 2
}
],
"m_Requirements": 16385,
"m_Textures": [
{
"m_BindPoint": 0,
"m_GeneratedName": "",
"m_Name": "CoTex",
"m_SamplerBindPoint": -1,
"m_TexDimension": 2
}
],
"m_ThreadGroupSize": [
1,
1,
1
]
}
],
"m_VariantIndices": [
{
"Key": "",
"Value": 0
}
]
},
{
"m_DynamicKeywords": [],
"m_GlobalKeywords": [],
"m_LocalKeywords": [],
"m_Name": "K1",
"m_UniqueVariants": [
{
"m_BuiltinSamplers": [],
"m_Cbs": [],
"m_CbVariantIndices": [],
"m_Code": "RFhCQ1kh8izR5VNiblln4jMkGigBAAAAhAIAAAQAAAAwAAAAQAAAAFAAAAB0AgAASVNHTggAAAAAAAAACAAAAE9TR04IAAAAAAAAAAgAAABTSEVYHAIAAFAABQCHAAAAaggAAVgYAAQAcBAAAAAAAFVVAACcGAAEAOARAAAAAABVVQAAngAABADgEQABAAAABAAAAF8AAAISAAIAaAAAAgIAAACbAAAEEAAAAAEAAAABAAAANgAABBIAEAAAAAAACgACADYAAAjiABAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAowAAicIAAIBDVRUAEgAQAAEAAADGDxAAAAAAAEbuEQAAAAAAOAAABxIAEAABAAAACgAQAAEAAAABQAAAAAB/Q0AAAAUSABAAAQAAAAoAEAABAAAAHAAABRIAEAABAAAACgAQAAEAAAABAAAHEgAQAAEAAAAKABAAAQAAAAFAAAD/AAAAHgAABhIAEAABAAAACgAQAAEAAAAKAAIAAQAABxIAEAABAAAACgAQAAEAAAABQAAA/wAAAC0AAInCAACAQ1UVABIAEAAAAAAARg4QAAAAAABGfhAAAAAAADgAAAcSABAAAAAAAAoAEAAAAAAAAUAAAAAAf0NAAAAFEgAQAAAAAAAKABAAAAAAABwAAAUSABAAAAAAAAoAEAAAAAAAAQAABxIAEAAAAAAACgAQAAAAAAABQAAA/wAAACcAAAcSABAAAAAAAAoAEAAAAAAACgAQAAEAAAAfAAQDCgAQAAAAAACoAAAJEuARAAEAAAABQAAAAAAAAAFAAAAAAAAAAUAAAAEAAAAVAAABPgAAAVNGSTAIAAAAAAgAAAAAAAA=",
"m_InBuffers": [],
"m_IsCompiled": false,
"m_Keywords": [],
"m_OutBuffers": [
{
"m_BindPoint": 0,
"m_GeneratedName": "",
"m_Name": "WorkTex",
"m_SamplerBindPoint": -1,
"m_TexDimension": 2
},
{
"m_BindPoint": 1,
"m_GeneratedName": "",
"m_Name": "SharedState",
"m_SamplerBindPoint": -1,
"m_TexDimension": -1
}
],
"m_Requirements": 16385,
"m_Textures": [
{
"m_BindPoint": 0,
"m_GeneratedName": "",
"m_Name": "CiTex",
"m_SamplerBindPoint": -1,
"m_TexDimension": 2
}
],
"m_ThreadGroupSize": [
16,
1,
1
]
}
],
"m_VariantIndices": [
{
"Key": "",
"Value": 0
}
]
},
{
"m_DynamicKeywords": [],
"m_GlobalKeywords": [],
"m_LocalKeywords": [],
"m_Name": "K2",
"m_UniqueVariants": [
{
"m_BuiltinSamplers": [
{
"m_BindPoint": 0,
"m_Sampler": 1
}
],
"m_Cbs": [
{
"m_BindPoint": 0,
"m_GeneratedName": "",
"m_Name": "Params",
"m_SamplerBindPoint": -1,
"m_TexDimension": -1
}
],
"m_CbVariantIndices": [
0
],
"m_Code": "RFhCQ686CHv0uY+JNM9tm21AJIcBAAAAmAQAAAMAAAAsAAAAPAAAAEwAAABJU0dOCAAAAAAAAAAIAAAAT1NHTggAAAAAAAAACAAAAFNIRVhEBAAAUAAFABEBAABqCAABWQAABEaOIAAAAAAAAgAAAFoAAAMAYBAAAAAAAFgYAAQAcBAAAAAAAFVVAABYGAAEAHAQAAEAAABVVQAAnBgABADgEQAAAAAAVVUAAJ4AAAQA4BEAAQAAAAQAAABfAAACMgACAGgAAAIEAAAAmwAABAgAAAAIAAAAAQAAAD0QAInCAACAQ1UVADIAEAAAAAAAAUAAAAAAAABG7hEAAAAAAFAAAAbCABAAAAAAAAYEAgAGBBAAAAAAADwAAAdCABAAAAAAADoAEAAAAAAAKgAQAAAAAAAfAAQDKgAQAAAAAAA+AAABFQAAAVYAAATCABAAAAAAAFYBAgBWAAAFMgAQAAAAAAAWBRAAAAAAAA4AAAcyABAAAAAAAOYKEAAAAAAARgAQAAAAAAAyAAANMgAQAAAAAABGABAAAAAAALaPIAAAAAAAAAAAAAJAAAAAAAC/AAAAvwAAAAAAAAAAPRAAicIAAIBDVRUAwgAQAAAAAAABQAAAAAAAAOZ0EAAAAAAAVgAABcIAEAAAAAAA9gsQAAAAAAAOAAAHQgAQAAAAAAAqABAAAAAAADoAEAAAAAAATQAACBIAEAABAAAAEgAQAAIAAAAKgCAAAAAAAAEAAAA4AAAHMgAQAAEAAABGABAAAAAAAAYAEAABAAAAMgAAChIAEAADAAAAGgAQAAAAAAAKABAAAgAAAAoAEIBBAAAAAQAAADIAAAkiABAAAAAAAAoAEAAAAAAACgAQAAIAAAAaABAAAQAAAA4AAAciABAAAwAAABoAEAAAAAAAKgAQAAAAAAAAAAAKYgAQAAAAAAAGARAAAwAAAAJAAAAAAAAAAAAAPwAAAD8AAAAApwAAiwIjAICDmRkAggAQAAAAAAABQAAAAAAAAAFAAAAAAAAABuARAAEAAAAgAAAHEgAQAAEAAAA6ABAAAAAAAAFAAAABAAAAHwAAAzoAEAAAAAAAMgAAC2IAEAABAAAABoEgAAAAAAAAAAAAVoUgAAAAAAABAAAAVgYQAAAAAABIAACNwgAAgENVFQDyABAAAgAAAJYFEAABAAAARn4QAAAAAAAAYBAAAAAAAAFAAAAAAAAAEgAAATYAAAjyABAAAgAAAAJAAAAAAAAAAAAAAAAAAAAAAIA/FQAAAR8ABAMKABAAAQAAADIAAAxiABAAAAAAAAaBIIBBAAAAAAAAAAAAAABWhSAAAAAAAAEAAABWBhAAAAAAAEgAAI3CAACAQ1UVAPIAEAACAAAAlgUQAAAAAABGfhAAAQAAAABgEAAAAAAAAUAAAAAAAAAVAAABAAAAC/IAEAABAAAARg4QgEEAAAACAAAAAkAAAAAAAAAAAAAAAAAAAAAAgD8yAAAJ8gAQAAAAAAAGABAAAAAAAEYOEAABAAAARg4QAAIAAACkAAAG8uARAAAAAABGBQIARg4QAAAAAAA+AAAB",
"m_InBuffers": [],
"m_IsCompiled": false,
"m_Keywords": [],
"m_OutBuffers": [
{
"m_BindPoint": 0,
"m_GeneratedName": "",
"m_Name": "OutputTex",
"m_SamplerBindPoint": -1,
"m_TexDimension": 2
},
{
"m_BindPoint": 1,
"m_GeneratedName": "",
"m_Name": "SharedState",
"m_SamplerBindPoint": -1,
"m_TexDimension": -1
}
],
"m_Requirements": 16385,
"m_Textures": [
{
"m_BindPoint": 0,
"m_GeneratedName": "",
"m_Name": "CorrectTex",
"m_SamplerBindPoint": -1,
"m_TexDimension": 2
},
{
"m_BindPoint": 1,
"m_GeneratedName": "",
"m_Name": "WrongTex",
"m_SamplerBindPoint": -1,
"m_TexDimension": 2
}
],
"m_ThreadGroupSize": [
8,
8,
1
]
}
],
"m_VariantIndices": [
{
"Key": "",
"Value": 0
}
]
}
],
"m_NeedsReflectionData": false,
"m_ResourcesResolved": true,
"m_TargetLevel": 0,
"m_TargetRenderer": 2
}
]
}
只需要使用windows系统自带的fxc.exe(注意要用全英路径!!!)
然后终端运行:"路径/fxc.exe" /dumpbin /Fc K0.asm K0.dxbc
此时便可得到txt的可读文件


虽然仍是汇编指令,但是已经具备可读性,直接扔给AI梭哈一下就可以了,之前我们还提到的cotex,citex等等数据,这些直接用AssetRipper找就可以,这里就不多赘述了


最后编写解密脚本即可
import base64
ci_b64 = "6Y6KirfnyeC4l7dLOyHTfLyKz9WogS6oo9KUa7qAnQ=="
def rol8(x, s):
s &= 7
x &= 0xFF
return ((x << s) | (x >> (8 - s))) & 0xFF
def ror8(x, s):
s &= 7
x &= 0xFF
return ((x >> s) | (x << (8 - s))) & 0xFF
INV7 = pow(7, -1, 256) # 183
def K0_inverse(out16):
k = 42
inp = []
for i, bout in enumerate(out16):
# out = (rol8(in^k, i) * 7 + i) mod 256
b0 = ((bout - i) * INV7) & 0xFF # b0 = rol8(in^k, i)
binp = (ror8(b0, i) ^ k) & 0xFF # in = ror8(b0,i) ^ k
inp.append(binp)
k = (k + bout) & 0xFF # 注意:k 用输出更新
return inp
def main():
ci = base64.b64decode(ci_b64)
ci0 = list(ci[:16]) # mip0
# K1 条件:ci[i] == (work3[i] + i) & 255
work3 = [ (b - i) & 0xFF for i, b in enumerate(ci0) ]
# 逆三轮 K0
work2 = K0_inverse(work3)
work1 = K0_inverse(work2)
work0 = K0_inverse(work1)
s = bytes(work0).decode("ascii")
print("answer =", s)
if __name__ == "__main__":
main()
最后就是外包,直接在ida中看b_0呢个函数的1026地址处就写的,此时我们可以得到准确答案

答案:alictf{5haderVM_Rep3at!}

Comments NOTHING