void Initialize(ModuleDefMD module) { var vtblHdr = module.Metadata.ImageCor20Header.VTableFixups; if (vtblHdr.VirtualAddress == 0 || vtblHdr.Size == 0) { return; } var peImage = module.Metadata.PEImage; var exportHdr = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[0]; if (exportHdr.VirtualAddress == 0 || exportHdr.Size < 0x28) { return; } if (!CpuArch.TryGetCpuArch(peImage.ImageNTHeaders.FileHeader.Machine, out var cpuArch)) { Debug.Fail($"Exported methods: Unsupported machine: {peImage.ImageNTHeaders.FileHeader.Machine}"); return; } var reader = peImage.CreateReader(); var offsetToInfo = GetOffsetToExportInfoDictionary(ref reader, peImage, exportHdr, cpuArch); reader.Position = (uint)peImage.ToFileOffset(vtblHdr.VirtualAddress); ulong endPos = (ulong)reader.Position + vtblHdr.Size; while ((ulong)reader.Position + 8 <= endPos && reader.CanRead(8U)) { var tableRva = (RVA)reader.ReadUInt32(); int numSlots = reader.ReadUInt16(); var flags = (VTableFlags)reader.ReadUInt16(); bool is64bit = (flags & VTableFlags.Bit64) != 0; var exportOptions = ToMethodExportInfoOptions(flags); var pos = reader.Position; reader.Position = (uint)peImage.ToFileOffset(tableRva); uint slotSize = is64bit ? 8U : 4; while (numSlots-- > 0 && reader.CanRead(slotSize)) { var tokenPos = reader.Position; uint token = reader.ReadUInt32(); bool b = offsetToInfo.TryGetValue(tokenPos, out var exportInfo); Debug.Assert(token == 0 || b); if (b) { exportInfo = new MethodExportInfo(exportInfo.Name, exportInfo.Ordinal, exportOptions); toInfo[token] = exportInfo; } if (slotSize == 8) { reader.ReadUInt32(); } } reader.Position = pos; } }
static Dictionary <long, MethodExportInfo> GetOffsetToExportInfoDictionary(IImageStream reader, IPEImage peImage, ImageDataDirectory exportHdr, CpuArch cpuArch) { reader.Position = (long)peImage.ToFileOffset(exportHdr.VirtualAddress); // Skip Characteristics(4), TimeDateStamp(4), MajorVersion(2), MinorVersion(2), Name(4) reader.Position += 16; uint ordinalBase = reader.ReadUInt32(); int numFuncs = reader.ReadInt32(); int numNames = reader.ReadInt32(); long offsetOfFuncs = (long)peImage.ToFileOffset((RVA)reader.ReadUInt32()); long offsetOfNames = (long)peImage.ToFileOffset((RVA)reader.ReadUInt32()); long offsetOfNameIndexes = (long)peImage.ToFileOffset((RVA)reader.ReadUInt32()); var names = ReadNames(reader, peImage, numNames, offsetOfNames, offsetOfNameIndexes); reader.Position = offsetOfFuncs; var allInfos = new MethodExportInfo[numFuncs]; var dict = new Dictionary <long, MethodExportInfo>(numFuncs); for (int i = 0; i < allInfos.Length; i++) { var currOffset = reader.Position; var nextOffset = reader.Position + 4; uint funcRva = 0; var rva = (RVA)reader.ReadUInt32(); reader.Position = (long)peImage.ToFileOffset(rva); bool rvaValid = rva != 0 && cpuArch.TryGetExportedRvaFromStub(reader, peImage, out funcRva); long funcOffset = rvaValid ? (long)peImage.ToFileOffset((RVA)funcRva) : 0; var exportInfo = new MethodExportInfo((ushort)(ordinalBase + (uint)i)); if (funcOffset != 0) { dict[funcOffset] = exportInfo; } allInfos[i] = exportInfo; reader.Position = nextOffset; } foreach (var info in names) { int index = info.Index; if ((uint)index >= (uint)numFuncs) { continue; } allInfos[index].Ordinal = null; allInfos[index].Name = info.Name; } return(dict); }