1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式

在介绍入口函数之前,先介绍一下几种运行时的库(Runtime Library)以及他们对应的链接选项:


1.Multi-threaded Debug (/MTd)

这个是debug版本的多线程库,静态链接的。
2.Multi-threaded (/MT)
这是release版本的多线程库,静态链接的。


3.Multi-threaded Debug DLL (/MDd)

这是debug版本的多线程库,动态链接的。

4.Multi-threaded DLL (/MD)

这是release版本的多线程库,动态链接的。


debug版本的运行库增加了一些错误检查的代码,如:堆栈的溢出检查,基于cookie的安全检查,基于CheckStackVar的检查。这些额外的代码可以帮助检测编码中的非安全错误。因此debug版本的运行效率没有release版本高。后面的章节将详细介绍debug运行时的安全检查策略。

静态链接运行时与动态链接运行时的区别在于,静态链接会将整个运行时的代码链接到模块中(也就是说每个模块都有一份运行时的代码),而动态链接会以共享的方式被模块使用(也就是说每个模块都会共享一份运行时的代码)。这样会导致在不同的链接方式下,它们有自己需要注意的地方。

1.采用/MD选项

a.由于是动态链接运行时,那么最终生成的模块体积会很小

b.每个模块都共享一份运行时代码,那么堆的申请与释放很自由,A模块申请堆,B模块释放堆,这样是可以得。

2.采用/MT选项

a.由于是静态链接的,那么每个模块都会包含一份运行时代码,自然会增加其体积。但是这样可以在缺少运行时的系统中稳定的运行。

b.每个模块都会包含一份运行时代码,那么只能在自己的模块中释放自己申请的堆,否则会出现错误。

注意:多个模块的情况下,必须选择相同的选项,不可以混用。


以下是测试方案:

在A DLL中添加申请堆和释放堆得代码,在B DLL中添加同样的代码,并将它们以不同的链接方式生成(/MD,/MT)。

在主程序中加载这两个DLL,并分别获取它们的导出函数。


A DLL代码如下:

// A_DLL.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"

char* MallocHeap( int n )
{
	if ( n <= 0 )
	{
		return NULL;
	}

	char* pHeap = new char( n );

	if ( pHeap )
	{
		return pHeap;
	}
	else
	{
		return NULL;
	}

	return NULL;
}


BOOL FreeHeap( char* pHeap )
{
	if ( pHeap )
	{
		delete pHeap;
		pHeap = NULL;

		return TRUE;
	}
	else
	{
		return FALSE;
	}

	return FALSE;
}

B DLL代码如下:

// B_DLL.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"


char* MallocHeap( int n )
{
	if ( n <= 0 )
	{
		return NULL;
	}

	char* pHeap = new char( n );

	if ( pHeap )
	{
		return pHeap;
	}
	else
	{
		return NULL;
	}

	return NULL;
}


BOOL FreeHeap( char* pHeap )
{
	if ( pHeap )
	{
		delete pHeap;
		pHeap = NULL;

		return TRUE;
	}
	else
	{
		return FALSE;
	}

	return FALSE;
}

主程序代码如下:

// LinkerOption.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include 
#include 

typedef char* ( *FunMallocHeap ) ( int );
typedef BOOL ( *FunFreeHeap ) ( char* );

