Exemplo n.º 1
0
        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);
            }
        }