老样子,下载,查壳,64位,IDA打开
f5查看伪代码
伪码分析:
一、整体流程
这个 main 函数只是一层输入输出外壳,本身不包含任何加密校验逻辑。所有核心的 flag 验证算法都封装在 flag() 函数里。
完整执行流程:
初始化栈保护机制
打印提示语,读取用户输入的字符串
将输入传入 flag() 函数执行校验
程序返回
点击flag函数,
函数代码分析
DWORD 全称 Double Word(双字),是 Windows C 开发体系里的经典数据类型,IDA 反编译时沿用了这个命名,前面加下划线写作 _DWORD。
大小:4 字节(32 位),对应 C 标准里的 unsigned int,是无符号 32 位整数。
命名由来:1 个 Word(字)是 2 字节(16 位),双字就是两个 Word,共 4 字节。
这是一道入门逆向题的核心函数,整体逻辑分为长度校验和flag 生成输出两部分。输入字符串的内容不参与校验,只有长度会决定是否能触发 flag 输出。
逐段逻辑拆解
- 前半段大段代码:快速计算字符串长度
你看到的大量位运算、循环跳转,本质是编译器内联优化的 strlen(字符串长度计算)实现,是标准的快速长度计算算法:
先检查指针对齐状态,未对齐时先逐个字节遍历到对齐位置;
对齐后按 4 字节(32 位)批量检测,通过经典位运算公式 ((i - 0x01010101) & ~i & 0x80808080) 快速判断 4 个字节中是否包含结束符 \0,大幅提升长字符串的计算效率;
最后处理剩余不足 4 字节的部分,逐个字节定位结束符位置。
最终 v6 会指向字符串末尾的 \0,v6 - 起始地址 就是输入字符串的总长度。
注:伪代码里大量 (_DWORD)指针、+1 偏移是 IDA 反编译的类型推断瑕疵,把指针运算错误转成了整数运算,不影响核心逻辑判断。
核心代码:
puts(“The length of flag is 13”);//输出语句The length of flag is 13
srand(seed);
printf(“NSSCTF{”);
for ( m = 0; m < 13; ++m )
{
v4 = rand();
printf(“%d”, (unsigned int)(v4 % 8 + 1));
}
putchar(125);
说明flag长度是13,生成一个随机数,C语言的随机数是伪随机,同一个种子生成的随机数是一样的,所以种子相当于密钥,先获取到种子,双击seed,
说明种子是0x2766,写解题脚本
#include<stdio.h>#include<stdlib.h>#include<string.h>intmain(){srand(0x2766);intm;printf("NSSCTF{");for(m=0;m<13;m++){intv4=rand();printf("%d",(unsignedint)(v4%8+1));}putchar(125);return0;}得到flag