2025腾讯游戏安全技术竞赛决赛题解

admin 2025年4月16日15:28:03评论1 views字数 11831阅读39分26秒阅读模式
作者坛账号:xia0ji233

题目描述

(1)在intel CPU/64位Windows10系统上运行sys,成功加载驱动(0.5分)

(2)能在双机环境运行驱动并调试(1分)

(3)优化驱动中的耗时算法,并给出demo能快速计算得出正确的key(1分)

(4)分析并给出flag的计算执行流程(1.5分),能准确说明其串联逻辑(0.5分)

(5)正确解出flag(1分)

(6)该题目使用了一种外挂常用的隐藏手段,请给出多种检测方法,要求demo程序能在题目驱动运行的环境下进行精确检测,方法越多分数越高(3分)

(7)文档编写,详细描述解题过程,详述提供的解题程序的演示方法。做到清晰易懂,操作可以复现结果;编码工整风格优雅、注释详尽(1.5分)

加载驱动

驱动带反调,且目测有 VMP 壳,于是选择 dump+Fix,由于驱动带反调,会蓝屏,于是 hook 蓝屏代码,选择该时机去 dump 内存,找到 Entry。

2025腾讯游戏安全技术竞赛决赛题解

随后跟进,遇到一些立即数的赋值,且有函数加密,直接选择模拟执行。

 复制代码 隐藏代码import idaapiimport idcfrom unicorn import *from unicorn.x86_const import *import ida_nameimport mmapimport sysimport idautilsimport structbase_addr = idaapi.get_imagebase()fix_function_start=0xFFFFF806FF8D9F0Cfix_function_end=0xFFFFF806FF8DA05FPAGE_SIZE=0x1000RSP=0xdead0000RBP=0xdead0000map_addr=idaapi.get_imagebase()offset=base_addr-map_addrdefhook_mem_unmapped(uc, access, address, size, value, user_data):    aligned_addr = address&0xFFFFFFFFFFFFF000try:        uc.mem_map(aligned_addr, PAGE_SIZE)        data=idaapi.get_bytes(aligned_addr,PAGE_SIZE)        uc.mem_write(aligned_addr,data)returnTrue# 表示错误已处理,继续执行except Exception as e:print(f"[-] 动态映射内存页失败: {e}")returnFalseinstr_count = 0cnt=0defhook_code(uc, address, size, user_data):global instr_count,cnt    instr_count += 1    rax=uc.reg_read(UC_X86_REG_RAX)    rcx=uc.reg_read(UC_X86_REG_RCX)    rdx=uc.reg_read(UC_X86_REG_RDX)    r8=uc.reg_read(UC_X86_REG_R8)    r9=uc.reg_read(UC_X86_REG_R9)    r10=uc.reg_read(UC_X86_REG_R10)    rbp=uc.reg_read(UC_X86_REG_RBP)    rsp=uc.reg_read(UC_X86_REG_RSP)    rip=uc.reg_read(UC_X86_REG_RIP)if rip==0xFFFFF806FF8DA05C:        st=b''        offset=0xE0whileTrue:if uc.mem_read(rsp+offset,2)==b'x00x00':break            st+=uc.mem_read(rsp+offset,1)            offset+=2print(st)#print(uc.mem_read(rsp+offset))mu = Uc(UC_ARCH_X86, UC_MODE_64)mu.reg_write(UC_X86_REG_RIP, fix_function_start)  # 设置执行起始地址mu.reg_write(UC_X86_REG_R13, 0xFF)mu.reg_write(UC_X86_REG_RSP, RSP)mu.reg_write(UC_X86_REG_RBP, RBP)mu.mem_map(RSP-PAGE_SIZE,PAGE_SIZE*2)mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, hook_mem_unmapped)mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED, hook_mem_unmapped)mu.hook_add(UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_unmapped)mu.hook_add(UC_HOOK_CODE, hook_code)instr_count=0print(hex(mu.reg_read(UC_X86_REG_RIP)))try:    mu.emu_start(fix_function_start,fix_function_end)except UcError as e:print(e)pass

最后得到一个注册表字符串 \Machine\System\CurrentControlSet\Services\ACEDriver\2025ACECTF

2025腾讯游戏安全技术竞赛决赛题解

