一、前记

杂项中的游戏题目在这两年可以算得上是一个热点,出题类型多种多样,可以糅合很多的知识(像密码知识,或者是其他的逻辑知识),因此在做完BUU里面的“新春红包题二”之后,我决定来总结一下游戏类出题。

二、游戏文件的几种形式以及解题方法

1、swf文件形式

swf是一种动画设计软件Flash的专用格式,里面包含丰富的视频、声音和动画,也允许用户之间相互交互(这才是游戏题目重要的一点),对于这一种游戏题目没有过多的方法,只有通过自己的视频播放器可以一帧一帧的播放出来,在这里推荐使用PotPlayer播放器

例题:XCTF 4th-SCTF-2018  肥仔快乐题

将文件放入Potplayer播放器里面,将帧数调整到57,就可以显现出来一个动画,里面的NPC对话要注意

将里面的内容进行base64解密就完事

当然也有正儿八经的做法,那就是启用swf的反编译器--JPEXS Free Flash Decompiler(丫的,这种文件格式也还有反编译器),在文件里面直接搜索flag或者搜索与flag有关的词汇都是可以的,例如在这个题里面,我们可以直接搜索“Normally”就可以找到结果。

swf文件算是游戏里面最简单的一种形式

2、jar类型游戏

众所周知,Java是可以用来进行游戏的编写的,jar文件是Java的一种文档格式,是一种Java的压缩包格式,对于Java格式的游戏因为接触的比较少,因此只掌握到一种比较方便的方法,就是将jar文件放到Java反编译工具—Java Decompiler里面进行反编译

例题:08067 做个游戏

打开游戏发现是一个持久度游戏,并且持久的时间不同,会出现不同的标语

盲猜不同标语会出现不同的标语,等到一段时间之后再死会出现flag(ps:写总结的时候发现的)

非预期解:将移动的方块藏在边边角角,待到时机成熟的时候再出现打死,但是flag出现的不完整还是要想其他的办法

预期解:将jar文件放到Java反编译器jd-gui里面去(自动反编译大法好),在java文件里面的PlaneGameFrame.class发现了flag

3、unity游戏类型

说实在的,这个类型确确实实太复杂了,涉及到太多的知识点了,在这里先列举之前做过的题,涉及到的知识点我会使用黄色打底。

unity是一种跨平台游戏引擎,用于开发各个平台的单机游戏(也就是说我们会遇到专门的Android,Windows等各个操作系统的文件,Android是.so文件,Windows是.exe文件)。

在不同的操作系统里面会包含有不同的文件:

  • Android

在产生App安装用的apk档之前,需要先安装过Android SDK。

  • BlackBerry

输出成一个App安装用的bar档。

  • iOS

输出成文件夹,一个Xcode项目,必须再到iMac等环境下用Xcode输出。

  • Linux

输出成文件夹,包含一个x86档与一个运行时所必需相关文件的文件夹。

  • Web Player

输出成文件夹,包含一个html档与一个运行时所必需的unity3d档。客户端必须另外先安装Unity Web Player。2015年,Google Chrome已中止此Unity插件支持。

  • Windows

输出成文件夹,包含一个可执行的exe档与一个运行时所必需相关文件的文件夹。

unity的两种打包方式:mono和IL2CPP。总的来说mono比较还原真实代码,IL2CPP加了不少的混淆(呜呜呜……),具体详情参考:https://www.jianshu.com/p/5aab2c163023

额外知识:unity的版本号为年份+版本号的复合形式。

例一 :Mine Sweeping(2019de1ctf)

打开题目,直接发现是一个用unity做的一个扫雷题目。在这里依然有多种解法。

第一种解法就是直接做一行一行的记录雷的位置,将不是雷的部分全部点击出来,形成一个二维码,扫描二维码即可得到flag(这个方法太麻烦了,就不再重复)

第二种方法:使用dnspy进行分析。对于未加壳的unity题目来说一般我们去找Assembly-CSharp.dll这个文件就可以进行反编译了。并且在这个题里面,unity打包的方式为mono,着实为我们省了不少力气。

在dnspy里面直接反编译这个文件就能得到整个游戏的代码,在这里重点查看Gris.cs里面的DevilsInHeaven和ChangeMap

