刷攻防世界的最后一道二星题,记录一下,大佬请飘过


题目


分析过程

我很勇,我先双击看看这是什么

是一个扫雷游戏,第一下运气好没踩雷,发现无法继续输入了;如果运气不好,会输出“您踩雷啦!”

丢到PE里面

无壳,64位

丢到IDA里面,shif+F12查看字符串,追踪可疑字符串,发现main函数

  1 int __cdecl main(int argc, const char **argv, const char **envp)
2 {
3 unsigned int v3; // eax
4 std::ostream *v4; // rax
5 __int64 v5; // rax
6 _BYTE *v6; // rax
7 std::istream *v7; // rax
8 __int64 v8; // rax
9 std::ostream *v9; // rax
10 std::ostream *v10; // rax
11 __int64 v11; // rax
12 int v13; // [rsp+28h] [rbp-58h]
13 int v14; // [rsp+2Ch] [rbp-54h]
14 int v15; // [rsp+30h] [rbp-50h]
15 int v16; // [rsp+34h] [rbp-4Ch]
16 int v17; // [rsp+38h] [rbp-48h]
17 int v18; // [rsp+3Ch] [rbp-44h]
18 int v19; // [rsp+40h] [rbp-40h]
19 int i1; // [rsp+44h] [rbp-3Ch]
20 int nn; // [rsp+48h] [rbp-38h]
21 int mm; // [rsp+4Ch] [rbp-34h]
22 int ll; // [rsp+50h] [rbp-30h]
23 int i2; // [rsp+54h] [rbp-2Ch]
24 int kk; // [rsp+58h] [rbp-28h]
25 int jj; // [rsp+5Ch] [rbp-24h]
26 int ii; // [rsp+60h] [rbp-20h]
27 int n; // [rsp+64h] [rbp-1Ch]
28 int m; // [rsp+68h] [rbp-18h]
29 int l; // [rsp+6Ch] [rbp-14h]
30 int k; // [rsp+70h] [rbp-10h]
31 int v32; // [rsp+74h] [rbp-Ch]
32 int j; // [rsp+78h] [rbp-8h]
33 int i; // [rsp+7Ch] [rbp-4h]
34
35 _main();
36 memset(grid, 0, 0x190ui64);
37 memset(randMark, 0, 0x9C40ui64);
38 memset(vis, 0, sizeof(vis));
39 for ( i = 0; i <= 9; ++i ) // 第一个循环-------------------------------------------------------------------------------
40 {
41 for ( j = 0; j <= 9; ++j )
42 showUs[100 * i + j] = 42;
43 }
44 v3 = time(0i64);
45 srand(v3);
46 v32 = 0;
47 do
48 {
49 v19 = rand() % 10; // 随机一个0~9
50 v18 = rand() % 10;
51 if ( randMark[100 * v19 + v18] != 1 )
52 {
53 randMark[100 * v19 + v18] = 1; // v32不到mine_sum,就一直循环
54 // 我怀疑这里是布雷
55 // mine_sum是雷的数量
56 ++v32;
57 }
58 }
59 while ( v32 != mine_sum );
60 res = 0;
61 for ( k = 0; k <= 9; ++k ) // 第二个循环-------------------------------------------------------------------------------------------
62 {
63 for ( l = 0; l <= 9; ++l )
64 {
65 if ( randMark[100 * k + l] )
66 grid[10 * k + l] = -1;
67 }
68 }
69 for ( m = 0; m <= 9; ++m ) // 第三个循环-----------------------------------------------------------------------------------------------------
70 {
71 for ( n = 0; n <= 9; ++n )
72 {
73 if ( grid[10 * m + n] != -1 )
74 {
75 for ( ii = 0; ii <= 7; ++ii )
76 {
77 v17 = *((_DWORD *)&dir + 2 * ii) + m;
78 v16 = dword_475044[2 * ii] + n;
79 if ( v17 >= 0 && v17 <= 9 && v16 >= 0 && v16 <= 9 && grid[10 * v17 + v16] == -1 )
80 ++grid[10 * m + n];
81 }
82 }
83 }
84 }
85 for ( jj = 0; jj <= 9; ++jj ) // 第四个循环--------------------------------------------------------------------------------------------------------
86 {
87 for ( kk = 0; kk <= 9; ++kk )
88 {
89 v4 = (std::ostream *)std::operator<<<std::char_traits<char>>(
90 refptr__ZSt4cout,
91 (unsigned int)showUs[100 * jj + kk]);
92 std::operator<<<std::char_traits<char>>(v4, " ");
93 }
94 std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
95 }
96 LABEL_42:
97 v5 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, asc_48B002);// 请输入要翻开的位置的坐标
98 std::ostream::operator<<(v5, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
99 while ( 100 - mine_sum != res ) // res是没有雷的地方
100 {
101 v7 = (std::istream *)std::istream::operator>>(refptr__ZSt3cin);
102 std::istream::operator>>(v7);
103 if ( grid[10 * v14 + v13] == -1 ) // 第一个if---检查是否踩雷
104 {
105 v8 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, asc_48B01D);// 您中雷啦
106 std::ostream::operator<<(v8, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
107 goto LABEL_69; // pause
108 }
109 if ( !vis[100 * v14 + v13] && grid[10 * v14 + v13] > 0 )// 第二个if---
110 {
111 ++res;
112 vis[100 * v14 + v13] = 1;
113 showUs[100 * v14 + v13] = LOBYTE(grid[10 * v14 + v13]) + 48;
114 system("cls");
115 for ( ll = 0; ll <= 9; ++ll )
116 {
117 for ( mm = 0; mm <= 9; ++mm )
118 {
119 v9 = (std::ostream *)std::operator<<<std::char_traits<char>>(
120 refptr__ZSt4cout,
121 (unsigned int)showUs[100 * ll + mm]);
122 std::operator<<<std::char_traits<char>>(v9, " ");
123 }
124 std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
125 }
126 goto LABEL_42;
127 }
128 if ( !vis[100 * v14 + v13] && !grid[10 * v14 + v13] )// 第三个if---
129 {
130 bfs(v14, v13);
131 system("cls");
132 for ( nn = 0; nn <= 9; ++nn )
133 {
134 for ( i1 = 0; i1 <= 9; ++i1 )
135 {
136 v10 = (std::ostream *)std::operator<<<std::char_traits<char>>(
137 refptr__ZSt4cout,
138 (unsigned int)showUs[100 * nn + i1]);
139 std::operator<<<std::char_traits<char>>(v10, " ");
140 }
141 std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
142 }
143 v11 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, asc_48B002);// 请输入要翻开的位置的坐标
144 std::ostream::operator<<(v11, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
145 }
146 } // while结束的地方
147 v15 = std::string::length((std::string *)&ans);
148 for ( i2 = 0; i2 < v15; ++i2 )
149 {
150 v6 = (_BYTE *)std::string::operator[](&ans, i2);
151 std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, (unsigned int)(char)((v15 - i2) ^ *v6));// 异或操作!!!!注意!!!!
152 }
153 std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
154 LABEL_69:
155 system("pause");
156 return 0;
157 }

