-
-
Save xpn/6f202a94123a1e51ed0035c441db5ef5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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