
今天的逆向题目也是非常精妙的!如果大家在前面几关已经培养出了“自大”的情绪,觉得 CrackMe 不过如此,那么这一个 CrackMe #5 绝对会给你们好好上一课。
先补一句,所有的案例资源下载都在 www.52xuejishu.com,0基础学逆向,就找小迪老师
这个程序的真正核心教学价值在于:考察大家对 C语言基础指针语法的熟悉程度,以及识破“逆向工程逻辑陷阱”的能力。
我们可以按照以下四个阶段来进行深度剖析:
阶段一:主函数梳理(建立大局观)
“拿到程序,第一步依然是打扫战场。通过重命名(快捷键 N),我们快速把主函数的逻辑清理干净。大家可以看到,这个程序依然是‘双重验证’结构。”
经过快速重命名,主逻辑如下:

memset(Str1, 0, sizeof(Str1));
printf("==== CrackMe #5 ====\n");
printf("Enter password: ");
scanf("%63s", Str1);
if ( Check_Method_1(Str1) ) // 原 sub_404796
{
printf("Success!\n");
return 0;
}
else
{
if ( Check_Method_2(Str1) ) // 原 sub_4021BC
printf("Success!\n");
else
printf("Fail!\n");
system("pause");
return 0;
}
结论: 依然有两条路可以通关。我们先来看第一条路。
阶段二:破解第一道门(指针的本质与 ASCII 码)
双击进入 Check_Method_1(底层其实是 sub_4088C0),我们看到了这样一行极其简练的代码:
BOOL __cdecl sub_4088C0(char *Str)
{
return j__strlen(Str) == 5 && *Str == 88;
}
硬核知识点拆解(新手重点科普):
j__strlen(Str) == 5: 这个很好理解,密码的长度必须刚好是 5 个字符。*Str == 88(核心难点!):
-
- 指针解引用: 在 C 语言里,数组的名字(也就是指针
Str)代表的是字符串的起始地址。而在指针前面加一个星号*(解引用),意思就是取这个地址里的第一个字节。所以,*Str完全等同于Str[0]。 - ASCII 码对照: 字符在计算机底层都是以数字(ASCII 码)存储的。数字
88对应的英文字符是什么?查阅 ASCII 码表(或者写个脚本chr(88)),答案是大写字母X。
- 指针解引用: 在 C 语言里,数组的名字(也就是指针
推导结果:
第一把钥匙根本不是一个固定的字符串!只要长度是 5,并且第一个字母是 X,无论后面写什么都能通关!
比如:X1234, Xabcd, X____ 全部都是正确的密码!
阶段三:破解第二道门(开发者的恶意陷阱!)
如果说第一道门是考基础,那么第二道门纯粹就是考“细心”了。
退回主函数,双击进入 Check_Method_2(底层是 sub_408900),逐行分析这段非常有迷惑性的代码:
int __cdecl sub_408900(char *Str1)
{
char v2 = *Str1; // 取出第一个字符
if ( *Str1 == 65 ) // 如果第一个字符是 'A' (ASCII 65)
{
if ( !j__strcmp(Str1, "Alpha") )
return 0; // 🚨 注意这里的返回值!
}
else if ( v2 == 66 ) // 如果第一个字符是 'B' (ASCII 66)
{
if ( !j__strcmp(Str1, "Bravo") )
return 0; // 🚨 注意这里的返回值!
}
else // 否则...
{
if ( v2 != 67 ) // 如果第一个字符也不是 'C' (ASCII 67),直接失败
return 0;
if ( !j__strcmp(Str1, "Charlie") )
return 1; // ✅ 只有这里返回了 1!
}
return 0;
}
陷阱讲解:
“很多同学看到这里,会非常兴奋地说:‘老师,我看到了三个密码!Alpha、Bravo 和 Charlie!’。
如果你真的这么想,那你就掉进了开发者精心设计的陷阱里!逆向分析最忌讳‘只看字面意思,不看逻辑流向’。
大家仔细看返回值:在 C 语言中,只有返回 1 (非零) 才代表 True(验证通过)。如果你输入了 "Alpha" 或者 "Bravo",程序确实进了 if 分支,但它最终 return 0;。这意味着验证失败!
开发者故意放了两个毫无用处的干扰密码在这里。真正的通关密码,只有最后那个返回了 1 的 "Charlie"!”

阶段四:实战总结与 IDA 类型重构演示
最后,小迪老师给大家做一次大总结,并教大家如何让代码更漂亮:
- 给数字披上字符的外衣: 在 IDA 的
sub_408900伪代码界面,选中数字65,按下快捷键R(Character constant),IDA 会立刻把65变成'A'。同理,把66变成'B',67变成'C',在sub_4088C0里把88变成'X'。 这个小技巧能让伪代码的可读性产生质的飞跃。
- 逆向心法传授:
-
- 不要被字符串字面量骗了: 看到明文字符串不要急着去试,一定要看清楚它所在的条件分支最终是引向了成功(
return 1)还是失败(return 0)。 - 理解基础指针操作:
*ptr和ptr[0]是同一个东西,这是 C 语言反编译中最常见的两种表现形式。
- 不要被字符串字面量骗了: 看到明文字符串不要急着去试,一定要看清楚它所在的条件分支最终是引向了成功(
通过这个关卡,大家不仅学到了 ASCII 和指针的转换,更重要的是,你们第一次在代码里体会到了逆向工程师与软件开发者之间的“心理博弈”!



没有回复内容