Roar CTF 2019 坦克大战 Writeup

下载压缩包 解压看到
Roar CTF 2019 坦克大战 Writeup_第1张图片
可知该游戏由Unity3D编写,由于没有相关逆向经验,上网查阅得知游戏代码部分都在Assembly-CSharp.dll文件中,通过dnspy可以打开此类型的dll.
Roar CTF 2019 坦克大战 Writeup_第2张图片
直接查看跟题目相关的函数,在MapManager下有名为WinGame的函数.源码如下

// MapManager
// Token: 0x06000029 RID: 41 RVA: 0x00003050 File Offset: 0x00001250
public static void WinGame()
{
	if (!MapManager.winGame && (MapManager.nDestroyNum == 4 || MapManager.nDestroyNum == 5))
	{
		string text = "clearlove9";
		for (int i = 0; i < 21; i++)
		{
			for (int j = 0; j < 17; j++)
			{
				text += MapManager.MapState[i, j].ToString();
			}
		}
		string a = MapManager.Sha1(text);
		if (a == "3F649F708AAFA7A0A94138DC3022F6EA611E8D01")
		{
			FlagText._instance.gameObject.SetActive(true);
			FlagText.str = "RoarCTF{wm-" + MapManager.Md5(text) + "}";
			MapManager.winGame = true;
		}
	}
}