int _tmain(int argc, _TCHAR* argv[])
{
	HMODULE hDllA = ::LoadLibrary( L"A_DLL.dll" );
	HMODULE hDllB = ::LoadLibrary( L"B_DLL.dll" );

	if ( !hDllA || !hDllB )
	{
		return 1;
	}

	//获取DLL A中MallocHeap地址
	FunMallocHeap pMallocHeapA = NULL;
	pMallocHeapA = ( FunMallocHeap )::GetProcAddress( hDllA, "MallocHeap" );

	//获取DLL B中MallocHeap地址
	FunMallocHeap pMallocHeapB = NULL;
	pMallocHeapB = ( FunMallocHeap )::GetProcAddress( hDllB, "MallocHeap" );

	if ( !pMallocHeapA || !pMallocHeapB )
	{
		return 1;
	}


	//获取DLL A中FreeHeap地址
	FunFreeHeap pFreeHeapA = NULL;
	pFreeHeapA = ( FunFreeHeap )::GetProcAddress( hDllA, "FreeHeap" );

	//获取DLL B中FreeHeap地址
	FunFreeHeap pFreeHeapB = NULL;
	pFreeHeapB = ( FunFreeHeap )::GetProcAddress( hDllB, "FreeHeap" );

	if ( !pFreeHeapA || !pFreeHeapA )
	{
		return 1;
	}

	if ( argc < 3 )
	{
		printf( "请输入参数:(A B)(A A)前者为申请模块,后者为释放模块\r\n" );

		return 3;
	}

	wchar_t szMallocObj[10];
	wcscpy( szMallocObj, argv[1] );

	wchar_t szFreeObj[10];
	wcscpy( szFreeObj, argv[2] );

	if ( wcscmp( szMallocObj, L"A") == 0 )//A模块申请
	{
		//使用A模块申请堆
		char*p = NULL;
		p = pMallocHeapA( 10 );

		if ( wcscmp( szFreeObj, L"A") == 0 )//A模块释放
		{
			//使用A模块释放堆
			BOOL bRet = pFreeHeapA( p );
			if ( bRet )
			{
				::MessageBox( NULL, L"A DLL FreeHeap OK", L"Tips", MB_OK );
			}
			else
			{
				::MessageBox( NULL, L"A DLL FreeHeap Fail", L"Tips", MB_OK );
			}

		}

		if ( wcscmp( szFreeObj, L"B") == 0 )//B模块释放
		{
			//使用B模块释放堆
			BOOL bRet = pFreeHeapB( p );
			if ( bRet )
			{
				::MessageBox( NULL, L"B DLL FreeHeap OK", L"Tips", MB_OK );
			}
			else
			{
				::MessageBox( NULL, L"B DLL FreeHeap Fail", L"Tips", MB_OK );
			}
		}
	}



	if ( wcscmp( szMallocObj, L"B") == 0 )//B模块申请
	{
		//使用B模块申请堆
		char*p = NULL;
		p = pMallocHeapB( 10 );

		if ( wcscmp( szFreeObj, L"A") == 0 )//A模块释放
		{
			//使用A模块释放堆
			BOOL bRet = pFreeHeapA( p );
			if ( bRet )
			{
				::MessageBox( NULL, L"A DLL FreeHeap OK", L"Tips", MB_OK );
			}
			else
			{
				::MessageBox( NULL, L"A DLL FreeHeap Fail", L"Tips", MB_OK );
			}

		}

		if ( wcscmp( szFreeObj, L"B") == 0 )//B模块释放
		{
			//使用B模块释放堆
			BOOL bRet = pFreeHeapB( p );
			if ( bRet )
			{
				::MessageBox( NULL, L"B DLL FreeHeap OK", L"Tips", MB_OK );
			}
			else
			{
				::MessageBox( NULL, L"B DLL FreeHeap Fail", L"Tips", MB_OK );
			}
		}
	}

	return 0;
}



先使用/MD链接各个模块并运行,效果如下:

A申请A释放:


1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式_第1张图片


A申请B释放:


1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式_第2张图片


B申请B释放:


1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式_第3张图片


B申请A释放:

1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式_第4张图片




现在使用/MT方式链接,并测试如下;

A申请A释放:

1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式_第5张图片


A申请B释放:

1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式_第6张图片


B申请B释放:

1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式_第7张图片


B申请A释放:

1-1 Windows下启动函数(真正的入口函数) 之 运行时链接方式_第8张图片



可见,测试结果说明了/MD和/MT的区别所在。

下一节将详细介绍这两张不同运行时的更细节的区别。

你可能感兴趣的:(C++逆向)