2010-07-26 74 views
4

我使用NASM在x86汇编中构建一个COM对象。我对COM的理解很好,我很了解x86的组装,但是把它们组合起来会让我挂断......(顺便说一下,如果你想阻止我使用x86汇编,请不要这么做,我有非常特别的原因,为什么我在x86组建这个!)在x86汇编中构建一个COM对象vtable

我想建立一个在我的COM对象中使用的Vtable,但我不断收到奇怪的指针,而不是实际指向我的函数。 (我想我正在获得相对偏移量或者NASM在那里嵌入临时值,并且在链接过程中它们不被替换为实际值)

我试图构建的当前接口是IClassFactory界面,代码如下:

%define S_OK 0x00000000 
%define E_NOINTERFACE 0x80004002 

section .text 

; All of these have very simple shells rather than implementations, but that is just until I can get the vtable worked out 

ClassFactory_QueryInterface: 
    mov eax, E_NOINTERFACE 
    retn 12 

ClassFactory_AddRef: 
    mov eax, 1 
    retn 4 

ClassFactory_Release: 
    mov eax, 1 
    retn 4 

ClassFactory_CreateInstance: 
    mov eax, E_NOINTERFACE 
    retn 16 

ClassFactory_LockServer: 
    mov eax, S_OK 
    retn 8 

global ClassFactory_vtable 
ClassFactory_vtable dd ClassFactory_QueryInterface, ClassFactory_AddRef, ClassFactory_Release, ClassFactory_CreateInstance, ClassFactory_LockServer 

global ClassFactory_object 
ClassFactory_object dd ClassFactory_vtable 

注:这还不是全部的代码,我的DllGetClassObject,DllMain中,等在不同的文件中。

但是当我组装(使用NASM:nasm -f win32 comobject.asm)和链路(使用MS链接:link /dll /subsystem:windows /out:comobject.dll comobject.obj),并检查使用OllyDbg的可执行文件,虚函数表出来奇怪值。例如,在我最后的构建,是功能的实际地址如下:

  • 的QueryInterface - 0x00381012
  • 的AddRef - 0x0038101A
  • 发布 - 0x00381020
  • 的CreateInstance - 0x00381026
  • LockServer - 0x0038102E

但是vtable出来这些值:

  • 的QueryInterface - 0x00F51012
  • 的AddRef - 0x00F5101A
  • 发布 - 0x00F51020
  • 的CreateInstance - 0x00F51026
  • LockServer - 0x00F5102E

这些值气色好可疑......几乎像搬迁没有采取。另外,vtable出现为0x00F5104A,所有这些都是不可访问的内存地址。 (仅供参考,这些值每次都会有所不同

我试过在使用Visual Studio 2010 Express的C++中做同样的事情,并且一切都很好。所以我假设这只是我在我的程序集中丢失的东西...


任何人都可以指出为什么这些值不能正确显示吗?

+1

我不知道你的vtable,但你的函数实现没有足够的参数。例如,AddRef应该是retn 4,你会一直忘记这个指针。 – 2010-07-26 00:46:08

+0

啊!是的,谢谢Logan!我完全忘了这个指针! – Miquella 2010-07-26 00:59:37

回答

2

我必须道歉,问题原来是我自己的错......在所有的混战中,我已经从链接器调用中删除/dll,导致它被构建为EXE,而不是DLL ...


让我来解释一下这个更好一点的下一个人谁跑过这个。

所有Windows可执行文件都有一个base address,它被假定为可执行文件将加载到的虚拟地址。在大多数情况下加载到正在运行的进程中的可执行文件不会加载到“首选”base address,因为另一个DLL(或应用程序本身)可能已占用该地址。为此,Windows PE可执行文件使用所谓的Relocation TableRelocation Table告诉Windows如果重定位到新的base address,那么可执行文件中的哪些位置需要重写。

然而,随着Virtual Memory来临,大部分链接器会忽略从EXE文件作为一个优化的重定位表,因为该可执行文件将永远被载入在它的基地址(除非它与保留的内核地址冲突,在这种情况下,将无法加载全部)。所以,因为我停止编译为DLL,所以我的可执行文件没有被赋予Relocation Table,因此无法正确加载到正在运行的进程地址空间中。


更新:

默认情况下,MSVC仅包括在DLL项目搬迁表,如所描述的on MSDN

By default, /FIXED:NO is the default when building a DLL, and /FIXED is the default for any other project type. 

此行为可以通过提供/FIXED:NO切换到被改变连接。非DLL项目的默认值是/FIXED,它告诉链接器目标具有固定的基址,并且不需要重定位表。

1

您是否尝试在C语言中构建存根COM接口并反汇编结果?这应该给你一个线索你的实现中出了什么问题。

+0

我有,是的。但是这并没有什么帮助,因为这是预初始化的vtable值是错误的... 没有任何代码被执行错误,它只是将指针表直接编译到可执行文件中。 – Miquella 2010-07-26 00:53:02

1

您是否尝试过将全局变量声明为导出?我很久没有做x86了。但是,阅读nasm的文档似乎意味着您需要全局和导出DLL重定位修复工作。