我偶然发现了这段代码:
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
}
而且我想知道如何编译这段代码。我的推理是:
根据 MSDN String.Empty
是只读的,因此应该不可能更改它并且编译应该以“无法分配静态只读字段”或类似错误结束。
我认为基类库程序集以某种方式受到保护和签名等等,以防止这种攻击。下次有人可能会更改 System.Security.Cryptography 或其他关键类。
我认为基类库程序集是在安装 .NET 后由 NGEN 编译的,因此更改 String 类的字段需要高级黑客技术,而且难度要大得多。
然而这段代码编译并工作。有人可以解释我的推理有什么问题吗?
最佳答案
A static readonly field cannot be assigned to
您没有分配给它。您在 System.Reflection
中调用公共(public)函数命名空间。编译器没有理由对此提示。
此外,typeof(string).GetField("Empty")
可以改用用户输入的变量,编译器没有确定的方法在所有情况下判断 GetField
的参数是否正确。最终会是 "Empty"
.
我想你想要 Reflection
看到该字段被标记为 initonly
并在运行时抛出错误。我明白你为什么会这样,但对于白盒测试,甚至写信给 initonly
领域有一些应用。
NGEN 没有效果的原因是您没有在此处修改任何代码,仅修改数据。与任何其他语言一样,.NET 将数据存储在内存中。 native 程序可能将只读内存部分用于诸如字符串常量之类的内容,但指向字符串的指针通常仍然是可写的,这就是这里发生的情况。
请注意,您的代码必须以完全信任的方式运行才能以这种有问题的方式使用反射。此外,更改仅影响一个程序,这并不是您所想的任何一种安全漏洞(如果您在完全信任的情况下在进程中运行恶意代码,则该设计决策是安全问题,而不是反射) .
进一步注意 initonly
的值里面的字段 mscorlib.dll
是 .NET 运行时的全局不变量。破坏它们之后,您甚至无法可靠地测试不变量是否被破坏,因为检查 System.String.Empty 当前值的代码也被破坏了,因为您违反了它的不变量。开始违反系统不变量,没有什么可以依赖。
通过在 .NET 规范中指定这些值,它使编译器能够实现一大堆性能优化。就一个简单的就是了
s == System.String.Empty
和
(s != null) && (s.Length == 0)
是等价的,但后者要快得多(相对而言)。
编译器也可以确定
if (int.Parse(s) > int.MaxValue)
永远不会为真,并生成到 else block 的无条件跳转(它仍然必须调用 Int32.Parse
才能具有相同的异常行为,但可以删除比较)。
System.String.Empty
在 BCL 实现中也被广泛使用。如果覆盖它,可能会发生各种疯狂的事情,包括泄漏到程序外部的损坏(例如,您可能会写入一个文件,该文件的名称是使用字符串操作构建的...当字符串中断时,你可能会覆盖错误的文件)
而且 .NET 版本之间的行为可能很容易不同。通常,当发现新的优化机会时,它们不会被反向移植到以前版本的 JIT 编译器(即使它们被反向移植,也可能存在反向移植实现之前的安装)。尤其是。 String.Empty
-相关的优化在 .NET 2.x 和 Mono 以及 .NET 4.5+ 之间明显不同。
关于c# - 要求反射 API 覆盖 System.String.Empty 的含义是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6293924/