在c#中分配引用时添加神秘调用

seb*_*bas 5 c# assembly native-code

我知道其他人写了类似的问题,但我认为我的情况不同,因为我找不到任何解决方案.

我有一个对象赋值,这个非常简单:

_buffer3 = buffer; //they are just simple reference types
Run Code Online (Sandbox Code Playgroud)

生成的汇编代码如下

 mov         edx,dword ptr [ebp-3Ch] 
 mov         eax,dword ptr [ebp-40h] 
 lea         edx,[edx+4] 
 call        69C322F0 
Run Code Online (Sandbox Code Playgroud)

现在,只是为了理解发生了什么,我想进入呼叫(为什么要在分配中使用呼叫?).但是,该地址的代码不存在,我无法介入.如果我在地址代码字段中键入地址,那就是显示的内容:

69C322F0  ???  
Run Code Online (Sandbox Code Playgroud)

试图解决这个问题的任何帮助?:)

编辑..显然,当在类的方法内分配引用时,会添加神秘的调用.

如果我有这个课程:

        private class Test
        {
            int _X;
            int _Y;
            Test _t;

            public void SetValues(int x, int y, Test t)
            {
                _X = x;
                _Y = y;
            }
        }
Run Code Online (Sandbox Code Playgroud)

为方法SetValues生成的程序集是:

                _X = x;
00000028  mov         eax,dword ptr [ebp-3Ch] 
0000002b  mov         edx,dword ptr [ebp-40h] 
0000002e  mov         dword ptr [eax+8],edx 
                _Y = y;
00000031  mov         eax,dword ptr [ebp-3Ch] 
00000034  mov         edx,dword ptr [ebp+0Ch] 
00000037  mov         dword ptr [eax+0Ch],edx 
Run Code Online (Sandbox Code Playgroud)

这是有道理的

但是,如果我写这个

        private class Test
        {
            int _X;
            int _Y;
            Test _t;

            public void SetValues(int x, int y, Test t)
            {
                _X = x;
                _Y = y;
                _t = t;
            }
        }
Run Code Online (Sandbox Code Playgroud)

神秘的电话出现了

                _X = x;
00000028  mov         eax,dword ptr [ebp-3Ch] 
0000002b  mov         edx,dword ptr [ebp-40h] 
0000002e  mov         dword ptr [eax+8],edx 
                _Y = y;
00000031  mov         eax,dword ptr [ebp-3Ch] 
00000034  mov         edx,dword ptr [ebp+0Ch] 
00000037  mov         dword ptr [eax+0Ch],edx 
                _t = t;
0000003a  mov         edx,dword ptr [ebp-3Ch] 
0000003d  mov         eax,dword ptr [ebp+8] 
00000040  lea         edx,[edx+4] 
00000043  call        515E2E48 
Run Code Online (Sandbox Code Playgroud)

恕我直言,它与垃圾收集有关,但我无法理解它是什么,我真的想弄明白.我知道有人必须知道:)

答案的附录,这是我通过C#从书籍CLR中获取的摘录:

这是我从本书的Google Books中摘录的:CLR来自C#

Han*_*ant 6

我会稍微讨论一下这个问题,一个完整的答案可以写满一本书,让每个人都入睡。您得到的机器代码视图非常不准确,32 位反汇编器在转换 CALL 地址方面做得非常糟糕。如果您查看 64 位代码,那么在最近的 VS 版本中,这一点已经有了很大的改进,它不再伪造机器代码指令的地址。到达那里:

  • 项目 > 属性 > 构建选项卡:平台目标 = AnyCPU,取消选中“首选 32 位”
  • 项目>属性>调试选项卡:勾选“启用本机代码调试”
  • 工具 > 选项 > 调试 > 符号:启用 Microsoft 符号服务器
  • 工具 > 选项 > 调试 > 常规:取消选中“抑制 JIT 优化”。

仅当您想查看真实的机器代码(即在用户计算机上运行的代码)时,才需要更改最后的设置。请注意,您现在正在查看未优化的调试代码。与这个问题无关。

这很好地照亮了反汇编器,尽管它仍然远非理想。Test.SetValues() 方法的尾部现在如下所示:

                _t = t;
00007FFA1ECB0C58  mov         rdx,qword ptr [rbp+50h]  
00007FFA1ECB0C5C  lea         rcx,[rdx+8]  
00007FFA1ECB0C60  mov         rdx,qword ptr [rbp+68h]  
00007FFA1ECB0C64  call        JIT_WriteBarrier (07FFA7E3312B0h)  
Run Code Online (Sandbox Code Playgroud)

现在显示的地址是准确的,0x07FFA7E3312B0。查看该代码需要一个额外的步骤,您必须强制调试器进入本机模式。调试 > Windows > 调用堆栈,然后双击跟踪底部的本机函数,例如 RtlUserThreadStart。现在您可以将“07FFA7E3312B0”复制/粘贴到反汇编器的地址框中,首先输入“0x”。我不会在这里展示它,这是手写的汇编代码,它做了一件相当神秘的事情,你永远无法从代码中进行逆向工程。

寻找这些抖动辅助函数的更好位置是源代码,尽管它不完全匹配,但github CoreCLR 项目是您最好的选择。带你来这里

一般来说,抖动会根据需要发出此类直接 CLR 函数调用,它们的名称通常以“JIT”开头。这个恰好是用汇编编写的,但并不常见;大多数是用 C++ 编写的。