正常直接加载驱动会返回 31 错误,猜测判定了注册表的某些东西,继续往下模拟可得一个字符串 Key。

2025腾讯游戏安全技术竞赛决赛题解

模拟执行可以尽量挑不依赖外部函数,且立即数比较多的片段,这样可以省略计算的过程。

下面也可以模拟,但是根据题目描述也能猜个大概,有一个 Key,有一个 Flag。再结合该函数的定义和调用

2025腾讯游戏安全技术竞赛决赛题解

不难得到 Key 应该是一个 __int64 的值,Flag 是一个字符串,保存到全局变量当中,创建对应的注册表项,成功加载驱动。

2025腾讯游戏安全技术竞赛决赛题解

调试驱动

前面说过,有反调试,观察导入表遍历了 NtQuerySystemInformation,于是想到可能是检测到了 kdcom.dll 模块(因为之前有游戏做过类似的检测),那么直接 hook 把 kdcom.dll 改名。

因为保护了 IAT,因此不能使用常规的 IAT hook,还是选择使用 inline hook

 复制代码 隐藏代码NTSTATUS gh_NtQuerySystemInformation(...){    unhook();auto ret = ((NtQuerySystemInformation_t)(TargetFunction))(...);if (SystemInformationLength&& SystemInformationClass== SystemModuleInformation) {        PSYSTEM_MODULE_INFORMATION pModInfo = (PSYSTEM_MODULE_INFORMATION)SystemInformation;for (int i = 0; i < pModInfo->ModulesCount; i++) {            PSYSTEM_MODULE_INFORMATION_ENTRY pEntry = &pModInfo->Modules[i];if (strcmp(pEntry->Name + pEntry->NameOffset, "kdcom.dll")) {                (pEntry->Name + pEntry->NameOffset)[0] = 'x';            }        }    }    rehook();return ret;}

绕过之后加载驱动不会蓝屏,但是会出现另一个错误。

2025腾讯游戏安全技术竞赛决赛题解

随后查看 DbgView 发现似乎是 vmp 自带的,手上有 3.8 版本,尝试编译放进去加载,果然如此,一摸一样的错误代码。

2025腾讯游戏安全技术竞赛决赛题解

Key算法分析

这个可以通过字符串定位,也可以由上面注册表继续往后分析得到。

2025腾讯游戏安全技术竞赛决赛题解

当输入的 Key 为 0 时,尝试使用算法生成。通过分析该函数,结合一些一些字符串可知,该算法自己实现了一个双端队列(deque),但是实际使用的时候是把它当成栈来用了,实现了一个深度优先搜索算法。

第一步恢复 deque 结构体,第一个 8 字节是一个指向自身的指针,但是似乎没有用过,正常来说应该是虚表。双向队列会有全队列大小(队列最多容纳的元素个数),头指针还有尾指针,而通常情况下,后两者可以使用头指针 + 有效元素个数来实现,因此最后得到以下定义:

 复制代码 隐藏代码structdeque{void *vtable;    data **map;    __int64 MAX_SIZE;    __int64 begin_idx;    __int64 size;};structdata{int x1;int y1;    _QWORD data2;    _QWORD data3;int x4;int y4;};

应用到 IDA 之后,配合注释,算法一目了然。

2025腾讯游戏安全技术竞赛决赛题解

深入阅读它实现 deque 的源码其实可以明白,第一,它的 MAX_SIZE 一定是 2 的整数幂,并且它是环形队列。第二,在取模的时候更加高效(即 &(MAX_SIZE-1))。

循环开头压入了 (44,22) 元素。

每次循环开始,取得尾部的元素,判断 x1 是否为 0,或者说 x==y,如果是则删除该元素。

否则尝试先往左走(即 x-1)并立刻将往左走的点压入栈中重新循环,经典的 DFS。

2025腾讯游戏安全技术竞赛决赛题解

往左走之后会将当前点标记为已经往左走过,这里 x4 的值有以下三种情况:

  • 0
    :还没走过。
  • 1
    :已经往左走过。
  • 2
    :已经往左走过,且已经往左下走过。

当 x4==2 时,该点也会被删除,并将,结合图中的注释大概也能看懂这个算法了,这里画了一个图更好理解