一堆循环与if,粗略看看,147行之前都没发现什么表明游戏通关的字符串或者跳转函数

一直到147行,突然出现一个ans,上来直接就是将它的长度赋给v15,做题有点经验的小伙伴应该会发现,一般能够单开一行赋长度的参数,很有可能是关键之一

特别是下面还有一个异或操作,简直就是重点怀疑对象


动态调试(X64dbg)

输出ans紧接着的是一个循环,我们看看地址与汇编

x64dbg的基址与IDA是一样的,不用改了——需要改地址的可以看看我之前的博客攻防世界 gametime 使用IDA pro+OD动调 - demo41 - 博客园 (cnblogs.com)

既然不用改地址,我们直接记下jmz的地址 0000000000401ED2 ,在x64dbg中跳转到

将jnz改成jz,运行直到出现字符串

输出结果: 7ii3VecVgof3r6ssiP2g7E3HqwqhM

直接拿去提交了,出错了,那应该是加密了

我试了很多,一直试不出来,还以为自己错了

后面看了wp,我解题没错,这是一个标准base58

大部分base58解密网站的字符序都是BTC-base58序列,顺序为123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

标准base58的解密序列是123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ

这里提供一个解密网站:Base58编码/解码 - 一个工具箱 - 好用的在线工具都在这里! (atoolbox.net)


