alictf2026 pixelflow
c# StateMachine, ezVM, Texture Render, ComputeShader kernel
工具们
.NET 编译产物基本构成#
编译一个项目通常得到一个可执行文件和一个 assembly
.cs 源码编译成 IL 装进一个程序集(assembly),常见的形态有
- .dll
- .exe(Windows 上的“托管 exe”)
跨平台的主体通常是 dll,运行时由 dotnet 去加载它,JIT 成本机指令执行。元数据也会放到里面。
编译得到的可执行文件通常是一个 launcher,负责:
- 找到合适的 .NET runtime, *.runtimeconfig.json, *.deps.json
- 启动并加载 assembly
.NET 逆向#
IL+元数据#
.NET 程序通常编译成中间语言 IL,还有丰富的元数据(类型、方法签名、属性、泛型信息),分析元数据常用 dnspy、ilspy
C# 状态机#
async/await 状态机本质是把一个函数切成多段,用 state 组织起来,并用回调把下一段安排在未来执行
async Task<int> Foo()
{
var a = 1;
await SomeIO(); // 伪阻塞
var b = 2;
return a + b;
}
编译后形成这样的逻辑
class FooStateMachine {
int state; // 记录状态,保证阻塞结束的运行
int a; // 需要的局部变量被提升成字段保存起来。阻塞后出现的 b 则不需要
TaskAwaiter awaiter
TskCompletionSource<int> tcs; // 用来完成返回的 Task
void MoveNext() {
try {
if (state == 0) {
a = 1;
awaiter = SomeIO().GetAwaiter();
if (!awaiter.IsCompleted) {
state = 1; // 若操作未完成,async 方法被挂起,调用 OnCompleted 来注册一个“续体”
awaiter.OnCompleted(MoveNext); // 注册回调,语义为等这个 awaiter 完成时再调用一次 MoveNext()
return;
}
}
if (state == 1) {
awaiter.GetResult();
int b = 2;
tcs.SetResult(a + b);
}
} catch (Exception e) {
tcs.SetException(e);
}
}
}
更完全的逻辑
async Task<int> Foo()
{
A();
await Bar();
B();
return 42;
}
private struct Foo_d__0 : IAsyncStateMachine
{
public int _state;
public AsyncTaskMethodBuilder<int> _builder;
private TaskAwaiter _awaiter;
private int _result;
public void MoveNext()
{
int result;
try
{
if (_state == 0) goto After Await0;
A();
// await Bar();
var awaiter = Bar().GetAwaiter();
if (!awaiter.IsCompleted)
{
_state = 0;
_awaiter = awaiter;
_builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
return;
}
AfterAwait0:
if (_state == 0)
{
awaiter = _awaiter;
_awaiter = default;
_state = -1;
}
awaiter.GetResult();
B();
result = 42;
}
catch (Exception ex)
{
_state = -2;
_builder.SetException(ex);
return;
}
_state = -2;
_builder.SetResult(result);
}
public void SetStateMachine(IAsyncStateMachine sm)
=> _builder.SetStateMachine(sm);
}
原方法 Foo() 被改写成
Task<int> Foo()
{
var sm = new Foo_d__0();
sm._builder = AsyncTaskMethodBuilder<int>.Create();
sm._state = -1;
sm._builder.Start(ref sm);
return sm._builder.Task;
}
普通 await 可能挂起 async(awaiter.IsCompleted 返回 false),也可能同步直通(awaiter.IsCompleted 返回 true,一般是缓存命中、完成态Task等),await Task.Yield() 强制在 await 处停下等待回调,制造一个必定异步的切分点
反编译#
反编译器做语法糖重建,可能出现 async
命名风格#
00000000 struct Controller_o // sizeof=0x90
00000000 {
00000000 Controller_c *klass;
00000008 void *monitor;
00000010 Controller_Fields fields;
00000090 };
00000000 struct Controller_c // sizeof=0x178
00000000 {
00000000 Il2CppClass_1 _1;
000000B8 void *static_fields;
000000C0 Il2CppRGCTXData *rgctx_data;
000000C8 Il2CppClass_2 _2;
00000138 Controller_VTable vtable;
00000178 };
00000000 struct __cppobj Controller_Fields : UnityEngine_MonoBehaviour_Fields // sizeof=0x80
00000000 { // XREF: Controller_o/r
00000010 struct TMPro_TMP_InputField_o *InputField0;
00000018 struct UnityEngine_UI_Button_o *Button0;
00000020 struct UnityEngine_ComputeShader_o *Shader0;
00000028 struct UnityEngine_Texture2D_o *Tex0;
00000030 struct UnityEngine_Texture2D_o *Tex1;
00000038 struct UnityEngine_Vector2_o tileScale;
00000040 float scrollSpeed;
00000044 float rotationDegrees;
00000048 struct UnityEngine_RenderTexture_o *TexF;
00000050 struct UnityEngine_Texture2D_o *TexC;
00000058 struct UnityEngine_Texture2D_o *TexV;
00000060 struct UnityEngine_ComputeBuffer_o *Buffer0;
00000068 struct UnityEngine_RenderTexture_o *TexR;
00000070 int32_t K0;
00000074 int32_t K1;
00000078 int32_t K2;
0000007C // padding byte
0000007D // padding byte
0000007E // padding byte
0000007F // padding byte
00000080 };
-
*_o 对象实例(Object)
-
*_c 类(运行时用来描述类型本身的元数据结构)
-
*_Fields 实例字段区
00000000 struct Controller__Check_d__18_Fields // sizeof=0x58
00000000 { // XREF: Controller__Check_d__18_o/r
00000000 int32_t __1__state;
00000004 // padding byte
00000005 // padding byte
00000006 // padding byte
00000007 // padding byte
00000008 struct System_Runtime_CompilerServices_AsyncVoidMethodBuilder_o __t__builder;
00000028 struct Controller_o *__4__this;
00000030 struct System_Func_byte____Task__o *_uploadFlagAsync_5__2;
00000038 struct System_Func_Task__o *_runEncryptAsync_5__3;
00000040 struct System_Func_Task__o *_runCheckAsync_5__4;
00000048 struct System_Runtime_CompilerServices_TaskAwaiter_byte____o __u__1;
00000050 struct System_Runtime_CompilerServices_TaskAwaiter_o __u__2;
00000058 };
- Check_d__18,即 <Check>d__18,表示方法 Check 的 StateMachine type,18 为元数据序号
00000000 struct Controller___Check_b__18_3_d_Fields // sizeof=0x30
00000000 { // XREF: Controller___Check_b__18_3_d_o/r
00000000 int32_t __1__state;
00000004 // padding byte
00000005 // padding byte
00000006 // padding byte
00000007 // padding byte
00000008 struct System_Runtime_CompilerServices_AsyncTaskMethodBuilder_o __t__builder;
00000020 struct Controller_o *__4__this;
00000028 struct System_Runtime_CompilerServices_YieldAwaitable_YieldAwaiter_o __u__1;
00000029 // padding byte
0000002A // padding byte
0000002B // padding byte
0000002C // padding byte
0000002D // padding byte
0000002E // padding byte
0000002F // padding byte
00000030 };
*b_* 即 <Check>b__18_3,表示某个 lambda 被编译器提升后的一个生成方法,3 表示这是 Check 中第四个 lambda
Delegate#
很像是一个虚调用
il2cpp:00007FFB93134A27 test r15, r15
il2cpp:00007FFB93134A2A jz short loc_7FFB93134A7F
il2cpp:00007FFB93134A2C mov rax, [r15+18h]
il2cpp:00007FFB93134A30 mov r8, [r15+28h]
il2cpp:00007FFB93134A34 mov rdx, r13
il2cpp:00007FFB93134A37 mov rcx, [r15+40h]
il2cpp:00007FFB93134A3B call raxil2cpp:00007FFB93134A27 test r15, r15
il2cpp:00007FFB93134A2A jz short loc_7FFB93134A7F
il2cpp:00007FFB93134A2C mov rax, [r15+18h]
il2cpp:00007FFB93134A30 mov r8, [r15+28h]
il2cpp:00007FFB93134A34 mov rdx, r13
il2cpp:00007FFB93134A37 mov rcx, [r15+40h]
il2cpp:00007FFB93134A3B call rax
c# 中,delegate 是一种类似函数指针的类型,它指向一个静态或实例方法,当指向实例方法时还能带上一个目标对象(实例方法的 this),还能多播(multicast,+= 叠加多个回调)。il2cpp 中,delegate 被写成一个堆对象(Il2CppDelegate),核心字段有:
- 要调用的函数指针(通常不指向函数本体,而是一个wrapper,详见后文)
- target:实例方法需要的 this (静态委托该字段为 null)
- method / MethodInfo:方法元信息(反射/泛型/调试/某些调用适配需要)
- (多播时)invocation list:一串子 delegate
test r15, r15 ; r15 是 Il2CppDelegate*,为空就不调。相当于 if
jz short loc_7FFB93134A7F
mov rax, [r15+18h] ; 从对象里取一个可执行地址
mov r8, [r15+28h]
mov rdx, r13
mov rcx, [r15+40h]
call raxil2cpp:00007FFB93134A27 test r15, r15
jz short loc_7FFB93134A7F
mov rax, [r15+18h]
mov r8, [r15+28h]
mov rdx, r13
mov rcx, [r15+40h]
call rax
alictf 2026 pixelflow#
Il2CppDumper dump 下来 Assembly-CSharp.dll 用 ilspy 看一眼

