Error when calling function in user32.dll directly

2019-03-06 01:07发布

问题:

I read an article some time ago from a guy who demonstrated how one can directly call a function in user32.dll in assembly (NASM) by its memory address. I do not have the article anymore but I'm trying to reproduce the experiment.

The function I want to execute is MessageBoxA in user32.dll and on my computer, the function should be located at the address 0x76cd75c0.

Here is the function:

int MessageBoxA(
     HWND hWnd,              # NULL
     LPCSTR IpText,          # text
     LPCSTR IpCaption,       # title
     UINT uType              # style
);

Here is the program:

global _main                        

section .data                       
msgText:    db 'Hello World', 0
msgCaption: db 'Title', 0       

section .text                   
_main:                          
    push 0
    push msgCaption
    push msgText
    push 0
    call 0x76cd75c0

    add esp, 4
    ret 0x10

For compiling the program I use:

nasm –f win32 message_box.asm

However, I receive this error message:

error: Win32 COFF does not correctly support relative references to absolute 
addresses

It doesn't matter if I use the normal address or the relative address, I receive the same error message anyway.

Anybody who knows what's the problem?

回答1:

The problem is that it doesn't exists a call that is direct (the address is given directly as an operand), near (no segment) and absolute.
See here.

call XXX is near and direct, so it cannot be absolute.
In fact, it is relative.
NASM tries to create a relocation for relative calls (note the OUT_REL4ADR type) but 0x76cd75c0 is outside any section defined in the source and apparently this is not supported.

The only way to call a function with an absolute address is by using a FAR call, but that requires an immediate segment value.
This rarely ends well in protected mode and a was noted in the comments, that would push cs too. (Otherwise you could use the 0x23 selector that Windows sets for 32-bit applications as in call 0x23:0x76cd75c0).

You can use an indirect call:

mov ebx, 0x76cd75c0
call ebx

Note that add esp, 4 looks very wrong here, the Win APIs follow the stdcall calling convetion (they clear the stack themselves).