模拟PE文件加载

模拟PE文件加载

0.说明

观看滴水逆向视频总结(部分截图来自于滴水课件)

编译器:vc++6.0

编写语言:c

欢迎大家留言交流😃^ __ ^

可以加我qq一起学习:1245885144😄🤣

1.PE加载原理

模拟系统加载一个exe的过程,

通过pe重载的方法,可以将原有exe分割、加密、任意操作后,再通过pe重载的方法去启动对应exe的代码。实现对其核心代码的保护什么的0.0 ……

第一步:将exe映射至内存

image-20200810144943052

PE的拉伸

第二步:修正重定位表的地址

PE模拟重定位表运作

第三步: 修正IAT表

读取exe的导入表

通过LoadLibrary函数加载dll(多个dll要循环加载)

LoadLibrary( 参数:dll的地址字符串 )

​ :将dll加载至内存,同时按需要修正dll的重定位表和IAT表,返回dll在文件中的句柄(首地址),失败返回NULL。

Ps:LoadLibrary不能用于加载exe,否则不会修正重定位表和IAT表

题外话:如果一个exe通过LoadLibrary加载dll,那他的导入表中不会出现该dll。

推荐资料:LoadLibrary函数详细说明

通过GetProcAddress获取对应函数地址

GetProcAddress(参数1:dll句柄or首地址, 参数2:函数名字符串)

​ :通过dll的句柄获取dll导出表信息,匹配参数2对应的函数名,返回该函数的地址,失败返回NULL。

Ps:GetProcAddress返回地址的默认类型是int (__stdcall *)(),即参数为空返回int型数据的函数。如果我们要返回的函数地址实际上是有参数的,那我们就得强转类型,不然会报错。

	//返回的函数地址,"Plus"这个函数实际上是有两个参数返回值为int的函数。
	int (*myPlus)(int , int) = ( int (*)(int , int))GetProcAddress( hModule , "Plus")

导出表工作方式

导入表与IAT表运作原理

第四步:跳转运行至PE入口

构造函数指针 void (*pFunc)( void ) 指向PE入口AddressOfEntryPoint

 	void (*pFunc)( void )  = (void (*)() )( (DWORD)pDosHeader + pOptionHeader->AddressOfEntryPoint );

然后pFunc( ); 即可跳转,执行对应PE的代码。

	printf("\n**************** PE Load *************************\n");
	pFunc();

2.PE加载总结

image-20200810151837708

3.一个小问题

效果展示:

image-20200810152100383

发现一个问题:这个重载PE程序并没有为我们弹出新的控制台黑框,而是在原有的控制台黑框里运行。

说明,一个控制台exe程序在运行的时候,系统会在运行代码段之前还有一个调用系统中“控制台黑框”的过程,但是似乎我以前一直都忽视了,不明白其中的底层原理。

4.源码

编译语言:c

编译环境:vc++6.0

Ps:因为这个代码写了很久,缝缝补补、修修改改,所以多少有点糙,见谅!


#include<stdio.h>
#include<windows.h>
#include<string.h>
#include<stdlib.h>
/*
#define Situation1  "C:/Windows/System32/"
#define Situation2  "C:/Windows/SysWOW64/"
#define Situation3  "./"
*/

//char DllSituation[300];

char FileName[500]={0};//读取的文件名(地址)



DWORD FileSize = 0;//文件状态下的大小

//功能:将文件PE读入内存1
//参数:文件地址
//返回值:指向内存1的指针
LPVOID ReadPeFile( char FileName[] );

//功能:将内存1的文件copy到内存2,构造成PE内存状态
//参数:指向内存1的指针
//返回值:指向内存2的指针
LPVOID CreateImageBuffer( LPVOID pFileBuffer);

//功能:修正重定位表
void AmendRelocation( LPVOID pImageBuffer );

//第六步函数指针启动exe
//参数:完成所有操作后的exe首地址
void ReloadPE( LPVOID pImageBuffer );

//第一步映射exe,修正重定位表表
//参数:exe地址名字
void ReadEXE( char FileName[] );

//第二步读取exe导入表
//参数:exe的首地址
//返回值:若成功返回pImageBuffer,失败返回NULL
LPVOID Read_EXE_Import( LPVOID pImageBuffer);
	

int main()
{
	printf("for example:   D:/user/Desktop/学习笔记/2020.8.8_PE重载/exe重载/实验.exe\n");
						
	printf("Please input: ");		
	gets(FileName);

	//第一步读取exe
	ReadEXE( FileName );
}


//第一步映射exe,修正重定位表表
//参数:exe地址名字
void ReadEXE( char FileName[] )
{
	LPVOID pFileBuffer = NULL;
	LPVOID pImageBuffer = NULL;


	pFileBuffer = ReadPeFile( FileName );
	if( pFileBuffer )
	{
		//映射exe
		pImageBuffer = CreateImageBuffer( pFileBuffer );
		if( pImageBuffer )
		{
			system("pause");

			//修正 重定位表
			AmendRelocation( pImageBuffer );
			
			//读取dll函数
			pImageBuffer = Read_EXE_Import( pImageBuffer );
			
			//第六步:函数指针启动exe
			if( pImageBuffer )
			{
				system("pause");
				ReloadPE( pImageBuffer );	
			}
		}
	}
	
}


