Building a vtable COM object in x86 assembly

I am creating a COM object in x86 assembly using NASM. I understand COM very well, and I understand that the x86 build is pretty good, but getting two in the grid is freezing ... (by the way, if you think you're trying to dissuade me from using the x86 build, please refrain, I have a very certain reasons why I build this in x86 build!)

I am trying to build a vtable for use in my COM object, but I keep getting weird pointers, not actual pointers to my functions. (I think I'm getting relative offsets, or that NASM embeds temporal values ​​there, and they are not replaced by real values ​​during binding)

The current interface I'm trying to build is an IClassFactory interface with code as follows:

 %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 

Note: This is not all code, I have DllGetClassObject, DllMain, etc. in another file.

But when I collect (using NASM: nasm -f win32 comobject.asm ) and the link (using MS Link: link /dll /subsystem:windows /out:comobject.dll comobject.obj ) and view the executable using OllyDbg, vtable is output with strange meanings. For example, in my last build, the actual addresses for the functions are as follows:

  • QueryInterface - 0x00381012
  • AddRef - 0x0038101A
  • Release - 0x00381020
  • CreateInstance - 0x00381026
  • LockServer - 0x0038102E

But vtable came out with these values:

  • QueryInterface - 0x00F51012
  • AddRef - 0x00F5101A
  • Release - 0x00F51020
  • CreateInstance - 0x00F51026
  • LockServer - 0x00F5102E

These values ​​look terribly suspicious ... almost the same as the move was not accepted. In addition, vtable displays as 0x00F5104A, all of which are inaccessible memory addresses. (for information purposes, these values ​​differ each time)

I tried to do the same in C ++ using Visual Studio 2010 Express, and everything worked out fine. So I assume that this is just what I am missing in my assembly ...


Can someone please tell me why these values ​​are not coming out properly?

+4
source share
3 answers

I have to apologize, the problem turned out to be my own mistake ... In all the destruction of the building, I removed /dll from the linker call, as a result of which it was created as an EXE, not a DLL ...


Let me explain this a little better for the next person who comes across this.

All Windows executables have a base address , which is considered the virtual address to which the executable will be downloaded. Executable files that are loaded into the running process in most cases will not be loaded at the "preferred" base address , since the other DLL (or the application itself) probably already occupies the address. For this reason, Windows PE executables use what is known as a relocation table . The relocation table tells Windows which locations in the executable file must be rewritten if relocated to a new base address .

However, with the advent of Virtual Memory , most linkers omit the movement table from EXE as an optimization, because the executable will always be downloaded to its base address (unless it conflicts with reserved kernel addresses, in which case it will not load together) . Therefore, since I stopped compiling as a DLL, my executable file was not provided with a relocation table and, as a result, the address space was not loaded properly into the running process.


Update:

By default, MSVC only includes relocation tables in DLL projects, as described in MSDN :

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

This behavior can be changed by setting the /FIXED:NO switch in the linker. By default, for projects other than DLLs, there is /FIXED , which tells the linker that the target has a fixed base address and does not require a relocation table.

+2
source

Have you tried building a stub COM interface in C and parsing the result? This should make you understand what is wrong with your implementation.

+1
source

Have you tried to declare your global markets as export? I have not done x86 for a long time. But reading the nasm doc seems to imply that you need both global and export to fix the movement of the DLL to work.

+1
source

All Articles