Skip to content

Instantly share code, notes, and snippets.

@unarist
Created July 3, 2016 16:32
Show Gist options
  • Save unarist/65faf28aa58aa5d34ef4aa234a4be6a4 to your computer and use it in GitHub Desktop.
Save unarist/65faf28aa58aa5d34ef4aa234a4be6a4 to your computer and use it in GitHub Desktop.
Mono.Cecilで配列を埋め込む
// 参考: http://lifeinhex.com/how-to-inject-byte-array-using-dnlib/
var asm = AssemblyDefinition.ReadAssembly("target.exe");
var data = File.ReadAllBytes("in.dat");
// 適当な型に、(ここではコンパイラと同じ名前を使うので競合に注意)
var cls = new TypeDefinition("", "<PrivateImplementationDetails>", Mono.Cecil.TypeAttributes.Sealed, asm.MainModule.TypeSystem.Object);
asm.MainModule.Types.Add(cls);
// a. 目的のサイズの構造体(メンバはなくてよい)
var sized = new TypeDefinition("", $"__StaticArrayInitTypeSize={data.Length}",
Mono.Cecil.TypeAttributes.NestedPrivate | Mono.Cecil.TypeAttributes.Sealed | Mono.Cecil.TypeAttributes.ExplicitLayout,
asm.MainModule.Import(typeof(ValueType)));
sized.PackingSize = 1;
sized.ClassSize = data.Length;
cls.NestedTypes.Add(sized);
// b. 上記構造体のフィールドに初期値としてデータを埋め込む
var field = new FieldDefinition("適当な名前",
Mono.Cecil.FieldAttributes.Static | Mono.Cecil.FieldAttributes.InitOnly | Mono.Cecil.FieldAttributes.HasFieldRVA,
sized);
field.InitialValue = asm2;
cls.Fields.Add(field);
// そして空の配列を生成し、RuntimeHelpers.InitializeArrayでデータをコピーしてくる
var initarr = asm.MainModule.Import(typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray"));
var write = asm.MainModule.Import(typeof(File).GetMethod("WriteAllBytes"));
// ※とりあえずEmitで書いたけど新規作成するなり挿入するなり
var il = asm.MainModule.EntryPoint.Body.GetILProcessor();
il.Emit(OpCodes.Ldstr, @"out.dat");
il.Emit(OpCodes.Ldc_I4, data.Length);
il.Emit(OpCodes.Newarr, asm.MainModule.TypeSystem.Byte);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldtoken, field);
il.Emit(OpCodes.Call, initarr);
il.Emit(OpCodes.Call, write);
il.Emit(OpCodes.Ret);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment