public static void VerifyMetadataEqualModuloMvid(Stream peStream1, Stream peStream2) { peStream1.Position = 0; peStream2.Position = 0; var peReader1 = new PEReader(peStream1); var peReader2 = new PEReader(peStream2); var md1 = peReader1.GetMetadata().GetContent(); var md2 = peReader2.GetMetadata().GetContent(); var mdReader1 = peReader1.GetMetadataReader(); var mdReader2 = peReader2.GetMetadataReader(); var mvidIndex1 = mdReader1.GetModuleDefinition().Mvid; var mvidIndex2 = mdReader2.GetModuleDefinition().Mvid; var mvidOffset1 = mdReader1.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex1) - 1); var mvidOffset2 = mdReader2.GetHeapMetadataOffset(HeapIndex.Guid) + 16 * (MetadataTokens.GetHeapOffset(mvidIndex2) - 1); if (!md1.RemoveRange(mvidOffset1, 16).SequenceEqual(md1.RemoveRange(mvidOffset2, 16))) { var mdw1 = new StringWriter(); var mdw2 = new StringWriter(); new MetadataVisualizer(mdReader1, mdw1).Visualize(); new MetadataVisualizer(mdReader2, mdw2).Visualize(); mdw1.Flush(); mdw2.Flush(); AssertEx.AssertResultsEqual(mdw1.ToString(), mdw2.ToString()); } }
public void CorLibWithAssemblyReferences_Pdb() { string sourceLib = @"namespace Namespace { public class Private { } }"; var compLib = CreateCompilationWithMscorlib(sourceLib, assemblyName: "System.Private.Library"); compLib.VerifyDiagnostics(); var refLib = compLib.EmitToImageReference(aliases: ImmutableArray.Create("A")); string sourceCorLib = @"extern alias A; #pragma warning disable 8019 using N = A::Namespace; namespace System { public class Object { public void F() { } } #pragma warning disable 0436 public class Void : Object { } #pragma warning restore 0436 }"; // Create a custom corlib with a reference to compilation // above and a reference to the actual mscorlib. var compCorLib = CreateCompilation(sourceCorLib, assemblyName: CorLibAssemblyName, references: new[] { MscorlibRef, refLib }); compCorLib.VerifyDiagnostics(); var objectType = compCorLib.SourceAssembly.GlobalNamespace.GetMember<NamedTypeSymbol>("System.Object"); Assert.NotNull(objectType.BaseType); var pdbPath = Temp.CreateDirectory().Path; ImmutableArray<byte> peBytes; ImmutableArray<byte> pdbBytes; ExpressionCompilerTestHelpers.EmitCorLibWithAssemblyReferences( compCorLib, pdbPath, moduleBuilder => new PEAssemblyBuilderWithAdditionalReferences(moduleBuilder, objectType), out peBytes, out pdbBytes); var symReader = SymReaderFactory.CreateReader(pdbBytes); using (var reader = new PEReader(peBytes)) { var metadata = reader.GetMetadata(); var module = metadata.ToModuleMetadata(ignoreAssemblyRefs: true); var metadataReader = metadata.ToMetadataReader(); var moduleInstance = ModuleInstance.Create(metadata, metadataReader.GetModuleVersionIdOrThrow(), symReader); // Verify the module declares System.Object. Assert.True(metadataReader.DeclaresTheObjectClass()); // Verify the PEModule has no assembly references. Assert.Equal(0, module.Module.ReferencedAssemblies.Length); // Verify the underlying metadata has the expected assembly references. var actualReferences = metadataReader.AssemblyReferences.Select(r => metadataReader.GetString(metadataReader.GetAssemblyReference(r).Name)).ToImmutableArray(); AssertEx.Equal(new[] { "mscorlib", "System.Private.Library" }, actualReferences); using (var runtime = RuntimeInstance.Create(new[] { moduleInstance })) { string error; var context = CreateMethodContext(runtime, "System.Object.F"); var testData = new CompilationTestData(); // Invalid import: "using N = A::Namespace;". context.CompileExpression( "new N.Private()", out error, testData); Assert.Equal("error CS0246: The type or namespace name 'N' could not be found (are you missing a using directive or an assembly reference?)", error); } } }
// Mimic what at least one version of at least one obfuscator has done to use the undocumented/non-standard extra-data flag. // If setFlag is false, do everything but setting the flag. private static unsafe byte[] ObfuscateWithExtraData(byte[] unobfuscated, bool setFlag = true) { int offsetToMetadata; int offsetToModuleTable; int offsetToMetadataSize; int tableStreamIndex = -1; StreamHeaderInfo[] streamHeaders; fixed (byte* ptr = unobfuscated) { using (var peReader = new PEReader(ptr, unobfuscated.Length)) { PEMemoryBlock metadata = peReader.GetMetadata(); offsetToMetadata = peReader.PEHeaders.MetadataStartOffset; offsetToMetadataSize = peReader.PEHeaders.CorHeaderStartOffset + 12; offsetToModuleTable = offsetToMetadata + peReader.GetMetadataReader().GetTableMetadataOffset(TableIndex.Module); // skip root header BlobReader blobReader = metadata.GetReader(); blobReader.ReadUInt32(); // signature blobReader.ReadUInt16(); // major version blobReader.ReadUInt16(); // minor version blobReader.ReadUInt32(); // reserved int versionStringSize = blobReader.ReadInt32(); blobReader.SkipBytes(versionStringSize); // read stream headers to collect offsets and sizes to adjust later blobReader.ReadUInt16(); // reserved int streamCount = blobReader.ReadInt16(); streamHeaders = new StreamHeaderInfo[streamCount]; for (int i = 0; i < streamCount; i++) { streamHeaders[i].OffsetToOffset = offsetToMetadata + blobReader.Offset; streamHeaders[i].Offset = blobReader.ReadInt32(); streamHeaders[i].OffsetToSize = offsetToMetadata + blobReader.Offset; streamHeaders[i].Size = blobReader.ReadInt32(); string name = blobReader.ReadUtf8NullTerminated(); if (name == "#~") { tableStreamIndex = i; } blobReader.Align(4); } } } const int sizeOfExtraData = 4; int offsetToTableStream = offsetToMetadata + streamHeaders[tableStreamIndex].Offset; int offsetToHeapSizeFlags = offsetToTableStream + 6; // copy unobfuscated to obfuscated, leaving room for 4 bytes of data right before the module table. byte[] obfuscated = new byte[unobfuscated.Length + sizeOfExtraData]; Array.Copy(unobfuscated, 0, obfuscated, 0, offsetToModuleTable); Array.Copy(unobfuscated, offsetToModuleTable, obfuscated, offsetToModuleTable + sizeOfExtraData, unobfuscated.Length - offsetToModuleTable); fixed (byte* ptr = obfuscated) { // increase size of metadata *(int*)(ptr + offsetToMetadataSize) += sizeOfExtraData; // increase size of table stream *(int*)(ptr + streamHeaders[tableStreamIndex].OffsetToSize) += sizeOfExtraData; // adjust offset of any streams that follow it for (int i = 0; i < streamHeaders.Length; i++) if (streamHeaders[i].Offset > streamHeaders[tableStreamIndex].Offset) *(int*)(ptr + streamHeaders[i].OffsetToOffset) += sizeOfExtraData; } // write non-zero "extra data" to make sure so that our assertion of leading Module.Generation == 0 // cannot succeed if extra data is interpreted as the start of the module table. for (int i = 0; i < sizeOfExtraData; i++) { obfuscated[offsetToModuleTable + i] = 0xCC; } if (setFlag) { // set the non-standard ExtraData flag indicating that these 4 bytes are present obfuscated[offsetToHeapSizeFlags] |= (byte)HeapSizes.ExtraData; } return obfuscated; }
public void CorLibWithAssemblyReferences() { string sourceLib = @"public class Private1 { } public class Private2 { }"; var compLib = CreateCompilationWithMscorlib(sourceLib, assemblyName: "System.Private.Library"); compLib.VerifyDiagnostics(); var refLib = compLib.EmitToImageReference(); string sourceCorLib = @"using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(Private2))] namespace System { public class Object { public Private1 F() => null; } #pragma warning disable 0436 public class Void : Object { } #pragma warning restore 0436 }"; // Create a custom corlib with a reference to compilation // above and a reference to the actual mscorlib. var compCorLib = CreateCompilation(sourceCorLib, assemblyName: CorLibAssemblyName, references: new[] { MscorlibRef, refLib }); compCorLib.VerifyDiagnostics(); var objectType = compCorLib.SourceAssembly.GlobalNamespace.GetMember<NamedTypeSymbol>("System.Object"); Assert.NotNull(objectType.BaseType); ImmutableArray<byte> peBytes; ImmutableArray<byte> pdbBytes; ExpressionCompilerTestHelpers.EmitCorLibWithAssemblyReferences( compCorLib, null, moduleBuilder => new PEAssemblyBuilderWithAdditionalReferences(moduleBuilder, objectType), out peBytes, out pdbBytes); using (var reader = new PEReader(peBytes)) { var metadata = reader.GetMetadata(); var module = metadata.ToModuleMetadata(ignoreAssemblyRefs: true); var metadataReader = metadata.ToMetadataReader(); var moduleInstance = ModuleInstance.Create(metadata, metadataReader.GetModuleVersionIdOrThrow()); // Verify the module declares System.Object. Assert.True(metadataReader.DeclaresTheObjectClass()); // Verify the PEModule has no assembly references. Assert.Equal(0, module.Module.ReferencedAssemblies.Length); // Verify the underlying metadata has the expected assembly references. var actualReferences = metadataReader.AssemblyReferences.Select(r => metadataReader.GetString(metadataReader.GetAssemblyReference(r).Name)).ToImmutableArray(); AssertEx.Equal(new[] { "mscorlib", "System.Private.Library" }, actualReferences); var source = @"class C { static void M() { } }"; var comp = CreateCompilation(source, options: TestOptions.DebugDll, references: new[] { refLib, AssemblyMetadata.Create(module).GetReference() }); comp.VerifyDiagnostics(); using (var runtime = RuntimeInstance.Create(new[] { comp.ToModuleInstance(), moduleInstance })) { string error; var context = CreateMethodContext(runtime, "C.M"); // Valid expression. var testData = new CompilationTestData(); context.CompileExpression( "new object()", out error, testData); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL( @"{ // Code size 6 (0x6) .maxstack 1 IL_0000: newobj ""object..ctor()"" IL_0005: ret }"); // Invalid expression: System.Int32 is not defined in corlib above. testData = new CompilationTestData(); context.CompileExpression( "1", out error, testData); Assert.Equal("error CS0518: Predefined type 'System.Int32' is not defined or imported", error); // Invalid expression: type in method signature from missing referenced assembly. testData = new CompilationTestData(); context.CompileExpression( "(new object()).F()", out error, testData); Assert.Equal("error CS0570: 'object.F()' is not supported by the language", error); // Invalid expression: type forwarded to missing referenced assembly. testData = new CompilationTestData(); context.CompileExpression( "new Private2()", out error, testData); Assert.Equal("error CS0246: The type or namespace name 'Private2' could not be found (are you missing a using directive or an assembly reference?)", error); } } }