为什么 ILSpy 在堆栈上而不是在指令上添加变量?
Why ILSpy is adding variables on stack instead of Instructions?
为什么 ILSpy 在堆栈上而不是在指令上添加变量?我的意思是,当推入或弹出 from/on 堆栈时,它会添加 Ldloc 和 Stloc 指令。谁能解释为什么它有这种行为?谢谢!
因为堆栈槽就像一个变量:它可以多次使用(例如在 if
的两个分支上),但是指令的效果只发生一次,当值被压入时堆栈。
使用指令堆栈的反编译器会有效地导致指令的副作用发生在从堆栈中弹出值的位置。这将是一个程序重新排序,可以巧妙地改变程序行为 -> 不正确的反编译。
原则上,在基本块中使用指令栈是可能的;但是当有控制流(传出或传入)或 dup
指令时,整个指令堆栈必须转换为变量堆栈。
目前,ILSpy ILReader
使用单通道(如 Ecma-335 规范中指定的那样),因此它不知道 ILReader
运行 期间的传入控制流,因此它必须总是使用一堆变量是安全的。
事实证明,这不是 .NET 框架读取 IL 字节码的方式,一些混淆器正在利用这种差异。所以在未来,我们可能会重写 ILReader
使其更像 .NET 字节码导入器,此时我们可能会转向混合变量堆栈+指令堆栈模型。 ILSpy issue #901
为什么 ILSpy 在堆栈上而不是在指令上添加变量?我的意思是,当推入或弹出 from/on 堆栈时,它会添加 Ldloc 和 Stloc 指令。谁能解释为什么它有这种行为?谢谢!
因为堆栈槽就像一个变量:它可以多次使用(例如在 if
的两个分支上),但是指令的效果只发生一次,当值被压入时堆栈。
使用指令堆栈的反编译器会有效地导致指令的副作用发生在从堆栈中弹出值的位置。这将是一个程序重新排序,可以巧妙地改变程序行为 -> 不正确的反编译。
原则上,在基本块中使用指令栈是可能的;但是当有控制流(传出或传入)或 dup
指令时,整个指令堆栈必须转换为变量堆栈。
目前,ILSpy ILReader
使用单通道(如 Ecma-335 规范中指定的那样),因此它不知道 ILReader
运行 期间的传入控制流,因此它必须总是使用一堆变量是安全的。
事实证明,这不是 .NET 框架读取 IL 字节码的方式,一些混淆器正在利用这种差异。所以在未来,我们可能会重写 ILReader
使其更像 .NET 字节码导入器,此时我们可能会转向混合变量堆栈+指令堆栈模型。 ILSpy issue #901