C# 要求反射API覆盖System.String.Empty的含义是什么?
我偶然发现了以下代码:C# 要求反射API覆盖System.String.Empty的含义是什么?,c#,.net,reflection,C#,.net,Reflection,我偶然发现了以下代码: static void Main() { typeof(string).GetField("Empty").SetValue(null, "evil");//from DailyWTF Console.WriteLine(String.Empty);//check //how does it behave? if ("evil" == String.Empty) Console.WriteLine("equal"); //o
static void Main()
{
typeof(string).GetField("Empty").SetValue(null, "evil");//from DailyWTF
Console.WriteLine(String.Empty);//check
//how does it behave?
if ("evil" == String.Empty) Console.WriteLine("equal");
//output:
//evil
//equal
}
我想知道如何编译这段代码。我的理由是:
根据MSDNString。Empty
是只读的,因此不可能对其进行更改,编译应以“无法分配静态只读字段”或类似错误结束
我认为基类库程序集在某种程度上受到保护和签名等等,以防止这种攻击。下次有人可能会更改System.Security.Cryptography或其他关键类
我认为基类库程序集是在.NET安装后由NGEN编译的,因此更改字符串类的字段应该需要高级的黑客攻击,而且要困难得多
但这段代码可以编译并运行。谁能解释一下我的推理有什么问题吗?反射可以让你无视物理定律做任何事情。您甚至可以设置私有成员的值
反射不遵循规则
另一个例子:
如果您使用的是web应用程序,则可以设置 ,在“中等信任”下,您可以限制反射访问 编辑:不要运行完全信任以外的web应用程序,这是ASP.NET团队的直接建议。要保护您的应用程序,请为每个网站创建一个应用程序池
此外,不建议对所有内容都使用反射。它有正确的使用地点和时间 无法将静态只读字段分配给 你没有分配给它。您正在
System.Reflection
命名空间中调用公共函数。编译器没有理由对此抱怨
此外,typeof(string).GetField(“Empty”)
可以使用用户输入的变量,编译器无法确定在所有情况下,GetField
的参数是否最终都是的“Empty”
我认为您希望Reflection
看到字段标记为initonly
,并在运行时抛出错误。我可以理解为什么您会期望这样,但是对于白盒测试,即使是写入initonly
字段也有一些应用程序
NGEN不起作用的原因是这里没有修改任何代码,只有数据。与任何其他语言一样,使用.NET将数据存储在内存中。本机程序可能会对字符串常量之类的内容使用只读内存部分,但字符串指针通常仍然是可写的,这就是这里发生的情况
请注意,您的代码必须以完全信任的方式运行,才能以这种可疑的方式使用反射。此外,更改只影响一个程序,这并不像您认为的那样是一种安全漏洞(如果您在进程中完全信任地运行恶意代码,那么设计决策是安全问题,而不是反射)
进一步注意,
mscorlib.dll
中的initonly
字段的值是.NET运行时的全局不变量。在破坏它们之后,您甚至无法可靠地测试不变量是否被破坏,因为检查System.String.Empty当前值的代码也被破坏了,因为您违反了它的不变量。开始违反系统不变量,任何东西都不可靠
通过在.NET规范中指定这些值,编译器可以实现一系列性能优化。一个简单的问题是
s == System.String.Empty
及
两者相当,但后者要快得多(相对而言)
编译器还可以确定
if (int.Parse(s) > int.MaxValue)
从不为true,并生成到else块的无条件跳转(它仍然必须调用Int32.Parse
以具有相同的异常行为,但可以删除比较)
System.String.Empty
在BCL实现中也被广泛使用。如果覆盖它,可能会发生各种疯狂的事情,包括泄漏到程序外部的损坏(例如,您可能会写入一个文件,该文件的名称是使用字符串操作生成的……当字符串中断时,您可能会覆盖错误的文件)
而且.NET版本之间的行为可能很容易有所不同。通常,当发现新的优化机会时,它们不会被后传到JIT编译器的早期版本(即使它们被后传,也可能在实现后传之前进行安装)。特别是
String.Empty
-与.NET 2.x和Mono以及.NET 4.5+相关的优化明显不同。只读是唯一强制的
在编译器级别
所以
可以在当前级别下更改代码编译,因为代码的每一行都是完全合法的。您认为哪一行应该是语法错误?这里没有指定给只读字段的代码行。有一行代码调用一个反射方法,分配给只读字段,但已经编译好了,最终破坏安全性的东西甚至没有用C语言编写,它是用C++编写的。它是运行时引擎本身的一部分 代码成功运行,因为完全信任意味着完全信任。您正在完全信任的环境中运行代码,并且由于完全信任意味着完全信任,所以运行时假设您知道您在做这件愚蠢的危险事情时在做什么 如果您尝试在部分受信任的环境中运行代码,那么您将看到反射抛出“您不允许这样做”异常 是的,集会是有签名的等等。如果您运行的是完全信任的代码,那么当然,他们可以随心所欲地处理这些程序集这就是完全信任的含义。部分信任的代码不能做到这一点,但完全信任的代码可以做到这一点
(s != null) && (s.Length == 0)
if (int.Parse(s) > int.MaxValue)
evil
equal