静态调试(IDA+py脚本)

我之前查看字符串的时候,还有追踪asc_48B002和asc_48B01D的时候,都发现一个特别可疑的字符串

追进去看看

 1 int __fastcall __static_initialization_and_destruction_0(int a1, int a2)
2 {
3 int result; // eax
4 char v3[17]; // [rsp+2Fh] [rbp-51h] BYREF
5
6 if ( a1 == 1 && a2 == 0xFFFF )
7 {
8 std::ios_base::Init::Init((std::ios_base::Init *)&std::__ioinit);
9 atexit(_tcf_0);
10 std::allocator<char>::allocator(v3);
11 std::string::string(&ans, "*ur)O}t@r{u!c&|}d\\9m>M4NtsrjL", v3);// 放进去吗?
12 std::allocator<char>::~allocator(v3);
13 result = atexit(_tcf_1);
14 }
15 return result;
16 }

竟然和ans联系在一起了,花指令我没查具体意思,七分逆向三分猜,我感觉就是把字符串放进ans里面,反正异或操作不难,脚本很容易写,试试再说

py脚本

1 ans="*ur)O}t@r{u!c&|}d\\9m>M4NtsrjL"
2 v15=len(ans)
3 str=""
4
5 for i in range(len(ans)):
6 str+=chr((v15-i)^ord(ans[i]))
7
8 print(str)

输出结果: 7ii3VecVgof3r6ssiP2g7E3HqwqhM

直接拿去提交了,出错了,那应该是加密了

我试了很多,一直试不出来,还以为自己错了

后面看了wp,我解题没错,这是一个标准base58

大部分base58解密网站的字符序都是BTC-base58序列,顺序为123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

标准base58的解密序列是123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ

这里提供一个解密网站:Base58编码/解码 - 一个工具箱 - 好用的在线工具都在这里! (atoolbox.net)


flag

flag{h4pp4-M1n3-G4m3}

攻防世界 Mine- IDA静调或x64dbg动调 两种方式的更多相关文章

  1. OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)

    OpenCV4Android释疑: 透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰) 前文曾详细探讨了关于OpenCV的使用,原本以为天下已太平.但不断有人反 ...

  2. 【攻防世界】 高手进阶区 Recho WP

    0x00 考察点 考察点有三个: ROP链构造 Got表劫持 pwntools的shutdown功能 0x01 程序分析 上来三板斧 file一下 checksec --file XXX chmod ...

  3. pwn篇:攻防世界进阶welpwn,LibcSearcher使用

    攻防世界welpwn (搬运一篇自己在CSDN写的帖子) 链接:https://blog.csdn.net/weixin_44644249/article/details/113781356 这题主要 ...

  4. 攻防世界(十三)unserialize3

    攻防世界系列 :unserialize3 1.打开题目,反序列化 2.代码审计 类xctf被调用时_weakeup()函数会被自动执行,但当序列化字符串中属性值个数大于属性个数,就会导致反序列化异常, ...

  5. 攻防世界pwn高手区——pwn1

    攻防世界 -- pwn1 攻防世界的一道pwn题,也有一段时间没有做pwn了,找了一道栈题热身,发现还是有些生疏了. 题目流程 拖入IDA中,题目流程如图所示,当v0为1时,存在栈溢出漏洞.在gdb中 ...

  6. 攻防世界逆向——game

    攻防世界逆向:game wp 攻防世界逆向新手区的一道题目. 是一道windows的creak,动态调试打开是这样的: 题目说明是让屏幕上所有的图像都亮之后,会出现flag,看来应该是可以玩出来的. ...

  7. 攻防世界PWN简单题 level0

    攻防世界PWN简单题 level0 开始考验栈溢出的相关知识了 Checksec 一下文件 看看都开了什么保护 和 是多少位的程序 发现是64位的程序, 扔进IDA64.IDA YYDS.. 进入主函 ...

  8. 攻防世界PWN简单题 level2

    攻防世界PWN简单题 level2 此题考验的是对ROP链攻击的基础 万事开头PWN第一步checksec 一下 32位的小端程序,扔进IDA 进入函数,找出栈溢出漏洞. 又是这个位置的栈溢出,rea ...

  9. 进阶区forgotg攻防世界

    攻防世界进阶区--forgot 前言,这题中看不中用啊宝友!!! 1.查看保护 第一反应就是蛮简单的,32位. 2.获取信息(先运行程序看看) 装的可以,蛮多的东西. 但是就是中看不中用 3.ida ...

  10. 【pwn】攻防世界 pwn新手区wp

    [pwn]攻防世界 pwn新手区wp 前言 这几天恶补pwn的各种知识点,然后看了看攻防世界的pwn新手区没有堆题(堆才刚刚开始看),所以就花了一晚上的时间把新手区的10题给写完了. 1.get_sh ...