//第二步读取exe导入表
//参数:exe的首地址
//返回值:若成功返回pImageBuffer,失败返回NULL
LPVOID Read_EXE_Import( LPVOID pImageBuffer)
{	
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS32 pNtHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionHeader =NULL;
	
	PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
	PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL;
	
	PBYTE pDllName = NULL;
	PDWORD pIAT = NULL;

	PIMAGE_IMPORT_BY_NAME pImportByName = NULL;

	int i;
	//dll句柄
	HINSTANCE hModule = NULL;
	
	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
	pNtHeader = (PIMAGE_NT_HEADERS32)( (DWORD)pDosHeader + pDosHeader->e_lfanew);
	pFileHeader = (PIMAGE_FILE_HEADER)( (DWORD)pNtHeader + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER );
	
	pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory ;
	

	if(pDataDirectory[1].VirtualAddress  )
	{
		pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)( (DWORD)pDosHeader + pDataDirectory[1].VirtualAddress );
		//遍历exe的导入表
		while( pImportDescriptor->OriginalFirstThunk && pImportDescriptor->FirstThunk )
		{	
			//初始化参数
			pDllName = (PBYTE)( (DWORD)pDosHeader + pImportDescriptor->Name );
			pIAT = (PDWORD)( (DWORD)pDosHeader + pImportDescriptor->FirstThunk );	

			hModule = LoadLibrary( pDllName );
				
			if(!hModule)
			{
				printf("Sorry,not found Dll:%s\n",pDllName);
				return NULL;
			}
			

			for(i=0 ; *(pIAT+i) ; i++)
			{
				if(*(pIAT+i) & 0x80000000)
					*(pIAT+i) = GetProcAddress( hModule , (char*)(*pIAT&0x7fffffff) );
				else
				{
					pImportByName = (PIMAGE_IMPORT_BY_NAME)( (DWORD)pDosHeader + *(pIAT+i) );
					*(pIAT+i) = GetProcAddress( hModule , (char*)pImportByName->Name );
				}
			}
			
			pImportDescriptor++;
		
		}
		//遍历
		
		
	}
	return pImageBuffer ;
}


//功能:将文件PE读入内存1
//参数:文件地址
//返回值:指向内存1的指针
LPVOID ReadPeFile( char FileName[] )
{	
	LPVOID pFileBuffer = NULL;
	FILE* pFile = NULL;
	DWORD FileSize = 0;
	size_t flag = 0;

	//打开文件
	pFile = fopen(FileName , "rb");
	if(!pFile)
	{
		printf("open file failure!\n");
		return NULL;
	}
	
	//读取文件大小
	fseek(pFile , 0 , SEEK_END);
	FileSize = ftell( pFile );
	fseek(pFile , 0 , SEEK_SET);
	
	//分配内存1 空间 并初始化为0
	pFileBuffer = calloc( FileSize , 1 );
	if(!pFileBuffer)
	{
		printf("Failed to allocate memory space_1!\n");
		fclose(pFile);
		return NULL;
	}

	
	//读取文件数据 至 内存1
	flag = fread(pFileBuffer , FileSize , 1 , pFile );
	if(!flag)
	{
		printf("read data failure!\n");
		fclose(pFile);
		free(pFileBuffer);
		return NULL;
	}

	//关闭文件
	fclose(pFile);
//

//	printf("%x\n" , *(PWORD)(pFileBuffer));
	

	return pFileBuffer;
}


