攻防世界逆向入门题之maze

攻防世界逆向入门题之maze

继续开启全栈梦想之逆向之旅~
这题是攻防世界逆向入门题的maze
在这里插入图片描述
我本来以为我越过了新手区,本来想信心满满地自己做出一道题,结果攻防世界还是给了我一个大巴掌。

附件下载扔入exeinpefo中查看信息:
在这里插入图片描述64位ELF文件,无壳,先扔入IDA中查看伪代码判断题目类型,再决定要不要在linux中运行:

在这里插入图片描述
从这里犯下第一个错误,我竟然对第一个判断语句的!=125的125不知所云,还去查了ASCII表,对后面的79,46这些竟然也想查。真的得给自己个一巴掌,flag基本都是字符和数字混合,而且在IDA里数字转ASCII字符直接快捷键R啊!!!!

然后判断题目类型是本身就有的存储型flag还是用用户输入一个个生成的生成型flag。答案是后者,那gdb调试就没法用了,直接静态分析代码即可。

转了字符后基本就明白了,现在开始代码分析了,

代码分析:

  puts("Input flag:");
  scanf("%s", &input_flag, 0LL);
  if ( strlen(&input_flag) != 24 || strncmp(&input_flag, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' )		//这里要求输入的flag是24个字符,且前5个和最后一个都确定了,一开始的125真的搞得我都不知道啥意思。后面的Oo.0也是如此
  {
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v3 = 5LL;
  if ( strlen(&input_flag) - 1 > 5 )		 
  {

    while ( 1 )
    {
      singleflag = *(&input_flag + v3);         // 这里v3是从5开始递增的数,目的是从第5个字符开始判断是否符合下述条件
      v5 = 0;
      if ( singleflag > 78 )	//这里给个范围,ASCII码大于78的划为第一类
      {
        singleflag = (unsigned __int8)singleflag;
        if ( (unsigned __int8)singleflag == 'O' )//如果第一个取O
        {
          v6 = sub_400650((_DWORD *)&v9 + 1);   // 这里犯下第二个错误,64位的v9分成取高底32字节其实是分到r14和r15两个寄存器的,底32位在r14,高32位在r15才有后面根据寄存器的分开操作,因为在两个不同寄存器中。
          goto LABEL_14;
        }
        if ( singleflag == 'o' )//如果第一个取o
        {
          v6 = sub_400660((int *)&v9 + 1);      // 有符号32位高字节操作,r15寄存器
          goto LABEL_14;
        }
      }
      else
      {
        singleflag = (unsigned __int8)singleflag;
        if ( (unsigned __int8)singleflag == '.' )//如果取到.
        {
          v6 = sub_400670(&v9);                 // 无符号底字节32位操作,r14寄存器
          goto LABEL_14;
        }
        if ( singleflag == '0' )
        {
          v6 = sub_400680((int *)&v9);          // 有符号底字节32位,r14寄存器
LABEL_14:
          v5 = v6;
          goto LABEL_15;
        }
      }
LABEL_15:
      if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v9), v9) )
        goto LABEL_22;
      if ( ++v3 >= strlen(&input_flag) - 1 )   //在flag范围内v3加1,对应前面singleflag取第6、7、8~个一个个比较
      {
        if ( v5 )		//如果flag取完了,且sub_这些函数没有返回flase,也就是没有越界,就可以判断是否抵达终点了
          break;
LABEL_20:
        v7 = "Wrong flag!";
        goto LABEL_21;
      }
    }
  }
  if ( asc_601060[8 * (signed int)v9 + SHIDWORD(v9)] != '#' )	  //判断是否为#这个终点。
    goto LABEL_20;
  v7 = "Congratulations!";
LABEL_21:
  puts(v7);
  return 0LL;
}

第二个错误看IDA反汇编结构图,底双字在r14寄存器,高双字在r15寄存器:
在这里插入图片描述

这里犯下的第三个错误就是对sub_400650、sub_400660、sub_400670、sub_400680、sub_400690、asc_601060、这些IDA自己命名的函数不敢去看!
总是觉得自己看不懂,害怕!!!后来才发现其实不应该害怕的!!要逼自己一把!!!

bool __fastcall sub_400650(_DWORD *a1)
{
  int v1; // eax

  v1 = (*a1)--;
  return v1 > 0;
}
bool __fastcall sub_400660(int *a1)
{
  int v1; // eax

  v1 = *a1 + 1;
  *a1 = v1;
  return v1 < 8;
}
bool __fastcall sub_400670(_DWORD *a1)
{
  int v1; // eax

  v1 = (*a1)--;
  return v1 > 0;
}
bool __fastcall sub_400680(int *a1)
{
  int v1; // eax

  v1 = *a1 + 1;
  *a1 = v1;
  return v1 < 8;
}

这四个函数点开之后是对传入参数+1 -1操作而已,真的不难,而且附带返回的比较后来查资料说是判断有没有越出迷宫边界,false就是越出了,就不用玩了,为true就是没越出,继续玩。

(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v9), v9)



__int64 __fastcall sub_400690(__int64 a1, int a2, int a3)
{
  __int64 result; // rax

  result = *(unsigned __int8 *)(a1 + a2 + 8LL * a3);
  LOBYTE(result) = (_DWORD)result == ' ' || (_DWORD)result == '#';
  return result;
}

在这里插入图片描述
这里sub_400690点进去分析后的(__int64)asc_601060如图是一串字符串,后来知道了是迷宫的图,sub_400690函数里传入v9的有符号高双字r15寄存器,和v9底双字的r14寄存器,然后运算表达式result = *(unsigned __int8 )(a1 + a2 + 8LL * a3); 就是在asc_601060字符串数组内取字符而已,可以看出a38,所以这是8个字符为一行,也就是说r14寄存器的底双字表示行,r15高双字表示列,+1-1分别对应着向上向下,向左向右移动。

O是左移,o是右移,0是下移,.是上移

所以这里可以写出asc_601060的迷宫图形:

  ******
*   *  *
*** * **
**  * **
*  *#  *
** *** *
**     *
********
  if ( asc_601060[8 * (signed int)v9 + SHIDWORD(v9)] != '#' )
    goto LABEL_20;
  v7 = "Congratulations!";
LABEL_21:
  puts(v7);
  return 0LL;

最后这里就是看最后跳出的flag末尾时是不是到了#这个字符,如果是就表示通关。

所以是:(看得我头晕)

右下右右下下左下下下右右右右上上左左

就是o0oo00O000oooo…OO

总结:

从这里犯下第一个错误,我竟然对第一个判断语句的!=125的125不知所云,还去查了ASCII表,对后面的79,46这些竟然也想查。真的得给自己个一巴掌,flag基本都是字符和数字混合,而且在IDA里数字转ASCII字符直接快捷键R啊!!!!

这里犯下第二个错误,64位的v9分成取高底32字节其实是分到r14和r15两个寄存器的,底32位在r14,高32位在r15才有后面根据寄存器的分开操作,因为在两个不同寄存器中。

这里犯下的第三个错误就是对sub_400650、sub_400660、sub_400670、sub_400680、sub_400690、asc_601060、这些IDA自己命名的函数不敢去看!
总是觉得自己看不懂,害怕!!!后来才发现其实不应该害怕的!!要逼自己一把!!!

解毕!敬礼!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐一 · 林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值