随机推荐

  1. 任务系统之API子任务

    日常运维工作中有许多的任务要执行,例如项目发布/数据备份/定时巡检/证书更新/漏洞修复等等,大部分的任务都会有多个步骤共同完成,例如一个发布任务会有拉代码.编译.分发.通知等等步骤,而不同的任务可能还 ...

  2. RibbonRoutingFilter是如何工作的

    在讲RibbonRoutingFilter是如何工作之前,也有一些比较重要的类需要去提前了解. 重要的类 RequestContext 请求上下文,用于存储线程中对应的请求以及响应 public cl ...

  3. MAUI调用.so库

    必要条件: (一)安装JDK (二)安装NDK (三)安装Android Studio(其实可以不用装也行) 使用Android Studio构件.so包 构件.so包 1. 使用Android st ...

  4. IISExpress 跨域cookie的奇怪问题

    测试环境 WIN10,IIS 10,IISExpress 10,Chrome 120,Microsoft Edge 114 网站A 端口7001 只有1个Default.aspx,无前端代码.逻辑很简 ...

  5. electron-vite 可用,本机软件开发环境搭建

    electron-vite 可用,本机软件开发环境搭建 https://electron-vite.github.io/

  6. vscode ctrl + 鼠标左键 点击 不进入组件,弹出一个框再点才进入的问题 目录名和vue文件名 开头不能大写 需从起生效

    vscode ctrl + 鼠标左键 点击 不进入组件,弹出一个框再点才进入的问题 目录名和vue文件名 开头不能大写 需从起生效 就是这个,很讨厌,原来是开头不能大写字母的问题造成的. 小写字母就没 ...

  7. GoFrame 优化接口的错误码和异常的思路

    前言 你是否想在使用 GoFrame 的过程中,拥有一个能打印异常堆栈,能自定义响应状态码,能统一处理响应数据的接口.如果你回答是,那么,请耐心看完本文,或许会对你有所启发.若文中由表达不当之处,恳请 ...

  8. AOSP下载且编译

    一.简介 AOSP:Android Open Source Project 二.环境要求 我们可以先了解官网(https://source.android.com/docs/setup/start/r ...

  9. c初探:数据类型、数组、内存布局、指针

    c初探:数据类型.数组.内存布局.指针 目录 c初探:数据类型.数组.内存布局.指针 1.基本数据类型 2.格式化 include <stdio.h> 输出控制符 3.数组与内存布局 动态 ...

  10. MySQL数据库InnnoDB引擎事务说明

    前言 本篇文章主要讲诉数据库中事务的四大特性(ACID)以及事务的隔离级别划分.   数据库事务及其特性 事务是指满足ACID特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Roll ...