2025腾讯游戏安全技术竞赛决赛题解

从黑色格子出发,只能向左或者向左上(y轴往下的情况下)。红色格子不能继续走,价值为1,同样在 y 0层也有一行红色格子价值为 1,其余格子价值均为 x%5,最后应该是计算黑色格子到红色格子的所有不同的路径的价值之和。

优化可以使用记忆化搜索,或者直接使用动态规划,记忆化搜索简单无脑,三行搞定。

 复制代码 隐藏代码#include<stdio.h>#include<string.h>int v[50][50];longlong f[50][50];longlongdfs(int x, int y) {if (x == y || !y)return1;if (f[x][y] != -1)return f[x][y];return f[x][y] = x%5+dfs(x-1,y)+dfs(x-1,y-1);}intmain() {memset(f, -1sizeof(f));printf("%lldn", dfs(44,22));}//7039739125714

调试驱动(续)

结论

反调试检测:

  • 题目检测 kdcom.dll 模块,检测到则直接 'ACE' 蓝屏。
  • 题目有个线程一直在调用,KdDisableDebugger

绕过:

  • 对于第一个检测,把蓝屏函数直接返回即可。
  • 对于第二个检测,把该api直接返回即可。

分析过程

尝试 hook NtQuerySystemInformationKeBugCheckEx,找到蓝屏的函数在 0x74F0,于是考虑在 hook NtQuerySystemInformation 的某个节点,把该函数 hook 直接返回,不会蓝屏,但是调试器被剥离。

调试发现是调用了 KdDisableDebugger 函数。

2025腾讯游戏安全技术竞赛决赛题解

同样也是直接返回,操作完成后,可以发现驱动已经可以正常运行,且调试器正常工作。

2025腾讯游戏安全技术竞赛决赛题解

