深入浅出,知无不答,言无不尽,力求详尽
老样子查壳
无壳, 可以直接IDA, 这还是windows控制台程序, 也可以od。
废话不多说, 直接F5
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
__m128i v5; // [esp+0h] [ebp-44h] BYREF
__int64 v6; // [esp+10h] [ebp-34h]
int v7; // [esp+18h] [ebp-2Ch]
__int16 v8; // [esp+1Ch] [ebp-28h]
char v9[32]; // [esp+20h] [ebp-24h] BYREF
v5 = _mm_loadu_si128((const __m128i *)&xmmword_413E34);
v7 = 0;
v6 = 0x7D465443545544i64;
v8 = 0;
printf("欢迎来到DUTCTF呦\n");
printf("这是一道很可爱很简单的逆向题呦\n");
printf("输入flag吧:");
scanf("%s", v9);
v3 = strcmp(v5.m128i_i8, v9);
if ( v3 )
v3 = v3 < 0 ? -1 : 1;
if ( v3 )
printf(aFlag_0);
else
printf(aFlagGet);
system("pause");
return 0;
}
这段代码里有挺多SSE2中的指令集, __m128i类型变量, _mm_loadu_si128函数, __xmmword关键字...等等
1、开头的初始化, 第一行不再赘述了, 详细可以看过往两篇文章:
[攻防世界]Hello,CTF (逆向CTF) 包含 main函数中的参数 二级指针envp 说明
[攻防世界]Open-source(逆向Hack-you) 包含 main函数中的两个参数argc和argv 说明
3-8行初始化变量类型, 有两个例外要讲一下, 第4行的 __m128i 这个数据类型是个啥玩意, 它比较特别, 是一个联合体(union), 可以用不同的方式解释相同的128位数据, 既可以是16个8位整数、8个16位整数、也可以是4个32位整数或2个64位整数, 把它当成一个非常灵活的整数型变量就可以了。
2、一部分赋值解析
v5 = _mm_loadu_si128((const __m128i *)&xmmword_413E34);
v7 = 0;
v6 = 0x7D465443545544i64;
v8 = 0;
这个_mm_loadu_si128函数是直接加载128位值(si128表示signed 128 big interger), 无需16字节对齐, 返回寄存器中的值, 函数内参数const __m128i * 代表创建了一个常量指针, 指向xmmword_413E34。
还有v6赋值的16进制(这个大家应该看得懂吧), 后缀i64则是把占用的内存空间扩展到了64位。
3、主体部分
printf("欢迎来到DUTCTF呦\n");
printf("这是一道很可爱很简单的逆向题呦\n");
printf("输入flag吧:");
scanf("%s", v9);
v3 = strcmp(v5.m128i_i8, v9);
if ( v3 )
v3 = v3 < 0 ? -1 : 1;
if ( v3 )
printf(aFlag_0);
else
printf(aFlagGet);
system("pause");
前三行输出一些文字, scanf函数把我们输入的数据传给v9。
strcmp函数比较v5和v9, v5后缀的.m128i_i8 是取出v5的8位整数元素的意思, 并赋值给v3, strcmp函数的输出只有三种可能, 等于0、小于或者大于0, 在if判断中只要不是0值(布尔类型), 都是1值, 会执行下面的语句。
进入判断
如果v3的值不是0就执行下面的语句:
v3 = v3 < 0 ? -1 : 1;
(注意加粗)这里用了一个三元运算符 "?", 这玩意初见很难理解。
"?" 的前面是条件, 后面一个条件为真执行的, 一个为假执行的, 我简单表述一下:
条件 ? (条件True时执行) : (条件False时执行)
回到题目, 这里v3小于0, 那么v3就会赋值成-1, 反之则赋值为1
第二个判断
v3不是0
输出aFlag_0
错了
v3是0
获得flag, 对了
我们总结一下条件:
v3的值决定了我们能不能获得flag, 而v3的值取决于v5和v9, v9是我们输入的值, v5是程序自带的, 所以我们溯源v5, v5指向xmmword_413E34, 双击跳转
发现两串十六进制数据, IDA中选中这条数据右键就可以将其转换成各种编码。
我们会发现这串东西好像反过来了一样, 确实, 你想的没错。
为什么呢?
这个原理在王克义教授所著的《微机原理》第2版的194页, 第二点提到了: (里面还提了一嘴为啥要叫大端和小端)
其实在《汇编语言》王爽写的那本里也提到了, 不过我很久没看了, 具体在哪记不清了...
好了, 今天就这样结束吧, 累了😩
把flag倒过来就行了:
flag:
DUTCTF{We1c0met0DUTCTF}