基于京华杯和阿里云ctf|alictf逆向中pixelflow对Unity引擎技术深入研究并进行逆向学习

Sher10ck 发布于 2026-02-12 269 次阅读


基于京华杯和阿里云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.dllGameAssembly.dll (根目录)
代码格式.NET IL (中间语言)Native x86/x64 (机器码)
关键文件夹MonoBleedingEdgeil2cpp_data
逆向难度简单 (★)困难 (★★★★)
主要工具dnSpy (直接改代码)Il2CppDumper + IDA Pro
能否还原源码能还原出几乎 100% 的 C# 源码只能看到汇编,需要结合伪代码猜逻辑

了解完了我们的unity引擎逻辑便可以通过工具对程序进行逆向解密了,我们先从简单的看起

例题一:25年京华杯binary-unity

工具链接:

AssetRipper/AssetRipper: GUI Application to work with engine assets, asset bundles, and serialized files

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,再 CopyTextureTexF。输入进入 GPU。

Controller__Check_b__18_2_d__MoveNext
ComputeShader.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": "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AwAAAAoAEAADAAAAAUAAAAEAAAACAAABBgAAAwFAAAABAAAANgAAB4IAEAAAAAAACjAgBAEAAAAqABAABAAAAAEAAAcSABAAAQAAADoAEAAAAAAAAUAAAA8AAACjAACJwgAAgENVFQCCABAAAAAAAEYOEAABAAAAluMRAAAAAAA4AAAHggAQAAAAAAA6ABAAAAAAAAFAAAAAAH9DQAAABYIAEAAAAAAAOgAQAAAAAAAcAAAFggAQAAAAAAA6ABAAAAAAAAEAAAeCABAAAAAAADoAEAAAAAAAAUAAAP8AAAA2AAAHEjAgBAEAAAAaABAABAAAADoAEAAAAAAAHgAABxIAEAADAAAACgAQAAMAAAABQAAAAQAAAAIAAAEGAAADAUAAAAIAAAA2AAAHggAQAAAAAAAKMCAEAQAAABoAEAAEAAAANgAABxIAEAABAAAACjAgBAEAAAAqABAABAAAAFcAAAeCABAAAAAAADoAEAAAAAAACgAQAAEAAAABAAAHggAQAAAAAAA6ABAAAAAAAAFAAAD/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!}

此作者没有提供个人介绍。
最后更新于 2026-02-12