public void InjectFromCecilSecurityAttributeDefinitions() { var assembly = AssemblyCompiler.CompileTempAssembly(@" class Foo { public void CriticalMethod() {} public void Bar(int value) {} public void Bar(string value) {} public void SafeCriticalMethod() {} public Foo(string value) {} } class CriticalType { } " ); var finder = new CecilDefinitionFinder(assembly); var safecriticalmethod = finder.FindMethod("System.Void Foo::SafeCriticalMethod()"); var criticalmethod = finder.FindMethod("System.Void Foo::CriticalMethod()"); var criticaltype = finder.FindType("CriticalType"); var instructions = new List <CecilSecurityAttributeDescriptor>() { new CecilSecurityAttributeDescriptor(criticalmethod, SecurityAttributeType.Critical), new CecilSecurityAttributeDescriptor(safecriticalmethod, SecurityAttributeType.SafeCritical), new CecilSecurityAttributeDescriptor(criticaltype, SecurityAttributeType.Critical), }; var injector = new Injector(assembly); injector.InjectAll(instructions); new AssemblySecurityVerifier(assembly.AssemblyPath()).Verify(instructions); }
public void SetUp() { var executingAssemblyDefinition = CecilUtilsForTests.GetExecutingAssemblyDefinition(); _finder = new CecilDefinitionFinder(executingAssemblyDefinition); _subject = new MethodMap(_finder.FindType(GetType().FullName)); }
public void InjectFromCecilSecurityAttributeDefinitions() { var assembly = AssemblyCompiler.CompileTempAssembly(@" class Foo { public void CriticalMethod() {} public void Bar(int value) {} public void Bar(string value) {} public void SafeCriticalMethod() {} public Foo(string value) {} } class CriticalType { } "); var finder = new CecilDefinitionFinder(assembly); var safecriticalmethod = finder.FindMethod("System.Void Foo::SafeCriticalMethod()"); var criticalmethod = finder.FindMethod("System.Void Foo::CriticalMethod()"); var criticaltype = finder.FindType("CriticalType"); var instructions = new List<CecilSecurityAttributeDescriptor>() { new CecilSecurityAttributeDescriptor(criticalmethod,SecurityAttributeType.Critical), new CecilSecurityAttributeDescriptor(safecriticalmethod,SecurityAttributeType.SafeCritical), new CecilSecurityAttributeDescriptor(criticaltype, SecurityAttributeType.Critical), }; var injector = new Injector(assembly); injector.InjectAll(instructions); new AssemblySecurityVerifier(assembly.AssemblyPath()).Verify(instructions); }
public void FindGenericMethod() { var assembly = CecilUtilsForTests.GetExecutingAssemblyDefinition(); var finder = new CecilDefinitionFinder(assembly); var found = finder.FindMethod(string.Format("System.Void {0}::GenericMethod<T>(T&)", GetType().FullName)); Assert.IsNotNull(found); }
private static IEnumerable <TypeDefinition> CriticalTypesFor(AssemblyDefinition assemblyDefinition, string profileDirectory) { string assemblyName = assemblyDefinition.Name.Name; var cdf = new CecilDefinitionFinder(assemblyDefinition); var file = Files.CriticalTypesFileFor(assemblyName, profileDirectory); if (!File.Exists(file)) { return(new TypeDefinition[0]); } return(File.ReadAllLines(file) .Select(s => cdf.GetType(s)).Where(t => t != null)); }
private void AssertMethodRoundtrip(Func <int> func) { var method = func.Method; var assembly = CecilUtilsForTests.GetExecutingAssemblyDefinition(); var finder = new CecilDefinitionFinder(assembly); // cecil uses / to introduce nested types, the runtime uses + var declaringTypeCecilName = method.DeclaringType.CecilTypeName(); var type = finder.FindType(declaringTypeCecilName); Assert.IsNotNull(type, "Type {0} not found!", declaringTypeCecilName); var actualDefinition = type.Methods.GetMethod(method.Name)[0]; var signature = SignatureFor(actualDefinition); Assert.AreSame(actualDefinition, finder.FindMethod(signature)); }
private static IEnumerable <MethodToMethodCall> ReadMethodToMethodCallsFromFile(IEnumerable <AssemblyDefinition> assemblies, string file) { if (!File.Exists(file)) { yield break; } foreach (var line in File.ReadAllLines(file)) { if (line.StartsWith("#")) { continue; } if (line.Trim().Length == 0) { continue; } var splitter = "=>"; int i = line.IndexOf(splitter); if (i == -1) { throw new ApplicationException("illegal line found in " + file + " was: " + line); } var caller = line.Substring(0, i).Trim(); var callee = line.Substring(i + splitter.Length).Trim(); var cecilDefinitionFinder = new CecilDefinitionFinder(assemblies); var mcaller = cecilDefinitionFinder.FindMethod(caller); if (mcaller == null) { throw new ApplicationException("couldnt find method while parsing " + file + " signarture: " + caller); } var mcallee = cecilDefinitionFinder.FindMethod(callee); if (mcallee == null) { throw new ApplicationException("couldnt find method while parsing " + file + " signarture: " + callee); } yield return(new MethodToMethodCall(mcaller, mcallee)); } }
private AssemblyDefinition PrepareTestForAssembly(string code, params string[] references) { _assembly = AssemblyCompiler.CompileTempAssembly(@" using System; using System.IO; using System.Runtime.CompilerServices;" + code + @" public static class Evil { [MethodImpl(MethodImplOptions.InternalCall)] public static void Do() { } } ", references); _cdf = new CecilDefinitionFinder(_assembly); _evilDo = _cdf.FindMethod("System.Void Evil::Do()"); return(_assembly); }
public void TwoAssembliesWithCriticalType() { var assembly1 = AssemblyCompiler.CompileTempAssembly(@" public interface IMyEnumerator { void M1(); }"); var assembly2 = PrepareTestForAssembly(@" public class CriticalType : IMyEnumerator { public void M1() { Evil.Do(); } } ", assembly1.AssemblyPath()); var finderForAssembly2 = new CecilDefinitionFinder(assembly2); var evilDo = finderForAssembly2.FindMethod("System.Void Evil::Do()"); var criticaltype = finderForAssembly2.FindType("CriticalType"); var assemblies = new[] { assembly1, assembly2 }; var propagation = new MethodPrivilegePropagation(assemblies, new[] { evilDo }, new MethodDefinition[] { }, new[] { criticaltype }, new List <MethodToMethodCall>()); var report = propagation.CreateReportBuilder().Build(); CollectionAssert.IsEmpty(report.GetInjectionsFor(assembly1)); var injections = report.GetInjectionsFor(assembly2); var expected = new[] { new CecilSecurityAttributeDescriptor(criticaltype, SecurityAttributeType.Critical), new CecilSecurityAttributeDescriptor(evilDo, SecurityAttributeType.Critical) }; CollectionAssert.AreEquivalent(expected, injections); }
private AssemblyDefinition PrepareTestForAssembly(string code, params string[] references) { _assembly = AssemblyCompiler.CompileTempAssembly(@" using System; using System.IO; using System.Runtime.CompilerServices;" +code+ @" public static class Evil { [MethodImpl(MethodImplOptions.InternalCall)] public static void Do() { } } ", references); _cdf = new CecilDefinitionFinder(_assembly); _evilDo = _cdf.FindMethod("System.Void Evil::Do()"); return _assembly; }
public void TwoAssembliesWithCriticalType() { var assembly1 = AssemblyCompiler.CompileTempAssembly(@" public interface IMyEnumerator { void M1(); }"); var assembly2 = PrepareTestForAssembly(@" public class CriticalType : IMyEnumerator { public void M1() { Evil.Do(); } } ", assembly1.AssemblyPath()); var finderForAssembly2 = new CecilDefinitionFinder(assembly2); var evilDo = finderForAssembly2.FindMethod("System.Void Evil::Do()"); var criticaltype = finderForAssembly2.FindType("CriticalType"); var assemblies = new[] { assembly1, assembly2 }; var propagation = new MethodPrivilegePropagation(assemblies, new[] { evilDo }, new MethodDefinition[] { }, new[] { criticaltype }, new List<MethodToMethodCall>()); var report = propagation.CreateReportBuilder().Build(); CollectionAssert.IsEmpty(report.GetInjectionsFor(assembly1)); var injections = report.GetInjectionsFor(assembly2); var expected = new[] { new CecilSecurityAttributeDescriptor(criticaltype, SecurityAttributeType.Critical), new CecilSecurityAttributeDescriptor(evilDo, SecurityAttributeType.Critical) }; CollectionAssert.AreEquivalent(expected, injections); }
public void Test() { // Step 1 - Step1: Detect methods that will fail at runtime if they're not [SC] or [SSC] const string requiresPrivilegesManual = @" System.Object Foo::Bar(System.Int32) "; var assembly1 = CompileTempAssembly(@" public class Foo { public static object Bar(int i) { return null; } } public class A { public unsafe void M1(int* i) {} public void M2() { Foo.Bar(0); } public void M3() { } public void M4() { M2(); } public unsafe void M5(int* i) { M1(i); } } unsafe public class CriticalType1 : I1 { int* a; public void M6() { Foo.Bar(3); } } public interface I1 { void M6(); } public interface I2 { void NotImplemented(); } "); var assembly2 = CompileTempAssembly(@" using System.Runtime.CompilerServices; public class B : I1 { public void M1() { Foo.Bar(0); } [MethodImpl(MethodImplOptions.InternalCall)] public extern void M2(); [MethodImpl(MethodImplOptions.InternalCall)] internal extern void M3(); [MethodImpl(MethodImplOptions.InternalCall)] public extern void M4(); public void M5() { M4(); } public void M6() { M1(); } } ", assembly1.MainModule.Image.FileInformation.FullName); var expectedRequiresPrivileges = new[] { @"# This file has a list of methods that were automatically detected to require privileges ([sc] or [ssc]) # in order to not generate an exception at runtime. # using 'System.Int32*' as a parameter type System.Void A::M1(System.Int32*) # using 'System.Int32*' as a parameter type System.Void A::M5(System.Int32*)", @"# This file has a list of methods that were automatically detected to require privileges ([sc] or [ssc]) # in order to not generate an exception at runtime. # internal call System.Void B::M2() # internal call System.Void B::M3() # internal call System.Void B::M4()".Replace("\n", "\r\n") }; var assemblies = new[] { assembly1, assembly2 }; AssemblySetResolver.SetUp(assemblies); var cdf = new CecilDefinitionFinder(assembly1); var criticalTypes = new[] { cdf.GetType("CriticalType1") }; var actualRequiresPrivileges = DetectMethodsRequiringPrivileges(criticalTypes, assemblies); Assert.AreEqual(expectedRequiresPrivileges, actualRequiresPrivileges.ToArray()); // Step 2 - "Floodfill" requiredprivileges methods to all their callers, only being stopped by [SSC] var canBeSscManual = new[] { // assembly1 Compatibility.ParseMoonlightAuditFormat(@" !SSC-AA4CC9592C6775C5327AAA826B6693FF System.Void A::M2() lucas - I checked this, it's totally safe" ), // assembly2 Compatibility.ParseMoonlightAuditFormat(@" !SSC-AA4CC9592C6775C5327AAA826B6693FF System.Void B::M2() lucas - I checked this, it's totally safe" ) }; /* * publicApis -> shows for each public entry point wether it's going to be [SC] or not. for each [SC] method. * injectionInstructions -> all methods (public/nonpublic) that require decoration go in here. */ actualRequiresPrivileges[0] += requiresPrivilegesManual; var propagationReport = PropagateRequiredPrivileges(criticalTypes, canBeSscManual, actualRequiresPrivileges.ToArray(), assembly1, assembly2); const string expectedInjectionInstructions = @" SC-M: System.Object Foo::Bar(System.Int32) SC-M: System.Void A::M1(System.Int32*) SC-M: System.Void A::M5(System.Int32*) SSC-M: System.Void A::M2() SC-M: System.Void B::M1() SSC-M: System.Void B::M2() SC-M: System.Void B::M3() SC-M: System.Void B::M4() SC-M: System.Void B::M5() SC-M: System.Void B::M6() SC-M: System.Void I1::M6() SC-T: CriticalType1 "; StringAssert.AssertLinesAreEquivalent(expectedInjectionInstructions, propagationReport.InjectionInstructions); const string expectedPublicApis = @" System.Void A::.ctor() #available System.Void A::M2() #available System.Void A::M3() #available System.Void A::M4() #available System.Void A::M5(System.Int32*) #unavailable: method itself requires privileges System.Void B::.ctor() #available System.Void B::M2() #available System.Void Foo::.ctor() #available System.Void I2::NotImplemented() #available System.Void A::M1(System.Int32*) #unavailable: method itself requires privileges System.Void B::M1() #unavailable: calls System.Object Foo::Bar(System.Int32) which requires privileges itself System.Void B::M4() #unavailable: method itself requires privileges System.Void B::M5() #unavailable: calls System.Void B::M4() which requires privileges itself System.Void B::M6() #unavailable: calls System.Void B::M1() which calls System.Object Foo::Bar(System.Int32) which requires privileges itself System.Object Foo::Bar(System.Int32) #unavailable: method itself requires privileges System.Void I1::M6() #unavailable: is the base method of System.Void B::M6() which calls System.Void B::M1() which calls System.Object Foo::Bar(System.Int32) which requires privileges itself System.Void CriticalType1::.ctor() #unavailable: lives in a critical type System.Void CriticalType1::M6() #unavailable: lives in a critical type "; Console.WriteLine(propagationReport.PublicApis); StringAssert.AssertLinesAreEquivalent(expectedPublicApis, propagationReport.PublicApis); }
public void Test() { var asssembly1src = @" using System; using System.Runtime.CompilerServices; public class A { public void Fine() {} unsafe public void NotFine(IntPtr* a) {} } unsafe public class B { IntPtr* bad; public void Fine() {} public void AlsoFine(IntPtr* a) {} [MethodImpl(MethodImplOptions.InternalCall)] public extern void AlsoFine2(); } public class C { public void NotFine(B b) {} public void Fine() {} } public class SubB : B { } public class D { SubB b; } public class E { public void NotFine(D d) {} } "; var assembly = CSharpCompiler.CompileTempAssembly(asssembly1src); var ad = AssemblyFactory.GetAssembly(assembly); var cdf = new CecilDefinitionFinder(ad); MethodPrivilegeDetector.CriticalTypes = new[] { "B", "SubB", "D", }.Select(s => cdf.FindType(s)).Cast<TypeReference>().ToList(); var results = MethodPrivilegeDetector.MethodsRequiringPrivilegesThemselvesOn(ad).Select(kvp => kvp.Key); var expectedresults = new[] { "System.Void A::NotFine(System.IntPtr*)", "System.Void C::NotFine(B)", "System.Void E::NotFine(D)", }.Select(s => cdf.FindMethod(s)); CollectionAssert.AreEquivalent(expectedresults.ToArray(),results.ToArray()); }
public void Test() { // Step 1 - Step1: Detect methods that will fail at runtime if they're not [SC] or [SSC] const string requiresPrivilegesManual = @" System.Object Foo::Bar(System.Int32) "; var assembly1 = CompileTempAssembly(@" public class Foo { public static object Bar(int i) { return null; } } public class A { public unsafe void M1(int* i) {} public void M2() { Foo.Bar(0); } public void M3() { } public void M4() { M2(); } public unsafe void M5(int* i) { M1(i); } } unsafe public class CriticalType1 : I1 { int* a; public void M6() { Foo.Bar(3); } } public interface I1 { void M6(); } public interface I2 { void NotImplemented(); } "); var assembly2 = CompileTempAssembly(@" using System.Runtime.CompilerServices; public class B : I1 { public void M1() { Foo.Bar(0); } [MethodImpl(MethodImplOptions.InternalCall)] public extern void M2(); [MethodImpl(MethodImplOptions.InternalCall)] internal extern void M3(); [MethodImpl(MethodImplOptions.InternalCall)] public extern void M4(); public void M5() { M4(); } public void M6() { M1(); } } ", assembly1.MainModule.Image.FileInformation.FullName); var expectedRequiresPrivileges = new[] { @"# This file has a list of methods that were automatically detected to require privileges ([sc] or [ssc]) # in order to not generate an exception at runtime. # using 'System.Int32*' as a parameter type System.Void A::M1(System.Int32*) # using 'System.Int32*' as a parameter type System.Void A::M5(System.Int32*)", @"# This file has a list of methods that were automatically detected to require privileges ([sc] or [ssc]) # in order to not generate an exception at runtime. # internal call System.Void B::M2() # internal call System.Void B::M3() # internal call System.Void B::M4()".Replace("\n","\r\n") }; var assemblies = new[] { assembly1, assembly2 }; AssemblySetResolver.SetUp(assemblies); var cdf = new CecilDefinitionFinder(assembly1); var criticalTypes = new[] { cdf.GetType("CriticalType1") }; var actualRequiresPrivileges = DetectMethodsRequiringPrivileges(criticalTypes, assemblies); Assert.AreEqual(expectedRequiresPrivileges, actualRequiresPrivileges.ToArray()); // Step 2 - "Floodfill" requiredprivileges methods to all their callers, only being stopped by [SSC] var canBeSscManual = new[] { // assembly1 Compatibility.ParseMoonlightAuditFormat(@" !SSC-AA4CC9592C6775C5327AAA826B6693FF System.Void A::M2() lucas - I checked this, it's totally safe"), // assembly2 Compatibility.ParseMoonlightAuditFormat(@" !SSC-AA4CC9592C6775C5327AAA826B6693FF System.Void B::M2() lucas - I checked this, it's totally safe") }; /* * publicApis -> shows for each public entry point wether it's going to be [SC] or not. for each [SC] method. * injectionInstructions -> all methods (public/nonpublic) that require decoration go in here. */ actualRequiresPrivileges[0] += requiresPrivilegesManual; var propagationReport = PropagateRequiredPrivileges(criticalTypes, canBeSscManual, actualRequiresPrivileges.ToArray(), assembly1, assembly2); const string expectedInjectionInstructions = @" SC-M: System.Object Foo::Bar(System.Int32) SC-M: System.Void A::M1(System.Int32*) SC-M: System.Void A::M5(System.Int32*) SSC-M: System.Void A::M2() SC-M: System.Void B::M1() SSC-M: System.Void B::M2() SC-M: System.Void B::M3() SC-M: System.Void B::M4() SC-M: System.Void B::M5() SC-M: System.Void B::M6() SC-M: System.Void I1::M6() SC-T: CriticalType1 "; StringAssert.AssertLinesAreEquivalent(expectedInjectionInstructions, propagationReport.InjectionInstructions); const string expectedPublicApis = @" System.Void A::.ctor() #available System.Void A::M2() #available System.Void A::M3() #available System.Void A::M4() #available System.Void A::M5(System.Int32*) #unavailable: method itself requires privileges System.Void B::.ctor() #available System.Void B::M2() #available System.Void Foo::.ctor() #available System.Void I2::NotImplemented() #available System.Void A::M1(System.Int32*) #unavailable: method itself requires privileges System.Void B::M1() #unavailable: calls System.Object Foo::Bar(System.Int32) which requires privileges itself System.Void B::M4() #unavailable: method itself requires privileges System.Void B::M5() #unavailable: calls System.Void B::M4() which requires privileges itself System.Void B::M6() #unavailable: calls System.Void B::M1() which calls System.Object Foo::Bar(System.Int32) which requires privileges itself System.Object Foo::Bar(System.Int32) #unavailable: method itself requires privileges System.Void I1::M6() #unavailable: is the base method of System.Void B::M6() which calls System.Void B::M1() which calls System.Object Foo::Bar(System.Int32) which requires privileges itself System.Void CriticalType1::.ctor() #unavailable: lives in a critical type System.Void CriticalType1::M6() #unavailable: lives in a critical type "; Console.WriteLine(propagationReport.PublicApis); StringAssert.AssertLinesAreEquivalent(expectedPublicApis, propagationReport.PublicApis); }
public void Test() { var asssembly1src = @" using System; using System.Runtime.CompilerServices; public class A { public void Fine() {} unsafe public void NotFine(IntPtr* a) {} } unsafe public class B { IntPtr* bad; public void Fine() {} public void AlsoFine(IntPtr* a) {} [MethodImpl(MethodImplOptions.InternalCall)] public extern void AlsoFine2(); } public class C { public void NotFine(B b) {} public void Fine() {} } public class SubB : B { } public class D { SubB b; } public class E { public void NotFine(D d) {} } "; var assembly = CSharpCompiler.CompileTempAssembly(asssembly1src); var ad = AssemblyFactory.GetAssembly(assembly); var cdf = new CecilDefinitionFinder(ad); MethodPrivilegeDetector.CriticalTypes = new[] { "B", "SubB", "D", }.Select(s => cdf.FindType(s)).Cast <TypeReference>().ToList(); var results = MethodPrivilegeDetector.MethodsRequiringPrivilegesThemselvesOn(ad).Select(kvp => kvp.Key); var expectedresults = new[] { "System.Void A::NotFine(System.IntPtr*)", "System.Void C::NotFine(B)", "System.Void E::NotFine(D)", }.Select(s => cdf.FindMethod(s)); CollectionAssert.AreEquivalent(expectedresults.ToArray(), results.ToArray()); }