GeekGame 2025 re wp
GeekGame 2025 re wp
签到
在线网站把所有帧提出来,第一个帧是背景可以写个妙妙小脚本
1 | from PIL import Image, ImageChops |
输出
然后在线网站DataMatrix提取flag
flag{see!!the-wind-of-miss-yooou-around-finally-blowwws-to-geek-game~~~}
二阶段提示:
测了下ChatGPT白色背景没识别,可能要透明
夸克可以扫出来
MISC
人机大战
flag1
1 | flag{dont-laugh-you-try-you-also-cant-beat-the-second-level} |
RE
团结引擎
flag13可以通过patch dll来,encodeText种有个揭秘字符串的操作,直接patch右键添加这一个日志操作,打印出来,编译然后左上角生成dll
替换原先的,运行dll就行了
- flag{gam4_ed2tor_pro}
- flag{T2me_M0GIC5him}
猜测也能通过飞天来找这两个flag
还有个没找到估计在墙里
flag1可以修改Unity.StarterAssets的ThirdPersonController
当然更简单的做法是直接让门升起来,我这么做只是好玩.
如door可以直接加start方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14 // Door2
// Token: 0x06000162 RID: 354
private void Start()
{
this._openingTriggered = true;
if (this.countdownText)
{
this.countdownText.text = "Opening";
}
if (this._mountedObject)
{
this._mountedObject.localPosition = this._mountedTargetPos;
}
}
patch成飞天
1 | using System; |
flag2:
flag{v2ew_beh2nd_the_scene}
7 岁的毛毛:我要写 Javabinary-java
flag1
利用 java.beans.Expression 代替我们手动调用 Class.getDeclaredField,从而绕过 Blocker 对 Class.* 的拦截;真正的反射动作发生在 JDK 类内部,我们自己的字节码里不出现受限调用。
得到 Field 之后,就可以正常 setAccessible(true) 并读取实例上的 flag 值,最后打印即可
1 | import java.beans.Expression; |
flag2
1 | import java.beans.Expression; |
枚举高手的 bomblab 审判
flag1
sub_16B0 自修改:调用 mprotect 将 loc_1550 区域改写可执行并基于地址 Xor 复原,再改回只读执行。静态分析时手动解密或运行到 mprotect 之后 dump 代码即可绕过
1 | 0x42 - base + (uintptr_t)p = 0x42 - base + (base + i) = 0x42 + i。 |
1 | import ida_bytes |
可以看到有个check_debugger
1 | enc = [ |
in1T_Arr@y_1S_s0_E@sy
exp:
1 | seed = bytes.fromhex("b42095440c4e330794fbfb70941ad0a30a5c429338e04f61151a005138c27d1d6cd1f12271decbd32f3c8b9f61") |
flag{iN1t_arR@Y_w1Th_sMc_@NTI_dBg_1s_S0_e@Sy}
flag2
是个虚拟机逆向
check_flag2_vm 要求输入长度 0x27;它将 “sneaky_key\n” 拼在 flag 之前放入工作区,再执行一个字节码虚拟机。
字节码常量见 g_vm_bytecode:
- 先对 VM 内存地址 0x100、0x101 设为 0;
- RC4 初始化(opcode 0x40)使用 0x100 处 key 区:由 “sneaky_key\n” 和用户输入拼接而成;
- RC4 生成 keystream 写入 0x400…;
0x40有个RC4
opcode 0x40 分支里,把一段缓冲区初始化为 S[i] = i,然后循环对 j 进行 j += S[i] + key[i % key_len],随即交换 S[i] 与 S[j]——这正是 RC4 的 KSA
0x41加密:
常量区里了有“sneaky_key\n” 作为 key 前缀,与用户输入拼起来给 RC4
低字节类(v4 <= 0x21):
0x00— 终止并比较:执行memcmp(&v52, &g_vm_target_state, 0x27)。0x01— push 一个 1 字节立即数(下一个字节)。v3 += 2,v47[v2++ + 8] = imm.0x03— push 一个 32 位常量(从字节流 + table 组合出来)。v3 += 5,v47[v2++ + 8] = const32。这是把复杂常量放到栈上的方法。0x04— pop(--v2)。0x05— 复制顶元素:v47[v2 + 8] = v47[v2 + 7]然后v2++(把栈顶复制一份)。0x20— 从v47[528 + idx]读取一个字节并 push(idx由栈值决定)。如果idx > 0x3FFF则返回比较失败。0x21— 把栈顶写入v47[528 + idx](即写到 keystream/key 区)。如果idx > 0x3FFF则返回比较失败。
高字节类(v4 > 0x21):在代码里只出现两种
0x40— 初始化 S-box(类似 RC4 的 KSA):从栈弹出若干参数(偏移、key 长度、key 偏移等),在
v48[offset + 0..0xFF]填入 0..255,然后根据v47[528 + key_off ..]的 key 做 256 次交换,最终将置换结果保存在v48[offset ..]。0x41— 产生/混合 keystream(RC4 的 PRGA)
因此可以把 VM 中的 0x40 + 0x41 看成“用存在于 v47[528...] 的 key 初始化 RC4,然后用 RC4 生成一个 keystream并 XOR 到 v47[528 + ...] 的某些位置”。
可能生成对s盒进行了变换
只能动调了,把反调试的jz改成jnz后
运行到这
向上跟踪到s盒处,把S盒替换了就行
还有几种可能的思路
- 模拟运行
- 识别修改处
- 把密文patch进去,跑一遍直接看输出
1 | content = [ |
flag{EAsy_vm_usINg_rC4_ALGo_1S_S0_e@SY}
又回去看了遍生成S盒没有变动,那我应该就是key搞错了,key是sneaky_key,而非’/nsneaky_key’,因为我发现生成S盒的%0xA而非0xB,所以猜测第一个不是密钥😂
关于本题还有其他的反反调试手段这里记录下。程序读取的是这里的TraceID来实现检测
我们把它hook掉就行
看TracePid说明当前进程已经被 PID 9467 跟踪 —— 的确存在调试/ptrace。
让AI给了一份脚本
1 | // hide_tracer.c |
这个最大的坑点是,远程调试需要用这个命令去设置环境变量启动调试器,在Parameters里设置没有用!!!:
1 | gcc -shared -fPIC -o hide_tracer.so hide_tracer.c -ldl |
这里还有个没注意到的点
test指令并不是跟网上说的那样用来比较的,而是一个位操作的指令
用于将寄存器 edx 与自身进行按位与操作。这其实是一个快捷方式,用来测试寄存器的内容是否为零
test 指令的执行结果会影响 CPU 的标志位,特别是 ZF(零标志位)。
如t
若 edx 的值是零,test edx, edx 的结果也会是零,进而设置 ZF 标志。如果 edx 的值不是零,ZF 标志不会被设置。
jne 0040BCA3 仅在 ZF 未被设置时(即 edx 不为零时)执行跳转。如果 edx 是零,则跳
简单的来说就是,当运算的结果值为 0 时,ZF = 1
edx = 0 zf = 1 不执行跳转(因为zf = 1时je跳转 jne不跳)


























