public ManagedExportsWriter(string moduleName, Machine machine, RelocDirectory relocDirectory, MetaData metaData, PEHeaders peHeaders, LogError logError) { this.moduleName = moduleName; this.machine = machine; this.relocDirectory = relocDirectory; this.metaData = metaData; this.peHeaders = peHeaders; this.logError = logError; vtableFixups = new VtableFixupsChunk(this); stubsChunk = new StubsChunk(this); sdataChunk = new SdataChunk(this); exportDir = new ExportDir(this); vtables = new List <VTableInfo>(); allMethodInfos = new List <MethodInfo>(); sortedNameInfos = new List <MethodInfo>(); // The error is reported later when we know that there's at least one exported method CpuArch.TryGetCpuArch(machine, out cpuArch); }
private static void RealMain(Config config, bool verbose) { // Copy input file to output file, so we do not need to touch input file again File.Copy(config.InputFile, config.OutputFile, true); using var file = File.Open(config.OutputFile, FileMode.Open, FileAccess.ReadWrite); using var exp = File.CreateText(config.DefFile); using var action = new PEAction(file); using var pdb = new PdbFileReader(config.PdbFile); using var db = new SQLiteConnection("" + new SQLiteConnectionStringBuilder { DataSource = config.FilterOutDatabase, SyncMode = SynchronizationModes.Off, NoSharedFlags = true, FailIfMissing = false }); db.Open(); var filterout = new SortedDictionary <string, uint>(StringComparer.Ordinal); var symdb = new SymbolDatabase(); Console.WriteLine("filtering ({0})", pdb.PublicSymbols.Length); // Collect all symbols Parallel.ForEach(pdb.PublicSymbols, (item) => { if (config.Filter?.Filter(item.IsCode, item.Name) ?? true) { lock (symdb) { symdb.Add((uint)item.RelativeVirtualAddress, item.Name); } } else { lock (filterout) { filterout.Add(item.Name, (uint)item.RelativeVirtualAddress); } } }); Console.WriteLine("symbols collected: {0}, filtered: {1}", symdb.Count(), filterout.Count()); // Exclude imported symbols foreach (var sym in action.GetImportSymbols()) { if (symdb.RemoveName(sym) && verbose) { Console.WriteLine("Removed {0}", sym); } else if (filterout.Remove(sym) && verbose) { Console.WriteLine("Removed {0} (filtered)", sym); } } Console.WriteLine("symbols fixed: {0}, filtered fixed: {1}", symdb.Count(), filterout.Count()); // Write to filter out db using (var transition = db.BeginTransaction()) { using (var dropCommand = db.CreateCommand()) { dropCommand.CommandText = "DROP TABLE IF EXISTS symbols"; dropCommand.Transaction = transition; dropCommand.ExecuteNonQuery(); } using (var createCommand = db.CreateCommand()) { createCommand.CommandText = "CREATE TABLE symbols(symbol TEXT PRIMARY KEY, rva INTEGER) WITHOUT ROWID"; createCommand.Transaction = transition; createCommand.ExecuteNonQuery(); } using (var insertCommand = db.CreateCommand()) { insertCommand.CommandText = "INSERT INTO symbols VALUES ($symbol, $rva)"; insertCommand.Transaction = transition; foreach (var item in filterout) { insertCommand.Parameters.AddWithValue("$symbol", item.Key); insertCommand.Parameters.AddWithValue("$rva", item.Value); insertCommand.ExecuteNonQuery(); insertCommand.Parameters.Clear(); insertCommand.Reset(); } } transition.Commit(); } // Build cache var cache = symdb.ToArray(); var sorted = symdb.Build(); // Print exported symbols exp.Write("LIBRARY " + config.DllName + "\n"); exp.Write("EXPORTS\n"); foreach (var(name, idx) in sorted) { exp.Write(string.Format("\t{0}\n", name)); } Console.WriteLine("starting rebuild PE file"); // Calculate append length uint length = 0; var expdirlength = (uint)Marshal.SizeOf <ExportDir>(); var dllnamelength = (uint)(config.DllName.Length + 1); var NumberOfFunctions = (uint)cache.Count(); var functionslength = NumberOfFunctions * 4; var NumberOfNames = (uint)cache.Select(item => item.Value.Count).Aggregate(0, (a, b) => a + b); var ordinalslength = NumberOfNames * 2; var nameslength = NumberOfNames * 4; var stringslength = (uint)sorted.Select(kv => kv.Key.Length + 1).Aggregate(0, (a, b) => a + b); Console.WriteLine("NumberOfFunctions: {0}", NumberOfFunctions); Console.WriteLine("NumberOfNames: {0}", NumberOfNames); Console.WriteLine("Length Of ExportDir: {0}", expdirlength); Console.WriteLine("Length Of DllName: {0}", dllnamelength); Console.WriteLine("Length Of Functions: {0}", functionslength); Console.WriteLine("Length Of Ordinals: {0}", ordinalslength); Console.WriteLine("Length Of Names: {0}", nameslength); Console.WriteLine("Length Of Strings: {0}", stringslength); length = expdirlength + dllnamelength + functionslength + ordinalslength + nameslength + stringslength; Console.WriteLine("Addition length: {0}", length); // Start modify header var VirtualEnd = action.GetEnding(); var OriginalSize = (uint)file.Length; action.PatchNtHeader(GetAlign(length)); action.PatchDir(0, VirtualEnd, length); { var header = new SectionHeader { }; header.SetName(".hacked"); header.Misc.VirtualSize = length; header.VirtualAddress = VirtualEnd; header.SizeOfRawData = GetAlign(length); header.PointerToRawData = OriginalSize; header.Characteristics = 0x40000040; action.AppendSection(header); } // Write export table file.SetLength(OriginalSize + GetAlign(length)); { var expdir = new ExportDir { }; expdir.Name = VirtualEnd + expdirlength; expdir.Base = 1; expdir.NumberOfFunctions = NumberOfFunctions; expdir.NumberOfNames = NumberOfNames; expdir.AddressOfFunctions = VirtualEnd + expdirlength + dllnamelength; expdir.AddressOfOrdinals = VirtualEnd + expdirlength + dllnamelength + functionslength; expdir.AddressOfNames = VirtualEnd + expdirlength + dllnamelength + functionslength + ordinalslength + stringslength; action.WriteExport(expdir); } action.Writer.WriteByteString(config.DllName); foreach (var(key, _) in cache) { action.Writer.WriteStruct(new RVA { Value = key }); } foreach (var(_, idx) in sorted) { action.Writer.WriteStruct(new Ordinal { Value = idx }); } { var strscache = new List <uint>(); var baseoff = (uint)file.Position; var baserva = VirtualEnd + expdirlength + dllnamelength + functionslength + ordinalslength; foreach (var(name, _) in sorted) { strscache.Add((uint)file.Position - baseoff + baserva); if (verbose) { Console.WriteLine("{0:X8} -> {1:X8}", file.Position, file.Position - baseoff + baserva); } action.Writer.WriteByteString(name); } foreach (var add in strscache) { action.Writer.WriteStruct(new RVA { Value = add }); } Console.WriteLine("VirtualEnd: {0} {0:X8}", VirtualEnd); Console.WriteLine("OriginalSize: {0} {0:X8}", OriginalSize); Console.WriteLine("RealAppend: {0} {0:X8}", file.Position - OriginalSize); } }
internal void WriteExport(ExportDir expdir) { Seek(Dirs[0].VirtualAddress); Writer.WriteStruct(expdir); }