Controller 瞩目。看一眼,是 UnityEngine.MonoBehaviour 的子类。
UnityEngine.MonoBehaviour#
挂在 GameObject 上的行为脚本的基类。有以下特点
- 必须附着在 GameObject 上
- 不能用 new 创建(如果 new 的话不会运行生命周期函数
- 必须通过 AddComponent<T>() 添加
不是普通的 C# 类,而是一个由引擎托管的对象
生命周期函数#
MonoBehaviour 定义了一套由引擎自动调用的回调函数,常见的声明周期顺序是:
- Awake() 对象被加载时调用,用于初始化
- Start() 第一次启动时调用
- Update() 每帧调用一次
- LateUpdate() 在 Update 之后执行,常用于相机跟随等收尾工作
- FixedUpdate() 固定时间间隔调用,用于物理计算
- OnDestroy() 对象被销毁时调用
继承后#
继承 MonoBehaviour 后,可以:
-
监听触发器(OnTriggerEnter)
-
监听碰撞(OnCollisionEnter)
-
使用 Unity 的系统事件
-
…
因此按钮绑定的逻辑和它强相关
Start()#
void Controller__Start(Controller_o *this, const MethodInfo *method)
{
Controller_o *v2; // rdi
struct UnityEngine_UI_Button_o *Button0; // rax
UnityEngine_Events_UnityEvent_o *m_OnClick; // rbx
UnityEngine_AI_NavMesh_OnNavMeshPreUpdate_o *v5; // rsi
int32_t Kernel; // eax
int32_t v7; // eax
int32_t v8; // eax
__int64 v9; // rdx
UnityEngine_ComputeBuffer_o *v10; // rbx
UnityEngine_ComputeBuffer_o *Buffer0; // rbx
__int64 v12; // rax
Il2CppObject *object; // rax
Il2CppObject *v14; // rax
__int64 v15; // rdx
UnityEngine_RenderTexture_o *v16; // rbx
v2 = this;
if ( !byte_180F4C9A0 )
{
sub_180157800(&UnityEngine_ComputeBuffer_TypeInfo);
sub_180157800(&Method_Controller_Check__);
sub_180157800(&int___TypeInfo);
sub_180157800(&UnityEngine_RenderTexture_TypeInfo);
sub_180157800(&UnityEngine_Events_UnityAction_TypeInfo);
sub_180157800(&StringLiteral_4359);
sub_180157800(&StringLiteral_3332);
sub_180157800(&StringLiteral_3956);
sub_180157800(&StringLiteral_3328);
sub_180157800(&StringLiteral_3330);
sub_180157800(&StringLiteral_1742);
sub_180157800(&StringLiteral_312);
sub_180157800(&StringLiteral_1800);
sub_180157800(&StringLiteral_320);
sub_180157800(&StringLiteral_1730);
byte_180F4C9A0 = 1;
} // il2cpp 常见的 lazy init,把后面用到的类型信息、方法指针、字符串常量加载进来
// 绑定回调
Button0 = v2->fields.Button0;
if ( !Button0 )
goto LABEL_27;
m_OnClick = Button0->fields.m_OnClick;
v5 = sub_1800F5060(UnityEngine_Events_UnityAction_TypeInfo, method); // new 一个 UnityAction 实例
UnityEngine_AI_NavMesh_OnNavMeshPreUpdate___ctor(v5, v2, Method_Controller_Check__, 0); // 构造 UnityAction:target = this, method = Controller.Check。反编译成 navmesh 应该是类型判断错位
if ( !m_OnClick )
goto LABEL_27;
UnityEngine_Events_UnityEvent__AddListener(m_OnClick, v5, 0);
this = v2->fields.Shader0; // 把 UnityAction 加到按钮 onClick
if ( !this )
goto LABEL_27;
// ComputeShader: 查三个 kernel (K0, K1, K2),分别绑定 TexR/Tex0/Tex1 三张纹理
Kernel = UnityEngine_ComputeShader__FindKernel(this, StringLiteral_3328, 0); // -> K0
this = v2->fields.Shader0;
v2->fields.K0 = Kernel;
if ( !this )
goto LABEL_27;
v7 = UnityEngine_ComputeShader__FindKernel(this, StringLiteral_3330, 0); // -> K1
this = v2->fields.Shader0;
v2->fields.K1 = v7;
if ( !this )
goto LABEL_27;
v8 = UnityEngine_ComputeShader__FindKernel(this, StringLiteral_3332, 0); // -> K2
this = v2->fields.Shader0;
v2->fields.K2 = v8;
if ( !this )
goto LABEL_27;
UnityEngine_ComputeShader__SetTexture_6451781712(this, v8, StringLiteral_3956, v2->fields.TexR, 0); // SetTextuer(Shader0, K2, "OutputTex", TexR); StringLiteral_3956 = OutputTex
this = v2->fields.Shader0;
if ( !this )
goto LABEL_27;
UnityEngine_ComputeShader__SetTexture_6451781712(this, v2->fields.K2, StringLiteral_1800, v2->fields.Tex0, 0); // SetTexture(Shader0, K2, "CorrectTex", Tex0); StringLiteral_1800 = CorrectTex
this = v2->fields.Shader0;
if ( !this )
goto LABEL_27;
UnityEngine_ComputeShader__SetTexture_6451781712(this, v2->fields.K2, StringLiteral_320, v2->fields.Tex1, 0); // SetTexture(Shader0, K2, "WrongTex", Tex1); StringLiteral_320 = WrongTex
v10 = sub_1800F5060(UnityEngine_ComputeBuffer_TypeInfo, v9);
// 创建 ComputeBuffer:1 个 4 字节的 Buffer,初始值 -1,绑定到 K1/K2
UnityEngine_ComputeBuffer___ctor(v10, 1, 4, 0);
v2->fields.Buffer0 = v10;
sub_180156C70(&v2->fields.Buffer0, v10);
Buffer0 = v2->fields.Buffer0;
v12 = sub_180156CF0(int___TypeInfo, 1);
if ( !v12 )
goto LABEL_27;
if ( !*(v12 + 24) )
sub_1801579E0();
*(v12 + 32) = -1;
if ( !Buffer0 )
goto LABEL_27;
UnityEngine_ComputeBuffer__SetData(Buffer0, v12, 0);
this = v2->fields.Shader0;
if ( !this )
goto LABEL_27;
UnityEngine_ComputeShader__SetBuffer_6451781152(this, v2->fields.K1, StringLiteral_4359, v2->fields.Buffer0, 0); // StringLiteral_4359 = SharedState
this = v2->fields.Shader0;
if ( !this )
goto LABEL_27;
UnityEngine_ComputeShader__SetBuffer_6451781152(this, v2->fields.K2, StringLiteral_4359, v2->fields.Buffer0, 0);
if ( !byte_180F4C9A3 )
{
sub_180157800(&Method_UnityEngine_Resources_Load_Texture2D___);
sub_180157800(&StringLiteral_1408);
sub_180157800(&StringLiteral_1380);
byte_180F4C9A3 = 1;
}
// 从 Resources 加载 Texture2D,
// object = Resources.Load<Texture2D>(ciTex); v2->fields.TexC = object;
// ciTex 是路径字符串
object = UnityEngine_Resources__Load_object_(StringLiteral_1380, Method_UnityEngine_Resources_Load_Texture2D___); // StringLiteral = ciTex
v2->fields.TexC = object;
sub_180156C70(&v2->fields.TexC, object);
v14 = UnityEngine_Resources__Load_object_(StringLiteral_1408, Method_UnityEngine_Resources_Load_Texture2D___); // StringLiteral = coTex
v2->fields.TexV = v14;
sub_180156C70(&v2->fields.TexV, v14);
this = v2->fields.Shader0;
if ( !this )
goto LABEL_27;
UnityEngine_ComputeShader__SetTexture_6451781712(this, v2->fields.K0, StringLiteral_1742, v2->fields.TexV, 0); // Shader0.SetTexture(K0, CoTex, TexV); StringLiteral = CoTex
this = v2->fields.Shader0;
if ( !this )
goto LABEL_27;
UnityEngine_ComputeShader__SetTexture_6451781712(this, v2->fields.K1, StringLiteral_1730, v2->fields.TexC, 0); // Shader0.SetTexture(K1, CiTex); StringLiteral = CiTex
// Construct RenderTexture
// v16 = new RenderTexture(16, 1, 0, 16, 1)
// v2.fields.TexF = v16
v16 = sub_1800F5060(UnityEngine_RenderTexture_TypeInfo, v15);
UnityEngine_RenderTexture___ctor_6451745168(v16, 16, 1, 0, 16, 1, 0);
v2->fields.TexF = v16;
sub_180156C70(&v2->fields.TexF, v16);
this = v2->fields.TexF;
if ( !this )
goto LABEL_27;
UnityEngine_RenderTexture__set_enableRandomWrite(this, 1, 0);
this = v2->fields.TexF;
if ( !this )
goto LABEL_27;
UnityEngine_Texture__set_filterMode(this, 0, 0);
this = v2->fields.TexF;
if ( !this
|| (UnityEngine_Texture__set_wrapMode(this, 1, 0), (this = v2->fields.TexF) == 0)
|| (UnityEngine_RenderTexture__Create(this, 0), (this = v2->fields.Shader0) == 0)
|| (UnityEngine_ComputeShader__SetTexture_6451781712(this, v2->fields.K0, StringLiteral_312, v2->fields.TexF, 0), // StringLiteral = WorkTex
(this = v2->fields.Shader0) == 0) )
{
LABEL_27:
sub_1801579F0(this, method);
}
UnityEngine_ComputeShader__SetTexture_6451781712(this, v2->fields.K1, StringLiteral_312, v2->fields.TexF, 0);
}
Unity 渲染链路#
图片资源导入引擎得到 Texture2D (由 ComputeShader 读取,计算完成后输出到一个 RenderTexture)
ComputeBuffer (结构化数据,optional)
把 Texture / Buffer 绑定到某个 kernel 的参数槽
ComputeShader(kernel) 计算 Texture2D(模糊处理等)
Shader 将 RenderTexture 渲染出来
// *.compute
#pragma kernel BlurH
#pragma kernel BlurV
Texture2D<float4> _Src;
RWTexture2D<float4> _Dst;
SamplerState samplerLinear;
[numthreads(8,8,1)]
void BlurH(uint3 id : SV_DispatchThreadID) { ... }
[numthreads(8,8,1)]
void BlurV(uint3 id : SV_DispatchThreadID) { ... }
.compute 文件里长这样,C# 与其交互:
- FindKernel(“BlurH”) 得到一个
kernelIndex - SetTexture(kernelIndex, “_Src”, tex) / SetBuffer(kernelIndex, “_Particles”, buf) 绑定资源到 kernel
- Dispatch(kernelIndex, groupX, groupY, groupZ) 让 GPU 跑起来
ComputeShader#
kernel 即核函数,就是一段可以被 GPU 并行执行的函数的入口
int kernel = computeShader.FindKernel("CSMain");
computeShader.Dispatch(kernel, 16, 16, 1); // Dispatch 的三个参数表示线程组数量,线程总数 = numthreads * Dispatch 数量
Texture 不只是贴图,也是一个二/三维的数据容器,常见类型有
- Texture2D // 只读
- RWTexture2D // 可读写
RWTexture2D Result;
[numthreads(8, 8, 1)]
void CSMain (uint3 id: SV_DispatchThreadID)
{
float2 uv = id.xy / 512.0;
Result[id.xy] = float4(uv, 9, 1);
}
Controller.Check()#
void Controller__Check(Controller_o *this, const MethodInfo *method)
{
System_Runtime_CompilerServices_AsyncVoidMethodBuilder_o v3; // [rsp+20h] [rbp-88h] BYREF
Controller__Check_d__18_o v4; // [rsp+40h] [rbp-68h] BYREF
if ( !byte_180F4C9A2 )
{
sub_180157800(&Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_Start_Controller__Check_d__18___);
byte_180F4C9A2 = 1;
}
memset(&v4, 0, sizeof(v4)); // 状态机结构体清零
v4.fields.__t__builder = *System_Runtime_CompilerServices_AsyncVoidMethodBuilder__Create(&v3, 0); // 创建 async void 的 builder(负责异常传播、继续执行、调度等)
sub_180156C70(&v4.fields.__t__builder, 0);
v4.fields.__4__this = this; // 把外层 Controller 实例捕获进去(等价于 C# 中的 this 被 state machine 持有)
sub_180156C70(&v4.fields.__4__this, this);
v4.fields.__1__state = -1; // 初始化 state,-1 表示尚未进入任何 await 分支
System_Runtime_CompilerServices_AsyncVoidMethodBuilder__Start_Controller__Check_d__18_(&v4.fields.__t__builder, &v4);// 启动状态机,内部调用 MoveNext()
}
这个函数是一个 async void 方法的启动器(真正的逻辑在 Controller__Check_d_18__),有以下特征:
- 用了 System.Runtime.CompilerServices.AsyncVoidMethodBuilder
- 调用了 AsyncVoidMethodBuilder.Create()
- __1__state = -1
- AsyncVoidMethodBuilder.Start<TStateMachine>(ref builder, ref stateMachine)
AsyncVoidMethodBuilder.Start() 里面可以找到对 MoveNext() 的调用,这就是核心逻辑
MoveNext()#
监听 Button 绑定到 Check(),做一些 kernel 的初始化和绑定
void Controller__Check_d__18__MoveNext(Controller__Check_d__18_o *this, const MethodInfo *method)
{
Il2CppObject *_4__this; // rdi
__int64 v4; // rsi
__int64 v5; // rdx
UnityEngine_UIElements_UIElementsRuntimeUtility_CreateRuntimePanelDelegate_o *v6; // r15
__int64 v7; // rdx
UnityEngine_UIElements_GetViewDataDictionary_o *v8; // r15
__int64 v9; // rdx
UnityEngine_UIElements_GetViewDataDictionary_o *v10; // r15
__int64 v11; // rdx
__int64 v12; // rcx
System_Threading_Tasks_Task_TResult__o *v13; // rax
__int64 v14; // rdx
__int64 v15; // rcx
Il2CppObject *Result; // rax
__int64 v17; // rdx
__int64 v18; // rcx
struct System_Func_byte____Task__o *uploadFlagAsync_5__2; // rcx
System_Threading_Tasks_Task_o *v20; // rax
__int64 v21; // rdx
__int64 v22; // rcx
__int64 v23; // rdx
struct System_Func_Task__o *runEncryptAsync_5__3; // rcx
System_Threading_Tasks_Task_o *v25; // rax
__int64 v26; // rdx
__int64 v27; // rcx
__int64 v28; // rdx
struct System_Func_Task__o *v29; // rcx
System_Threading_Tasks_Task_o *v30; // rax
__int64 v31; // rdx
__int64 v32; // rcx
__int64 v33; // rdx
struct System_Func_Task__o *v34; // rcx
System_Threading_Tasks_Task_o *v35; // rax
__int64 v36; // rdx
__int64 v37; // rcx
__int64 v38; // rdx
struct System_Func_Task__o *runCheckAsync_5__4; // rcx
System_Threading_Tasks_Task_o *v40; // rax
__int64 v41; // rdx
__int64 v42; // rcx
UnityEngine_ComputeBuffer_o *klass; // rdi
__int64 v44; // rax
__int64 v45; // rdx
__int64 v46; // rcx
System_Runtime_CompilerServices_ConfiguredTaskAwaitable_ConfiguredTaskAwaiter_TResult__o v47; // [rsp+80h] [rbp+18h] BYREF
if ( !byte_180F4C9B1 )
{
sub_180157800(&Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_AwaitUnsafeOnCompleted_TaskAwaiter_byte_____Controller__Check_d__18___);
sub_180157800(&Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18___);
sub_180157800(&Method_Controller__Check_b__18_0__);
sub_180157800(&Method_Controller__Check_b__18_1__);
sub_180157800(&Method_Controller__Check_b__18_2__);
sub_180157800(&Method_Controller__Check_b__18_3__);
sub_180157800(&System_Func_Task__TypeInfo);
sub_180157800(&System_Func_Task_byte_____TypeInfo);
sub_180157800(&System_Func_byte____Task__TypeInfo);
sub_180157800(&int___TypeInfo);
sub_180157800(&Method_System_Runtime_CompilerServices_TaskAwaiter_byte____GetResult__);
sub_180157800(&Method_System_Runtime_CompilerServices_TaskAwaiter_byte____get_IsCompleted__);
sub_180157800(&Method_System_Threading_Tasks_Task_byte____GetAwaiter__);
byte_180F4C9B1 = 1;
}
*&v47.fields.m_continueOnCapturedContext = 0;
v47.fields.m_task = 0;
_4__this = this->fields.__4__this;
switch ( this->fields.__1__state ) // 第一次进入 default 分支,之后恢复对应的 await,共 6 次
{
case 0:
*&v47.fields.m_continueOnCapturedContext = this->fields.__u__1.fields.m_task;
this->fields.__u__1.fields.m_task = 0;
this->fields.__1__state = -1;
goto LABEL_13;
case 1:
v47.fields.m_task = this->fields.__u__2.fields.m_task;
this->fields.__u__2.fields.m_task = 0;
this->fields.__1__state = -1;
goto LABEL_17;
case 2:
v47.fields.m_task = this->fields.__u__2.fields.m_task;
this->fields.__u__2.fields.m_task = 0;
this->fields.__1__state = -1;
goto LABEL_20;
case 3:
v47.fields.m_task = this->fields.__u__2.fields.m_task;
this->fields.__u__2.fields.m_task = 0;
this->fields.__1__state = -1;
goto LABEL_23;
case 4:
v47.fields.m_task = this->fields.__u__2.fields.m_task;
this->fields.__u__2.fields.m_task = 0;
this->fields.__1__state = -1;
goto LABEL_26;
case 5:
v47.fields.m_task = this->fields.__u__2.fields.m_task;
this->fields.__u__2.fields.m_task = 0;
this->fields.__1__state = -1;
goto LABEL_29;
default:
// 创建 4 个委托(v4, v6, v8, v10)
// v4 = new Func<Task<byte[]>>(_4__this, Check_b__18_0);
v4 = sub_1800F5060(System_Func_Task_byte_____TypeInfo, method);
UnityEngine_UIElements_GetViewDataDictionary___ctor(v4, _4__this, Method_Controller__Check_b__18_0__, 0); // 编译成 UIElements 依旧是类型判断错位
// v6 = new Func<byte[], Task>(_4__this, Check_b__18_1);
v6 = sub_1800F5060(System_Func_byte____Task__TypeInfo, v5);
UnityEngine_UIElements_UIElementsRuntimeUtility_CreateRuntimePanelDelegate___ctor(
v6,
_4__this,
Method_Controller__Check_b__18_1__,
0);
this->fields._uploadFlagAsync_5__2 = v6;
sub_180156C70(&this->fields._uploadFlagAsync_5__2, v6);
// v8 = new Func<Task>(_4__this, Check_b__18_2);
v8 = sub_1800F5060(System_Func_Task__TypeInfo, v7);
UnityEngine_UIElements_GetViewDataDictionary___ctor(v8, _4__this, Method_Controller__Check_b__18_2__, 0);
this->fields._runEncryptAsync_5__3 = v8;
sub_180156C70(&this->fields._runEncryptAsync_5__3, v8);
// v10 = new Func<Task>(_4__this, Check_b__18_3);
v10 = sub_1800F5060(System_Func_Task__TypeInfo, v9);
UnityEngine_UIElements_GetViewDataDictionary___ctor(v10, _4__this, Method_Controller__Check_b__18_3__, 0);
this->fields._runCheckAsync_5__4 = v10;
sub_180156C70(&this->fields._runCheckAsync_5__4, v10);
// 这段 new 了一堆 Func,相当于写了一堆 lambda:
/*
var get = new Func<Task<byte[]>>(() => ... );
Func<byte[], Task> uploadFlagAsync = (bytes) => ...;
Func<Task> runEncryptAsync = () => ...;
Func<Task> runCheckAsync = () => ...;
*/
if ( !v4 ) // 判断有没有 get 到 byte[] Result
sub_1801579F0(v12, v11); // 没 get 到抛出 nullException
v13 = (*(v4 + 24))(*(v4 + 64), *(v4 + 40)); // Task<byte[]> t = v4.Invoke();
if ( !v13 )
sub_1801579F0(v15, v14);
*&v47.fields.m_continueOnCapturedContext = System_Threading_Tasks_Task___Il2CppFullySharedGenericType___GetAwaiter(
v13,
Method_System_Threading_Tasks_Task_byte____GetAwaiter__); // awaiter = t.GetAwaiter();
if ( System_Runtime_CompilerServices_ConfiguredTaskAwaitable_ConfiguredTaskAwaiter___Il2CppFullySharedGenericType___get_IsCompleted(
&v47.fields.m_continueOnCapturedContext,
Method_System_Runtime_CompilerServices_TaskAwaiter_byte____get_IsCompleted__) ) // 判断 IsCompleted
{
LABEL_13: // 第一个 await
Result = System_Runtime_CompilerServices_ConfiguredTaskAwaitable_ConfiguredTaskAwaiter_object___GetResult(
&v47.fields.m_continueOnCapturedContext,
Method_System_Runtime_CompilerServices_TaskAwaiter_byte____GetResult__); // 先 getResult
if ( Result )
{
// 调 uploadFlagAsync
uploadFlagAsync_5__2 = this->fields._uploadFlagAsync_5__2;
if ( !uploadFlagAsync_5__2 )
sub_1801579F0(0, v17);
v20 = (uploadFlagAsync_5__2->fields.invoke_impl)(
uploadFlagAsync_5__2->fields.method_code,
Result,
uploadFlagAsync_5__2->fields.method);
if ( !v20 )
sub_1801579F0(v22, v21);
v47.fields.m_task = System_Threading_Tasks_Task__GetAwaiter(v20, 0).fields.m_task;
if ( !System_Runtime_CompilerServices_ConfiguredTaskAwaitable_ConfiguredTaskAwaiter___Il2CppFullySharedGenericType___get_IsCompleted(
&v47,
0) )
{
this->fields.__1__state = 1;
this->fields.__u__2.fields.m_task = v47.fields.m_task;
sub_180156C70(&this->fields.__u__2, 0);
System_Runtime_CompilerServices_AsyncVoidMethodBuilder__AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18_(
&this->fields.__t__builder,
&v47,
this,
Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18___);
return;
}
LABEL_17: // 第二个 await
System_Runtime_CompilerServices_TaskAwaiter__GetResult(&v47, 0);
// 调 runEncryptAsync
runEncryptAsync_5__3 = this->fields._runEncryptAsync_5__3;
if ( !runEncryptAsync_5__3 )
sub_1801579F0(0, v23);
v25 = (runEncryptAsync_5__3->fields.invoke_impl)(
runEncryptAsync_5__3->fields.method_code,
runEncryptAsync_5__3->fields.method);
if ( !v25 )
sub_1801579F0(v27, v26);
v47.fields.m_task = System_Threading_Tasks_Task__GetAwaiter(v25, 0).fields.m_task;
if ( !System_Runtime_CompilerServices_ConfiguredTaskAwaitable_ConfiguredTaskAwaiter___Il2CppFullySharedGenericType___get_IsCompleted(
&v47,
0) )
{
this->fields.__1__state = 2;
this->fields.__u__2.fields.m_task = v47.fields.m_task;
sub_180156C70(&this->fields.__u__2, 0);
System_Runtime_CompilerServices_AsyncVoidMethodBuilder__AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18_(
&this->fields.__t__builder,
&v47,
this,
Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18___);
return;
}
LABEL_20: // 第三个 await
System_Runtime_CompilerServices_TaskAwaiter__GetResult(&v47, 0);
// 调 runEncryptAsync
v29 = this->fields._runEncryptAsync_5__3;
if ( !v29 )
sub_1801579F0(0, v28);
v30 = (v29->fields.invoke_impl)(v29->fields.method_code, v29->fields.method);
if ( !v30 )
sub_1801579F0(v32, v31);
v47.fields.m_task = System_Threading_Tasks_Task__GetAwaiter(v30, 0).fields.m_task;
if ( !System_Runtime_CompilerServices_ConfiguredTaskAwaitable_ConfiguredTaskAwaiter___Il2CppFullySharedGenericType___get_IsCompleted(
&v47,
0) )
{
this->fields.__1__state = 3;
this->fields.__u__2.fields.m_task = v47.fields.m_task;
sub_180156C70(&this->fields.__u__2, 0);
System_Runtime_CompilerServices_AsyncVoidMethodBuilder__AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18_(
&this->fields.__t__builder,
&v47,
this,
Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18___);
return;
}
LABEL_23: // 第四个 await
System_Runtime_CompilerServices_TaskAwaiter__GetResult(&v47, 0);
// 调 runEncryptAsync
v34 = this->fields._runEncryptAsync_5__3;
if ( !v34 )
sub_1801579F0(0, v33);
v35 = (v34->fields.invoke_impl)(v34->fields.method_code, v34->fields.method);
if ( !v35 )
sub_1801579F0(v37, v36);
v47.fields.m_task = System_Threading_Tasks_Task__GetAwaiter(v35, 0).fields.m_task;
if ( !System_Runtime_CompilerServices_ConfiguredTaskAwaitable_ConfiguredTaskAwaiter___Il2CppFullySharedGenericType___get_IsCompleted(
&v47,
0) )
{
this->fields.__1__state = 4;
this->fields.__u__2.fields.m_task = v47.fields.m_task;
sub_180156C70(&this->fields.__u__2, 0);
System_Runtime_CompilerServices_AsyncVoidMethodBuilder__AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18_(
&this->fields.__t__builder,
&v47,
this,
Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18___);
return;
}
LABEL_26: // 第五个 await
System_Runtime_CompilerServices_TaskAwaiter__GetResult(&v47, 0);
// 调 runCheckAsync
runCheckAsync_5__4 = this->fields._runCheckAsync_5__4;
if ( !runCheckAsync_5__4 )
sub_1801579F0(0, v38);
v40 = (runCheckAsync_5__4->fields.invoke_impl)(
runCheckAsync_5__4->fields.method_code,
runCheckAsync_5__4->fields.method);
if ( !v40 )
sub_1801579F0(v42, v41);
v47.fields.m_task = System_Threading_Tasks_Task__GetAwaiter(v40, 0).fields.m_task;
if ( !System_Runtime_CompilerServices_ConfiguredTaskAwaitable_ConfiguredTaskAwaiter___Il2CppFullySharedGenericType___get_IsCompleted(
&v47,
0) )
{
this->fields.__1__state = 5;
this->fields.__u__2.fields.m_task = v47.fields.m_task;
sub_180156C70(&this->fields.__u__2, 0);
System_Runtime_CompilerServices_AsyncVoidMethodBuilder__AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18_(
&this->fields.__t__builder,
&v47,
this,
Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_AwaitUnsafeOnCompleted_TaskAwaiter__Controller__Check_d__18___);
return;
}
LABEL_29: // 第六个 await
// 清理字段,SetResult()
System_Runtime_CompilerServices_TaskAwaiter__GetResult(&v47, 0);
}
else
{
if ( !_4__this )
sub_1801579F0(v18, v17);
klass = _4__this[7].klass;
v44 = sub_180156CF0(int___TypeInfo, 1);
if ( !v44 )
sub_1801579F0(v46, v45);
if ( !*(v44 + 24) )
sub_1801579E0();
*(v44 + 32) = 1;
if ( !klass )
sub_1801579F0(v46, v45);
UnityEngine_ComputeBuffer__SetData(klass, v44, 0);
}
this->fields.__1__state = -2;
this->fields._uploadFlagAsync_5__2 = 0;
sub_180156C70(&this->fields._uploadFlagAsync_5__2, 0);
this->fields._runEncryptAsync_5__3 = 0;
sub_180156C70(&this->fields._runEncryptAsync_5__3, 0);
this->fields._runCheckAsync_5__4 = 0;
sub_180156C70(&this->fields._runCheckAsync_5__4, 0);
System_Runtime_CompilerServices_AsyncVoidMethodBuilder__SetResult(&this->fields.__t__builder, 0);
}
else
{
this->fields.__1__state = 0;
this->fields.__u__1.fields.m_task = *&v47.fields.m_continueOnCapturedContext;
sub_180156C70(&this->fields.__u__1, 0);
System_Runtime_CompilerServices_AsyncVoidMethodBuilder__AwaitUnsafeOnCompleted_TaskAwaiter_object___Controller__Check_d__18_( // OnCompleted 在这里
&this->fields.__t__builder,
&v47.fields.m_continueOnCapturedContext,
this,
Method_System_Runtime_CompilerServices_AsyncVoidMethodBuilder_AwaitUnsafeOnCompleted_TaskAwaiter_byte_____Controller__Check_d__18___);
}
return;
}
}
async 函数启动器#
跟进 Controller___Check_b__18_x,很常规的 async 函数启动器。分析一个
System_Threading_Tasks_Task_byte____o *Controller___Check_b__18_0(Controller_o *this, const MethodInfo *method)
{
const MethodInfo *v2; // r8
UnityEngine_Bounds_o v5; // [rsp+20h] [rbp-58h] BYREF
Controller___Check_b__18_0_d_o v6; // [rsp+38h] [rbp-40h] BYREF
if ( !byte_180F4C9A5 )
{
sub_180157800();
sub_180157800();
sub_180157800();
sub_180157800();
byte_180F4C9A5 = 1;
} // 初始化栅栏
// v6 为 StateMachine 对象
*&v6.fields.__1__state = 0;
*&v6.fields.__4__this = 0;
if ( !System_Runtime_CompilerServices_AsyncTaskMethodBuilder_byte____TypeInfo->_2.cctor_finished ) // C# 第一次用到某个类型前,CLR 会保证静态构造(.cctor)已经执行
il2cpp_runtime_class_init(System_Runtime_CompilerServices_AsyncTaskMethodBuilder_byte____TypeInfo, method);
// 这段莫名其妙,应该是反编译误判
// v6.fields.__t__builder = AsyncTaskMethodBuiler<byte>.Create();
TMPro_TMP_Text__GetCompoundBounds(
&v5,
Method_System_Runtime_CompilerServices_AsyncTaskMethodBuilder_byte____Create__,
v2);
v6.fields.__t__builder = v5;
sub_180156C70(&v6.fields.__t__builder, 0);
v6.fields.__4__this = this;
sub_180156C70(&v6.fields.__4__this, this);
v6.fields.__1__state = -1;
// v6.__t__builder.Start(ref v6.builder, ref v6)
// builder 启动方法
System_Runtime_CompilerServices_AsyncTaskMethodBuilder_object___Start_Controller___Check_b__18_0_d_(
&v6.fields.__t__builder,
&v6,
Method_System_Runtime_CompilerServices_AsyncTaskMethodBuilder_byte____Start_Controller___Check_b__18_0_d___);
return System_Runtime_CompilerServices_AsyncTaskMethodBuilder_object___get_Task(
&v6.fields.__t__builder,
Method_System_Runtime_CompilerServices_AsyncTaskMethodBuilder_byte____get_Task__); // return v6.builder.Task 返回 Task
}
sub_180156C70 是 GC 写屏障(避免 GC 漏记引用)
Check() 业务逻辑#
Check_b__18_0:没有名字,就是从文本框取花括号内的文本转成 ASCII 写到 Result
Check_b__18_1:uploadFlagAsync,把输入当成宽 16,高 1 的 Texture2D 写入 TexF
Check_b__18_2:runEncryptAsync,就是 UnityEngine_ComputeShader__Dispatch(Shader0, _4__this->fields.K0, 1, 1, 1, 0);
Check_b__18_3:runCheckAsync,就是 UnityEngine_ComputeShader__Dispatch(Shader0, _4__this->fields.K1, 1, 1, 1, 0);
uploadFlagAsync#
Pixel#
pixel 是 Texture 里一个格子的颜色值,Texture2D 的像素通常按行排(线性索引第 i 个像素 x = i % width, y = i / width)
Color32#
Unity 由两种常用颜色结构:
- Color:float 的 RGBA(0~1),精度高,性能低
- Color32:byte 的 RGBA(0~255),更适合像素操作
Color32 本质就是 4 个 byte,r, g, b, a
v9 = sub_180156CF0(UnityEngine_Color32___TypeInfo, 16); // new 一个 Color32[16]
for ( i = 0; i < 16; i = (i + 1) )
{
bytes = this->fields.bytes; // 输入
if ( !bytes )
sub_1801579F0();
if ( i >= LODWORD(bytes->max_length) )
sub_1801579E0(bytes, i, v8, v9);
v12 = bytes->m_Items[i];
LOBYTE(v17) = v12; // R: input
*(&v17 + 1) = 0;
HIBYTE(v17) = -1; // A: 255
if ( !v9 )
sub_1801579F0();
if ( i >= *(v9 + 24) )
sub_1801579E0(v12, i, v8, v9);
*(v9 + 4LL * i + 32) = v17; // 把 v17 放到 Color32[16] 里面,+32 是在跳过对象头
}
v7 = sub_1800F5060(UnityEngine_Texture2D_TypeInfo, v6); // new 一个 宽 16 高 1 的 Texture2D
UnityEngine_Texture2D___ctor_6451756016(v7, 16, 1, 63, 0, 1, 0);
UnityEngine_Texture2D__SetPixels32_6451755632(v7, v9, 0); // 把 Pixel 写入纹理
UnityEngine_Texture2D__Apply_6451753536(v7, 0); // 上传到 GPU
TexF = _4__this->fields.TexF; // 取 TexF 字段指针
if ( !UnityEngine_Graphics_TypeInfo->_2.cctor_finished )
il2cpp_runtime_class_init(UnityEngine_Graphics_TypeInfo, v13);
UnityEngine_Graphics__CopyTexture(v7, 0, 0, TexF, 0, 0, 0); // 把输入得到的 Texture copy 到 TexF
runCheckAsync#
Buffer0 = _4__this->fields.Buffer0; // 取 ComputeBuffer(Start 里面分配的)
v7 = sub_180156CF0(int___TypeInfo, 1);
if ( !Buffer0 )
sub_1801579F0();
UnityEngine_ComputeBuffer__SetData(Buffer0, v7, 0); // 值设成 0
Shader0 = _4__this->fields.Shader0;
if ( !Shader0 )
sub_1801579F0();
UnityEngine_ComputeShader__Dispatch(Shader0, _4__this->fields.K1, 1, 1, 1, 0);
信息整理#
K0: TexV(CoTex),TexF
K1: TexC(CiTex),TexF
K2: TexR(OutputTex),Tex0(CorrectTex),Tex1(WrongTex)
# dump_png.py
from PIL import Image
def dump_png(png_path):
img = Image.open(png_path).convert("RGBA")
w, h = img.size
px = img.load()
N = min(w, 1024)
result = []
for x in range(N):
r,g,b,a = px[x,0]
result.append((r,g,b,a))
for i,(op,y,z,w_) in enumerate(result[:50]):
print(f"({op}, {y}, {z}, {w_}),")
dump_png("ExportedProject/Assets/Resources/coTex.png")
print()
dump_png("ExportedProject/Assets/Resources/ciTex.png")
"""
(0, 1, 0, 42),
(0, 2, 0, 0),
(1, 0, 2, 0),
(2, 0, 1, 0),
(3, 0, 2, 0),
(4, 0, 0, 7),
(6, 0, 2, 0),
(7, 2, 0, 0),
(6, 1, 0, 0),
(5, 2, 2, 1),
(8, 2, 0, 16),
(9, 0, 0, 247),
(10, 0, 0, 0),
(233, 0, 0, 255),
(142, 0, 0, 255),
(138, 0, 0, 255),
(138, 0, 0, 255),
(183, 0, 0, 255),
(231, 0, 0, 255),
(201, 0, 0, 255),
(224, 0, 0, 255),
(184, 0, 0, 255),
(151, 0, 0, 255),
(183, 0, 0, 255),
(75, 0, 0, 255),
(59, 0, 0, 255),
(33, 0, 0, 255),
(211, 0, 0, 255),
(124, 0, 0, 255),
"""
ComputeShader#
AssetRipper 把 asset 搞下来,跑一下 assets2dxbc,然后 HLSLDecompiler 拿到 kernel
K0 是 vm,coTex 是 opcode;K1 做校验,结果写入 Buffer;K2 根据 Buffer 渲染贴图
vm dump 下来大概是
0000: MOV R01, #42
0001: MOV R02, #0
0002: LDK R00, KEY[R02 & 0x0F]
0003: XOR R00, R01
0004: ROL8 R00, (R02 & 7)
0005: MUL R00, R00, #7
0006: ADD R00, R02
0007: STO O[R02 & 0x0F], R00
0008: ADD R01, R00
0009: ADDI R02, R02, #1
0010: CMPLO R02, #16 ; flag = (R02 < 16)
0011: JLT 0002 (pc-9) ; if flag jump
0012: DB 10,0,0,0 ; unknown
逆过来
def vm(r_value: List[int]) -> List[int]:
R1 = 42
Data = r_value
OutVar = [0] * 16
for i, d in enumerate(Data):
x = (d - i) & 0xFF
x = (x * 183) & 0xFF
x = ror8(x, i & 7)
x = x ^ R1
OutVar[i] = x
R1 = (R1 + d) & 0xFF
print("Check:", OutVar)
return OutVar
K1 的校验加了一步 TexF[i] == (TexC[i] + i) mod 256
if __name__ == "__main__":
texc = [(233, 0, 0, 255),
(142, 0, 0, 255),
(138, 0, 0, 255),
(138, 0, 0, 255),
(183, 0, 0, 255),
(231, 0, 0, 255),
(201, 0, 0, 255),
(224, 0, 0, 255),
(184, 0, 0, 255),
(151, 0, 0, 255),
(183, 0, 0, 255),
(75, 0, 0, 255),
(59, 0, 0, 255),
(33, 0, 0, 255),
(211, 0, 0, 255),
(124, 0, 0, 255)]
texc_fixed = [r-i for i, (r,g,b,a) in enumerate(texc)]
out = vm(vm(vm(texc_fixed)))
print(''.join(chr(_) for _ in out))
"""
Check: [165, 25, 18, 163, 62, 189, 40, 59, 248, 25, 127, 183, 91, 50, 9, 119]
Check: [217, 219, 244, 246, 250, 159, 161, 152, 107, 203, 228, 21, 213, 6, 122, 104]
Check: [53, 104, 97, 100, 101, 114, 86, 77, 95, 82, 101, 112, 51, 97, 116, 33]
5haderVM_Rep3at!
"""
alictf{5haderVM_Rep3at!}