[Request] EMPYRE: Dukes of the Far Frontier

Ask about cheats/tables for single player games here
Post Reply
User avatar
zurls
Expert Cheater
Expert Cheater
Posts: 143
Joined: Sat Feb 15, 2020 7:46 am
Reputation: 22

[Request] EMPYRE: Dukes of the Far Frontier

Post by zurls »

It's cowboys and robots in a retro-futuristic city. The game is a isometric steampunk CRPG. The character building is great, there are some great ideas, but parts of the game have some real rough edges.



Runs on the Unity Engine. Here is the SteamDB page about the game:
[Link]

WintermuteX
Cheater
Cheater
Posts: 46
Joined: Sun Oct 29, 2017 10:20 am
Reputation: 8

Re: [Request] EMPYRE: Dukes of the Far Frontier

Post by WintermuteX »

I can help a bit here.
First: All values are longwords (4 Byte), it's quite easy to find them at character creation.

Second: You can use dnSpy to modify the game library to create savefiles / load savefiles without encryption. Which results in cleartext XML files.
One thing about it: the game can't do both! Save/load unencrypted AND encrypted saves! So you modify the dll and THEN start a new game, your encrypted saves would NOT load or even show up!

To do so, start dnSpy, load the assembly-casrp.dll from EMPYRE Dukes of the Far Frontier\Empyre2_Data\Managed and then search for "SaveData". Doubleclick the result and you will get the source. It will look like this:

Code: Select all

public static void SaveData(Stream aStream, string aFilePath, bool aUseEncrypt, bool aUseCompress)
		{
			using (FileStream fileStream = cgFileManager.OpenFile(aFilePath, FileMode.Create))
			{
				using (Stream stream = cgEncrypter.Compress(aStream, aUseCompress))
				{
					if (aUseEncrypt)
					{
						using (ICryptoTransform cryptoTransform = cgEncrypter.CreateEncrypter())
						{
							using (CryptoStream cryptoStream = new CryptoStream(fileStream, cryptoTransform, CryptoStreamMode.Write))
							{
								cgEncrypter.WriteData(stream, cryptoStream);
								return;
							}
						}
					}
					cgEncrypter.WriteData(stream, fileStream);
				}
			}
		}
The dll this code is located at is the COG_gamelib.dll.
After making and compiling the changes, save it.

I also attached the modified dll to this post. This was the initial release version of the game (reminder for the future).
The password is: wintermutex

Now add the line aUseEncrypt = false; before the if (aUseEncrypt) statement like this:

