Skip to content

Reverse Engineering

RewardedIvan edited this page Nov 16, 2022 · 4 revisions

Yoooo

whas upp??? dog

The ceiling

Jokes out the way.....

Every request is sent to http://delugedrop.com/3Dash/whatever with http v1 and your favorite certified by robtop php security

findings lmao

POST A Level

> POST /push_level_data.php
> Content-Type: application/x-www-form-urlencoded
># URL Encoded Forms data:
> name = "self explanatory"
> author = "why not make an account system"
> difficulty = "0-5"
> data = {"name":"normally the limit is 24 chars","author":"same here","difficulty":0-5,"songId":0-21,"songStartTime":0-songlength,"floorId":0-3,"backgroundId":0-2,"startingColor":[red,green,blue],"levelData":[#Level data],"pathData":[#Path Data],"cameraData":[#Camera Data]}

GET Recent Levels

private void PopulateRecentLevels(string data)
{
	string[] array = data.Split("\n", StringSplitOptions.None);
	for (int i = 0; i < array.Length; i += 4)
	{
		int id = int.Parse(array[i]);
		string levelName = array[i + 1];
		string author = array[i + 2];
		int difficulty = int.Parse(array[i + 3]);
		this.AddButton(this.recentContent, id, levelName, author, difficulty);
	}
}

> GET /get_recent.php
< Level ID
< Level Name
< Level Author
< Level Difficulty
< Repeat.............

GET A Level

> POST /get_json.php certified robtop POST request
> Content-Type: application/x-www-form-urlencoded
># URL Encoded Forms data:
> id = 0-yes
< #Level Data (in json)

Datas

Pretty much every function mentioned here uses this class

public class Level
{
	// Token: 0x04000088 RID: 136
	public string name = "default";

	// Token: 0x04000089 RID: 137
	public string author = "default";

	// Token: 0x0400008A RID: 138
	public int difficulty;

	// Token: 0x0400008B RID: 139
	public int songId;

	// Token: 0x0400008C RID: 140
	public int songStartTime;

	// Token: 0x0400008D RID: 141
	public int floorId;

	// Token: 0x0400008E RID: 142
	public int backgroundId;

	// Token: 0x0400008F RID: 143
	public int[] startingColor;

	// Token: 0x04000090 RID: 144
	public int[] levelData;

	// Token: 0x04000091 RID: 145
	public int[] pathData;

	// Token: 0x04000092 RID: 146
	public int[] cameraData;
}

Level Data

Just look at the name of the function

public static int[,] FlatDataToEditorData(List<GameObject>[][] inData, int totalItems)
{
	int[,] array = new int[totalItems, 5];
	int num = 0;
	for (int i = 0; i < inData[0].Length; i++)
	{
		for (int j = 0; j < inData.Length; j++)
		{
			List<GameObject> list = inData[j][i];
			for (int k = 0; k < list.Count; k++)
			{
				FlatItem component = list[k].GetComponent<FlatItem>();
				array[num, 0] = component.index;
				array[num, 1] = component.x;
				array[num, 2] = component.y;
				array[num, 3] = component.z;
				array[num, 4] = component.angle;
				num++;
			}
		}
	}
	return array;
}

Yep, one of the many numbers in a single array would look like [index, x, y, z, angle] remove the brackets and continue it with every object and you get the level data

Path Data

TODO

Save Data

Saving

public static void SaveLevel()
{
	SaveSelect.SaveFile(LevelEditor.ExportToLevelObject(), LevelEditor.currentSave);
}

This function gives info to this function.

public static void SaveFile(Level level, string number)
	{
		string path = SaveSelect.GetPath(number);
		FileStream fileStream;
		if (File.Exists(path))
		{
			fileStream = File.OpenWrite(path);
		}
		else
		{
			fileStream = File.Create(path);
		}
		new BinaryFormatter().Serialize(fileStream, level);
		fileStream.Close();
	}

This function writes to a file using the BinaryFormatter class and the Serialize method.

Loading

public static Level LoadFile(string number)
	{
		string path = SaveSelect.GetPath(number);
		if (File.Exists(path))
		{
			FileStream fileStream = File.OpenRead(path);
			Level result = (Level)new BinaryFormatter().Deserialize(fileStream);
			fileStream.Close();
			return result;
		}
		Debug.LogError("File not found");
		return null;
	}

Basically the same thing, just Deserializeing it.

The real question

How the fuck do we turn this shit into JSON???
Well obviously just use the same class in a diffrent c# app.

Camera Data

private void RecordArm()
{
	float[] array = new float[4];
	Vector3 myEulerAngles = this.boomArm.myEulerAngles;
	array[0] = myEulerAngles.x;
	array[1] = myEulerAngles.y;
	array[2] = myEulerAngles.z;
	array[3] = this.time;
	CameraAnimator.recordedPoints.Add(array);
}

This function is called every frame update if the "playtester" has not ended and you haven't pressed escape. This is pretty similar to the #Level Data, but its more like [x, y, z, time] and continue with every angle squish it in to one array and ya done

Data When Uploading

public static Level ExportToLevelObject()
{
	return new Level
	{
		name = LevelEditor.levelName,
		author = LevelEditor.levelAuthor,
		difficulty = LevelEditor.difficulty,
		songId = LevelEditor.songId,
		songStartTime = LevelEditor.songStartTime,
		floorId = LevelEditor.floorId,
		backgroundId = LevelEditor.backgroundId,
		startingColor = LevelEditor.ColorToArray(LevelEditor.startingColor),
		levelData = LevelEditor.GridToArray(LevelEditor.levelData),
		pathData = LevelEditor.GridToArray(LevelEditor.pathData),
		cameraData = LevelEditor.GridToArray(LevelEditor.cameraData)
	};
}

This gets converted to JSON

public string LevelToJSON(Level level)
{
	return JsonUtility.ToJson(level);
}

And gets hand crafted in to a request, also is it just me or did delugedrop forget that the name, author and difficulty is also in the Level class??

private IEnumerator SetRequest(string uri, string levelName, string levelAuthor, int difficulty, string JSON)
{
	WWWForm wwwform = new WWWForm();
	wwwform.AddField("name", levelName);
	wwwform.AddField("author", levelAuthor);
	wwwform.AddField("difficulty", difficulty);
	wwwform.AddField("data", JSON);
	using (UnityWebRequest www = UnityWebRequest.Post(uri, wwwform))
	{
		yield return www.SendWebRequest();
		int responseCode;
		if (www.result == UnityWebRequest.Result.ConnectionError || www.result ==UnityWebRequest.Result.DataProcessingError || www.result ==UnityWebRequest.Result.ProtocolError)
		{
			Debug.Log(www.error);
			responseCode = 0;
		}
		else
		{
			Debug.Log("No Unity Errors");
			responseCode = (int)www.responseCode;
		}
		this.ManageOutput(www.downloadHandler.text, responseCode);
	}
	UnityWebRequest www = null;
	yield break;
	yield break;
}