查壳
32位,拖进IDA,老方法,找到flag,进入伪代码
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char v3[29]; // [esp+17h] [ebp-35h] BYREF
int v4; // [esp+34h] [ebp-18h]
int v5; // [esp+38h] [ebp-14h] BYREF
int i; // [esp+3Ch] [ebp-10h]
_BYTE v7[12]; // [esp+40h] [ebp-Ch] BYREF
__main();
v4 = 0;
strcpy(v3, "*11110100001010000101111#");
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &v5);
if ( v5 == 2 )
{
++*(_DWORD *)&v3[25];
}
else if ( v5 > 2 )
{
if ( v5 == 3 )
{
--v4;
}
else
{
if ( v5 != 4 )
LABEL_13:
exit(1);
++v4;
}
}
else
{
if ( v5 != 1 )
goto LABEL_13;
--*(_DWORD *)&v3[25];
}
for ( i = 0; i <= 1; ++i )
{
if ( *(int *)&v3[4 * i + 25] < 0 || *(int *)&v3[4 * i + 25] > 4 )
exit(1);
}
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == 49 )
exit(1);
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == 35 )
{
puts("\nok, the order you enter is the flag!");
exit(0);
}
}
}
这个伪代码有点意思,我也是研究了好久(个人比较笨),解说一下思路
依旧先找正确的输出,满足条件是v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == 35 --> 等于'#'时就说明是正确的flag
'#'哪里来 --> 拉到开头我们能见到
是字符串的最后一个,这个字符串的长度为25,即 0~24。还有 " 1上 2下 3左 4右",让人迷茫,
再看看输入和判断,v5 和 v4 跟 v3 有什么关系为什么每个判断上或多或少的都有他两,甚至还有v7
对内存的解读,v3的内存为[esp+17h][esp+34h],v4为[esp+34h][esp+38h],v5为[esp+38h]~[esp+3Ch]
知道内存的分布后,我们先看异常退出的点(exit(1))
我们已经知道内存的分布,那么算一下(int类型的转换(int是四个字节即(双字)))即可知道,在这个循环中,检查的是v4和v5的值是否是小于 0 或者大于 4 的,满足则异常退出
在看看语句
++,我们知道自增嘛,那么*(_DWORD *)是什么意思呢DWORD的意思是双字(也就是四个字节),这句话的意思是指向v3[25]后边的四个字节(包括v3[25]),使它自增 1。这样这篇伪代码几乎就能看懂了(这里注意,这里的内存依旧属于v3的内存)
在看看最后的判断语句
-41?看看v7的内存分布,我们可以知道,v7对应的是v3前25个内存中各个的字符,结合上述,走迷宫? --> 在判断中还有 5 *
将v3前25给字符以5*5的排列来看
*1111
01000
01010
00010
1111#