Original link: http://www.titilima.cn /? Action = show & id = 275
In general, the method for dynamically calling the DLL export function is:
- Use typedef to define the function pointer type for the target function.
- Use getprocaddress to obtain the function pointer.
- Use the function pointer for calling.
However, if you want to call too many functions, this method will inevitably be cumbersome-there are too many typedef, too many getprocaddress and too many function pointers. In this article, we will provide a general solution to make these dynamic calls easier.
Let's take a look at the Declaration of this function:
- Bool _ cdecl dllcall (
- Pctstr lpszdll, // name of the DLL where the target function is located
- Pcstr lpszfunc, // target function name
- Int argc, // number of parameters to be called
- Pvoid Pret, // return value of function call
- ...
- );
Take messageboxa as an example. The usage is as follows:
- Int ret;
- Dllcall (_ T ("user32.dll"), "messageboxa", 4, & ret,
- Null, "Hello, world! "," Hello ", mb_iconinformation | mb_yesno );
Replace messageboxindirecta with the following parameter:
- Msgboxparamsa Param;
- Zeromemory (memory M, sizeof (msgboxparamsa ));
- Param. cbsize = sizeof (msgboxparamsa );
- Param. dwlanguageid = getsystemdefaultlangid ();
- Param. dwstyle = mb_iconinformation;
- Param. lpszcaption = "hello ";
- Param. lpsztext = "Hello, world ";
- Int ret;
- Dllcall (_ T ("user32.dll"), "messageboxindirecta", 1, & ret, ¶ M );
The implementation principle is to dynamically generate assembly code, which is similar to the following:
- _ Declspec (naked) DWORD _ cdecl dllcallproc (void)
- {
- _ ASM
- {
- Push argn
- ...
- Push arg2
- Push arg1
- Call proc
- RET
- };
- }
The code for dllcall is listed below, which is similar to the implementation of all variable parameter functions (such as sprintf.
- Bool _ cdecl dllcall (
- Pctstr lpszdll,
- Pcstr lpszfunc,
- Int argc,
- Pvoid Pret,
- ...)
- {
- Va_list Arglist;
- Int ret;
- Va_start (Arglist, Pret );
- Ret = vdllcall (lpszdll, lpszfunc, argc, Pret, Arglist );
- Va_end (Arglist );
- Return ret;
- }
The most critical is the vdllcall code, as shown below:
- # Pragma pack (push, 1)
- Typedef struct {
- Byte op;
- Dword_ptr dwvalue;
- } Opcode, * popcode;
- # Pragma pack (POP)
- Typedef DWORD (_ cdecl * dllcall) (void );
- Bool _ cdecl vdllcall (
- Pctstr lpszdll,
- Pcstr lpszfunc,
- Int argc,
- Pvoid Pret,
- Va_list Arglist)
- {
- Hmodule hdll = loadlibrary (lpszdll );
- If (null = hdll)
- Return false;
- Farproc proc = getprocaddress (hdll, lpszfunc );
- If (null = proc)
- Return false;
- Handle hheap = getprocessheap ();
- Popcode P = (popcode) heapalloc (hheap, 0, sizeof (opcode) * (argc + 2 ));
- Int I;
- For (I = argc-1; I> = 0; -- I)
- {
- // Push Arg [I]
- P [I]. Op = 0x68;
- P [I]. dwvalue = va_arg (Arglist, dword_ptr );
- }
- // Call proc
- P [argc]. Op = 0xe8;
- P [argc]. dwvalue = (int_ptr) proc-(int_ptr) & P [argc + 1];
- // RET
- P [argc + 1]. Op = 0xc3;
- P [argc + 1]. dwvalue = 0x90909090; // NOP
- Dllcall PFN = (dllcall) P;
- DWORD ret = PFN ();
- Heapfree (hheap, 0, P );
- Freelibrary (hdll );
- If (null! = Pret)
- * (Pdword) Pret = ret;
- Return true;
- }
The pointer P is the call code generated dynamically, and is finally converted to the dllcall type function pointer for calling.
Finally, four points need to be added:
- Dllcall is only applicable to _ stdcall calling the agreed target function.
- This vdllcall code is only applicable to x86 CPUs. If it is used in the wince environment (such as arm or mips cpu), you need to rewrite the dynamic calling assembly code as appropriate.
- The argc parameter refers to the number of actual pressure stack parameters, rather than the number of parameters called by C language. For example, if the API function windowfrompoint has only one parameter in the function declaration, the stack is actually pressed by point: X and point: Y respectively. In this case, set argc to 2.
- The returned value of dllcall only obtains eax. If some functions return a large structure larger than 4 bytes, the returned value is not what you want.