这里代码实现仅仅变动了 hook 的 NtQuerySystemInformation 函数,因为有 vmp 壳,所以在加载的时候去 hook 是不明智的,直接在调用 NtQuerySystemInformation 的某一刻过掉即可。

 复制代码 隐藏代码NTSTATUS gh_NtQuerySystemInformation(...){    unhook();//...    PVOID stack[MAX_BACKTRACE_DEPTH+1] = { 0 };    RtlWalkFrameChain(stack, MAX_BACKTRACE_DEPTH,0);bool flag = 0;staticint cnt = 0;for(int i = 0; i < MAX_BACKTRACE_DEPTH; i++) {if(stack[i]>= Hooks::Base && stack[i] <= (PVOID)((UINT64)Hooks::Base + Hooks::Size)) {            flag = 1;break;        }    }if (flag) {char code = 0xC3;        cnt += 1;if (cnt == 3) {            DriverUtil::MDLWriteMemory((PVOID)((UINT64)Hooks::Base + 0x74f0), &code, 1);            DriverUtil::MDLWriteMemory((PVOID)(KdDisableDebugger), &code, 1);return ret;        }    }    rehook();return ret;}

因为壳似乎有 API 防 hook 的检测,如果不及时下掉钩子则会加载失败,因此选择在第三次调用之后下掉钩子并做反调试的相关 hook。

Flag逻辑分析

结论:

  • 读取 flag 之后,先做一次单表映射的替换,这里是由 VT 实现的,hook点在(+0x95DF
  • 用输入的 key 对输入的 flag 进行异或加密。
  • 开启 VT,使用 VT hook 过的 TEA 加密逻辑加密上一步得到的密文。
  • 用VT hook rdmsr,使得 rdmsr(0xE8) 在 check 之前异或了一个密钥,这个密钥由输入的 flag 长度决定。

从后续的逻辑来看,生成的 key 就是 flag 做某种加密的密钥。

2025腾讯游戏安全技术竞赛决赛题解

这里的 v10,经过动态调试,记录了最高有效位,例如我现在输入的 key=0x25312620c4fe,占用 6 字节,所以最高有效位为第五位(从零开始),如图所示

2025腾讯游戏安全技术竞赛决赛题解

因此第一步就是实现一个简单的异或加密,根据密钥的长度而定。

2025腾讯游戏安全技术竞赛决赛题解

紧随其后的是 TEA 加密,和初赛一样,每两个字符零扩展成 int 之后放入 TEA 加密。

2025腾讯游戏安全技术竞赛决赛题解

乍一看这里居然用了 key 的地址进行运算,实则不需要被他吓到,这么玩确实会导致每次加密的结果不一样,但是不代表就不可逆(后来嘎嘎被打脸),逆了一下发现逆推到第一个式子的时候推不动了。

经过调试,发现是代码被 VT hook 了,联想到之前要求一定是 Intel CPU

2025腾讯游戏安全技术竞赛决赛题解

可以看到单步执行得到的指令结果不符合预期,题目在此处开启 VT 环境。

2025腾讯游戏安全技术竞赛决赛题解

在 +0x5150 处的函数实现 hook 的分发。

2025腾讯游戏安全技术竞赛决赛题解

计算正确的 Flag

答案:flag: flag{ACE_C0n9raTs0nPA55TheZ02S9AmeScTf#}

由于分发函数过于庞大,且 VT 的hook是无痕的,因此考虑能否使用加密的弱点去实现 flag 的解密,由于 TEA 加密的输入是被零扩展的,因此实际 8 字节的分组只有 2 字节是有效的。

可以计算两字节的所有组合,获得它的密文结果,实施这个方法之前,需要确定,相同的密文,相同的 key,得到的一定是相同的输出,断 TEA 加密的 call,选中 RCX 的内存,改成全 0,得到 A9 59 CF AB EB 9D A3 0A,多个位置尝试发现得到的始终是这个结果,因此判定该方法可行。

这里方法就多起来了,第一可以把注册表写满 0000-FFFF,然后指定 Key 为 0xFF,就可以 dump 得到一份表,或者可以直接写一个驱动去调用那个功能,这里我选择了后者。

 复制代码 隐藏代码typedefVOID(*TEAEnc)(unsignedint*, unsignedint*);extern"C" NTSTATUS DriverEntry(    _In_ PDRIVER_OBJECT  DriverObject,    _In_ PUNICODE_STRING RegistryPath) {    DriverObject->DriverUnload = DriverUnload;    TEAEnc teaEnc = (TEAEnc)0xFFFFF8032AC51560;unsignedint key[4] = { 0x000000890x000000FE0x000000760x000000A0 };unsignedint data[2] = { 0x000000000x00000000 };    teaEnc((unsignedint*)data, (unsignedint*)key);for(int i = 0; i < 8; i++) {        DBG_PRINT("data[%d]=%02xn", i,((unsignedchar*)data)[i]);    }return STATUS_SUCCESS;}

观察 windbg 的输出,得到了正确的运行结果:

2025腾讯游戏安全技术竞赛决赛题解

理论可行,那就直接 for 爆一遍,然后存到内存里面,最后 windbg 直接 dump 出来。

2025腾讯游戏安全技术竞赛决赛题解

但是发现直接 dump 无法直接查找得到,经检查,原来是 rdmsr 被 VT hook,做了一次异或加密,并且根据长度生成异或的密钥,很简单,直接把内存都置 0 就能直接拿到异或的密钥,并且密钥由输入的 flag 长度决定,34 长度的密钥为 03 39 49 26 2F F6 F8 4E

做完异或加密之后,就可以配合 dump 的密文查表。

2025腾讯游戏安全技术竞赛决赛题解

用如下脚本查表:

 复制代码 隐藏代码target=b'xc0x6dxdax3fxc9x8dx05xffx56x62x69x55x6cxbbxa4x90x57xa0xa6x82xfbxa7x8exe7x69x52xf3xc9xf1xd7x1ax88xfdx7bxeaxa9x91x95xe4x02xc5xddxe7xf6x64xcbx0ex88xd9xd2x4ex1ex3bxaex27x64x2dxfdxcax5cx1cx7bxccxd0xe7x40x6ex5exefxa9x5dx8axd3x5dx42xfax72x9ax1bx30x2fxddx72xc2xe5xf3x1cx9bxa4xf0x3bx91xe8x3bxc8x4ex1fx8ax40x09xf8x6bx7bxb4x8bx42x1dx71x81x43xacxb9x76x42x56x05x5fxf1xeex5dx7ax2cxfex48x92x7dx5ax41x93xd1x4ax47x32xb8x98xa1'table=open("./enc.bin","rb").read()for i in range(0,136,8):    num = table.find(target[i:i+8])//8    x=num//256    y=num%256    print(f"{x:02x} {y:02x}",end=" ")

得到结果

 复制代码 隐藏代码f659 ab d7 ea 1894 ab d457 b1 d484c6f0d45343281 bc 86c33215f56784c30596c601

为了验证 TEA,选择在做完异或加密之后直接把以上密文贴到 check 的内存中,结果返回正确。

2025腾讯游戏安全技术竞赛决赛题解

随后拿 Key 异或还是无法得到正确的结果,经查在 +0x95DF 处的指令,读取 flag 的时候存在 VT hook

2025腾讯游戏安全技术竞赛决赛题解

可以发现内存实际是 A 但是读取结果为 0x24,存在类似的单表替换,而刚刚好,TEA 解密得到的信息异或 key 之后得到的值刚好是 0x24

2025腾讯游戏安全技术竞赛决赛题解

结合初赛的 flag 格式,A 应该是正确的明文了。

这里就是动调大法,按了三个小时调试器,在取内存的地方下断点,然后每次给内存自增 1,观察 ax 寄存器是否符合预期,最终得到正确的结果

2025腾讯游戏安全技术竞赛决赛题解

检测方法

题目明显使用 VT 技术实现对内存某些部分的无痕 hook,因此我们的做法就是去检测自身运行是否处于 VT 环境。

MSR检测

 复制代码 隐藏代码boolis_vt_enabled1(){constunsignedint IA32_FEATURE_CONTROL = 0x3A;unsignedlonglong msr_val = __readmsr(IA32_FEATURE_CONTROL);return (msr_val & (1 << 2)) != 0// VMX outside SMX enabled}if (is_vt_enabled1()) {    DBG_PRINT("VT1 is enabledn");}else {    DBG_PRINT("VT1 is not enabledn");}

但是题目做了 hook,题目运行的时候,我们读取的 MSR 显示是没开启 VT 的。

2025腾讯游戏安全技术竞赛决赛题解

如图所示,前者开启题目驱动,VT1 提示 not enable,卸载题目驱动后又能够检测到 VT 处于开启状态。

于是这里我想到,如果题目要 hook,那么在读取 MSR 的时候必然要运行很多额外代码,这里选择对比开启题目驱动和关闭题目驱动之间的时间差。

 复制代码 隐藏代码boolis_vt_enabled1(){    LARGE_INTEGER freq; // 获取频率    LARGE_INTEGER start = KeQueryPerformanceCounter(&freq);constunsignedint IA32_FEATURE_CONTROL = 0x3A;unsignedlonglong msr_val;for (int i = 0; i < 100000; i++){        msr_val = __readmsr(IA32_FEATURE_CONTROL);    }    LARGE_INTEGER end = KeQueryPerformanceCounter(NULL);    LONGLONG delta = end.QuadPart - start.QuadPart;    LONGLONG elapsed_us = (delta * 1000) / freq.QuadPart;    DBG_PRINT("Elapsed time: %lld msn", elapsed_us); // 打印经过的时间return (msr_val & (1 << 2)) != 0// VMX outside SMX enabled}

运行结果:

2025腾讯游戏安全技术竞赛决赛题解

可以发现,我测试了 100000 条 MSR 指令,正常虚拟机运行 132ms,而开启题目驱动之后来到了 2079ms,接近 20 倍的差距。那么第一种方法可以是找一条跟 MSR 指令差不多周期的指令,但是这个指令不会被 VT 影响,最后计算两者的偏差率,超过很多则时间判定不通过,当然它如果不 hook MSR,就可以选择直接判定对应的 VT 位是否处于开启状态,两者联合检测怎么都是可以检测到的。

这里我使用 inc 指令去比较。

 复制代码 隐藏代码start = KeQueryPerformanceCounter(NULL);int a = 1;int* k = &a;for (int i = 0; i < 100000000; i++) {    *k *= 3;}end = KeQueryPerformanceCounter(NULL);delta = end.QuadPart - start.QuadPart;LONGLONG elapsed_us2 = (delta * 1000) / freq.QuadPart;DBG_PRINT("Elapsed time: %lld msn", elapsed_us2); // 打印经过的时间

这里使用指针来保证每次循环的结果均写入内存中。

2025腾讯游戏安全技术竞赛决赛题解

结果也很完美,那么最终检测 VT 环境可以判断 elapsed_us2/elapsed_us1>5,如果是则说明处于 VT 环境中被 hook。

最终代码:

 复制代码 隐藏代码boolis_vt_enabled1(){    LARGE_INTEGER freq; // 获取频率    LARGE_INTEGER start = KeQueryPerformanceCounter(&freq);constunsignedint IA32_FEATURE_CONTROL = 0x3A;unsignedlonglong msr_val;for (int i = 0; i < 100000; i++){        msr_val = __readmsr(IA32_FEATURE_CONTROL);    }    LARGE_INTEGER end = KeQueryPerformanceCounter(NULL);    LONGLONG delta = end.QuadPart - start.QuadPart;    LONGLONG elapsed_us1 = (delta * 1000) / freq.QuadPart;    DBG_PRINT("Elapsed time: %lld msn", elapsed_us1); // 打印经过的时间    start = KeQueryPerformanceCounter(NULL);int a = 1;int* k = &a;for (int i = 0; i < 100000000; i++) {        *k *= 3;    }    end = KeQueryPerformanceCounter(NULL);    delta = end.QuadPart - start.QuadPart;    LONGLONG elapsed_us2 = (delta * 1000) / freq.QuadPart;    DBG_PRINT("Elapsed time: %lld msn", elapsed_us2); // 打印经过的时间return elapsed_us1 / elapsed_us2 > 5;}

运行效果:

2025腾讯游戏安全技术竞赛决赛题解

能够在开启题目驱动的情况下检测到。

CPUID检测

伪造虚假的 cpuid 参数,通常情况下真机会返回 0,而开启了 VT 则会接管返回正常的值。参考文章:https://secret.club/2020/04/13/how-anti-cheats-detect-system-emulation.html

 复制代码 隐藏代码boolcheck_invalid_leaf(){constexprunsignedint invalid_leaf = 0x04201337;constexprunsignedint valid_leaf   = 0x40000000;_cpuid_buffer_t InvalidLeafResponse = {};_cpuid_buffer_t ValidLeafResponse   = {};    __cpuid(reinterpret_cast<int32_t*>(&InvalidLeafResponse), invalid_leaf);    __cpuid(reinterpret_cast<int32_t*>(&ValidLeafResponse), valid_leaf);if ((InvalidLeafResponse.EAX != ValidLeafResponse.EAX) ||        (InvalidLeafResponse.EBX != ValidLeafResponse.EBX) ||        (InvalidLeafResponse.ECX != ValidLeafResponse.ECX) ||        (InvalidLeafResponse.EDX != ValidLeafResponse.EDX))returntrue;returnfalse;}

该代码可以运行在用户层,经测试,该代码在开启题目驱动的真机上返回为 true,未运行题目的真机返回为 false,虚拟机中则一律返回 true

目录说明

  • XSafe:包含驱动的源码,编译之后先加载该驱动,后加载题目给的驱动,配置正确的情况下可以双机调试且成功加载驱动(无法二次加载及卸载)。
  • XSafe.sys:XSafe编译的二进制文件。
  • XSafe2:包含爆破 TEA 加密爆破的源码,需要借助驱动 1 找到 TEA 函数的具体位置,并且根据输出的内存地址手动 dump 文件,得到 enc.bin。
  • XSafe2.sys:XSafe2编译的二进制文件
  • VT-Detection1:包含方法1所述的MSR检测源码,加载时可以判断当前是否处于题目的 VT hook 环境中,虚拟机和真机均有效。
  • VT-Detection1.sys:VT-Detection1编译的二进制文件
  • VT-Detection2:包含方法2所属的检测方法,只在真机有效。
  • VT-Detection2.exe:VT-Detection2编译的二进制文件
  • enc.bin:由 XSafe2.sys dump 分配的内存文件。
  • exp.py:TEA 加密的还原脚本

原文始发于微信公众号(吾爱破解论坛):2025腾讯游戏安全技术竞赛决赛题解

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月16日15:28:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2025腾讯游戏安全技术竞赛决赛题解http://cn-sec.com/archives/3964865.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息