Loading external DLL from the server (Mono backend Unity game)
Back in the DLL modding days, some game developers like to hide external DLL inside game assets or load from server, leaving nothing useful in Assembly-Csharp.dll. This slows down modders, but in fact it’s not really hard to figure out
I know DLL are dead now, just take it as educational purposes
Let’s take this game as an example Romance of Heroes:Realtime 3v3 for Android - APK Download
It loads DLL from encrypted xgame.ezfun file inside APK
Just dump memory using GameGuardian to get the decrypted extra DLL (See tutorial https://www.andnixsh.com/2019/04/how-to-dump-decrypted-dll-files-using.html)
You would mod it as usually and after that, upload to your own server
Then in Assembly-Csharp.dll, this is the code that loads and decrypt DLL either from locally or from server
//Class: GameStart
private void LoadDLL()
{
string url = Application.streamingAssetsPath + "/xgame.ezfun";
string path = Application.persistentDataPath + "/DLL/xgame.ezfun";
if (this.CheckUseUpdate())
{
using (Stream stream = File.OpenRead(path))
{
byte[] array = new byte[stream.Length];
stream.Read(array, 0, array.Length);
stream.Close();
this.InitCry();
byte[] rawAssembly = this.Decrypte(array);
Assembly xgameData = Assembly.Load(rawAssembly);
this.m_xgameData = xgameData;
}
}
else
{
WWW www = new WWW(url);
while (!www.isDone)
{
}
Stream stream2 = new MemoryStream(www.bytes);
byte[] array2 = new byte[stream2.Length];
stream2.Read(array2, 0, array2.Length);
stream2.Close();
this.InitCry();
byte[] rawAssembly2 = this.Decrypte(array2);
Assembly xgameData2 = Assembly.Load(rawAssembly2);
this.m_xgameData = xgameData2;
}
}
You then modify the code to load from your server, it’s very simple. Avoid calling decryption tho, you don’t need it
private void LoadDLL()
{
WWW www = new WWW("https://example.com/modded.dll");
while (!www.isDone)
{
}
MemoryStream memoryStream = new MemoryStream(www.bytes);
byte[] array2 = new byte[memoryStream.Length];
memoryStream.Read(array2, 0, array2.Length);
memoryStream.Close();
this.InitCry();
Assembly xgameData2 = Assembly.Load(array2);
this.m_xgameData = xgameData2;
}
Another example from other games
Original code:
private void LoadGameDllFinish(string name, AssetBundle bundle)
{
TextAsset textAsset = (TextAsset)bundle.Load("WuXiaGameE.dll", typeof(TextAsset));
byte[] bytes = textAsset.bytes;
this.DecryptBytes(bytes);
Assembly assembly = Assembly.Load(bytes);
if (assembly != null)
{
Type type = assembly.GetType("WuXiaGame");
this._gameStart = type.GetMethod("Start");
this._gameUpdate = type.GetMethod("Update");
this._gameOnGUI = type.GetMethod("OnGUI");
this._gameOnApplicationQuit = type.GetMethod("OnApplicationQuit");
Type[] types = new Type[]
{
typeof(bool)
};
this._gameOnBecameInvisible = type.GetMethod("OnBecameInvisible");
this._gameOnBecameVisible = type.GetMethod("OnBecameVisible");
this._gameOnAppPause = type.GetMethod("OnApplicationPause", types);
MethodInfo method = type.GetMethod("SetDistributor");
method.Invoke(null, new object[]
{
"XinLangWeiBo"
});
}
if (this._gameStart != null)
{
this._gameStart.Invoke(null, null);
}
bundle.Unload(true);
}
Modified code:
private void LoadGameDllFinish(string name, AssetBundle bundle)
{
TextAsset textAsset = (TextAsset)bundle.Load("WuXiaGameE.dll", typeof(TextAsset));
this.bytes = textAsset.bytes;
this.DecryptBytes(this.bytes);
WWW www = new WWW("https://example.com/modded.dll");
while (!www.isDone)
{
}
Assembly assembly = Assembly.Load(www.bytes);
if (assembly != null)
{
Type type = assembly.GetType("WuXiaGame");
this._gameStart = type.GetMethod("Start");
this._gameUpdate = type.GetMethod("Update");
this._gameOnGUI = type.GetMethod("OnGUI");
this._gameOnApplicationQuit = type.GetMethod("OnApplicationQuit");
Type[] types = new Type[]
{
typeof(bool)
};
this._gameOnBecameInvisible = type.GetMethod("OnBecameInvisible");
this._gameOnBecameVisible = type.GetMethod("OnBecameVisible");
this._gameOnAppPause = type.GetMethod("OnApplicationPause", types);
type.GetMethod("SetDistributor").Invoke(null, new object[]
{
"XinLangWeiBo"
});
}
if (this._gameStart != null)
{
this._gameStart.Invoke(null, null);
}
bundle.Unload(true);
}