Esempio n. 1
0
        /// <summary>
        /// Add imports to the PE file.
        /// </summary>
        /// <param name="additionalImports">List with additional imports.</param>
        public void AddImports(List <AdditionalImport> additionalImports)
        {
            if (ImageNtHeaders is null || ImageSectionHeaders is null || _dataDirectoryParsers is null)
            {
                throw new Exception("NT Headers, Section Headers and Data Directory must not be null.");
            }

            const int sizeOfImpDesc   = 0x14;
            var       sizeOfThunkData = Is32Bit ? 4 : 8;
            var       numAddImpDescs  = additionalImports.Count;
            var       importRva       = ImageNtHeaders.OptionalHeader.DataDirectory[(int)DataDirectoryType.Import].VirtualAddress;
            var       importSize      = ImageNtHeaders.OptionalHeader.DataDirectory[(int)DataDirectoryType.Import].Size;

            ImageSectionHeader GetImportSection()
            => ImageSectionHeaders.First(sh => sh.VirtualAddress + sh.VirtualSize >= importRva);

            int EstimateAdditionalNeededSpace()
            => additionalImports.Select(ai => ai.Functions).Count() * 64;

            var impSection             = GetImportSection();
            var newUnalignedRawSecSize = EstimateAdditionalNeededSpace();

            // First copy the current import descriptor array to the start of the new section to have enough space to
            // add additional import descriptors.
            AddSection(".addImp", (int)(impSection !.SizeOfRawData + newUnalignedRawSecSize), (ScnCharacteristicsType)0xC0000000);
            var newImpSec       = ImageSectionHeaders.First(sh => sh.Name == ".addImp");
            var oldImpDescBytes = RawFile.AsSpan(importRva.RvaToOffset(ImageSectionHeaders), importSize);

            RawFile.WriteBytes(newImpSec.PointerToRawData, oldImpDescBytes);

            // Set the import data directory to the new import section and adjust the size
            ImageNtHeaders.OptionalHeader.DataDirectory[(int)DataDirectoryType.Import].VirtualAddress = newImpSec.VirtualAddress;
            ImageNtHeaders.OptionalHeader.DataDirectory[(int)DataDirectoryType.Import].Size           = (uint)(importSize + (sizeOfImpDesc * numAddImpDescs));
            var newImportRva  = ImageNtHeaders.OptionalHeader.DataDirectory[(int)DataDirectoryType.Import].VirtualAddress;
            var newImportSize = ImageNtHeaders.OptionalHeader.DataDirectory[(int)DataDirectoryType.Import].Size;

            var paAdditionalSpace = newImpSec.PointerToRawData + newImportSize;

            // Update import descriptors and imported functions to reflect the new
            // position in the new section.
            _dataDirectoryParsers.ReparseImportDescriptors(ImageSectionHeaders);
            _dataDirectoryParsers.ReparseImportedFunctions();

            uint AddModName(ref uint offset, string module)
            {
                var tmp   = Encoding.ASCII.GetBytes(module);
                var mName = new byte[tmp.Length + 1];

                Array.Copy(tmp, mName, tmp.Length);

                var paName = offset;

                RawFile.WriteBytes(offset, mName);

                offset = (uint)(offset + mName.Length);
                return(paName);
            }

            List <uint> AddImpByNames(ref uint offset, List <string> funcs)
            {
                var adrList = new List <uint>();

                foreach (var f in funcs)
                {
                    var ibn = new ImageImportByName(RawFile, offset)
                    {
                        Hint = 0,
                        Name = f
                    };

                    adrList.Add(offset);

                    offset += (uint)ibn.Name.Length + 2;
                }

                // Add zero DWORD to end array
                RawFile.WriteUInt(offset + 1, 0);
                offset += 5;

                return(adrList);
            }

            uint AddThunkDatas(ref uint offset, List <uint> adrList)
            {
                var paThunkStart = offset;

                foreach (var adr in adrList)
                {
                    _ = new ImageThunkData(RawFile, offset, Is64Bit)
                    {
                        AddressOfData = adr.OffsetToRva(ImageSectionHeaders !)
                    };

                    offset += (uint)sizeOfThunkData;
                }

                // End array with empty thunk data
                _ = new ImageThunkData(RawFile, offset, Is64Bit)
                {
                    AddressOfData = 0
                };

                offset += (uint)sizeOfThunkData;

                return(paThunkStart);
            }

            void AddImportWithNewImpDesc(ref uint tmpOffset, ref long paIdesc, AdditionalImport ai)
            {
                var paName    = AddModName(ref tmpOffset, ai.Module);
                var funcAdrs  = AddImpByNames(ref tmpOffset, ai.Functions);
                var thunkAdrs = AddThunkDatas(ref tmpOffset, funcAdrs);

                _ = new ImageImportDescriptor(RawFile, paIdesc)
                {
                    Name = paName.OffsetToRva(ImageSectionHeaders),
                    OriginalFirstThunk = 0,
                    FirstThunk         = thunkAdrs.OffsetToRva(ImageSectionHeaders),
                    ForwarderChain     = 0,
                    TimeDateStamp      = 0
                };
                paIdesc += (uint)sizeOfImpDesc;
            }

            var paIdesc   = newImportRva.RvaToOffset(ImageSectionHeaders) + ImageImportDescriptors !.Length * sizeOfImpDesc;
            var tmpOffset = paAdditionalSpace;

            // Add new imports
            foreach (var ai in additionalImports)
            {
                AddImportWithNewImpDesc(ref tmpOffset, ref paIdesc, ai);
            }

            // End with zero filled idesc
            _ = new ImageImportDescriptor(RawFile, paIdesc)
            {
                Name = 0,
                OriginalFirstThunk = 0,
                FirstThunk         = 0,
                ForwarderChain     = 0,
                TimeDateStamp      = 0
            };


            // Reparse imports
            _dataDirectoryParsers.ReparseImportDescriptors(ImageSectionHeaders);
            _dataDirectoryParsers.ReparseImportedFunctions();
        }
    }
