NO

Author Topic: Calling a function from DLL at runtime  (Read 6017 times)

Offline Vortex

  • Member
  • *
  • Posts: 865
    • http://www.vortex.masmcode.com
Calling a function from DLL at runtime
« on: October 01, 2023, 01:30:33 PM »
Here is an example of calling the undocumented function MessageBoxTimeout at runtime.

Code: [Select]
include     Test.inc

CallFunc64  PROTO :QWORD,:QWORD,:QWORD

.data

user32  db 'user32.dll',0
MyFunc  db 'MessageBoxTimeoutA',0

message db 'This message box will be destroyed after 4 seconds.',0
caption db 'Hello',0

;   int MessageBoxTimeoutA(HWND hWnd, LPCSTR lpText,
;       LPCSTR lpCaption, UINT uType,
;       WORD wLanguageId, DWORD dwMilliseconds);

array   dq 0,OFFSET message,OFFSET caption
        dq MB_ICONWARNING,LANG_NEUTRAL,TIMEOUT

.code


main PROC PARMAREA=4*QWORD

LOCAL hMod:QWORD

    invoke  LoadLibrary,ADDR user32
    mov     hMod,rax

    invoke  GetProcAddress,rax,ADDR MyFunc

    invoke  CallFunc64,rax,6,ADDR array

    invoke  FreeLibrary,hMod

    invoke  ExitProcess,0

main ENDP


END main
« Last Edit: October 02, 2023, 11:32:05 PM by Vortex »
Code it... That's all...

Offline John Z

  • Member
  • *
  • Posts: 860
Re: Calling a function from DLL at runtime
« Reply #1 on: October 02, 2023, 03:46:02 PM »
Thanks Vortex!

Very neat, always wanted something like this, never knew it was there.
Hope I can get it to work in C.

John Z

Offline MrBcx

  • Global Moderator
  • Member
  • *****
  • Posts: 189
    • Bcx Basic to C/C++ Translator
Re: Calling a function from DLL at runtime
« Reply #2 on: October 02, 2023, 05:02:34 PM »

Hope I can get it to work in C.

John Z

Hi JJ,

This will get you there.  This is the A version. 
If you want the W versions, it's only minor edits.

Code: [Select]

#include <windows.h>
#include <stdio.h>

long __stdcall MessageBoxTimeoutA (HWND, char*, char*, int, int, int);

long __stdcall MessageBoxTimeoutA (HWND hwnd,char* Txt,char* Title,int MBType,int Langid,int Milliseconds)
{
  typedef int (__stdcall *MBTYPEDEF)(HWND, char *, char *, long, int, int);
  static MBTYPEDEF MsgBoxTimeout;
  static int Result;
  HMODULE  HMOD_USER32 = LoadLibrary("user32.dll");
  MsgBoxTimeout = (MBTYPEDEF)GetProcAddress(HMOD_USER32, "MessageBoxTimeoutA");
  Result=MsgBoxTimeout(hwnd,Txt,Title,MBType,Langid,Milliseconds);
  return Result;
}

#define MBTYPE MB_YESNOCANCEL|MB_SETFOREGROUND|MB_SYSTEMMODAL|MB_ICONINFORMATION


// Demo

int main(int argc, char *argv[])
{
   printf("% d",(int)MessageBoxTimeoutA(NULL, "This works with all compilers...", "Title Goes Here", MBTYPE, 0, 4000));
   return EXIT_SUCCESS;
}

« Last Edit: October 02, 2023, 11:50:24 PM by MrBcx »
Bcx Basic to C/C++ Translator
https://www.BcxBasicCoders.com

Offline Vortex

  • Member
  • *
  • Posts: 865
    • http://www.vortex.masmcode.com
Re: Calling a function from DLL at runtime
« Reply #3 on: October 02, 2023, 09:33:26 PM »
Hi Kevin,

Thanks for your code. Checking the object module with Agner Fog's objconv tool, I saw that the stack was balanced after calling MessageBoxTimeoutA. This should not happen as MessageBoxTimeoutA is a STDCALL function. The code is built as 32-bit in this case.

Code: [Select]
_main   PROC NEAR
        push    4000
        push    0
        push    69699
        push    offset @1044
        push    offset @1043
        push    0           
        call    _MessageBoxTimeoutA
        add     esp, 24           
        push    eax               
        push    offset @1042       
        call    _printf           
        add     esp, 8             
        xor     eax, eax
        ret                       
_main   ENDP

The solution is inserting the __stdcall statment just before MessageBoxTimeoutA :

Code: [Select]
/*long __stdcall MessageBoxTimeoutA (HWND, char*, char*, int, int, int);*/

