题目文件已同步到github仓库:https://github.com/LunaticQuasimodo/HITCTF-2025-Personal-base/tree/main/REVERSE
将程序拖入 IDA Pro 分析 main 函数 (0x140001780)。
程序主要逻辑如下:
- 打印欢迎信息 "Flag Checker Program(by EasyVM)"。
- 调用
sub_140001270两次,传入不同的上下文结构体。- 第一次调用:加载并执行一段较短的字节码(位于
0x14001DBA8),主要用于打印提示字符串 "Enter flag: "。 - 第二次调用:加载并执行核心校验逻辑的字节码(位于
0x14001DA90),长度为 280 字节。
- 第一次调用:加载并执行一段较短的字节码(位于
核心函数 sub_140001270 是一个典型的基于栈/寄存器的虚拟机解释器。通过分析可以还原其结构:
- 寄存器: 结构体起始位置包含 8 个通用寄存器 (R0-R7),每个 4 字节。
- 指令指针 (IP): 结构体偏移
+1060处。 - 标志位: 结构体偏移
+1064处,用于比较指令 (CMP) 后的跳转 (JNZ)。 - 输入/输出缓冲区:
- Input: 偏移
+1084 - Output: 偏移
+1134
- Input: 偏移
通过分析 sub_140001270 中的 switch-case 结构,还原出以下操作码 (Opcode):
| Opcode | Mnemonic | Operands | Description |
|---|---|---|---|
| 0 | EXIT | None | 退出虚拟机 |
| 1 | MOV | Out[idx], Imm | 将立即数写入输出缓冲区 |
| 2 | MOV | Reg, In[idx] | 将输入缓冲区的字符加载到寄存器 |
| 3 | MOV | Reg, Reg | 寄存器间赋值 |
| 4 | MOV | Reg, Imm | 寄存器赋值立即数 |
| 5 | ADD | Reg, Reg | 寄存器加法 |
| 6 | ADD | Reg, Imm | 寄存器加立即数 |
| 7 | SUB | Reg, Reg | 寄存器减法 |
| 8 | SUB | Reg, Imm | 寄存器减立即数 |
| 9 | XOR | Reg, Reg | 寄存器异或 |
| 10 | XOR | Reg, Imm | 寄存器异或立即数 |
| 11 | CMP | Reg, Reg | 寄存器比较 |
| 12 | CMP | Reg, Imm | 寄存器比较立即数 |
| 13 | JMP | Addr | 无条件跳转 |
| 14 | JNZ | Addr | 结果不为零时跳转 (用于检测错误) |
| 16 | READ | None | 读取用户输入 |
| 17 | None | 打印输出缓冲区 |
从内存地址 0x14001DA90 提取出核心校验字节码,并编写脚本进行反汇编。
反汇编后的伪代码逻辑如下(地址为相对偏移):
-
输入读取:
03c: READ Input -
第一组检查 (flag):
Input[0] == 102 ('f')Input[1] + 1 == 109 ('m')=>Input[1] = 'l'Input[2] ^ Input[3] == 6Input[3] ^ Input[4] == 28Input[2] ^ Input[4] == 26- 解方程得:
Input[2]='a',Input[3]='g',Input[4]='{' - 当前部分:
flag{
-
第二组检查 (HiT):
Input[6] == 105 ('i')Input[5] ^ Input[6] == 33=>Input[5] = 33 ^ 'i' = 'H'Input[7] ^ Input[6] == 61=>Input[7] = 61 ^ 'i' = 'T'- 当前部分:
HiT
-
第三组检查 (CTF):
R3 = Input[7] ('T')Input[9] == R3=>Input[9] = 'T'Input[8] ^ Input[9] == 23=>Input[8] = 23 ^ 'T' = 'C'Input[10] ^ Input[9] == 18=>Input[10] = 18 ^ 'T' = 'F'- 当前部分:
CTF
-
第四组检查 (_2025):
Input[12] == Input[14]Input[11] * 2 == 190=>Input[11] = 95 ('_')Input[17] == 0(字符串结束符)Input[12] + 0 == 50=>Input[12] = '2'Input[12] - 2 == 48(验证)Input[12] - 2 + 5 == Input[15]=>50 - 2 + 5 = 53 ('5')=>Input[15] = '5'Input[16] - Input[4] == 2=>Input[16] = '{' + 2 = '}'- 关于 Input[13]:
- 代码中有
MOV R3, Input[13](地址0cb),但在后续的CMP或计算中未显式使用该值进行跳转判断。 - 结合上下文
_2?25}以及常见的 CTF 年份惯例,推测Input[13]为'0'。
- 代码中有
- 当前部分:
_2025}
最终flagflag{HiTCTF_2025}

![[HITCTF2025] Reverse - EasyVM Writeup](https://lunaticquasimodo.top/uploads/Weixin_Image_20251127215810_517_1118_67748b60e8.png)