Code: Select all

				using (Stream stream = cgEncrypter.Compress(aStream, aUseCompress))
				{
					aUseEncrypt = false;
					if (aUseEncrypt)
					{
Repeat this for the next class shown in dnSpy which is "LoadData".
When you start a new game every save will be an unencrypted XML file. It is minified, so use Notepad++ with the XML plugin to use the "pretty print" function to get it human readable.
Pro tip: when creating the character choose a very unique name for the character profession so you find your character in the VAST(30+MB!) XML file!
In the XML look for:
<field name="mName" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" value="GeneratedCharacter"/>
<field name="mTitle" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" value="<YOUR-PROFESSION-NAME>"/>
From this location search BACKWARDS for the string value="Melee" to find the character stats.
<field name="key" type="game.data.controller.entity.instance.cgEntityInstanceSkillController+eSkillType, Assembly-CSharp, Version=1.4.1.0, Culture=neutral, PublicKeyToken=null" value="Melee"/>
<object name="value" type="game.data.controller.entity.instance.component.cgEntitySkillItem, Assembly-CSharp, Version=1.4.1.0, Culture=neutral, PublicKeyToken=null">
<field name="mIsMain" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" value="True"/>
<field name="cgaEntityComponentItem+mBase" type="System.Single, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" value="80"/>
<field name="cgaEntityComponentItem+mPermanentAdditive" type="System.Single, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" value="20"/>
<field name="cgaEntityComponentItem+mPermanentMultiplier" type="System.Single, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" value="1"/>
In my example I set the BaseValue for Melee to 80 and I add an modifier of 20 to it.
You can do this for all main skills and subskills (which you can review by hovering over a skill to see the tooltip).

You can fine the attributes too, but they are less easy to find. And you can also add perks to your char, I added a bunch later to get the special dialogue options. But adding perks this way is a pita as you have to add them at 3 positions and use GUIDs which you have to extract from the asset file of the game.

Password for attachment: wintermutex
Attachments
COG_gamelib.zip
(3.87 KiB) Downloaded 48 times
Last edited by WintermuteX on Thu Jun 09, 2022 4:59 am, edited 3 times in total.

WintermuteX
Cheater
Cheater
Posts: 46
Joined: Sun Oct 29, 2017 10:20 am
Reputation: 8

Re: [Request] EMPYRE: Dukes of the Far Frontier

Post by WintermuteX »

And I also have a third method, but it only works half the way :(
I made a powershell script to decrypt the savefile, but my encryption PS script doesn't produce a file which will be loaded by the game. If someone finds my mistake: I would be happy to learn. :D

The decrypt.ps1

Code: Select all

#!/usr/bin/env powershell

param ( [String]$InputFile, [String]$OutputFile )

$InputStream = New-Object IO.FileStream($InputFile,
  [IO.FileMode]::Open, [IO.FileAccess]::Read)
$OutputStream = New-Object IO.FileStream($OutputFile,
  [IO.FileMode]::Create, [IO.FileAccess]::Write)

# The password
$Password=[String]"coinoperation"

# The salt
$Salt = [Byte]99,111,105,110,103,97,109,101

# The iterations
$Iterations = [int]1024

# Generate PBKDF2 from password, salt and iterations
$PBKDF2 = New-Object System.Security.Cryptography.Rfc2898DeriveBytes(
  $Password, $Salt, $Iterations)

# Get our AES key and iv
$AESKey  = $PBKDF2.GetBytes(32)
$AESIV   = $PBKDF2.GetBytes(16)

# Decryptor
$AES = New-Object Security.Cryptography.AesManaged
$Dec = $AES.CreateDecryptor($AESKey, $AESIV)
Write-Output $AES

$CryptoStream = New-Object System.Security.Cryptography.CryptoStream(
  $InputStream, $Dec, [System.Security.Cryptography.CryptoStreamMode]::Read)

$CryptoStream.CopyTo($OutputStream)
$OutputStream.Dispose()
First parameter is the inputsave and second parameter is the decrypted file:
decrypt.ps1 save_1.sav save_1.dec

And here is my not working encryptor. It encrypts the decrypted file, but the result isn't valid and the game doesn't load the file.

The encrypt.ps1

Code: Select all

#!/usr/bin/env powershell

param ( [String]$InputFile, [String]$OutputFile )

$InputStream = New-Object IO.FileStream($InputFile,
  [IO.FileMode]::Open, [IO.FileAccess]::Read)
$OutputStream = New-Object IO.FileStream($OutputFile,
  [IO.FileMode]::Create, [IO.FileAccess]::Write)

# The password
$Password=[String]"coinoperation"

# The salt
$Salt = [Byte]99,111,105,110,103,97,109,101

# The iterations
$Iterations = [int]1024

# Derive random bytes using PBKDF2 from Salt and Password
$PBKDF2 = New-Object System.Security.Cryptography.Rfc2898DeriveBytes(
  $Password, $Salt, $Iterations )

# Get our AES key and iv from the PBKDF2 stream
$AESKey  = $PBKDF2.GetBytes(32)
$AESIV   = $PBKDF2.GetBytes(16)

# Setup our encryptor
$AES = New-Object Security.Cryptography.AesManaged
$AES.Mode = [System.Security.Cryptography.CipherMode]::CBC
$Enc = $AES.CreateEncryptor($AESKey, $AESIV)
Write-Output $AES

$CryptoStream = New-Object System.Security.Cryptography.CryptoStream(
  $OutputStream, $Enc, [System.Security.Cryptography.CryptoStreamMode]::Write)

$InputStream.CopyTo($CryptoStream)
$CryptoStream.Dispose()
Same parameters as the decrypt:
encrypt.ps1 save_1.dec save_1.sav

Post Reply