0

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?

zx485
  • 28,498
  • 28
  • 50
  • 59
Lavonen
  • 606
  • 1
  • 10
  • 21
  • 1
    This looks like an overly complicated way of using the Win32 API. Why don't you use Hutch's MASM32 package? Its include and library files, and using `invoke`, make accessing the Win32 API very comfortable. And if you like to stick with open software, try the MASM-compatible `JWASM`. – zx485 Nov 24 '18 at 19:10
  • Yes, it's the point :) Else I would have used _MessageBoxA@16. It's purely experimental, would be kind of cool if it worked. – Lavonen Nov 24 '18 at 19:27

1 Answers1

2

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).

Margaret Bloom
  • 41,768
  • 5
  • 78
  • 124
  • 1
    `call 0x23:0x76cd75c0` will be a lot slower, and will push CS:EIP. If the function looks for any args on the stack, it will get CS as the first arg. `mov eax, 0x76cd75c0` / `call eax` should be a lot better. Or use the normal DLL mechanism of calling through a pointer in memory. – Peter Cordes Nov 24 '18 at 20:08
  • Worth mentioning that Linux/ELF position-dependent code can use relative calls to reach absolute addresses; I don't know why Windows would omit that and force asm to be inefficient. But at least that explains why there's no answer to [How to write an absolute target for a near direct relative call/jmp in MASM](https://stackoverflow.com/q/50058523) – Peter Cordes Nov 24 '18 at 20:12
  • @PeterCordes Good point about the far call, better remove that. – Margaret Bloom Nov 24 '18 at 20:14
  • I have already tried by moving the address to ECX and then call ECX which solved the problem with the compiler. But... the program crashes... Any ideas why? I linked with "ld -e _main hello.obj -lkernel32" – Lavonen Nov 24 '18 at 20:25
  • @Lavonen Have you tried stepping with a debugger? Like OllyDbg/x96dbg and similar? There could be a lot of reasons, including the fact that `MessageBoxA` not being there or `user32.dll` itself. A debugger will rule these basic problems out. – Margaret Bloom Nov 24 '18 at 22:37
  • @Lavonen Adding also that `user32` is most probably subject to ASLR. – Neitsa Nov 25 '18 at 14:24
  • Sorry for such a late answer, I found an example online of my script that works and the problem was a little bigger than what I thought. However, Margaret was completely right concerning my question so I vote it up :) – Lavonen Nov 28 '18 at 12:21