bool IBinaryAppender <ImageImportDescriptor, ReaderWithOffsetArgs> .Attach(ref ImageImportDescriptor s, uint size, ReaderWithOffsetArgs arg) { // check if data not empty: if (s.TimeDateStamp == 0 && s.Name == 0) { return(false); } // read proper data: Name = arg.Source.ReadStringAnsiAt(s.Name - arg.Delta); if (s.TimeDateStamp == uint.MaxValue) { BindDate = DateTime.Now; isBinded = true; } else { BindDate = new DateTime(1970, 1, 1).AddSeconds(s.TimeDateStamp); isBinded = s.TimeDateStamp != 0; } ForwarderChain = s.ForwarderChain; NextModuleAddress = s.CharacteristicsOrOriginalFirstThunk; if (NextModuleAddress == 0) { NextModuleAddress = s.FirstThunk; } FirstThunk = s.FirstThunk; return(true); }
protected override ImageImportDescriptor[]? ParseTarget() { if (Offset == 0) { return(null); } var idescs = new List <ImageImportDescriptor>(); uint idescSize = 20; // Size of ImageImportDescriptor (5 * 4 Byte) uint round = 0; while (true) { var idesc = new ImageImportDescriptor(PeFile, Offset + idescSize * round); // Found the last ImageImportDescriptor which is completely null (except TimeDateStamp). if (idesc.OriginalFirstThunk == 0 //&& idesc.TimeDateStamp == 0 && idesc.ForwarderChain == 0 && idesc.Name == 0 && idesc.FirstThunk == 0) { break; } idescs.Add(idesc); round++; } return(idescs.ToArray()); }
internal ImageImportDll(MappedImage mappedImage, ImageImportDescriptor* descriptor) { _mappedImage = mappedImage; _descriptor = descriptor; if (_descriptor->OriginalFirstThunk != 0) _lookupTable = _mappedImage.RvaToVa(_descriptor->OriginalFirstThunk); else _lookupTable = _mappedImage.RvaToVa(_descriptor->FirstThunk); if (_lookupTable != null) { int i = 0; if (_mappedImage.Magic == Win32.Pe32Magic) { while (((int*)_lookupTable)[i] != 0) i++; } else if (_mappedImage.Magic == Win32.Pe32PlusMagic) { while (((long*)_lookupTable)[i] != 0) i++; } _count = i; } }
public void ImageImportDescriptorConstructorWorks_Test() { var importDescriptor = new ImageImportDescriptor(new BufferFile(RawStructures.RawImportDescriptor), 2); Assert.Equal((uint)0x33221100, importDescriptor.OriginalFirstThunk); Assert.Equal((uint)0x77665544, importDescriptor.TimeDateStamp); Assert.Equal(0xbbaa9988, importDescriptor.ForwarderChain); Assert.Equal(0xffeeddcc, importDescriptor.Name); Assert.Equal((uint)0x44332211, importDescriptor.FirstThunk); }
/// <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(); } }
public static IEnumerable <uint> ReadImportLocationTable(this PEStream stream, ImageImportDescriptor descriptor) { // The thunk processing is the same for PE32 and PE32+, however the size of the thunks differ to support 64-bit addresses // when translating the ImportAddressTable (IAT). Luckily only 32-bits of the 64 are actually required in both // PE32 and PE32+ for the ImportLookupTable (ILT) so we can just normalize the data into a DWORD and avoid having to create // two *almost* identical methods. var is32Bit = stream.OptionalHeader.Magic == H.IMAGE_NT_OPTIONAL_HDR32_MAGIC; var thunkSize = (uint)(is32Bit ? sizeof(uint) : sizeof(ulong)); var buffer = new byte[thunkSize]; var thunkOffset = 0U; var thunk = 0U; while (true) { stream.SeekVirtualAddress(descriptor.OriginalFirstThunk + thunkOffset); stream.FullRead(buffer, 0, buffer.Length); if (is32Bit) { thunk = BitConverter.ToUInt32(buffer, 0); } else { var thunk64 = BitConverter.ToUInt64(buffer, 0); thunk = (uint)((thunk64 & 0x7FFFFFFF) | ((thunk64 >> 32) & 0x80000000)); } if (thunk == 0) { break; } thunkOffset += thunkSize; yield return(thunk); } }