using System.IO;
using Mono.Cecil;
+using Mono.Cecil.Binary;
using Mono.Cecil.Cil;
+using Mono.Cecil.Metadata;
namespace Mono.CilStripper {
class AssemblyStripper {
AssemblyDefinition assembly;
- string outputFileName;
+ BinaryWriter writer;
- AssemblyStripper (AssemblyDefinition assembly, string outputFileName)
+ Image original;
+ Image stripped;
+
+ ReflectionWriter reflection_writer;
+ MetadataWriter metadata_writer;
+
+ TablesHeap original_tables;
+ TablesHeap stripped_tables;
+
+ AssemblyStripper (AssemblyDefinition assembly, BinaryWriter writer)
{
this.assembly = assembly;
- this.outputFileName = outputFileName;
+ this.writer = writer;
}
void Strip ()
{
+ FullLoad ();
ClearMethodBodies ();
+ CopyOriginalImage ();
+ PatchMethods ();
+ PatchFields ();
+ PatchResources ();
Write ();
}
+ void FullLoad ()
+ {
+ assembly.MainModule.FullLoad ();
+ }
+
void ClearMethodBodies ()
{
- foreach (TypeDefinition type in assembly.MainModule.GetTypes()) {
+ foreach (TypeDefinition type in assembly.MainModule.Types) {
+ ClearMethodBodies (type.Constructors);
ClearMethodBodies (type.Methods);
}
}
- void ClearMethodBodies (ICollection methods)
+ static void ClearMethodBodies (ICollection methods)
{
foreach (MethodDefinition method in methods) {
- method.ImplAttributes |= MethodImplAttributes.NoInlining;
-
if (!method.HasBody)
continue;
- var processor = method.Body.GetILProcessor ();
- processor.Body.Instructions.Clear ();
- processor.Emit (OpCodes.Ret);
+ MethodBody body = new MethodBody (method);
+ body.CilWorker.Emit (OpCodes.Ret);
- method.Body.Variables.Clear ();
- method.Body.ExceptionHandlers.Clear ();
+ method.Body = body;
+ }
+ }
+
+ void CopyOriginalImage ()
+ {
+ original = assembly.MainModule.Image;
+ stripped = Image.CreateImage();
+
+ stripped.Accept (new CopyImageVisitor (original));
+
+ assembly.MainModule.Image = stripped;
+
+ original_tables = original.MetadataRoot.Streams.TablesHeap;
+ stripped_tables = stripped.MetadataRoot.Streams.TablesHeap;
+
+ TableCollection tables = original_tables.Tables;
+ foreach (IMetadataTable table in tables)
+ stripped_tables.Tables.Add(table);
+
+ stripped_tables.Valid = original_tables.Valid;
+ stripped_tables.Sorted = original_tables.Sorted;
+
+ reflection_writer = new ReflectionWriter (assembly.MainModule);
+ reflection_writer.StructureWriter = new StructureWriter (assembly, writer);
+ reflection_writer.CodeWriter.Stripped = true;
+
+ metadata_writer = reflection_writer.MetadataWriter;
+
+ PatchHeap (metadata_writer.StringWriter, original.MetadataRoot.Streams.StringsHeap);
+ PatchHeap (metadata_writer.GuidWriter, original.MetadataRoot.Streams.GuidHeap);
+ PatchHeap (metadata_writer.UserStringWriter, original.MetadataRoot.Streams.UserStringsHeap);
+ PatchHeap (metadata_writer.BlobWriter, original.MetadataRoot.Streams.BlobHeap);
+
+ if (assembly.EntryPoint != null)
+ metadata_writer.EntryPointToken = assembly.EntryPoint.MetadataToken.ToUInt ();
+ }
+
+ static void PatchHeap (MemoryBinaryWriter heap_writer, MetadataHeap heap)
+ {
+ if (heap == null)
+ return;
+
+ heap_writer.BaseStream.Position = 0;
+ heap_writer.Write (heap.Data);
+ }
+
+ void PatchMethods ()
+ {
+ MethodTable methodTable = (MethodTable) stripped_tables [MethodTable.RId];
+ if (methodTable == null)
+ return;
+
+ RVA method_rva = RVA.Zero;
+
+ for (int i = 0; i < methodTable.Rows.Count; i++) {
+ MethodRow methodRow = methodTable[i];
+
+ methodRow.ImplFlags |= MethodImplAttributes.NoInlining;
+
+ MetadataToken methodToken = MetadataToken.FromMetadataRow (TokenType.Method, i);
+
+ MethodDefinition method = (MethodDefinition) assembly.MainModule.LookupByToken (methodToken);
+
+ if (method.HasBody) {
+ method_rva = method_rva != RVA.Zero
+ ? method_rva
+ : reflection_writer.CodeWriter.WriteMethodBody (method);
+
+ methodRow.RVA = method_rva;
+ } else
+ methodRow.RVA = RVA.Zero;
+ }
+ }
+
+ void PatchFields ()
+ {
+ FieldRVATable fieldRvaTable = (FieldRVATable) stripped_tables [FieldRVATable.RId];
+ if (fieldRvaTable == null)
+ return;
+
+ for (int i = 0; i < fieldRvaTable.Rows.Count; i++) {
+ FieldRVARow fieldRvaRow = fieldRvaTable [i];
+
+ MetadataToken fieldToken = new MetadataToken (TokenType.Field, fieldRvaRow.Field);
+
+ FieldDefinition field = (FieldDefinition) assembly.MainModule.LookupByToken (fieldToken);
+
+ fieldRvaRow.RVA = metadata_writer.GetDataCursor ();
+ metadata_writer.AddData (field.InitialValue.Length + 3 & (~3));
+ metadata_writer.AddFieldInitData (field.InitialValue);
+ }
+ }
+
+ void PatchResources ()
+ {
+ ManifestResourceTable resourceTable = (ManifestResourceTable) stripped_tables [ManifestResourceTable.RId];
+ if (resourceTable == null)
+ return;
+
+ for (int i = 0; i < resourceTable.Rows.Count; i++) {
+ ManifestResourceRow resourceRow = resourceTable [i];
+
+ if (resourceRow.Implementation.RID != 0)
+ continue;
+
+ foreach (Resource resource in assembly.MainModule.Resources) {
+ EmbeddedResource er = resource as EmbeddedResource;
+ if (er == null)
+ continue;
+
+ if (resource.Name != original.MetadataRoot.Streams.StringsHeap [resourceRow.Name])
+ continue;
+
+ resourceRow.Offset = metadata_writer.AddResource (er.Data);
+ }
}
}
void Write ()
{
- if (outputFileName == null)
- assembly.Write ();
- else
- assembly.Write (outputFileName);
+ stripped.MetadataRoot.Accept (metadata_writer);
}
- public static void StripAssembly (AssemblyDefinition assembly, string outputFileName)
+ public static void StripAssembly (AssemblyDefinition assembly, string file)
{
- new AssemblyStripper (assembly, outputFileName).Strip ();
+ using (FileStream fs = new FileStream (file, FileMode.Create, FileAccess.Write, FileShare.None)) {
+ new AssemblyStripper (assembly, new BinaryWriter (fs)).Strip ();
+ }
}
}
}