有人向我提供了他需要进行逆向工程和替换的实用程序的源代码。代码中有很多赋值如下:
var a = checked(checked(checked((int)SomeArray.Length) - 1) + 1);
这是一些我不知道的设计模式,还是它反编译的方式
var a = SomeArray.Length;
答案 0 :(得分:1)
在为Array.Length
生成代码时,我从未知道C#编译器会发出额外的算术指令。在IL中,Array.Length
看起来像这样:
ldloc.1 // Assuming an array was stored in local slot 1
ldlen
即使在经过检查的情况下,这就是它的样子。现在,在IL中没有像C#中那样的已检查上下文。 IL只是检查了不同的算术指令(例如add.ovf
而不是add
)。
如果有人写了这样的代码:
int length = checked( array.Length - 1 + 1 );
发出的IL代码如下所示:
ldloc.1
ldlen
conv.i4
ldc.i4.1
sub.ovf
ldc.i4.1
add.ovf
stloc.2
如果反编译器将每个*.ovf
指令和conv.i4
指令视为具有自己的已检查上下文,则不会让我感到惊讶。阅读说明并逐步构建C#表达式将得到如下内容:
ldloc.1 // array
ldlen // array.Length
conv.i4 // checked( (int) array.Length )
ldc.i4.1
sub.ovf // checked( checked( (int) array.Length ) - 1 )
ldc.i4.1
add.ovf // checked( checked( checked( (int) array.Length ) - 1 ) + 1 )
stloc.2
答案 1 :(得分:0)
这就是我的想法。
这是因为C#编译器是有损的,'因为C#编译器会计算出数据类型转换之类的内容,然后将这些转换直接输出到它正在编写的DLL中。所有DLL都是用CIL编写的,它不像C#那样丰富,因此复杂的检查和构造被转换为更多但更简单的指令。
例如,C#具有lambda函数的思想,但CIL没有,所以C#编译器将生成一个带有方法的类,然后调用该方法。 E.g;
str => str.Length
变得类似
class DisplayClass234
{
public int Execute(string str)
{
return str.Length;
}
}
那么,如果您尝试反编译,Telerik会看到该类" DisplayClass234"而不是原来的lambda。
答案 2 :(得分:0)
如果JustDecompile有Kyle所描述的错误,我不会感到惊讶。我无法记得收到涉及checked
的任何支持请求,因此部分代码确实没有进行过良好的声音检查。
如果原始代码是checked(SomeArray.Length + 1 - 1)
,则编译器可能会取消1-1部分,因此它永远不会到达反编译器。
为什么不要求IL发表该声明并将其发布在此处?反编译它的人也应该能够获得IL。