.net 为什么可以';在调试/反汇编期间,我是否单步执行调用指令?
分解过程如下所示:.net 为什么可以';在调试/反汇编期间,我是否单步执行调用指令?,.net,x86-64,cil,reflection.emit,disassembly,.net,X86 64,Cil,Reflection.emit,Disassembly,分解过程如下所示: methShort( ref x, ref y ); 000007FF00163F67 lea r8,[rsp+34h] 000007FF00163F6C lea rdx,[rsp+30h] 000007FF00163F71 mov rcx,qword ptr [rsp+20h] 000007FF00163F76 mov rcx,qword ptr [rcx+8
methShort( ref x, ref y );
000007FF00163F67 lea r8,[rsp+34h]
000007FF00163F6C lea rdx,[rsp+30h]
000007FF00163F71 mov rcx,qword ptr [rsp+20h]
000007FF00163F76 mov rcx,qword ptr [rcx+8]
000007FF00163F7A mov rax,qword ptr [rsp+20h]
000007FF00163F7F call qword ptr [rax+18h]
方法“methShort”是在.NET中使用Reflection.Emit动态创建的。它将两个Int32参数作为“byRef”值。这将作为“发布模式”版本进行调试
我可以一步一步地完成组装,直到“调用”指令。R8和RDX(参数)指向的内存内容看起来很好。我不知道是什么样的魔法允许JIT使用寄存器来调用而不是堆栈,但这不是重点
当我尝试“单步执行”call指令时,调试器将“单步执行”该指令。确实调用了例程-该方法正确地执行了其功能。但我似乎无法分解,也无法进入方法
在调用之前的一点上,RAX包含值000000000 25C67A8H。当向该地址添加18h时,间接寻址的地址变为000000000 25C67C0H。此地址的QWORD为00000000 1B64DC48H
如果我尝试反汇编此地址(00000000 1B64DC48H),调试器将返回“无法显示指定的地址。在提供的位置没有代码”
作为一次万岁的尝试,我尝试在RAX上无需间接地反汇编代码,但正如我预期的那样,这也失败了
有谁能告诉我如何访问地址中的任何代码,或者在分解地址中的代码之前是否需要对地址(RAX+18h)执行类似LEA的操作?您需要记住,调试器正试图避免浪费您数小时的生命
methShort()
是一个委托调用,在该调用完成之前还需要做很多工作。您将不会喜欢单步执行将动态方法编译为机器代码、CAS检查链接请求、CLR创建代理存根并将其绑定到调用站点的过程
我将回答发布的问题,调试器不会向您显示调用目标代码,因为它是非托管代码。您可以从地址中看出,它远离jitted代码的位置。要让它相信你想看到它,需要几个技巧:
- 项目+属性,调试选项卡,勾选“启用本机代码调试”选项
- 您必须将调试器从托管模式切换到非托管模式。没有明确的命令,最简单的方法就是使用调用堆栈窗口。双击底部框架(__RtlUserThreadStart@8)
- 单击源代码不可用弹出窗口中的“查看反汇编”链接,以便返回反汇编窗口。调试器现在处于非托管模式。请注意,新的调试引擎现在显示正确的代码地址,因此您无法再轻松地分辨
- 现在,您可以在地址框中输入您发现的地址。一定要在它前面加上“0x”
另一种完全不同的方法是临时向方法发出对Debugger.Break()的调用,现在更容易了。在x64上,方法调用的前两个参数位于RCX中,RDX.VS拒绝向您显示运行时的某些部分。这必须是运行时帮助程序调用。我一直不明白为什么他们绝对确保调试器甚至不能反汇编运行时。