2026 腾讯游戏安全 PC 初赛 WP
驱动加载
使用 EfiGuard 进行 PG 和 DSE 修复
1 | // 挂载 EFI 到 M:,注意在 explorer 中是看不到的 |
绿字进系统后关闭 DSE 就可以加载驱动了
1 | EfiDSEFix.exe -d |
启动驱动后运行程序

exe 分析
1 | int __fastcall main_0(int argc, const char **argv, const char **envp) |
重点在驱动交互,其余均为负责输入的逻辑
IO_8001200C
初始化
1 | BOOL __fastcall IO_8001200C(__int64 a1, void *lpOutBuffer) |
1 | struct __unaligned ioctl_8001200c_out |
IO_80012004
1 | __int64 __fastcall IO_80012004(void *hDevice, __int64 _RDX, int a3, _BYTE *buf, DWORD *out) |
负责移动,发送给驱动的数据结构见下
1 | struct ioctl_80012004_in |
1 | from struct import pack |
IO_80012008_Reset
重置迷宫
1 | BOOL IO_80012008_Reset() |
sys 分析
有一些难以分析的 call,nop 掉看整体流程

载入点
1 | __int64 __fastcall sub_140003208(struct _DRIVER_OBJECT *DriverObject) |
Contorl 里面也有两处难以分析 call,nop 掉看整体逻辑
1 | __int64 __fastcall IRP_Control_Func(__int64 a1, IRP *IRP, __int64 a3, char a4) |
CODE 0x8001200C
传递迷宫大小,位置信息
CODE 0x80012008
重置
CODE 0x80012004
移动,主要逻辑
移动延迟
KeDelayExecutionThread 对每步移动都进行一点延迟,所以算法爆破特别慢,需要 patch

VA 0x1400026BD,RVA 0x26BD 全 nop (5字节)
1 | eq ShadowGateSys+0x26bd c483489090909090 |
五个泄漏点
sys data 段起始有一个花指令魔数,通过该魔数可以定位四个泄漏点

1. Event 泄漏
exe 0x140001340 创建 Global Event

sys 0x1400022B0 中 event 泄漏:n2==0/2 置 MazeMoveOK,否则置 MazeMoveWall

2. 信号量 泄漏
exe 0x14021B91F 创建信号量,异或 0x4B 解密字符串


得到
1 | Global\{A7F3B2C1-9E4D-4C8A-B5D6-1F2E3A4B5C6D} |
sys 0x140319A37 中 semaphore 泄漏,_EDX ==0/2 释放 {A7F3B2C1-9E4D-4C8A-B5D6-1F2E3A4B5C6D} ,否则释放 {B8E2C3D0-0F5A-5D9B-C6E7-2A3F4B5C6D7E}

3. TEB.LastError 泄漏
sys 0x140316ADF 中修改 exe LastErrorValue ,n2 为 0 时设置 0xC0DE0001, 2 时设置 0xC0DE0002, 其他时设置 0xC0DE0000

4. TEB + 0x1748 泄漏
exe 0x14021BC88 在释放时有部分提示

sys 0x14031857E 中,使用 PsGetThreadTeb 获取 TEB 后使用 ZwSetInfomationObject 对 teb + 0x1748 处进行设置
在 icall 分发处能够看到实际调用的 call 为 PsGetThreadTeb 和 ZwSetInfomationObject

两个 icall 都清理为 call rax 不然反编译有问题

n2 = 0/2,设置 1,否则设置 0

5. 内存属性 泄漏
在 _guard_dispatch_icall_nop 下断点,当输入断在 rax=ZwProtectVirtualMemory 时就是触发第五个漏洞
调用参数为
rdx = ShadowGateApp.exe 的 .data 页
rcx = ShadowGateApp.exe 的 .data 页长度
将 .data 页的属性修改为 RW 或 ERW
1 | 3: kd> dq rdx L1 |

找了下没找到,看堆栈这个是真的在 vm 里面了,该泄漏通过观察页得到,猜测 sys 会修改名为 .data 的页