//功能:将内存1的文件copy到内存2,构造成PE内存状态(拉伸)
//参数:指向内存1的指针
//返回值:指向内存2的指针
LPVOID CreateImageBuffer( LPVOID pFileBuffer)
{
	LPVOID pImageBuffer = NULL;//指向内存2

	PIMAGE_DOS_HEADER pDosHeader = NULL;//DOS头 指针
	PIMAGE_NT_HEADERS32 pNtHeader = NULL ;//NT头 指针
	PIMAGE_FILE_HEADER pFileHeader = NULL;//文件头 指针
	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;//可选头 指针
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;//节区头 指针

	size_t i;//记录节区

//	printf("%x\n" , *(PWORD)(pFileBuffer));

	//检测是否是'MZ'标志
	if( *(PWORD)pFileBuffer != IMAGE_DOS_SIGNATURE )
	{
		printf("sorry , not a void 'MZ' signature!\n");
		free(pFileBuffer);
		return NULL;
	}
	pDosHeader = ( PIMAGE_DOS_HEADER )pFileBuffer;

	//检测是否是'PE'标志
	pNtHeader = ( PIMAGE_NT_HEADERS32 )( (DWORD)pFileBuffer + pDosHeader->e_lfanew );
	if(pNtHeader->Signature != IMAGE_NT_SIGNATURE )
	{
		printf("sorry , not a void 'PE' signature\n");
		free(pFileBuffer);
		return NULL;
	}

	pFileHeader = ( PIMAGE_FILE_HEADER )( (DWORD)pNtHeader + 4 );
	
	pOptionHeader = ( PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER );

	//分配内存2 空间 并初始化为0
	pImageBuffer = calloc( pOptionHeader->SizeOfImage , 1 );//
	if(!pImageBuffer)
	{
		printf("failed to allocate memory space_2!\n");
		free( pFileBuffer );
		return NULL;
	}

//	printf("size = %x\n",pOptionHeader->SizeOfImage );

	

	//将header复制到ImageBuffer
	memcpy( pImageBuffer , pFileBuffer , pOptionHeader->SizeOfHeaders );

//	printf("SizeOfHeaders = %x\n",pOptionHeader->SizeOfHeaders );

//printf("1\n");

	//将 多个 节区复制到ImageBuffer
	pSectionHeader = (PIMAGE_SECTION_HEADER)( (DWORD)pOptionHeader + pFileHeader->SizeOfOptionalHeader );
	for(i=pFileHeader->NumberOfSections ; i>0 ; i--)
	{
		memcpy( (LPVOID)( (DWORD)pImageBuffer + pSectionHeader->VirtualAddress) , (LPVOID)( (DWORD)pDosHeader + pSectionHeader->PointerToRawData ) , pSectionHeader->SizeOfRawData  );
		//循环遍历 再 copy
		pSectionHeader = (PIMAGE_SECTION_HEADER)( (DWORD)pSectionHeader + IMAGE_SIZEOF_SECTION_HEADER );
	}

	//释放 内存1 的空间
	free(pFileBuffer);
	

//	printf("%x\n" , *(PWORD)(pImageBuffer));
	

	return pImageBuffer;
}

//功能:修正重定位表
void AmendRelocation( LPVOID pImageBuffer )
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS32 pNtHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;

	PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
	PIMAGE_BASE_RELOCATION pBaseRelocation = NULL;
	
//	int j=0;
	DWORD i =0;
	DWORD ImageBaseOffset = 0;//ImageBase的偏移
	PWORD pRelocation = NULL;

	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer ;
	pNtHeader = (PIMAGE_NT_HEADERS32)( (DWORD)pDosHeader + pDosHeader->e_lfanew );
	pFileHeader = (PIMAGE_FILE_HEADER)( (DWORD)pNtHeader + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
	
	pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory ;
	
	if(pDataDirectory[5].VirtualAddress == 0)
	{
		printf("exe have not Base Relocation Table!\n");
		return ;
	}

	pBaseRelocation = (PIMAGE_BASE_RELOCATION)( (DWORD)pDosHeader + pDataDirectory[5].VirtualAddress );

	ImageBaseOffset = (DWORD)pDosHeader - pOptionHeader->ImageBase ;

	printf("ImageBase :%X\n",pOptionHeader->ImageBase );
	pOptionHeader->ImageBase = (DWORD)pDosHeader;
	printf("Amended,ImageBase :%X\n",pOptionHeader->ImageBase );

	while(pBaseRelocation->SizeOfBlock && pBaseRelocation->VirtualAddress )
	{
		pRelocation = (PWORD)( (DWORD)pBaseRelocation + 8);

		for(i=(pBaseRelocation->SizeOfBlock - 8)/2 ; i>0 ;i--,pRelocation++)
			if( (*pRelocation) >> 12 )
			{
				*(PDWORD)( (DWORD)pDosHeader + (pBaseRelocation->VirtualAddress| ((*pRelocation)&0xfff) )  ) += ImageBaseOffset;
//				j++;
			}
			pBaseRelocation = (PIMAGE_BASE_RELOCATION)( (DWORD)pBaseRelocation + pBaseRelocation->SizeOfBlock  );
	}
//	printf("j=%d\n",j);

}
//第六步函数指针启动exe
//参数:完成所有操作后的exe首地址
void ReloadPE( LPVOID pImageBuffer )
{
	void (*pFunc)() = NULL;

	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS32 pNtHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;

	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer ;
	pNtHeader = (PIMAGE_NT_HEADERS32)( (DWORD)pDosHeader + pDosHeader->e_lfanew );
	pFileHeader = (PIMAGE_FILE_HEADER)( (DWORD)pNtHeader + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER)( (DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);

	*pFunc = (void (*)() )( (DWORD)pDosHeader + pOptionHeader->AddressOfEntryPoint );

	printf("\n**************** PE Load *************************\n");
	pFunc();


	printf("666\n");
	getchar();\
}

—————————————————————————————————————
欢迎大家留言交流!😃

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值