You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用64位DLL中rundll函数触发访问违例,栈需如何调整?

解决x64 DLL函数调用的访问违例问题

先看你给出的汇编代码片段:

invoke LoadLibraryA, $("64.dll")
invoke GetProcAddress, rax, $("rundll")
call rax

出现访问违例的核心原因是x64 Windows平台的调用约定对栈有严格要求,你的代码没满足这些规则,导致函数调用时栈状态非法,触发内存访问错误。下面是具体需要调整的栈操作:

1. 强制保证调用前栈16字节对齐

在x64 Windows环境下,任何函数调用执行前,RSP寄存器的值必须是16字节的整数倍。invoke宏通常会自动处理部分栈对齐,但手动执行call指令时,需要自己检查并修正:

  • 你可以在call rax前添加指令调整栈,比如如果当前RSP是8字节偏移的状态,就执行:
    sub rsp, 8  ; 调整后RSP回到16字节对齐状态
    
    实际调试时,可以直接查看调试器里的RSP值,按需调整。

2. 必须预留32字节的影子空间(Shadow Space)

x64 Windows调用约定强制要求:无论被调用函数有没有参数,调用者都要在栈上预留32字节的空间,供被调用者用来保存RCX/RDX/R8/R9这四个寄存器的值。哪怕你的rundll函数没有参数,这个空间也不能少。

修改后的完整代码示例:

invoke LoadLibraryA, $("64.dll")
invoke GetProcAddress, rax, $("rundll")
; 预留影子空间+保证栈对齐(如果之前栈未对齐的话)
sub rsp, 32 + 8  
call rax
; 调用完成后恢复栈空间
add rsp, 32 + 8

如果确认调用前栈已经是16字节对齐状态,只需要单独预留32字节影子空间即可:

sub rsp, 32
call rax
add rsp, 32

3. 带参数的函数额外处理(如果rundll有参数)

如果rundll函数需要传入参数:

  • 前4个参数依次放入RCX、RDX、R8、R9寄存器
  • 第5个及以后的参数,按从右到左的顺序压入栈中(注意要先预留影子空间,再压入参数)
  • 调用完成后,调用者不需要清理栈上的参数(被调用者负责清理),但必须恢复之前预留的影子空间和对齐用的栈空间

调试验证小技巧

在调试器里执行call rax前,先检查两个关键点:

  • 确认RSP的值最后一位十六进制是0(即16字节对齐)
  • 确认已经预留了足够的影子空间
    如果调整后还是出错,可以检查rundll的参数传递是否正确,或者确认DLL和你的EXE都是64位(位数不匹配也会导致这类错误)

内容的提问来源于stack exchange,提问作者h goe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:21:49