News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Invoke an external procedure on a memory address?

Started by 2B||!2B, May 06, 2019, 07:04:40 PM

Previous topic - Next topic

2B||!2B

Hello,

Does anyone have an idea how to make invoke works on an external function that resides in a memory address?

Example:

.Data?
MyFunction          dd       ?

Mov EAX,MyMemAddress   ;[MyMemAdress contains a pointer to an external function lets say GetTickCount]
MOV MyFunction,EAX
invoke [MyFunction]

hutch--


jj2007

Exactly! There are a number of more or less acrobatic methods to do that, including the Declare macro, but why bother? Just push the arguments in inverse order and call the function. If you are keen on complicated things: The jinvoke macro does exactly what you want, it's in \Masm32\MasmBasic\Res\JBasic.inc - only 325 lines and 6.8 kBytes.

2B||!2B

Using Call must push all arguments in a reverse order and also makes code very unreadable.

2B||!2B

Quote from: jj2007 on May 06, 2019, 07:15:56 PM
Exactly! There are a number of more or less acrobatic methods to do that, including the Declare macro, but why bother? Just push the arguments in inverse order and call the function. If you are keen on complicated things: The jinvoke macro does exactly what you want, it's in \Masm32\MasmBasic\Res\JBasic.inc - only 325 lines and 6.8 kBytes.

Hi jj,

Thanks for the tip but i can not seem to find the 32bit version of this macro. Is this a 64bit only?

jj2007

No, JBasic is a package that builds both 32- and 64-bit code from the same identical source. Simple example:

include \Masm32\MasmBasic\Res\JBasic.inc
Init           ; OPT_64 0      ; put 0 for 32 bit, 1 for 64 bit assembly
  PrintLine Chr$("This program was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format.")
  jinvoke MessageBox, 0, Chr$("There are LoadLibrary and GetProcAddress under the hood"), Chr$("Just a test:"), MB_OK
EndOfCode


Output: This program was assembled with ml64 in 64-bit format. (plus the MsgBox, of course)

The macro works fine but it is damn complicated (inter alia, it checks the parameter count and type), and it requires also a tiny static library that cares for the LoadLibrary & GetProcAddress part. I am no longer working on it because I am not interested in 64-bit coding.

2B||!2B

Thanks for the info. I couldn't compile your example though

Error A2102: Symbol not defined : iaApi

Its indeed sounds a complicated task. Might just stick with the SPROTO.

hutch--

If you want it to look more high level, just write a macro for it. Push reverse order then call the procedure address. It is a trivial macro to write.

fearless

Lua_setglobalProto      TYPEDEF PROTO C luastate:DWORD, ptr_name:DWORD
Lua_setglobalPtr        TYPEDEF PTR Lua_setglobalProto

.data
F_Lua_setglobal         Lua_setglobalPtr 0 ; similar to defining F_Lua_setglobal as: F_Lua_setglobal DD 0
.code
...
; Assign the F_Lua_setglobal variable a function address value somewhere:
; mov eax, dwSomeAddress
; mov F_Lua_setglobal, eax
...
Invoke F_Lua_setglobal, g_lua, lpszFunctionName
...

aw27

Try like this for a function with 2 ptr arguments:

lea eax, funcToCall
FuncProto typedef PROTO :ptr, :ptr
assume eax : ptr FuncProto
invoke eax, dest, src
assume eax:nothing

2B||!2B

Quote from: hutch-- on May 06, 2019, 08:22:55 PM
If you want it to look more high level, just write a macro for it. Push reverse order then call the procedure address. It is a trivial macro to write.

Very good solution! i have not thought of it. Do you know how to make the arguments variable in Macro? because not all API's have the same number of arguments.

Quote from: fearless on May 06, 2019, 08:42:08 PM
Lua_setglobalProto      TYPEDEF PROTO C luastate:DWORD, ptr_name:DWORD
Lua_setglobalPtr        TYPEDEF PTR Lua_setglobalProto

.data
F_Lua_setglobal         Lua_setglobalPtr 0 ; similar to defining F_Lua_setglobal as: F_Lua_setglobal DD 0
.code
...
; Assign the F_Lua_setglobal variable a function address value somewhere:
; mov eax, dwSomeAddress
; mov F_Lua_setglobal, eax
...
Invoke F_Lua_setglobal, g_lua, lpszFunctionName
...


Thanks fearless for the example but this will also call the function from within the address space of the compiled exe. Exactly like SPROTO.

Quote from: AW on May 07, 2019, 12:37:01 AM
Try like this for a function with 2 ptr arguments:

lea eax, funcToCall
FuncProto typedef PROTO :ptr, :ptr
assume eax : ptr FuncProto
invoke eax, dest, src
assume eax:nothing

Nice work AW.
Example works, very good method.

hutch--

I still don't know what you are after, "invoke" works with a normal address, the SPROTO macro works on addresses and you can manually use the standard PUSH/CALL Notation. What else are you after ?

Vortex

Hi 2B||!2B,

You can use a macro simulating invoke to call functions through pointers :

include  InvkReg.inc

.data

user32   db 'user32.dll',0
ApiFunc  db 'MessageBoxA',0

.data?

hModule  dd ?
mbox     dd ?

.code

start:

    invoke  LoadLibrary,ADDR user32
    mov     hModule,eax
    invoke  GetProcAddress,eax,ADDR ApiFunc
    mov     mbox,eax

;   mbox can be replaced with eax

   _invoke  mbox,0,"MessageBox test","Hello",MB_OK

    invoke  FreeLibrary,hModule
               
    invoke ExitProcess,0

END start


Vortex

Thanks AW for your macro. Combining your code, the prX macros from Windows.inc and some previous code :

_invoke MACRO p:REQ,args:VARARG

LOCAL counter,p2,tmp

    counter=0

    FOR param,<args>

        counter=counter+1

    ENDM

    IF counter EQ 0

        call p

    ELSE

        tmp TEXTEQU %(OPATTR(p))

        IF tmp EQ 42

            mov ecx,p
            p2  TEXTEQU <ecx>

        ELSE

            p2  TEXTEQU <p>

        ENDIF

        FuncProto TYPEDEF @CatStr(<pr>,%counter)

        ASSUME p2:PTR FuncProto

        invoke p2,args

        ASSUME p2:NOTHING

    ENDIF

ENDM


include  InvkReg.inc

.data

user32   db 'user32.dll',0
ApiFunc  db 'MessageBoxA',0

.data?

hModule  dd ?
mbox     dd ?

.code

start:

    invoke  LoadLibrary,ADDR user32
    mov     hModule,eax
    invoke  GetProcAddress,eax,ADDR ApiFunc
    mov     mbox,eax

;   mbox can be replaced with eax

   _invoke  mbox,0,CTXT("MessageBox test"),\
    CTXT("Hello"),MB_OK

    invoke  FreeLibrary,hModule
               
    invoke ExitProcess,0

END start

aw27

OK. No problem.
This is a more "modern" way of doing the same:

   lea eax, myCalledFunction
   FuncProto typedef PROTO :ptr, :ptr
   invoke FuncProto ptr eax, dest, source