long __stdcall MessageBoxTimeoutA (HWND hwnd,char* Txt,char* Title,int MBType,int Langid,int Milliseconds)
{
  typedef int (__stdcall *MBTYPEDEF)(HWND, char *, char *, long, int, int);
  static MBTYPEDEF MsgBoxTimeout;
  static int Result;
  HMODULE  HMOD_USER32 = LoadLibrary("user32.dll");
  MsgBoxTimeout = (MBTYPEDEF)GetProcAddress(HMOD_USER32, "MessageBoxTimeoutA");
  Result=MsgBoxTimeout(hwnd,Txt,Title,MBType,Langid,Milliseconds);
  return Result;
}

Objconv reports now the correct output :

Code: [Select]
_main   PROC NEAR
        push    4000
        push    0   
        push    69699
        push    offset @104
        push    offset @104
        push    0   
        call    _MessageBoxTimeoutA@24  ;  no stack balance after the call to MessageBoxTimeoutA
        push    eax                   
        push    offset @1042         
        call    _printf               
        add     esp, 8               
        xor     eax, eax             
        ret                           
_main   ENDP
Code it... That's all...

Offline Vortex

  • Member
  • *
  • Posts: 865
    • http://www.vortex.masmcode.com
Re: Calling a function from DLL at runtime
« Reply #4 on: October 02, 2023, 10:21:20 PM »
Hello,

Pelle's Podump tool can be used to disassemble the object module :

Code: [Select]
podump.exe /DISASM MBoxTimeOut.obj
Code: [Select]
Dump of MBoxTimeOut.obj

File type: OBJ

_MessageBoxTimeoutA@24:
  [00000000] 55                     push              ebp
  [00000001] 89E5                   mov               ebp,esp
  [00000003] 53                     push              ebx
  [00000004] 56                     push              esi
  [00000005] 57                     push              edi
  [00000006] 8B5D08                 mov               ebx,dword ptr [ebp+8]
  [00000009] 8B750C                 mov               esi,dword ptr [ebp+C]
  [0000000C] 8B7D10                 mov               edi,dword ptr [ebp+10]
  [0000000F] 6800000000             push              @1025
  [00000014] FF1500000000           call              dword ptr [__imp__LoadLibraryA@4]
  [0000001A] 6800000000             push              @1027
  [0000001F] 50                     push              eax
  [00000020] FF1500000000           call              dword ptr [__imp__GetProcAddress@8]
  [00000026] A300000000             mov               dword ptr [@1023],eax
  [0000002B] FF751C                 push              dword ptr [ebp+1C]
  [0000002E] FF7518                 push              dword ptr [ebp+18]
  [00000031] FF7514                 push              dword ptr [ebp+14]
  [00000034] 57                     push              edi
  [00000035] 56                     push              esi
  [00000036] 53                     push              ebx
  [00000037] FF1500000000           call              dword ptr [@1023]
  [0000003D] A300000000             mov               dword ptr [@1024],eax
  [00000042] 5F                     pop               edi
  [00000043] 5E                     pop               esi
  [00000044] 5B                     pop               ebx
  [00000045] 89EC                   mov               esp,ebp
  [00000047] 5D                     pop               ebp
  [00000048] C21800                 ret               18
  [0000004B] 0F1F440000             nop               [eax+eax+0]

_main:
  [00000050] 68A00F0000             push              FA0
  [00000055] 6A00                   push              0
  [00000057] 6843100100             push              11043
  [0000005C] 6800000000             push              @1044
  [00000061] 6800000000             push              @1043
  [00000066] 6A00                   push              0
  [00000068] E893FFFFFF             call              00000000
  [0000006D] 50                     push              eax
  [0000006E] 6800000000             push              @1042
  [00000073] E800000000             call              _printf
  [00000078] 83C408                 add               esp,8
  [0000007B] 31C0                   xor               eax,eax
  [0000007D] C3                     ret

SUMMARY
       8 .bss
      10 .debug$F
      28 .drectve
      53 .rdata
      7E .text
Code it... That's all...

Offline Robert

  • Member
  • *
  • Posts: 247
Re: Calling a function from DLL at runtime
« Reply #5 on: October 02, 2023, 11:24:14 PM »
Here is an example of calling the undocumented function MessageBoxTimeout at runtime.

Code: [Select]
include     Test.inc

CallFunc64  PROTO :QWORD,:QWORD,:QWORD

.data

user32  db 'user32.dll',0
MyFunc  db 'MessageBoxTimeoutA',0

message db 'This message box will be destroyed after 4 seconds.',0
caption db 'Hello',0

;   int MessageBoxTimeoutA(HWND hWnd, LPCSTR lpText,
;       LPCSTR lpCaption, UINT uType,
;       WORD wLanguageId, DWORD dwMilliseconds);

array   dq 0,OFFSET message,OFFSET caption
        dq MB_ICONWARNING,LANG_NEUTRAL,TIMEOUT

.code


