首页 > 其他分享 >Using classes exported from a DLL using LoadLibrary

Using classes exported from a DLL using LoadLibrary

时间:2024-01-24 14:23:45浏览次数:38  
标签:function DLL classes CCalc address using exported

Using classes exported from a DLL using LoadLibrary

Anup. V Rate me:   4.94/5 (67 votes) 25 Jan 20056 min read 368.5K    10.8K    129    41 An article on loading a DLL explicitly using LoadLibrary and using the classes exported by the DLL. Is your email address OK? You are signed up for our newsletters or notifications but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please click here to have a confirmation email sent so we can start sending you newsletters again.

Sample Image - classesexportedusingLL

Introduction

I have seen quite a lot of code explaining how to use classes exported from a DLL in an application. However, all these describe the usage of the exported classes by linking implicitly to the DLL. Refreshing our DLL concepts, there are two ways for an application to use a function written in a DLL. The first way is to have your application's source code simply reference symbols contained in the DLL. This causes the loader to implicitly load (and link) the required DLL when the application is invoked. This is known as implicit linking.

The second way is for the application to explicitly load the required DLL (using a LoadLibrary() call) and explicitly link to the desired exported symbol while the application is running. In other words, if the application decides that it wants to call a function in a DLL, it can explicitly load the DLL into the process' address space, get the virtual memory address of the function contained within the DLL, and then call the function using this memory address. The beauty of this technique is that everything is done while the application is running and the application can unload the DLL from its process address space when it has finished its work with the DLL. As you might have guessed, this technique is known as explicit linking.

Background

So far, I spoke of using functions, but hey, what about using classes exported from a DLL? Well, in the case of implicitly linked DLLs, there is no difference at all. But what about loading DLLs explicitly and using the exported classes? Well, under normal circumstances, it cannot be done, but I wrote this article not to explain to you why it cannot be done, but to give you an idea as to how you can do it. That's right!! Using exported classes by loading a DLL using a LoadLibrary() call.

But before proceeding further, I warn you that the method given below is sort of a hack, and if for any reason you plan to use it in your project, please take the prior approval of your boss ... (if by any chance you do manage to get his/her approval on this technique!!). However, this column is basically for your understanding and also for extreme cases when you just cant do without this hack.

Using the code

