有什么要求的反射API覆盖System.String.Empty的含义是什么? [英] What are the implications of asking Reflection APIs to overwrite System.String.Empty?

查看:117
本文介绍了有什么要求的反射API覆盖System.String.Empty的含义是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我偶然发现了这个code:

 静态无效的主要()
{
    typeof运算(字符串).GetField(空)的SetValue(NULL,神雕侠侣); //从DailyWTF

    Console.WriteLine(的String.Empty); //检查

    //它是如何表现?
    如果(神雕侠侣==的String.Empty)Console.WriteLine(相等);

    //输出:
    //邪恶
    //等于

 }
 

和我不知道是怎么回事,甚至可以通过编译这块code。我的理由是:

根据MSDN 的String.Empty 是只读的,因此更改它应该是不可能的,应编制与静态只读域不能被分配​​到或类似的错误结束

我还以为基类库组件以某种方式保护,并签署和诸如此类的东西,以prevent正是这种攻击。下一次,有人可能会改变System.Security.Cryptography或发生其他紧急类。

我还以为基类库组件由NGEN因此后安装.NET改变String类的字段应该需要先进的黑客和更难进行编译。

然而,这code编译和作品。有人可以请解释什么是错我的推理?

解决方案
  

一个静态只读字段不能被分配​​到

你并没有使用它。你调用了的System.Reflection 命名空间的公共职能。没有理由让编译器抱怨说。

此外, typeof运算(字符串).GetField(空)可以使用用户,而不是输入变量,没有法子的编译器告诉所有情况下,参数 getfield命令是否最终会被

我觉得你想要反射地看到,现场被标记 initonly 和扔在运行时错误。我可以看到你为什么会想到的是,却为白盒测试,甚至写入 initonly 领域具有一定的应用程序。

原因NGEN没有效果的是,你不修改任何code在这里,唯一的数据。数据存储在内存中的.NET就像任何其他语言。本机程序可以使用只读存储器部分对于像字符串常量,但字符串指针大致仍旧可写,这就是这里发生的一切。

请注意,您的code必须是具有完全信任的运行使用反射在这个有问题的方式。此外,变化只影响一个程序,这不是任何形式的安全漏洞,你似乎认为(如果你正在运行的进程中恶意code以完全信任,即设计决策是安全问题,不反射)。


另外需要注意的是对 initonly 领域内的 mscorlib.dll中的值是.NET运行时的全局变量。打破他们之后,你甚至不能可靠地测试不变是否被打破,因为code检查System.String.Empty的电流值也坏了,因为你已经侵犯了其不变量。开始违反制度不变,并没有什么可以依靠。

由内而外的.NET规范指定这些值,它使编译器来实现一大堆的性能优化。只需一个简单的是,

 取值== System.String.Empty
 

 (S!= NULL)及和放大器; (s.Length == 0)
 

是等效的,但后者的速度要快得多(相对而言)。

此外,编译器可以判断

 如果(int.Parse(S)> int.MaxValue)
 

是不正确的,并生成一个无条件跳转到else块(它仍然需要调用 Int32.Parse 有相同的异常行为,但比较能删除)。

System.String.Empty 也被广泛用于内BCL实现。如果您覆盖它,各种疯狂的事情都可能发生,包括泄漏你的程序之外的伤害(例如,你可以写一个文件,其名称中使用字符串操作建...当弦断,你可能会覆盖错误的文件)


和行为可能很容易.NET版本之间的差异。发现新的优化机会通常当,他们没有得到回迁到JIT编译器的previous版本(即使他们是,有可能是从反向移植实施前安装)。尤其是。 的String.Empty - 相关优化是.NET 2.x和单声道和.NET 4.5 +之间observably不同。

I stumbled upon this code:

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

 }

and I wonder how is it even possible to compile this piece of code. My reasoning is:

According to MSDN String.Empty is read-only therefore changing it should be impossible and compiling should end with "A static readonly field cannot be assigned to" or similar error.

I thought Base Class Library assemblies are somehow protected and signed and whatnot to prevent exactly this kind of attack. Next time someone may change System.Security.Cryptography or another critical class.

I thought Base Class Library assemblies are compiled by NGEN after .NET installation therefore changing fields of String class should require advanced hacking and be much harder.

And yet this code compiles and works. Can somebody please explain what is wrong with my reasoning?

解决方案

A static readonly field cannot be assigned to

You're not assigning to it. You're calling public functions in the System.Reflection namespace. No reason for the compiler to complain about that.

Besides, typeof(string).GetField("Empty") could use variables entered in by the user instead, there's no sure way for the compiler to tell in all cases whether the argument to GetField will end up being "Empty".

I think you're wanting Reflection to see that the field is marked initonly and throw an error at runtime. I can see why you would expect that, yet for white-box testing, even writing to initonly fields has some application.

The reason NGEN has no effect is that you're not modifying any code here, only data. Data is stored in memory with .NET just as with any other language. Native programs may use readonly memory sections for things like string constants, but the pointer to the string is generally still writable and that is what is happening here.

Note that your code must be running with full-trust to use reflection in this questionable way. Also, the change only affect one program, this isn't any sort of a security vulnerability as you seem to think (if you're running malicious code inside your process with full trust, that design decision is the security problem, not reflection).


Further note that the values of initonly fields inside mscorlib.dll are global invariants of the .NET runtime. After breaking them, you can't even reliably test whether the invariant was broken, because the code to inspect the current value of System.String.Empty has also broken, because you've violated its invariants. Start violating system invariants and nothing can be relied on.

By specifying these values inside the .NET specifications, it enables the compiler to implement a whole bunch of performance optimizations. Just a simple one is that

s == System.String.Empty

and

(s != null) && (s.Length == 0)

are equivalent, but the latter is much faster (relatively speaking).

Also the compiler can determine that

if (int.Parse(s) > int.MaxValue)

is never true, and generate an unconditional jump to the else block (it still has to call Int32.Parse to have the same exception behavior, but the comparison can be removed).

System.String.Empty is also used extensively inside BCL implementations. If you overwrite it, all sorts of crazy things can happen, including damage that leaks outside your program (for example you might write to a file whose name is built using string manipulation... when string breaks, you might overwrite the wrong file)


And the behavior might easily differ between .NET versions. Normally when new optimization opportunities are found, they don't get backported to previous versions of the JIT compiler (and even if they were, there could be installations from before the backport was implemented). In particular. String.Empty-related optimizations are observably different between .NET 2.x and Mono and .NET 4.5+.

这篇关于有什么要求的反射API覆盖System.String.Empty的含义是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