main PROC PARMAREA=4*QWORD

LOCAL hMod:QWORD

    invoke  LoadLibrary,ADDR user32
    mov     hMod,rax

    invoke  GetProcAddress,rax,ADDR MyFunc

    invoke  CallFunc64,rax,6,ADDR array

    invoke  FreeLibrary,hMod

    invoke  ExitProcess,0

main ENDP


END main

Hi Vortex:

There is no "test.inc" file in the zip hence error

Quote
CallFunc64\Test.asm(1): fatal error: Can't open file 'Test.inc'.

Offline Vortex

  • Member
  • *
  • Posts: 865
    • http://www.vortex.masmcode.com
Re: Calling a function from DLL at runtime
« Reply #6 on: October 02, 2023, 11:32:54 PM »
Hi Robert,

My apologies, it's now fixed. New upload at the top.
Code it... That's all...

Offline MrBcx

  • Global Moderator
  • Member
  • *****
  • Posts: 189
    • Bcx Basic to C/C++ Translator
Re: Calling a function from DLL at runtime
« Reply #7 on: October 02, 2023, 11:51:55 PM »
Erol .. thanks for the insight and correction.

I've updated the code in my post.

Bcx Basic to C/C++ Translator
https://www.BcxBasicCoders.com

Offline John Z

  • Member
  • *
  • Posts: 860
Re: Calling a function from DLL at runtime
« Reply #8 on: October 03, 2023, 11:51:20 AM »
Vortex, MrBCX,

Thanks very much!  It will be very handy to now have this proc.
No longer need to thread out a dialog box and start a timer to kill it.

Very neat!'

John Z

Offline Vortex

  • Member
  • *
  • Posts: 865
    • http://www.vortex.masmcode.com
Re: Calling a function from DLL at runtime
« Reply #9 on: October 03, 2023, 07:54:01 PM »
Hi John,

Your method based on dialog boxes is safer. Not easy to predict if MS is deciding one day to remove a particular undocumented function.
Code it... That's all...

Offline Pelle

  • Administrator
  • Member
  • *****
  • Posts: 2266
    • http://www.smorgasbordet.com
Re: Calling a function from DLL at runtime
« Reply #10 on: October 03, 2023, 08:41:14 PM »
... I can't really see the point/need for a message box that disappears after a while:
- If you have something (reasonably) important to say, don't you want confirmation it was seen?
- If it wasn't that important, why bother with a message box in the first place?

... anyway, not that important since it was an example for this example...  ::)
/Pelle

Offline Vortex

  • Member
  • *
  • Posts: 865
    • http://www.vortex.masmcode.com
Re: Calling a function from DLL at runtime
« Reply #11 on: October 03, 2023, 09:34:18 PM »
Hi Pelle,

No worries, this is just a quick example. The LoadLibrary\GetProcAddress\Call Function method is useful to exit gracefully when a particular DLL is not everytime available.
Code it... That's all...

Offline John Z

  • Member
  • *
  • Posts: 860
Re: Calling a function from DLL at runtime
« Reply #12 on: October 04, 2023, 10:08:47 AM »
No worries - I would not knowingly use any undocumented API feature in software released into the wild.
BUT
I see uses for it during development as part of a debug process.  Plus the sample C code is informative.


John Z

Offline TimoVJL

  • Global Moderator
  • Member
  • *****
  • Posts: 2115
Re: Calling a function from DLL at runtime
« Reply #13 on: October 04, 2023, 11:31:19 AM »
What we learned, missing WINAPI leads problems.

Code: [Select]
;   int WINAPI MessageBoxTimeoutA(HWND hWnd, LPCSTR lpText,
;       LPCSTR lpCaption, UINT uType,
;       WORD wLanguageId, DWORD dwMilliseconds);
x64 don't need it, only x86
May the source be with you

Offline Vortex

  • Member
  • *
  • Posts: 865
    • http://www.vortex.masmcode.com
Re: Calling a function from DLL at runtime
« Reply #14 on: October 04, 2023, 07:42:37 PM »
Thanks to Pelle, the user32.lib import libraries are already providing the function MessageBoxTimeout :

Code: [Select]
D:\PellesC\Bin>podump.exe /EXPORTS ..\Lib\Win\user32.lib | findstr "MessageBoxTimeout"
User32.dll: MessageBoxTimeoutA (_MessageBoxTimeoutA@24)
User32.dll: MessageBoxTimeoutW (_MessageBoxTimeoutW@24)

Code: [Select]
D:\PellesC\Bin>podump.exe /EXPORTS ..\Lib\Win64\user32.lib | findstr "MessageBoxTimeout"
User32.dll: MessageBoxTimeoutA (MessageBoxTimeoutA)
User32.dll: MessageBoxTimeoutW (MessageBoxTimeoutW)
Code it... That's all...