If you look at the sample code, you can see that I have created a Calculator DLL called Calc.DLL and I am using the calculating powers present in the DLL in my console application called UserOfCalc (I couldn't think of a better name!).

 
// Calc.DLL contains an exported class
// called CCalc that contains 3 methods called Add,
Sub and GetLastFunc (). It is as follows:

// CALC.H - declares the CCalc class
// that is exported from the DLL
// and is imported in the EXE

#include <tchar.h>

#ifdef CALC_EXPORTS
#define CALC_API __declspec (dllexport)
#else
#define CALC_API __declspec (dllimport)
#endif

#define SOME_INSTN_BUF        260

class CALC_API CCalc
{
private:
TCHAR m_szLastUsedFunc[SOME_INSTN_BUF];

public:
    CCalc (); 

    int Add (int i, int j);
    int Sub (int i, int j);
    TCHAR* GetLastUsedFunc ();

};

The implementation of this DLL is as shown in the file Calc.cpp:

 
#include "Calc.h"
#include <windows.h>

BOOL APIENTRY DllMain (HANDLE, DWORD, LPVOID)
{
    return TRUE;
}

// Ctor, initializes the m_szLastFuncCalled array
CCalc::CCalc ()
{

    memset (m_szLastUsedFunc, 0, sizeof (m_szLastUsedFunc));
    strcpy (m_szLastUsedFunc, "No function used yet");
}


int CCalc::Add (int i, int j)
{
    strcpy (m_szLastUsedFunc, "Add used");
    return (i + j);
}

int CCalc::Sub (int i, int j)
{
    strcpy (m_szLastUsedFunc, "Sub used");
    return (i - j);
}

Now, how do we use the functions present in this Calc class by explicitly loading the DLL? The steps are as follows:

  1. The first step is to load the Calc.DLL library in your application using LoadLibrary.  
    HMODULE hMod = LoadLibrary ("Calc.dll");
    if (NULL == hMod)
    {
        printf ("LoadLibrary failed\n");
        return 1;
    }
  2. Since you have the header file of Calc.DLL, the next step is to allocate a block of memory that matches the class layout, and call your constructor code.  
    CCalc *pCCalc = (CCalc *) malloc (sizeof (CCalc));
    if (NULL == pCCalc)
    {
        printf ("memory allocation failed\n");
        return 1;
    }

    But why in the C++ world are we using malloc instead of new!! Because the new operator calls CCalc's constructor for which we don't have any access. Remember, we have to load the DLL dynamically and hence there is no definition of CCalc's constructor available to us at build time.

    Hence we just obtain an uninitialized block of memory whose size equals the CCalc class' size.

  3. If you look up the exported functions in Dumpbin.exe (that's located under your Microsoft Visual Studio\VC98\Bin directory), and type dumpbin /exports, <path to="" calc.dll="">you will see a list of functions exported by the DLL. (By the way, I have used a DEF file to unmangle the mangled function names.) It is as shown in the figure.

    Figure 1 - Dumpbin output

    The list contains the virtual memory address of the functions AddSubGetLastUsedFunc and the constructor.

    Since we obtained the block of memory, we have to call the constructor to initialize the block of memory. So, we get the relative virtual address of the constructor in the DLL.

     
    PCTOR pCtor = (PCTOR) GetProcAddress (hMod, "CCalc");
    if (NULL == pCtor)
    {
        printf ("GetProcAddress failed\n");
        return 1;
    }

    PCTOR is a function pointer and is present at the top of UserOfCalc.cpp. It is defined as follows:

     
    typedef void (WINAPI * PCTOR) ();
  4. Since we have the address of the constructor, we have to explicitly call it to initialize the block of memory obtained by malloc. Yes, but how do we associate an object for the constructor?

    If you remember, when any member function is called, including the constructor, the address of the object gets quietly passed to the called function and this address is stored in the stack. On an Intel based machine, this address of the object is pushed onto the stack via the ECX register. So, if you create a class and call its member function, the ECX register contains the 'this' pointer. This screen shot should make things clearer.

    Figure 2 - Watch window output

    If you observe the disassembly window, just after the execution of the line:

     

    ASM  
    LEA ECX, [EBP-4]

    you will see that the contents of ECX and '&bmw' are the same. On a machine having a different processor architecture, it could be another register instead of ECX. We just have to figure that out.

  5. Coming back to our Calc.dll, since we already have the address of a block of memory (that will in the future be an object), we move this address into the ECX register by using the Visual C++ inline assembler syntax: ASM  
    __asm { MOV ECX, pCCalc }
  6. Since we have already obtained the address of the constructor, we just say:  
    pCtor ();
  7. When your function pointer pCtor() returns from the DLL, it would have initialized the object of the class contained in the DLL. Voila!!
  8. To call any other member function of the Calc class, once again move pCalc to ECX and obtain the proc address of the exported function and simply call the function. If you look at the disassembly for any simple class, you will observe that before any member function call, there is always an assembly instruction to move 'this' into ECX. This is basically what we have done.

Points of Interest

If you single step through the source code, this concept will be much clearer to you. For understanding the working of DLLs, please refer 'Programming Applications for Microsoft Windows' or 'Advanced Windows NT', both written by Jeffrey Richter. They are awesome!!

Finally, this is my first shot at writing something (anything!!). So, I would be really happy if you enjoy reading this article and if you find this useful. If you have any suggestions or criticisms, please feel free to mail me at [email protected].

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By Anup. V Software Developer (Senior) United States United States This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.    

标签:function,DLL,classes,CCalc,address,using,exported
From: https://www.cnblogs.com/ioriwellings/p/17984583

相关文章

  • Qt如何调用VS编写的动态链接库(dll文件)
     下面是我在VS编译器上写的一个简单的dll文件,关于dll文件如何编写,我就不再赘述了。.h文件#ifndef_MYDLL_H#define_MYDLL_H#ifdefMYDLL_EXPORTS#defineMYDLL_API__declspec(dllexport)#else#defineMYDLL_API__declspec(dllimport)#endifextern"C"MYDLL_......
  • dllhost.exe
    什么是dllhost.exe?Dllhost.exe是一个合法的Windows进程,负责托管和执行DLL(动态链接库)文件。DLL文件包含多个程序可以同时使用的代码和数据,这有助于提高效率并减少系统中的冗余。dllhost.exe进程是Windows操作系统的重要组成部分,用于运行COM(组件对象模型)对象。COM对象是......
  • 使用日志类库log4net.dll出现代码loginfo.IsInfoEnabled等于false的解决办(转)
    按语:   工程进行了裁剪,发现原来的日志功能失效了,调试时发现loginfo.IsInfoEnabled一直为false。后参考下面博客内容修改了log4net.config的文件属性修改,解决问题。===========================================================================在使用wpf开发日志方面......
  • 深挖 Rundll32.exe 的多种“滥用方式”以及其“独特”之处
    恶意软件作者通常会编写恶意软件模仿合法的Windows进程。因此,我们可能会看到恶意软件伪装成svchost.exe、rundll32.exe或lsass.exe进程,攻击者利用的就是大多数Windows用户可能都不清楚这些系统进程在正常情况下的行为特征。在这篇文章中,我们将深挖rundll32.exe,以期对其有所了解。......
  • CMake链接DLL可行实践
    DLL作为Windows下的动态库格式,其同Linux等平台的动态库稍有不同,比如对MSVC编译器需要导出符号等。本文简述一种情况,即仅有dll文件及对应头文件时应当如何在CMake中完成链接。首先必须提示的一点是,DLL文件是程序运行时会调用的文件。编译器在编译链接时并不关心DLL文件在哪,而是会......
  • 《c++dll篇》VS2019生成dll及调用
    VS2019生成dll及调用生成DLL1.创建dll工程2.编写dll函数经过上述过程后工程中会生成几个自带的文件,可以自行创建或者更名,我直接在上面进行编写了。如下我先在pch.h中创建我需要调用函数的声明,他们分别用于实现加法和取最大值的功能,你可以根据自己的需求更改成自己的子程序。......
  • 《c++dll篇》VS2015生成dll及调用
    VS2015生成dll及调用原文链接:https://blog.csdn.net/qq_20792765/article/details/109801411创建DLL文件创建的DLL文件包括三个文件(.h/.dll/.lib),1、打开VS新建一个项目。2、选择DLL,附加选项选择空项目3、在头文件和源文件下分别添加如下文件4、在头文件CaculatorDLL.h......
  • 《c++dll篇》VS2008生成dll及调用
    VS2008生成dll及调用原文链接:https://www.cnblogs.com/Ich-Sun/p/6593703.html生成dlladd.h里面的代码:#ifndefDlladd_H_#defineDlladd_H_#ifdefMYLIB#defineMYLIBextern"c"_declspec(dllimport)#else#defineMYLIBextern"C"_declspec(dllexport)#e......
  • 通过 KernelUtil.dll 劫持 QQ / TIM 客户端 QQClientkey / QQKey 详细教程(附源码)
    前言由于QQ9.7.20版本后已经不能通过模拟网页快捷登录来截取QQClientkey/QQKey,估计是针对访问的程序做了限制,然而经过多方面测试,诸多的地区、环境、机器也针对这种获取方法做了相应的措施,导致模拟网页快捷登录来截取数据被彻底的和谐,为了解决这个问题我们只能更改思路对......
  • bat利用rundll32执行程序的函数执行程序
    利用rundll32执行程序的函数执行程序来源 https://www.cnblogs.com/17bdw/p/8668780.html1、前言无意间发现hexacorn这个国外大佬,给出了很多通过rundll32执行DLL中的函数执行程序的方法,思路很灵巧。2、原理rundll32加载dll用法:rundll32<dllname>,<entrypoint><option......