maze writeup

  攻防世界的一道迷宫题,第一次接触这样的题,个人感觉很有意思,收获也挺多,做一篇笔记记录一下。

程序分析

__int64 sub_4006B0()
{
signed __int64 v0; // rbx
signed int v1; // eax
bool v2; // bp
bool v3; // al
const char *v4; // rdi
__int64 v6; // [rsp+0h] [rbp-28h] v6 = 0LL;
puts("Input flag:");
scanf("%s", &s1, 0LL);
if ( strlen(&s1) != 24 || strncmp(&s1, "nctf{", 5uLL) || *(&byte_6010BF + 24) != 125 )// flag长度为24字节,前五个字节为"nctf{",最后一个字节要是"}"
{
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
v0 = 5LL;
if ( strlen(&s1) - 1 > 5 )
{
while ( 1 )
{
v1 = *(&s1 + v0); // 对每一位进行判断
v2 = 0;
if ( v1 > 78 )
{
v1 = (unsigned __int8)v1;
if ( (unsigned __int8)v1 == 'O' ) // "O"表示向左移动
{
v3 = sub_400650((__int64)&v6 + 4);
goto LABEL_14;
}
if ( v1 == 'o' ) // "o"表示向右移动
{
v3 = sub_400660((__int64)&v6 + 4);
goto LABEL_14;
}
}
else
{
v1 = (unsigned __int8)v1;
if ( (unsigned __int8)v1 == '.' ) // "."表示向上移动
{
v3 = sub_400670((__int64)&v6);
goto LABEL_14;
}
if ( v1 == '0' ) // "0"表示向下移动
{
v3 = sub_400680((__int64)&v6);
LABEL_14:
v2 = v3;
goto LABEL_15;
}
}
LABEL_15:
if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v6), v6) )// asc_601060是字符串首地址
goto LABEL_22;
if ( ++v0 >= strlen(&s1) - 1 )
{
if ( v2 )
break;
LABEL_20:
v4 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * (signed int)v6 + SHIDWORD(v6)] != '#' )
goto LABEL_20;
v4 = "Congratulations!";
LABEL_21:
puts(v4);
return 0LL;
}

  主函数如上所示。我开始看的时候没有看明白,后来发现给出了四种操作符,对应上下左右四种移动,给出的字符串要想象成一个二维图像,相当于要用一个二维数组表示出来。

  flag的格式已经给我们规定好了:nctf{......}。

__int64 __fastcall sub_400690(__int64 a1, int a2, int a3)
{
__int64 result; // rax result = *(unsigned __int8 *)(a1 + a2 + 8LL * a3);
LOBYTE(result) = (_DWORD)result == 32 || (_DWORD)result == 35;
return result;
}
if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v6), v6) )// asc_601060是字符串首地址
goto LABEL_22;

  sub_400690函数这里拉出来看一下,SHIDWORD这里是一个宏定义,定义如下:

#define SHIDWORD(x)  (*((int32*)&(x)+1))

  对字符串如何取值或者对二级指针理解还不清楚的,可以尝试敲一下下面的测试代码:

#include<stdio.h>
#include<string.h> int main()
{
__int64 v6;
v6=1LL;char* a="abcdefghjk";
printf("%p\n",a);
printf("%p\n",*(&a));
printf("%p\n",&a);
printf("%c\n",*a);
printf("%c",*(a+1));
return 0;
}

  宏定义和四种操作符理解不了,尝试下面的测试代码:

#include<stdio.h>
#include<string.h> #define SHIDWORD(x) (*((__int32*)&(x)+1))
int main()
{
__int64 v6;
v6=1LL;
char* a="abcdefghjk";
printf("%p\n",&v6);
printf("%p\n",(__int64)&v6);
printf("%p\n",&v6+4);
printf("%p\n",(__int64)&v6+4);
printf("%p",&(SHIDWORD(v6)));
return 0;
}

  sub_400690中,v6是行数,即y坐标,SHIDWORD(v6)是列数,即x坐标,(__int64)asc_601060是字符串首地址。后面的判断表示走的时候,只能走“#”和空格。

  我们先把字符串转换成一个二维的迷宫

maze="  *******   *  **** * ****  * ***  *#  *** *** ***     *********"
x=""
New_maze=""
for a in maze:
if a==" ":
New_maze+="0"
elif a=="*":
New_maze+="1"
else:
New_maze+=a
x=""
for i in range(len(New_maze)):
x+=New_maze[i]
if (i+1)%8==0:
print(x)
x=""

  然后从头开始,“O”表示向左移动,“o”表示向右移动,“.”表示向上移动,“0”表示向下移动(上下这里要注意,容易搞错)。四种操作符看不懂,就好好看一下上面给出的测试代码。

  最后得到flag:nctf{o0oo00O000oooo..OO}。

最新文章

  1. fastcgi 性能初配 504 gateway time-out
  2. Intention.js – 动态重构 HTML 为响应式模式
  3. 使用VIM插件ctags来阅读C代码
  4. RabbitMQ官方中文入门教程(PHP版) 第四部分:路由(Routing)
  5. java多线程:并发包中ReentrantReadWriteLock读写锁的原理
  6. MultiMap
  7. Newtonsoft.Json.dll使用
  8. 转-[Python 学习]2.5版yield之学习心得
  9. java打jar包 命令行cmd在当前路径打jar包
  10. while和for可以相互转换例子
  11. Mutex(测量)
  12. 鸟哥的linux私房菜学习-(二)VMware虚拟机及linux系统安装过程
  13. 2017&quot;百度之星&quot;程序设计大赛 - 初赛(A)-1001.小C的倍数问题(HDU6108) 1005.今夕何夕-蔡勒公式 (HDU6112)
  14. HiveServer2的WEB UI界面
  15. 第七周博客作业 &lt;西北师范大学| 周安伟&gt;
  16. python学习之旅(五)
  17. mac电脑对ntfs格式硬盘进行写操作(简单说就是向ntfs硬盘拷贝东西)
  18. [Spark Core] Spark Shell 实现 Word Count
  19. 阿里云上部署kafka--遇到的坑
  20. Spring Cloud 学习网址

热门文章

  1. Redis之阻塞分析
  2. centos7 system自定义服务
  3. 流程自动化RPA,Power Automate Desktop系列 - 批量备份Git仓库做好灾备
  4. QPainter::begin: Paint device returned engine == 0, type: 1
  5. 1、centos7修改网卡名称为传统的eth0
  6. 7、基本数据类型(tuple)
  7. CRM软件从哪些方面帮助企业更上一层楼
  8. Maven中dependencies和dependencyManagement的区别
  9. 第二章 - Java与协程
  10. PHP利用百度ai实现文本和图片审核