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(); if (offsetToInfo.TryGetValue(tokenPos, out var exportInfo)) { toInfo[token] = new MethodExportInfo(exportInfo.Name, exportInfo.Ordinal, exportOptions); } if (slotSize == 8) { reader.ReadUInt32(); } } reader.Position = pos; } }
public static bool TryGetCpuArch(Machine machine, out CpuArch cpuArch) { switch (machine) { case Machine.I386: case Machine.I386_Native_Apple: case Machine.I386_Native_FreeBSD: case Machine.I386_Native_Linux: case Machine.I386_Native_NetBSD: case Machine.I386_Native_Sun: cpuArch = x86CpuArch; return(true); case Machine.AMD64: case Machine.AMD64_Native_Apple: case Machine.AMD64_Native_FreeBSD: case Machine.AMD64_Native_Linux: case Machine.AMD64_Native_NetBSD: case Machine.AMD64_Native_Sun: cpuArch = x64CpuArch; return(true); case Machine.IA64: cpuArch = itaniumCpuArch; return(true); case Machine.ARMNT: case Machine.ARMNT_Native_Apple: case Machine.ARMNT_Native_FreeBSD: case Machine.ARMNT_Native_Linux: case Machine.ARMNT_Native_NetBSD: case Machine.ARMNT_Native_Sun: cpuArch = armCpuArch; return(true); case Machine.ARM64: case Machine.ARM64_Native_Apple: case Machine.ARM64_Native_FreeBSD: case Machine.ARM64_Native_Linux: case Machine.ARM64_Native_NetBSD: case Machine.ARM64_Native_Sun: //TODO: Support ARM64 goto default; default: cpuArch = null; return(false); } }
static Dictionary <uint, MethodExportInfo> GetOffsetToExportInfoDictionary(ref DataReader reader, IPEImage peImage, ImageDataDirectory exportHdr, CpuArch cpuArch) { reader.Position = (uint)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(); uint offsetOfFuncs = (uint)peImage.ToFileOffset((RVA)reader.ReadUInt32()); uint offsetOfNames = (uint)peImage.ToFileOffset((RVA)reader.ReadUInt32()); uint offsetOfNameIndexes = (uint)peImage.ToFileOffset((RVA)reader.ReadUInt32()); var names = ReadNames(ref reader, peImage, numNames, offsetOfNames, offsetOfNameIndexes); reader.Position = offsetOfFuncs; var allInfos = new MethodExportInfo[numFuncs]; var dict = new Dictionary <uint, MethodExportInfo>(numFuncs); for (int i = 0; i < allInfos.Length; i++) { var nextOffset = reader.Position + 4; uint funcRva = 0; var rva = (RVA)reader.ReadUInt32(); reader.Position = (uint)peImage.ToFileOffset(rva); bool rvaValid = rva != 0 && cpuArch.TryGetExportedRvaFromStub(ref reader, peImage, out funcRva); uint funcOffset = rvaValid ? (uint)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); }