Hack The Box - Challenges - GamePWN
The files within the download look like they're from the Unity Game engine. I've worked with Unity before for a simulator game.
I have a Windows VM specifically for CTFs and CrackMes so I started up HackTheBox CubeMadness1.exe
.
Looks like the objective of the game is to collect the cubes, but when you try to collect all the cubes, you can only 6 out of 20 cubes. We can either decompile these binaries to look for the flag or we can manipulate the memory so we can achieve 20 out of 20 cubes. I think the challenge intends the user to do the latter.
Cheat Engine
I've used game trainers in the past for single-player games and I think we need something similar. This is where Cheat Engine comes in. I started going through the tutorial which is packaged with the tool. I highly recommend it and the series of official YouTube tutorial videos.
New Scan
Start with the value of 0
since that is the number of cubes we have. The Value Type
should be 4 bytes for integer values. The Scan Type
can be Exact Value
.
Next Scan
Now grab a cube using the arrow keys and space bar to jump. Update the Value
to 1
and click Next Scan
.
We can see all the memory addresses that changed from 0
to 1
. Rinse and repeat. By the time we get to 3, there are a lot fewer memory addresses that are listed:
By the time we get to all 6
cubes, we have three possible memory addresses:
Change Value
Not much change from 5 to 6. We select the first address and try changing the value from 6
to 20
by selecting it and double-clicking on the value in the bottom pane list box.
Flag
Once the value is changed the game gives us the flag:
Reverse Engineer
Strings
The first step would be to just search for a flag prefix of HTB{
.
Windows using strings and running under the directory of the Cube Madness.
strings64.exe -a * | findstr /i "HTB{"
Linux
find . -type f | strings | grep "HTB{"
This yielded no results, so it could be that the flag is encoded.
DotPeek
DotPeek is useful for .NET
applications, but it could be that this is a Win32
application complied to C++
using IL2CPP
.
IL2CPPDUMPER
Knowing this, we can fire up Ghidra, but it would take me a while to search for what would be relevant. IL2CPPDumper is better suited and even has an online version. IL2CppInspector is also helpful. Cpp2IL also has the same functionality and is supposedly significantly faster than either option. Since the .NET Code was compiled to Intermediate Language (IL) and then to C++, we need to map the C++ code back using the metadata provided.
Il2CppDumper.exe <path_to_GameAssembly.dll> <path_to_global_metadata.dat> <output_path>
After it's been analyzed, the files should be dumped to the specified output path in the DummyDll
directory:
Now we can use dnSpy
or DotPeek
to some more details. IL2CPPDumper
should also produce il2cpp.h
, dump.cs
, script.json
. It also comes with Python scripts to be able to load up the metadata/function names for IDA
and Ghidra.
DnSpy
DnSpy is a .NET debugger and assembly editor and if we open just the .exe
we would see the same thing as DotPeek
.
If we open the Assembly-CSharp
from the IL2CPPDumper
output directory (DummyDll
) and look at the {} -
subtree:
Seems like we want FlagCheck
method implementation, but if we try to look for the implementation they are missing. All these are just stubs/interfaces to the actual C++ code.
Even so, you can glean some information from what we've done so far. You can tell that the developer(s) speaks/understands Korean from some of the method names. One can infer that they were Korean, but this could also be disinformation when it comes to malware attribution.
Ghidra
To actually see the decompiled assembly code and then map that back to C++ we use Ghidra.
Open Ghidra and select the
GameAssembly.dll
to open.- Don't have Ghidra perform the auto-analysis when the binary is opened. This is to avoid the
Conflicting data exists at address
error.
- Don't have Ghidra perform the auto-analysis when the binary is opened. This is to avoid the
From the Code Browser, select
File
->Parse C Source
Create a new profile or clear the existing one.
Add the Generated C++ type header file from
IL2CPPDumper
. It should beil2cpp.h
.Use
-D_GHIDRA_
for the `Parse Options`. This might not be necessary anymore, but not sure.Click the
Parse to Program
and accept any other prompts/warnings (may take awhile).Open the
Script Manager
and add the directory ofIL2CppDumper
, NOT theDumpDll
(output directory).Click
Refresh
to make the script appear in theScript Manager
. Should beghidra_with_
struct.py
Select the script and click the
Run
the button or right-click it and selectRun
. The script will ask for the generatedscript.json
.
The Code Browser
window will be available, but you'll get prompted to run Analysis. The progress will be in the lower right corner.
We can see a lot more than we did before and actual functions
. Before we could only see the Exports
populated.
We have the implementation, but it's still like finding a needle in a haystack:
Even searching for the known flag value, partial flag value, CheckFlag
, flag
in the strings search yielded nothing relevant. Neither did a scalar
search of 20
. I either don't have the actual implementation or the flag is encoded.
Sad/disappointed panda.
I'd imagine the original C# code was like this:
using UnityEngine;
public class CubeCounter: MonoBehaviour
{
var _flagCheck = FlagCheck()
public CubeCounter(IFlagCheck flagCheck)
{
_flagCheck = flagCheck;
}
public void CheckCount(int score)
{
if (score== 20)
{
_flagCheck.GetFlag()
}
}
}
public class FlagCheck: MonoBehaviour
{
string _flag;
public FlagCheck(TextAsset flagAsset) {
_flag = flagAsset.text;
}
public void GetFlag()
{
// 축하합니다 깃발을 찾았네요
if (score== 20)
{
GameObject.Find("Canvas").transform.Find("flagText").GetComponent<Text>().text = _flag;
}
}
}
Takeaways
It was a fun challenge and exposed me to Cheat Engine
. It's worth going through the packaged tutorial where you analyze an application to learn all the features of the tool. You can also create code injection and patch the binary with the pretty cool tool. In our case, it could be patched to instantly give us the flag. It's much easier to reverse-engineer a Mono/C#
Unity game compiled to just IL
than if IL2Cpp
was used in the compilation process. No flag from reverse engineering the assembly, but did learn about tools to assist in reverse engineering a binary compiled with IL2Cpp
. Maybe someone out there can dive deeper on this.