首页
社区
课程
招聘
[分享][原创][SWPUCTF 2025 秋季新生赛]CodeRunner
发表于: 2天前 180

[分享][原创][SWPUCTF 2025 秋季新生赛]CodeRunner

2天前
180

### [SWPUCTF 2025 秋季新生赛]CodeRunner

做这道题的时候我一直在网上找wp,根本没有
个人感觉超级难,一开始打开是这样的

img

运行之后发现脚底下是一个二维码,但是看不到全貌,这道题的提示说扫码就可以得到flag,是不是非常简单,实则不然,所以我想应该只有两种可能,一种是生成二维码,一种是二维码已经在了,所以我打算拆包,使用AssetStudio,但是没有找到二维码,但是找到了和黑块和白块,以及QRCodeBuilder函数,所以基本断定应该是制作二维码

img

后面我想使用 Il2CppDumper 来找找结构信息,看看能不能对解题产生什么帮助,但是这一步报错了,是没有其中一个文件,但是是有的,所以才发现是壳,蜕壳之后成功取得结构信息

img

把结构信息中的Assembly-CSharp.dll拉入ILSpy,找到QRCodeBuilder类,发现伪造的 DLL 是空壳,但拿到了函数的真实内存地址,将脱壳后的 GameAssembly.dll 拖入 IDA Pro。利用快捷键 G 跳至 ConstructQRCode 方法。按 F5 反编译后,发现这里只有“按图纸铺地砖”的双重 for 循环逻辑,通过读取 *(a1 + 72)(即 qrMatrix)来判断放黑块还是白块

跳入 QRCodeBuilder 的构造函数(.ctor),终于看到了决定性代码

v8[0] = 29;
v8[1] = 29; // 创建 29x29 的矩阵 (Version 3 二维码)
sub_181652960(v9, qword_182F726A8, 0); // 从内存深处拷贝数据

在 IDA 的 .data 段追踪 182F726A8,发现那里的数据是 80000003h。这并不是真实数据,而是 IL2CPP 引擎的 Metadata Token。它指向了存放在 global-metadata.dat 中的一串二进制死数据

既然我们知道数据在 global-metadata.dat 里,且二维码大小是 29×2,那干脆不按常理出牌,直接祭出 CTF 的终极奥义:特征码****扫描。 所有二维码的左上角都有一个 7x7 的定位方块(黑黑黑黑黑黑黑白)。在 int 数组中,这就意味着必然存在连续的 7 个 1 和 1 个 0。 编写 Python 脚本,直接在 global-metadata.dat 里进行地毯式爆破:

import os
from PIL import Image

def find_and_draw():
    filepath = "global-metadata.dat"
    # 二维码左上角特征:连续 7 个黑块(1) 和 1 个白块(0)
    # 扫描模式 A:int 数组 (4字节 Little Endian)
    pattern_int = (b'\x01\x00\x00\x00' * 7) + b'\x00\x00\x00\x00'
    
    print(f"[*] 正在扫描 {filepath} ...")
    with open(filepath, "rb") as f:
        data = f.read()
        
    offset = 0
    while True:
        offset = data.find(pattern_int, offset)
        if offset == -1:
            break
            
        # 截取 29x29 = 3364 字节
        chunk = data[offset : offset + 3364]
        # 校验:确保这 3364 字节全是 0 或 1
        if len(chunk) == 3364 and all(chunk[i:i+4] in (b'\x00\x00\x00\x00', b'\x01\x00\x00\x00') for i in range(0, 3364, 4)):
            print(f"[+] 在偏移 {hex(offset)} 处成功捕获矩阵!")
            
            # 画图还原
            width, height = 29, 29
            img = Image.new('1', (width, height), 1)
            pixels = img.load()
            
            for y in range(height):
                for x in range(width):
                    val = chunk[(y * width + x) * 4] 
                    if val == 1:
                        pixels[x, y] = 0  # 1 代表黑块
                        
            img = img.resize((290, 290), Image.NEAREST)
            img.save("flag_qrcode.png")
            print("[+] 二维码已生成!")
            return
        offset += 1

if __name__ == "__main__":
    find_and_draw()

传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!

收藏
免费 0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回