MSBuild中记录的PE结构,C#的,可能有用贴出来,完整代码在github上
#region NT header stuff
internal const uint IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
internal const uint IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
internal const uint IMAGE_DIRECTORY_ENTRY_COMHEADER = 14;
internal const uint COMIMAGE_FLAGS_STRONGNAMESIGNED = 0x08;
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_FILE_HEADER
{
internal ushort Machine;
internal ushort NumberOfSections;
internal uint TimeDateStamp;
internal uint PointerToSymbolTable;
internal uint NumberOfSymbols;
internal ushort SizeOfOptionalHeader;
internal ushort Characteristics;
}
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_DATA_DIRECTORY
{
internal uint VirtualAddress;
internal uint Size;
}
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_OPTIONAL_HEADER32
{
internal ushort Magic;
internal byte MajorLinkerVersion;
internal byte MinorLinkerVersion;
internal uint SizeOfCode;
internal uint SizeOfInitializedData;
internal uint SizeOfUninitializedData;
internal uint AddressOfEntryPoint;
internal uint BaseOfCode;
internal uint BaseOfData;
internal uint ImageBase;
internal uint SectionAlignment;
internal uint FileAlignment;
internal ushort MajorOperatingSystemVersion;
internal ushort MinorOperatingSystemVersion;
internal ushort MajorImageVersion;
internal ushort MinorImageVersion;
internal ushort MajorSubsystemVersion;
internal ushort MinorSubsystemVersion;
internal uint Win32VersionValue;
internal uint SizeOfImage;
internal uint SizeOfHeaders;
internal uint CheckSum;
internal ushort Subsystem;
internal ushort DllCharacteristics;
internal uint SizeOfStackReserve;
internal uint SizeOfStackCommit;
internal uint SizeOfHeapReserve;
internal uint SizeOfHeapCommit;
internal uint LoaderFlags;
internal uint NumberOfRvaAndSizes;
// should be:
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] internal IMAGE_DATA_DIRECTORY[] DataDirectory;
// but fixed size arrays only work with simple types, so I have to use ulongs and convert them to IMAGE_DATA_DIRECTORY structs
// Fortunately, IMAGE_DATA_DIRECTORY is only 8 bytes long... (whew)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
internal ulong[] DataDirectory;
}
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_OPTIONAL_HEADER64
{
internal ushort Magic;
internal byte MajorLinkerVersion;
internal byte MinorLinkerVersion;
internal uint SizeOfCode;
internal uint SizeOfInitializedData;
internal uint SizeOfUninitializedData;
internal uint AddressOfEntryPoint;
internal uint BaseOfCode;
internal ulong ImageBase;
internal uint SectionAlignment;
internal uint FileAlignment;
internal ushort MajorOperatingSystemVersion;
internal ushort MinorOperatingSystemVersion;
internal ushort MajorImageVersion;
internal ushort MinorImageVersion;
internal ushort MajorSubsystemVersion;
internal ushort MinorSubsystemVersion;
internal uint Win32VersionValue;
internal uint SizeOfImage;
internal uint SizeOfHeaders;
internal uint CheckSum;
internal ushort Subsystem;
internal ushort DllCharacteristics;
internal ulong SizeOfStackReserve;
internal ulong SizeOfStackCommit;
internal ulong SizeOfHeapReserve;
internal ulong SizeOfHeapCommit;
internal uint LoaderFlags;
internal uint NumberOfRvaAndSizes;
// should be:
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] internal IMAGE_DATA_DIRECTORY[] DataDirectory;
// but fixed size arrays only work with simple types, so I have to use ulongs and convert them to IMAGE_DATA_DIRECTORY structs
// Fortunately, IMAGE_DATA_DIRECTORY is only 8 bytes long... (whew)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
internal ulong[] DataDirectory;
}
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_NT_HEADERS32
{
internal uint signature;
internal IMAGE_FILE_HEADER fileHeader;
internal IMAGE_OPTIONAL_HEADER32 optionalHeader;
}
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_NT_HEADERS64
{
internal uint signature;
internal IMAGE_FILE_HEADER fileHeader;
internal IMAGE_OPTIONAL_HEADER64 optionalHeader;
}
[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_COR20_HEADER
{
internal uint cb;
internal ushort MajorRuntimeVersion;
internal ushort MinorRuntimeVersion;
internal IMAGE_DATA_DIRECTORY MetaData;
internal uint Flags;
internal uint EntryPointTokenOrEntryPointRVA;
internal IMAGE_DATA_DIRECTORY Resources;
internal IMAGE_DATA_DIRECTORY StrongNameSignature;
internal IMAGE_DATA_DIRECTORY CodeManagerTable;
internal IMAGE_DATA_DIRECTORY VTableFixups;
internal IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
internal IMAGE_DATA_DIRECTORY ManagedNativeHeader;
}
[StructLayout(LayoutKind.Sequential)]
internal struct CRYPTOAPI_BLOB
{
internal uint cbData;
internal IntPtr pbData;
}
#endregion
读元数据的函数
#region Methods
/// <summary>
/// Given a pointer to a metadata blob, read the string parameter from it. Returns true if
/// a valid string was constructed and false otherwise.
///
/// Adapted from bizapps\server\designers\models\packagemodel\nativemethods.cs (TryReadStringArgument) and
/// the original ARD implementation in vsproject\compsvcspkg\enumcomplus.cpp (GetStringCustomAttribute)
/// This code was taken from the vsproject\ReferenceManager\Providers\NativeMethods.cs
/// </summary>
[HandleProcessCorruptedStateExceptions]
internal static unsafe bool TryReadMetadataString(string fullPath, IntPtr attrData, uint attrDataSize, out string strValue)
{
IntPtr attrDataPostProlog = IntPtr.Zero;
int attrDataOffset = 0;
int strLen = 0;
int i = 0;
strValue = null;
try
{
// Blob structure for an attribute with a constructor receiving one string
// and no named parameters:
//
// [2 bytes] Prolog: unsigned int16 with value 0x0001
// [1, 2 or 4 bytes] PackedLen: Number of bytes of string parameter
// [PackedLen bytes] String parameter encoded as UTF8
// [1 byte] Name Parameter Count: Named parameter count equal to 0
// Minimum size is 4-bytes (Prolog + PackedLen). Prolog must be 0x0001.
if ((attrDataSize >= 4) && (Marshal.ReadInt16(attrData, attrDataOffset) == 1))
{
int preReadOffset = 2; // pass the prolog
attrDataPostProlog = attrData + preReadOffset;
// Get the offset at which the uncompressed data starts, and the
// length of the uncompressed data.
attrDataOffset = CorSigUncompressData(attrDataPostProlog, out strLen);
if (strLen != -1)
{
// the full size of the blob we were passed in should be sufficient to
// cover the prolog, compressed string length, and actual string.
if (attrDataSize >= preReadOffset + attrDataOffset + strLen)
{
// Read in the uncompressed data
byte[] bytes = new byte[(int)strLen];
for (i = 0; i < strLen; i++)
{
bytes[i] = Marshal.ReadByte(attrDataPostProlog, attrDataOffset + i);
}
// And convert it to the output string.
strValue = new String(Encoding.UTF8.GetChars(bytes));
}
else
{
return false;
}
}
}
else
{
return false;
}
}
catch (AccessViolationException)
{
// The Marshal.ReadXXXX functions throw AVs when they're fed an invalid pointer, and very occasionally,
// for some reason, on what seem to be otherwise perfectly valid assemblies (it must be
// intermittent given that otherwise the user would be completely unable to use the reference
// manager), the pointer that we generate to look up the AssemblyTitle is apparently invalid,
// or for some reason Marshal.ReadByte thinks it is.
//
return false;
}
return (strValue != null);
}
/// <summary>
/// Returns the number of bytes that compressed data -- the length of the uncompressed
/// data -- takes up, and has an out value of the length of the string.
///
/// Decompression algorithm stolen from ndp\clr\src\toolbox\mdbg\corapi\metadata\cormetadata.cs, which
/// was translated from the base implementation in ndp\clr\src\inc\cor.h
/// This code was taken from the vsproject\ReferenceManager\Providers\NativeMethods.cs
/// </summary>
/// <param name="data">Pointer to the beginning of the data block</param>
/// <param name="uncompressedData">Length of the uncompressed data block</param>
internal static unsafe int CorSigUncompressData(IntPtr data, out int uncompressedDataLength)
{
// As described in bizapps\server\designers\models\packagemodel\nativemethods.cs:
// The maximum encodable integer is 29 bits long, 0x1FFFFFFF. The compression algorithm used is as follows (bit 0 is the least significant bit):
// - If the value lies between 0 (0x00) and 127 (0x7F), inclusive, encode as a one-byte integer (bit 7 is clear, value held in bits 6 through 0)
// - If the value lies between 2^8 (0x80) and 2^14 - 1 (0x3FFF), inclusive, encode as a 2-byte integer with bit 15 set, bit 14 clear (value held in bits 13 through 0)
// - Otherwise, encode as a 4-byte integer, with bit 31 set, bit 30 set, bit 29 clear (value held in bits 28 through 0)
// - A null string should be represented with the reserved single byte 0xFF, and no following data
int count = -1;
byte* bytes = (byte*)(data);
uncompressedDataLength = 0;
// Smallest.
if ((*bytes & 0x80) == 0x00) // 0??? ????
{
uncompressedDataLength = *bytes;
count = 1;
}
// Medium.
else if ((*bytes & 0xC0) == 0x80) // 10?? ????
{
uncompressedDataLength = (int)(((*bytes & 0x3f) << 8 | *(bytes + 1)));
count = 2;
}
else if ((*bytes & 0xE0) == 0xC0) // 110? ????
{
uncompressedDataLength = (int)(((*bytes & 0x1f) << 24 | *(bytes + 1) << 16 | *(bytes + 2) << 8 | *(bytes + 3)));
count = 4;
}
return count;
}
#endregion