具体就是对数组进行字符化累加后,判断Hash值是否与给定值相等.
其中nDestroyNum和MapManager.MapState是关键所在.
先看MapManager.MapState(在MapManager.init()中定义.

// MapManager
// Token: 0x06000028 RID: 40 RVA: 0x000027AC File Offset: 0x000009AC
public static void Init()
{
	MapManager.MapState = new int[,]
	{
		{
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8
		},
		{
			8,
			8,
			4,
			5,
			8,
			1,
			1,
			1,
			1,
			1,
			1,
			8,
			8,
			8,
			8,
			4,
			8
		},
		{
			8,
			2,
			8,
			1,
			8,
			8,
			5,
			1,
			8,
			8,
			8,
			1,
			8,
			1,
			8,
			4,
			8
		},
		{
			8,
			5,
			8,
			2,
			8,
			8,
			8,
			8,
			1,
			8,
			8,
			4,
			8,
			1,
			1,
			5,
			8
		},
		{
			8,
			8,
			8,
			8,
			2,
			4,
			8,
			1,
			1,
			8,
			8,
			1,
			8,
			5,
			1,
			5,
			8
		},
		{
			8,
			8,
			8,
			8,
			5,
			8,
			8,
			1,
			5,
			1,
			8,
			8,
			8,
			1,
			8,
			8,
			8
		},
		{
			8,
			8,
			8,
			1,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			1,
			8,
			1,
			5,
			8
		},
		{
			8,
			1,
			8,
			8,
			1,
			8,
			8,
			1,
			1,
			4,
			8,
			8,
			8,
			8,
			8,
			1,
			8
		},
		{
			8,
			4,
			1,
			8,
			8,
			5,
			1,
			8,
			8,
			8,
			8,
			8,
			4,
			2,
			8,
			8,
			8
		},
		{
			1,
			1,
			8,
			5,
			8,
			2,
			8,
			5,
			1,
			4,
			8,
			8,
			8,
			1,
			5,
			1,
			8
		},
		{
			0,
			1,
			4,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8
		},
		{
			1,
			1,
			8,
			1,
			8,
			8,
			2,
			1,
			8,
			8,
			5,
			2,
			1,
			8,
			8,
			8,
			8
		},
		{
			8,
			8,
			8,
			8,
			4,
			8,
			8,
			2,
			1,
			1,
			8,
			2,
			1,
			8,
			1,
			8,
			8
		},
		{
			8,
			1,
			1,
			8,
			8,
			4,
			4,
			1,
			8,
			4,
			2,
			4,
			8,
			4,
			8,
			8,
			8
		},
		{
			8,
			4,
			8,
			8,
			1,
			2,
			8,
			8,
			8,
			8,
			1,
			8,
			8,
			1,
			8,
			1,
			8
		},
		{
			8,
			1,
			1,
			5,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			1,
			8,
			8,
			8,
			8
		},
		{
			8,
			8,
			1,
			1,
			5,
			2,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			2,
			8,
			8
		},
		{
			8,
			8,
			4,
			8,
			1,
			8,
			2,
			8,
			1,
			5,
			8,
			8,
			4,
			8,
			8,
			8,
			8
		},
		{
			8,
			8,
			2,
			8,
			1,
			8,
			8,
			1,
			8,
			8,
			1,
			8,
			2,
			2,
			5,
			8,
			8
		},
		{
			8,
			2,
			1,
			8,
			8,
			8,
			8,
			2,
			8,
			4,
			5,
			8,
			1,
			1,
			2,
			5,
			8
		},
		{
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8,
			8
		}
	};
}

查看游戏地图.
Roar CTF 2019 坦克大战 Writeup_第3张图片
对游戏地图分析.大致可以知道关键部分

0 对应 自己的基地.
1 对应 墙体
8 对应 空白处
9 对应 毁坏后的基地

再看nDestroyNum在dll中的引用

// Bullect
// Token: 0x0600000A RID: 10 RVA: 0x00002898 File Offset: 0x00000A98
private void OnTriggerEnter2D(Collider2D collision)
{
	int num = (int)collision.gameObject.transform.position.x;
	int num2 = (int)collision.gameObject.transform.position.y;
	string tag = collision.tag;
	if (tag != null)
	{
		if (!(tag == "Tank"))
		{
			if (!(tag == "Heart"))
			{
				if (!(tag == "Enemy"))
				{
					if (!(tag == "Wall"))
					{
						if (tag == "Barrier")
						{
							if (this.isPlayerBullect)
							{
								collision.SendMessage("PlayAudio");
							}
							UnityEngine.Object.Destroy(base.gameObject);
						}
					}
					else
					{
						MapManager.MapState[num + 10, num2 + 8] = 8;
						MapManager.nDestroyNum++;
						UnityEngine.Object.Destroy(collision.gameObject);
						UnityEngine.Object.Destroy(base.gameObject);
					}
				}
				else if (this.isPlayerBullect)
				{
					collision.SendMessage("Die");
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
			else
			{
				MapManager.MapState[num + 10, num2 + 8] = 9;
				MapManager.nDestroyNum++;
				collision.SendMessage("Die");
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
		else if (!this.isPlayerBullect)
		{
			collision.SendMessage("Die");
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}
}

分析代码,num和num2是方块在地图里的坐标(有负数),但经过"num+10,num2+8"调整后即为MapState数组中的下标.每当击中墙体,将墙体变成空白(MapManager.MapState[num + 10, num2 + 8] = 8;),再增加nDestroyNum的值,同理,击中基地时,将基地变成毁坏后的基地(MapManager.MapState[num + 10, num2 + 8] = 9;)再增加nDestroyNum的值.

那么大致思路就出来了: 累计击中4次或5次墙体或基地,进行Hash判断是否与给定Hash相等.游戏内一一尝试击中不太现实.我们可以直接在WinGame函数做点动作.更改后的WinGame函数如下

// MapManager
// Token: 0x06000029 RID: 41 RVA: 0x00003044 File Offset: 0x00001244
public static void WinGame()
{
	int num = 65;
	for (int i = 0; i < num - 2; i++)
	{
		for (int j = i + 1; j < num - 1; j++)
		{
			for (int k = j + 1; k < num; k++)
			{
				if (!MapManager.winGame)
				{
					MapManager.Init();
					MapManager.MapState[10, 0] = 9; //10,0是基地在MapState中的下标
					int num2 = -1;
					string text = "clearlove9";
					for (int l = 0; l < 21; l++)
					{
						for (int m = 0; m < 17; m++)
						{
							if (MapManager.MapState[l, m] == 1)
							{
								num2++;
								if (num2 == i || num2 == j || num2 == k)
								{
									MapManager.MapState[l, m] = 8;
								}
							}
							text += MapManager.MapState[l, m].ToString();
						}
					}
					if (MapManager.Sha1(text) == "3F649F708AAFA7A0A94138DC3022F6EA611E8D01")
					{
						FlagText._instance.gameObject.SetActive(true);
						FlagText.str = "RoarCTF{wm-" + MapManager.Md5(text) + "}";
						StreamWriter streamWriter = new StreamWriter("flag.txt");
						streamWriter.WriteLine(FlagText.str);
						streamWriter.Close();
						MapManager.winGame = true;
						return;
					}
				}
			}
		}
	}
}

大致就是设置标记位,将墙体标记起来并设置为8,每次循环都调用MapManager.init()以来恢复初始值.
理论上有4种情况

  1. 击中3次墙体 + 1次基地(也就是上述代码) (nDestroyNum == 4)
  2. 击中4次墙体 (nDestroyNum == 4)
  3. 击中4次墙体 + 1次基地 (nDestroyNum == 5)
  4. 击中5次墙体 (nDestroyNum == 5)

然而,就算得到Flag.str,游戏内好像没有相关函数将他显示出来(也有可能我没看见).所以调用写文件函数.

为了方便起见,在进入游戏时就调用WinGame进行判断,进入游戏后查看有无flag.txt文件就知道是否成功

// Option
// Token: 0x0600002F RID: 47 RVA: 0x00003264 File Offset: 0x00001464
private void Update()
{
	if (Input.GetKeyDown(KeyCode.W))
	{
		this.choice = 1;
		base.transform.position = this.posOne.position;
	}
	else if (Input.GetKeyDown(KeyCode.S))
	{
		this.choice = 2;
		base.transform.position = this.posTwo.position;
	}
	if (this.choice == 1 && Input.GetKeyDown(KeyCode.Space))
	{
		MapManager.Init();
		SceneManager.LoadScene(1);
		MapManager.WinGame();
	}
}

运行游戏.
Roar CTF 2019 坦克大战 Writeup_第4张图片
查看游戏文件夹.
Roar CTF 2019 坦克大战 Writeup_第5张图片
得到flag.

你可能感兴趣的:(Roar CTF 2019 坦克大战 Writeup)