/// <summary> /// Writes the .sdata blob. We could write the data in any order, but we write the data in the same order as ILASM /// </summary> /// <param name="timestamp">PE timestamp</param> void WriteSdataBlob(uint timestamp) { var stream = new MemoryStream(); var writer = new BinaryWriter(stream); // Write all vtables (referenced from the .text section) Debug.Assert((writer.BaseStream.Position & 7) == 0); foreach (var vtbl in vtables) { vtbl.SdataChunkOffset = (uint)writer.BaseStream.Position; foreach (var info in vtbl.Methods) { info.ManagedVtblOffset = (uint)writer.BaseStream.Position; writer.Write(0x06000000 + metaData.GetRid(info.Method)); if ((vtbl.Flags & VTableFlags._64Bit) != 0) { writer.Write(0U); } } } var namesBlob = new NamesBlob(1 == 2); int nameIndex = 0; bool error = false; foreach (var info in allMethodInfos) { var exportInfo = info.Method.ExportInfo; var name = exportInfo.Name; if (name == null) { if (exportInfo.Ordinal != null) { sortedOrdinalMethodInfos.Add(info); continue; } name = info.Method.Name; } if (string.IsNullOrEmpty(name)) { error = true; logError("Exported method name is null or empty, method: {0} (0x{1:X8})", info.Method, info.Method.MDToken.Raw); continue; } info.NameOffset = namesBlob.GetMethodNameOffset(name, out info.NameBytes); info.NameIndex = nameIndex++; sortedNameMethodInfos.Add(info); } Debug.Assert(error || sortedOrdinalMethodInfos.Count + sortedNameMethodInfos.Count == allMethodInfos.Count); sdataBytesInfo.MethodNameOffsets = namesBlob.GetMethodNameOffsets(); Debug.Assert(sortedNameMethodInfos.Count == sdataBytesInfo.MethodNameOffsets.Length); sdataBytesInfo.moduleNameOffset = namesBlob.GetOtherNameOffset(moduleName); sortedOrdinalMethodInfos.Sort((a, b) => a.Method.ExportInfo.Ordinal.Value.CompareTo(b.Method.ExportInfo.Ordinal.Value)); sortedNameMethodInfos.Sort((a, b) => CompareTo(a.NameBytes, b.NameBytes)); int ordinalBase, nextFreeOrdinal; if (sortedOrdinalMethodInfos.Count == 0) { ordinalBase = 0; nextFreeOrdinal = 0; } else { ordinalBase = sortedOrdinalMethodInfos[0].Method.ExportInfo.Ordinal.Value; nextFreeOrdinal = sortedOrdinalMethodInfos[sortedOrdinalMethodInfos.Count - 1].Method.ExportInfo.Ordinal.Value + 1; } int nameFuncBaseIndex = nextFreeOrdinal - ordinalBase; int lastFuncIndex = 0; for (int i = 0; i < sortedOrdinalMethodInfos.Count; i++) { int index = sortedOrdinalMethodInfos[i].Method.ExportInfo.Ordinal.Value - ordinalBase; sortedOrdinalMethodInfos[i].FunctionIndex = index; lastFuncIndex = index; } for (int i = 0; i < sortedNameMethodInfos.Count; i++) { lastFuncIndex = nameFuncBaseIndex + i; sortedNameMethodInfos[i].FunctionIndex = lastFuncIndex; } int funcSize = lastFuncIndex + 1; if (funcSize > 0x10000) { logError("Exported function array is too big"); return; } // Write IMAGE_EXPORT_DIRECTORY Debug.Assert((writer.BaseStream.Position & 3) == 0); exportDirOffset = (uint)writer.BaseStream.Position; writer.Write(0U); // Characteristics writer.Write(timestamp); writer.Write(0U); // MajorVersion, MinorVersion sdataBytesInfo.exportDirModuleNameStreamOffset = (uint)writer.BaseStream.Position; writer.Write(0U); // Name writer.Write(ordinalBase); // Base writer.Write((uint)funcSize); // NumberOfFunctions writer.Write(sdataBytesInfo.MethodNameOffsets.Length); // NumberOfNames sdataBytesInfo.exportDirAddressOfFunctionsStreamOffset = (uint)writer.BaseStream.Position; writer.Write(0U); // AddressOfFunctions writer.Write(0U); // AddressOfNames writer.Write(0U); // AddressOfNameOrdinals sdataBytesInfo.addressOfFunctionsStreamOffset = (uint)writer.BaseStream.Position; WriteZeroes(writer, funcSize * 4); sdataBytesInfo.addressOfNamesStreamOffset = (uint)writer.BaseStream.Position; WriteZeroes(writer, sdataBytesInfo.MethodNameOffsets.Length * 4); sdataBytesInfo.addressOfNameOrdinalsStreamOffset = (uint)writer.BaseStream.Position; WriteZeroes(writer, sdataBytesInfo.MethodNameOffsets.Length * 2); sdataBytesInfo.namesBlobStreamOffset = (uint)writer.BaseStream.Position; namesBlob.Write(writer); sdataBytesInfo.Data = stream.ToArray(); }
/// <summary> /// Writes the .sdata blob. We could write the data in any order, but we write the data in the same order as ILASM /// </summary> /// <param name="timestamp">PE timestamp</param> void WriteSdataBlob(uint timestamp) { var stream = new MemoryStream(); var writer = new BinaryWriter(stream); // Write all vtables (referenced from the .text section) Debug.Assert((writer.BaseStream.Position & 7) == 0); foreach (var vtbl in vtables) { vtbl.SdataChunkOffset = (uint)writer.BaseStream.Position; foreach (var info in vtbl.Methods) { info.ManagedVtblOffset = (uint)writer.BaseStream.Position; writer.Write(0x06000000 + metaData.GetRid(info.Method)); if ((vtbl.Flags & VTableFlags._64Bit) != 0) { writer.Write(0U); } } } var namesBlob = new NamesBlob(1 == 2); int nameIndex = 0; foreach (var info in allMethodInfos) { var exportInfo = info.Method.ExportInfo; var name = exportInfo.Name; if (name == null) { if (exportInfo.Ordinal != null) { continue; } name = info.Method.Name; } if (string.IsNullOrEmpty(name)) { logError("Exported method name is null or empty, method: {0} (0x{1:X8})", info.Method, info.Method.MDToken.Raw); continue; } info.NameOffset = namesBlob.GetMethodNameOffset(name, out info.NameBytes); info.NameIndex = nameIndex++; sortedNameInfos.Add(info); } sdataBytesInfo.MethodNameOffsets = namesBlob.GetMethodNameOffsets(); sdataBytesInfo.moduleNameOffset = namesBlob.GetOtherNameOffset(moduleName); sortedNameInfos.Sort((a, b) => CompareTo(a.NameBytes, b.NameBytes)); Debug.Assert(sortedNameInfos.Count == sdataBytesInfo.MethodNameOffsets.Length); uint ordinalBase = uint.MaxValue; foreach (var info in allMethodInfos) { if (info.Method.ExportInfo.Ordinal != null) { ordinalBase = Math.Min(ordinalBase, info.Method.ExportInfo.Ordinal.Value); } } if (ordinalBase == uint.MaxValue) { ordinalBase = 0; } // Write IMAGE_EXPORT_DIRECTORY Debug.Assert((writer.BaseStream.Position & 3) == 0); exportDirOffset = (uint)writer.BaseStream.Position; writer.Write(0U); // Characteristics writer.Write(timestamp); writer.Write(0U); // MajorVersion, MinorVersion sdataBytesInfo.exportDirModuleNameStreamOffset = (uint)writer.BaseStream.Position; writer.Write(0U); // Name writer.Write(ordinalBase); // Base writer.Write((uint)allMethodInfos.Count); // NumberOfFunctions writer.Write(sdataBytesInfo.MethodNameOffsets.Length); // NumberOfNames sdataBytesInfo.exportDirAddressOfFunctionsStreamOffset = (uint)writer.BaseStream.Position; writer.Write(0U); // AddressOfFunctions writer.Write(0U); // AddressOfNames writer.Write(0U); // AddressOfNameOrdinals sdataBytesInfo.addressOfFunctionsStreamOffset = (uint)writer.BaseStream.Position; WriteZeroes(writer, allMethodInfos.Count * 4); sdataBytesInfo.addressOfNamesStreamOffset = (uint)writer.BaseStream.Position; WriteZeroes(writer, sdataBytesInfo.MethodNameOffsets.Length * 4); sdataBytesInfo.addressOfNameOrdinalsStreamOffset = (uint)writer.BaseStream.Position; WriteZeroes(writer, sdataBytesInfo.MethodNameOffsets.Length * 2); sdataBytesInfo.namesBlobStreamOffset = (uint)writer.BaseStream.Position; namesBlob.Write(writer); sdataBytesInfo.Data = stream.ToArray(); }