根据上面规则猜测 n2 = 0/2 时,页属性变成 PAGE_EXECUTE_READWRITE 其他时,保持 PAGE_READWRITE
查询迷宫 & 探索迷宫
方法一:r3 下通过泄漏探索迷宫
伪代码,完整见附件
1 | Init(): |
得到以下迷宫图
1 | .......#..... |
方法二:可以通过 sys 直接读取分配内存读取到迷宫


最短路径求解
bfs
1 | from __future__ import annotations |
Flag
flag{SHAD0WNT_HYPERVMX}
1 | ============================================= |
内网 ss 服务端搭建
在某某内网环境下,手机需要通过某内网设备来连接到互联网(内网设备已连接外网),且为了安全考虑,所以采用 ss 的加密,故有此篇记录
下载&启动 ss 服务端
选取 https://github.com/shadowsocks/shadowsocks-rust
笔者使用 shadowsocks-v1.24.0.x86_64-pc-windows-gnu.zip 进行测试
1 | \shadowsocks-v1.24.0.x86_64-pc-windows-gnu 的目录 |
生成密钥
1 | ssservice.exe genkey -m "aes-256-gcm" |
编写 config.json
1 | { |
启动服务端(这里不做服务安装,仅作为 cli server)
1 | ssserver.exe -c config.json |
导出 ss 链接
1 | ssurl.exe -e config.json |
注意
由于服务端接收 0.0.0.0 也就是所有 ip 请求,所以生成的 ss 链接也是 0.0.0.0 所以需要改成目标设备 ip,例如 192.168.1.2@8388
注意最后要开启对应端口的防火墙,例如 8388
1+13T Root 记录
1+13T 刷机记录
目标:SukiSU-Ultra
准备
https://yun.daxiaamu.com/OnePlus_Roms/一加OnePlus 13T/
新机搭载 ColorOS PKX110_15.0.2.602(CN01) ,上面没有
1 | > getprop | grep ro.build.display |
https://optool.daxiaamu.com/install_adb_drivers?src=pctool 下载并安装 fastboot 驱动
解锁BL
开发者 → OEM 解锁 开启
1 | > adb devices |
1 | adb reboot bootloader |
1 | > fastboot devices |
1 | > fastboot flashing unlock |
按音量下键并确认,出现黄字即成功
Root
本来想要采用 DSU + GSI Sideload 的方式启动下载本机的 init_boot.img 的,但是没找到编译好的,要不就是版本不对,所以不采用 DSU + GSI Sideload 的方式
更新系统到 603
https://yun.daxiaamu.com/OnePlus_Roms/一加OnePlus 13T/ColorOS PKX110_15.0.2.603(CN01) A.54/
系统 → 软件更新 → 本地更新,使用全量包安装
提取 img
https://yun.daxiaamu.com/files/tool/Fastboot Enhance/
加载全量包的 payload.bin 使用工具提取 init_boot.img 和 boot.img

刷入 img
首先安装 SukiSu.apk,将刚才提取的 init_boot.img 进行修补,下载修补完成的 img
eg. kernelsu_patched_20241231_195134.img
进入 bootloader
1 | adb reboot bootloader |
注意这是持久化刷入
1 | fastboot flash init_boot path\to\kernelsu_patched_20241231_195134.img |
1 | fastboot reboot |
刷入 TWRP(可不刷)
https://yun.daxiaamu.com/files/TWRP/OnePlus 13T/kmiit/
1 | adb reboot bootloader |
fastboot 下
1 | fastboot getvar all |
slot-count: 如果显示 2,说明是 A/B 分区;如果显示 1 或找不到,则是传统的 A-only 分区
current-slot: 显示当前活跃的分区(如 a 或 b)
has-slot:recovery: 如果显示 yes,说明你有独立的 recovery 分区;如果显示 no,说明你的 Recovery 是集成在 boot 分区(或 Android 13+ 的 init_boot / vendor_boot)里的
1 | fastboot flash recovery_? TWRP.img |
在拥有全量包的情况下其实无需安装 TWRP,如果出现故障,fastboot boot 到 TWRP 临时用即可
备份
字库备份
吐槽:这是哪个大聪明发明的词,就是备份分区 :(
使用多系统工具箱 / TWRP 直接备份均可,super 可不用备份
保留 root 升级
见视频
不可禁用/删除 app
| 名称 | 解决方案 | |
|---|---|---|
| 软件包安装程序 | CrossProfileTestApp.apk 禁用 or CtsPermissionApp(未测试) |
需要删除的
com.coloros.phonemanager
com.oplus.appdetail
基本模块
ref
https://github.com/eritpchy/FingerprintPay/releases(指纹)
https://www.bilibili.com/video/av115547337459255(晨钟酱)
https://www.bilibili.com/video/av115042041206760
https://www.bilibili.com/video/av616455200/ or https://www.bilibili.com/video/av616455200/(CrossProfileTestApp)
SU_Protocol-WriteUp
前言
此题采取 Themida 静态压缩 + 动态修改密钥 + 预期多解的思路防止 ai 一把梭(被一些师傅骂 misc 了 😭
WP
密钥写在段名中,预期解法是 x64dbg 运行时进行 dump,由于 Themida 的原因一定会查看段内存(下断点),所以人类选手(应该)能找到此 key
1 | su2026-keysecret |

有个别师傅被 ida 坑了,见下图

流程
注册 /flag POST 路由来接收用户输入

整体字段(感谢 r3 的师傅图表做的这么好 :D)
1 | Offset Value Meaning |
构造 payload (使用正确的 key 和 delta 进行 tea 加密)
1 | 802ba5e6806f7dd07b988241146e350f481ec220fe1536b67193671193ca08060fd065ddf9c197a119d2f732d8c574e7fc8ca862a2a15e3e7312df0fe81b0f810bf27f7f8982b9a1880ac3d3fd128acabe866e82655cb2b536edf8714ec03162c91ed2c534c132a3347375323032362d6b6579736563726574 |
构造整体
1 | 60 00 7c 80 55 00 <payload> 45 16 |
1 | 60007c805500802ba5e6806f7dd07b988241146e350f481ec220fe1536b67193671193ca08060fd065ddf9c197a119d2f732d8c574e7fc8ca862a2a15e3e7312df0fe81b0f810bf27f7f8982b9a1880ac3d3fd128acabe866e82655cb2b536edf8714ec03162c91ed2c534c132a3347375323032362d6b65797365637265744516 |
补上外层 # 和 \n 之后再做一次 hex string
1 | #60007c805500802ba5e6806f7dd07b988241146e350f481ec220fe1536b67193671193ca08060fd065ddf9c197a119d2f732d8c574e7fc8ca862a2a15e3e7312df0fe81b0f810bf27f7f8982b9a1880ac3d3fd128acabe866e82655cb2b536edf8714ec03162c91ed2c534c132a3347375323032362d6b65797365637265744516\x0a |
1 | 233630303037633830353530303830326261356536383036663764643037623938383234313134366533353066343831656332323066653135333662363731393336373131393363613038303630666430363564646639633139376131313964326637333264386335373465376663386361383632613261313565336537333132646630666538316230663831306266323766376638393832623961313838306163336433666431323861636162653836366538323635356362326235333665646638373134656330333136326339316564326335333463313332613333343733373533323330333233363264366236353739373336353633373236353734343531360a |
对该字符串做 md5 即为 flag
flag: SUCTF{ad1b51464c1b679fe731c7d718af241f}
反调试




当检测父进程为 explorer.exe 或 cmd.exe 时,对程序进行修补
delta = 0x9E3779B0
Other
1 | struct ranges // sizeof=0x10 |
unpackData
编译器做了向量优化,这里可以看出结构体总大小为 121 字节,105 和 23 * 4 + 3 处有部分重合

反序列化
将函数从十六进制字符串转换为 bytes,要求第一个字节为 0x60,然后

可以看出将 payload 写入结构体

补码计算,约束 opcode = 0x55 走正确的 unpackData 逻辑