public bool GameWin()
    {
        foreach (Elements ele in eleGrids)
        {
            if (!ele.bIsOpen && !ele.bIsMine)
            {   //存在没翻开且不是雷的
                return false;
            }
        }
        foreach (Elements ele in eleGrids)
        {   //加载最后的图片
            ele.DawnsLight();
        }
        return true;
    }

    public void ChangeMap()
    {
        System.Random ran = new System.Random((int)System.DateTime.Now.Millisecond);
        const int SwingNum = 6;
        const int Start = 0;
        const int End = 100;
        int[] SwingPosX = new int[SwingNum]{ 9, 15, 21, 10, 18, 12, };
        int[] SwingPosY = new int[SwingNum]{ 0, 7, 15, 3, 16, 28 };
        int[] RandomNum = new int[SwingNum];
        for (int i = 0; i < SwingNum; i++)
        {
            RandomNum[i] = ran.Next(Start, End);
        }

        for (int i = 0; i < SwingNum; i++)
        {
            int x = SwingPosX[i];
            int y = SwingPosY[i];
            eleGrids[x, y].bIsMine = RandomNum[i] > 60 ? false : true ;
            DevilsInHeaven[x, y] = eleGrids[x, y].bIsMine == true ? 1 : 0;
        }
    }

我们能根据DevilsInHeaven来判断出有哪些是雷,哪些是数字。

这样就可以巧妙的避开雷区,得到flag

例二:2019SCTF 头号玩家(并未解决)

这个打飞机的题目靠分析是分析不出来的,因为它使用的是IL2CPP的打包方式,把这个题拿出来说是想了解一下在IL2CPP打包前提下,应该使用什么工具,并且应该如何操作。

使用Il2CppDumper进行IL2CPP的反编译,点击Il2CppDumper.exe,选择程序的exe文件,再选择global-metadata.dat(一般这个玩意儿会被加密,反正在这个题里面我没有解密成功,只是碰到这个类型的题了,刚好可以借用一下)。再输入unity的版本号,我们可以在data.unity3d里面查看版本号内容,输入再选择模式,完事。

工具参考指南:https://github.com/Perfare/Il2CppDumper/blob/master/README.zh-CN.md

4、RPG游戏系列

RPG游戏系列,电子角色扮演游戏,现目前接触到的有RPGXP类型,RPGMV类型,做这种题十分的简单,找到相对应的修改器,或者直接在代码里面修改参数都没有问题,修改器的话多半是叫做RPGXX的,是MV类型就找MV的,是XP类型的就找XP的。下面通过两个例子来进一步理解

例一:2019 *ctf she (RPGXP)

这是一道RPGXP类型的游戏题,在网上找到相应的修改器下载使用(并没有必要去阅读代码,当然阅读代码也是可行的),我找到的是RPGMakerXPv1.03,汉化完整,对于我这种萌新简直太友好。

在RPGMakerXP里面新建一个项目(文件->新建一个工程project1),将project1里面的Game.rxproj放到游戏文件夹里面,就像下图一样:

然后双击打开Game.rxproj,工具->数据库,发现游戏里面所有的东西都跃然于这个软件里面。都可以随意修改里面的东西(最好是修改自身等级和怪的血量)

接下来我们来看看主人公的N种死法(也就是未破解的几种死法)

第一种:打不过左下角房子里面的鸡,一刀被砍9999,毫无还手之力

解决方法:在编译器里面将那个鸡的生命值下降(弄成1铁定没问题),工具->数据库->敌人->Julia->MAXHP(所有都变成1都可以)。然后自身的攻击力和等级都可以提高(保险起见)。

最贵的武器变成0元,战力提升到999
猛得一批

接下来就是第二种死法:被吸血鬼咬死(一碰吸血鬼必死)

简单分析了一下之后,发现这算一个事件,做法就是把这个事件删除就好了

这个游戏需要改的部分就是这么多,最后的wp自行Google一下就好

例二:2020 BUUCTF 新春红包题2(RPGMV)

一开始在做这个题的时候,并没有使用修改器,直接靠着底层代码就可以改。在这里不再叙述修改器如何修改的,直接讲解如何改变底层代码来进行修改。

在www里面的data文件夹找到你可阅读的游戏的各种代码(当然可以通过阅读代码找到各种flag,但是为了学习还是要分析一下代码)。我们先来看一下在没有修改之前的游戏代码

首先看到的是游戏目录英文名称就已经很清楚了有武器部分的,有人物部分的,还有地图部分的。我们打开商店页面的代码,发现价格写在最后,我们可以修改价格为0元(暗指白嫖)。

改好之后在游戏里面检查一下

白嫖成功,修改代码就能在游戏里面开到不少的挂。同理,可以修改自己和敌方的生命值,也可以修改打败怪之后获得的经验值和金币,当然也可以在游戏里面直接寻找flag

三、总结

总的来说其实游戏题目并不是很难,一道题可以通过不同的解法可以获得一样的有效信息。最主要的是游戏题目与其他知识相互混合的话,其实还是可以创造出不同的难度的综合题。