Esempio n. 2
0
        /// <summary>
        /// Remove a section from the PE file.
        /// </summary>
        /// <param name="name">Name of the section to remove.</param>
        /// <param name="removeContent">Flag if the content should be removed or only the section header entry.</param>
        public void RemoveSection(string name, bool removeContent = true)
        {
            var sectionToRemove = ImageSectionHeaders.First(s => s.Name == name);

            // Remove section from list of sections
            var newSections = ImageSectionHeaders.Where(s => s.Name != name).ToArray();

            // Change number of sections in the file header
            ImageNtHeaders !.FileHeader.NumberOfSections--;

            if (removeContent)
            {
                // Reloc the physical address of all sections
                foreach (var s in newSections)
                {
                    if (s.PointerToRawData > sectionToRemove.PointerToRawData)
                    {
                        s.PointerToRawData -= sectionToRemove.SizeOfRawData;
                    }
                }

                // Remove section content
                RawFile.RemoveRange(sectionToRemove.PointerToRawData, sectionToRemove.SizeOfRawData);
            }

            // Fix virtual size
            for (var i = 1; i < newSections.Count(); i++)
            {
                if (newSections[i - 1].VirtualAddress < sectionToRemove.VirtualAddress)
                {
                    newSections[i - 1].VirtualSize = newSections[i].VirtualAddress - newSections[i - 1].VirtualAddress;
                }
            }

            // Replace old section headers with new section headers
            var sectionHeaderOffset = ImageDosHeader !.E_lfanew + ImageNtHeaders !.FileHeader.SizeOfOptionalHeader + 0x18;
            var sizeOfSection       = 0x28;
            var newRawSections      = new byte[newSections.Count() * sizeOfSection];

            for (var i = 0; i < newSections.Count(); i++)
            {
                Array.Copy(newSections[i].ToArray(), 0, newRawSections, i * sizeOfSection, sizeOfSection);
            }

            // Null the data directory entry if any available
            var de = ImageNtHeaders
                     .OptionalHeader
                     .DataDirectory
                     .FirstOrDefault(d => d.VirtualAddress == sectionToRemove.VirtualAddress &&
                                     d.Size == sectionToRemove.VirtualSize);

            if (de != null)
            {
                de.Size           = 0;
                de.VirtualAddress = 0;
            }

            // Null the old section headers
            RawFile.WriteBytes(sectionHeaderOffset, new byte[ImageSectionHeaders.Count() * sizeOfSection]);

            // Write the new sections headers
            RawFile.WriteBytes(sectionHeaderOffset, newRawSections);

            // Reparse section header
            _nativeStructureParsers.ReparseSectionHeaders();
        }