【攻防世界】reverse | Mysterious 详细题解 WP
下载附件

DialogFunc_0函数伪代码:
c
int __stdcall DialogFunc_0(HWND hWnd, int a2, int a3, int a4)
{
int v4; // eax
char Source[260]; // [esp+50h] [ebp-310h] BYREF
_BYTE Text[257]; // [esp+154h] [ebp-20Ch] BYREF
__int16 v8; // [esp+255h] [ebp-10Bh]
char v9; // [esp+257h] [ebp-109h]
int Value; // [esp+258h] [ebp-108h]
CHAR String[260]; // [esp+25Ch] [ebp-104h] BYREF
memset(String, 0, sizeof(String));
Value = 0;
if ( a2 == 16 )
{
DestroyWindow(hWnd);
PostQuitMessage(0);
}
else if ( a2 == 273 )
{
if ( a3 == 1000 )
{
GetDlgItemTextA(hWnd, 1002, String, 260);
strlen(String);
if ( strlen(String) > 6 )
ExitProcess(0);
v4 = atoi(String);
Value = v4 + 1;
if ( v4 == 122 && String[3] == 120 && String[5] == 122 && String[4] == 121 )
{
strcpy(Text, "flag");
memset(&Text[5], 0, 0xFCu);
v8 = 0;
v9 = 0;
_itoa(Value, Source, 10);
strcat(Text, "{");
strcat(Text, Source);
strcat(Text, "_");
strcat(Text, "Buff3r_0v3rf|0w");
strcat(Text, "}");
MessageBoxA(0, Text, "well done", 0);
}
SetTimer(hWnd, 1u, 0x3E8u, TimerFunc);
}
if ( a3 == 1001 )
KillTimer(hWnd, 1u);
}
return 0;
}
WinMain函数伪代码:
c
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
DialogBoxParamA(hInstance, (LPCSTR)0x65, 0, (DLGPROC)DialogFunc, 0);
return 0;
}
exp:
python
def generate_flag(input_str: str) -> str:
"""
复现DialogFunc_0的Flag生成逻辑
:param input_str: 输入框字符串(需满足条件:122xyz)
:return: 生成的Flag
"""
# 步骤1:验证输入长度
if len(input_str) > 6:
raise ValueError("输入字符串长度不能超过6!")
# 步骤2:转换为整数(模拟atoi)
try:
v4 = int(input_str[:3]) # atoi遇到非数字停止,取前3位转整数
except ValueError:
raise ValueError("输入字符串前3位必须是数字!")
# 步骤3:验证核心条件
if not (v4 == 122 and
len(input_str) >=6 and
input_str[3] == 'x' and
input_str[4] == 'y' and
input_str[5] == 'z'):
raise ValueError("输入字符串不符合条件!需为122xyz")
# 步骤4:计算Value
value = v4 + 1
# 步骤5:拼接Flag(模拟strcat逻辑)
flag = f"flag{{{value}_Buff3r_0v3rf|0w}}"
return flag
# 测试:输入符合条件的字符串
if __name__ == "__main__":
# 满足条件的输入字符串
valid_input = "122xyz"
try:
final_flag = generate_flag(valid_input)
print(f"✅ 生成的Flag:{final_flag}")
except ValueError as e:
print(f"❌ 错误:{e}")
运行 exp 脚本:
flag{123_Buff3r_0v3rf|0w}
【攻防世界】reverse | Mysterious 详细题解 WP 原理深度解析:
CTF 逆向实战:Mysterious 对话框程序 Flag 深度解析与解题方法论
一、题目背景与逆向目标
在 CTF 逆向领域,Windows 对话框程序是常见题型之一。这类程序通常通过对话框与用户交互,核心逻辑封装在回调函数中,Flag 生成往往依赖特定输入条件。本文以攻防世界 reverse 题目「Mysterious」为例,从逆向分析到 Flag 推导,全程还原解题思路,并提炼同类题目的通用解法。
二、程序结构初探:从入口到核心逻辑
2.1 程序入口定位
通过反编译工具(如 IDA Pro/Ghidra)分析程序,首先找到入口函数WinMain:
c
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
DialogBoxParamA(hInstance, (LPCSTR)0x65, 0, (DLGPROC)DialogFunc, 0);
return 0;
}
WinMain仅调用了DialogBoxParamA,这是 Windows 创建模态对话框的 API,其第四个参数DialogFunc为对话框回调函数(DLGPROC)------ 这是程序的核心逻辑所在,所有用户交互(如输入、按钮点击)的处理都在这里。
2.2 核心函数定位:DialogFunc_0
对话框回调函数DialogFunc_0负责处理所有对话框消息(如关闭窗口、按钮点击)。通过分析伪代码,我们发现其内部包含了 Flag 生成的关键逻辑。
三、DialogFunc_0 深度逆向:拆解 Flag 生成条件
3.1 变量与初始化逻辑
c
int __stdcall DialogFunc_0(HWND hWnd, int a2, int a3, int a4)
{
int v4; // 存储输入字符串转换的整数
char Source[260]; // 存储Value的字符串形式
_BYTE Text[257]; // 存储最终Flag
int Value; // 存储v4+1的结果
CHAR String[260]; // 存储用户输入的字符串
memset(String, 0, sizeof(String)); // 初始化输入缓冲区
Value = 0;
// ... 消息处理逻辑
}
变量作用清晰:String接收用户输入,v4是输入字符串转换的整数,Value是计算结果,Text用于拼接 Flag。
3.2 消息处理:聚焦关键交互
对话框回调函数通过a2(消息 ID)区分不同事件:
- 当
a2 == 16:处理窗口关闭消息(WM_CLOSE),调用DestroyWindow和PostQuitMessage退出程序,与 Flag 无关。 - 当
a2 == 273:处理按钮点击消息(BN_CLICKED),这是核心交互逻辑,其中a3表示按钮 ID。
3.3 核心逻辑:按钮 ID=1000 的处理流程
当点击 ID=1000 的按钮时,程序执行以下操作(按顺序解析):
步骤 1:读取用户输入
c
GetDlgItemTextA(hWnd, 1002, String, 260);
通过GetDlgItemTextA读取 ID=1002 的输入框内容到String,最多 260 字节。
步骤 2:输入长度检查
c
if (strlen(String) > 6) ExitProcess(0);
若输入长度超过 6,则直接退出程序。** 关键限制:输入长度必须≤6 **。
步骤 3:输入字符串转整数
c
v4 = atoi(String);
Value = v4 + 1;
atoi函数将字符串转为整数,规则是「遇到非数字字符停止转换」。例如,输入 "122xyz" 时,atoi只会处理前 3 位 "122",得到v4=122。
步骤 4:Flag 生成的核心条件
程序通过以下if语句判断是否生成 Flag:
c
if (v4 == 122 && String[3] == 120 && String[5] == 122 && String[4] == 121)
拆解条件(结合 ASCII 码表):
v4 == 122:输入字符串的数字部分必须为 122(即前 3 位为 "122");String[3] == 120:输入字符串第 4 个字符(索引 3)的 ASCII 码为 120 → 字符 'x';String[4] == 121:输入字符串第 5 个字符(索引 4)的 ASCII 码为 121 → 字符 'y';String[5] == 122:输入字符串第 6 个字符(索引 5)的 ASCII 码为 122 → 字符 'z'。
步骤 5:Flag 拼接逻辑
满足条件后,程序拼接 Flag:
c
strcpy(Text, "flag"); // Text = "flag"
_itoa(Value, Source, 10); // Source = "123"(因Value=122+1)
strcat(Text, "{"); // Text = "flag{"
strcat(Text, Source); // Text = "flag{123"
strcat(Text, "_"); // Text = "flag{123_"
strcat(Text, "Buff3r_0v3rf|0w"); // Text = "flag{123_Buff3r_0v3rf|0w"
strcat(Text, "}"); // Text = "flag{123_Buff3r_0v3rf|0w}"
MessageBoxA(0, Text, "well done", 0); // 弹窗显示Flag
3.4 干扰逻辑排除
代码中包含SetTimer和KillTimer(定时器相关),但这与 Flag 生成无关,属于干扰项。CTF 逆向中需学会过滤无关逻辑,聚焦MessageBoxA、strcat等与 Flag 直接相关的代码。
四、Flag 推导与验证
4.1 输入字符串确定
结合所有条件,输入字符串需满足:
- 长度 = 6(因需包含索引 0-5 的字符);
- 前 3 位:"122"(确保
v4=122); - 后 3 位:索引 3='x'、索引 4='y'、索引 5='z'。
最终输入为:122xyz。
4.2 Python 代码复现验证
编写代码模拟 Flag 生成逻辑,验证结果:
python
def generate_flag(input_str: str) -> str:
if len(input_str) > 6:
raise ValueError("输入长度不能超过6")
# 模拟atoi:取前3位数字
try:
v4 = int(input_str[:3])
except:
raise ValueError("前3位必须为数字")
# 验证核心条件
if not (v4 == 122 and len(input_str) == 6
and input_str[3] == 'x'
and input_str[4] == 'y'
and input_str[5] == 'z'):
raise ValueError("输入不符合条件")
# 生成Flag
return f"flag{{{v4+1}_Buff3r_0v3rf|0w}}"
# 测试
print(generate_flag("122xyz")) # 输出:flag{123_Buff3r_0v3rf|0w}
五、同类 CTF 题目解题方法论
5.1 题型特征识别
对话框程序逆向的典型特征:
- 入口函数调用
DialogBoxParamA或CreateDialogParamA; - 存在回调函数(DLGPROC),参数包含
HWND、消息 ID(a2)、控件 ID(a3); - 关键 API:
GetDlgItemTextA(读输入)、MessageBoxA(显 Flag)、strcpy/strcat(字符串拼接)。
5.2 核心解题步骤
-
定位关键函数:
搜索
MessageBoxA、flag等关键词,快速定位 Flag 生成位置;通过GetDlgItemTextA找到输入处理逻辑。 -
解析输入验证规则:
- 关注长度限制(
strlen); - 数值转换(
atoi/itoa):注意atoi遇非数字截断的特性; - 字符位置校验(如
String[i] == 0xXX):转换 ASCII 码为字符,推导输入格式。
- 关注长度限制(
-
过滤干扰逻辑:
忽略定时器(
SetTimer)、绘图(DrawText)等与 Flag 无关的代码,聚焦条件判断(if)和字符串拼接。 -
动态调试验证:
若静态分析有歧义,用 x64dbg 在
MessageBoxA处下断点,输入推测的字符串,直接查看弹窗内容。
5.3 工具链推荐
- 静态分析:IDA Pro(伪代码清晰)、Ghidra(开源免费);
- 动态调试 :x64dbg(断点
MessageBoxA快速获取 Flag); - 辅助脚本:Python(复现字符串逻辑、验证输入条件)。
六、总结
本题通过分析对话框回调函数DialogFunc_0,提炼出输入验证的核心条件,最终推导出输入122xyz,生成 Flagflag{123_Buff3r_0v3rf|0w}。解题的关键在于:
- 快速定位 Flag 生成的核心逻辑(聚焦
MessageBoxA和条件判断); - 准确解析输入验证规则(长度、数值、字符位置);
- 过滤干扰代码,不被无关逻辑迷惑。
掌握这类方法后,面对同类对话框程序逆向题,可快速套用「定位关键函数→解析输入规则→验证生成 Flag」的流程,高效解题。