【BUUCTF】[FlareOn5]Ultimate Minesweeper 1 WP
运行

30*30=900 个格子里有 897 个雷,随便点一个都是雷。
分析
C# 写的,拖入 dnSpy。

GetKey 函数十分惹眼,下意识地都会点过去(
// UltimateMinesweeper.MainForm
// Token: 0x0600000D RID: 13 RVA: 0x000023E4 File Offset: 0x000005E4
private string GetKey(List<uint> revealedCells)
{
revealedCells.Sort();
Random random = new Random(Convert.ToInt32(revealedCells[0] << 20 | revealedCells[1] << 10 | revealedCells[2]));
byte[] array = new byte[32];
byte[] array2 = new byte[]
{
245,75,65,142,68,71,100,185,74,127,62,130,231,129,254,243,28,58,103,179,60,91,195,215,102,145,154,27,57,231,241,86
};//手动压行
random.NextBytes(array);
uint num = 0U;
while ((ulong)num < (ulong)((long)array2.Length))
{
byte[] array3 = array2;
uint num2 = num;
array3[(int)num2] = (array3[(int)num2] ^ array[(int)num]);
num += 1U;
}
return Encoding.ASCII.GetString(array2);
}
但当时我还是更想通关扫雷于是就不管这函数了,后来重新看了这函数察觉到之前是对的,这随机函数一眼就不好爆破或瞎蒙的样子……更何况我不怎么了解 C# 各种函数细节。
顺着找扫雷图生成逻辑的思路,一通乱翻点进了这个函数:
// UltimateMinesweeper.MainForm
// Token: 0x0600000A RID: 10 RVA: 0x000022DC File Offset: 0x000004DC
private void AllocateMemory(MineField mf)
{
for (uint num = 0U; num < MainForm.VALLOC_NODE_LIMIT; num += 1U)
{
for (uint num2 = 0U; num2 < MainForm.VALLOC_NODE_LIMIT; num2 += 1U)
{
bool flag = true;
uint r = num + 1U;
uint c = num2 + 1U;
if (this.VALLOC_TYPES.Contains(this.DeriveVallocType(r, c)))
{
flag = false;
}
mf.GarbageCollect[(int)num2, (int)num] = flag;
}
}
}
套着“分配内存”的名义,长得却与分配地雷的逻辑十分甚至九分相似,这里面肯定有问题。
MainForm.VALLOC_NODE_LIMIT 是 30,和扫雷图的边长一样,再加上这个二重循环,大概可以推断就是在遍历扫雷图或者一个和它相关的数据块。
点进 VALLOC_TYPES 看一眼
private static uint VALLOC_TYPE_HEADER_PAGE = 4294966400U;
// Token: 0x04000008 RID: 8
private static uint VALLOC_TYPE_HEADER_POOL = 4294966657U;
// Token: 0x04000009 RID: 9
private static uint VALLOC_TYPE_HEADER_RESERVED = 4294967026U;
// Token: 0x0400000A RID: 10
private uint[] VALLOC_TYPES = new uint[]
{
MainForm.VALLOC_TYPE_HEADER_PAGE,
MainForm.VALLOC_TYPE_HEADER_POOL,
MainForm.VALLOC_TYPE_HEADER_RESERVED
};
三个数刚好可以对应三个雷,简直就是在明示。然而稀奇古怪毫不相干的名字还在尽全力维护自己蹩脚的伪装……
点进 DeriveVallocType 看一眼
private uint DeriveVallocType(uint r, uint c)
{
return ~(r * MainForm.VALLOC_NODE_LIMIT + c);
}
十分明显的文不对题,这个函数在做的很明显就是把行列坐标合并为一个整数,但是另外加了个按位取反,这也解释了为什么前面那三个数那么大。
直接做个逆运算验证一下想法:
#include <iostream>
using namespace std;
void getpos(unsigned v) {
v = ~v;
unsigned r = v / 30;
unsigned c = v % 30;
printf("%u %u\n", r, c);
}
int main() {
getpos(4294966400);
getpos(4294966657);
getpos(4294967026);
return 0;
}
得到了三组坐标:
29 25
21 8
8 29
r 是行数 c 是列数,不确定或者分不清行列那就都试一下就行,直接打开扫雷对着这几个坐标点就对了

结语
网上搜到了各种奇奇怪怪的作弊 WP 诸如不死挂透视挂的各种调试找的,我寻思有那么麻烦嘛……于是写了此 WP(太菜不会改不会调试 C# 导致的
浙公网安备 33010602011771号