【问题标题】:call immediate versus call dword near [dword addr]立即调用与在 [dword addr] 附近调用 dword
【发布时间】:2011-10-30 16:25:37
【问题描述】:

所以最近我一直想从汇编中调用一些 win32 调用,并且我一直在使用 NASM 作为我的外部汇编器。我通过以下方式在我的代码中调用SendMessage

call __imp__SendMessageW@16

这被组装成一个相对跳转(0xE8 操作码),结果是访问冲突。在调试器中,计算出的跳转偏移量似乎是正确的(__imp__SendMessageW@16 似乎确实存在于那里),但它仍然不起作用。当我从 C++ 调用该函数时,检查 Visual Studio 生成的程序集,我注意到它使用的不是相对直接的跳转,而是(在 MASM 的语言中)call dword ptr [__imp__SendMessageW@16],对应于 0xFF15 操作码。经过一番折腾后,我发现 NASM 语法将其编码为call dword near [dword __imp__SendMessageW@16],并让我的代码突然生效。

我的问题是,为什么一个有效而另一个无效?是否有一些代码重定位导致相对立即调用跳转到不友好的地方?我从来都不是汇编程序员,但我的印象始终是这两个调用应该做同样的事情,主要区别是一个是位置独立的,另一个不是(假设他们将 IP 移动到同一个地方)。考虑到这一点,代码理论的重定位是有道理的,但是你如何解释调试器显示正确的地址呢?

另外:这个调用中[] 语法背后的逻辑是什么?偏移量仍然是立即数(只是在 0xFF15 之后立即编码的小端序),除了指令获取之外,这里没有内存访问(我倾向于将[] 视为lea 上下文之外的取消引用)。

【问题讨论】:

    标签: windows winapi assembly nasm


    【解决方案1】:
    call dword[__imp__SendMessageW@16]
    

    _imp_SendMessageW@16 是导入部分的地址,其中包含 API 函数的地址。你使用方括号来尊重(调用这个地址存储的地址)

    【讨论】:

    • 啊,等一下……__imp__SendMessageW@16是函数指针吗?所以问题可能是这些数据驻留在一个不可执行的页面上,这就是我遇到访问冲突的原因,对吗?
    • 那么,接下来的问题是:产生这种间接的背后的逻辑是什么?一个小实验证实我不能直接调用_SendMessageWSendMessageW,尽管VS 调试器将[dword __imp__SendMessageW@16] 的值识别为SendMessageW。我知道在 Linux 系统上共享库通过表索引函数,但我想我记得读过 Windows 确实进行了实际重定位,即它维护代码中的偏移列表并在加载时对其进行修补。我是不是误会了?
    • 它是 PE(便携式可执行文件)规范的一部分。外部函数作为引用存储在 EXE 的“idata”部分中,然后在加载 EXE(DLL 加载到内存中)时,API 的确切位置作为数据放置在这些引用中。
    • 像往常一样,Raymond Chen 有关于为什么事情是这样的所有血淋淋的细节:blogs.msdn.com/b/oldnewthing/archive/2006/07/27/680250.aspx 我建议至少阅读“重新思考 DLL 导出的解决方式 32 -bit Windows”以及其后的两篇文章。
    • 这是一个很棒的系列文章,马丁。谢天谢地,Raymond Chen,我发誓,当我想知道真正发生了什么时,我总会回到他的博客上。
    猜你喜欢
    • 2011-03-27
    • 2013-12-11
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 2011-12-31
    • 1970-01-01
    相关资源
    最近更新 更多