PE之拉伸文件添加shellcode并保存文件

//获得文件buffer
BOOL GetFileBuffer(__in char* m_fileName, __inout char** LPFilebuffer)
{
	// 初始化输出参数
	*LPFilebuffer = NULL;
	if (m_fileName == NULL || LPFilebuffer == NULL)
	{
		perror("m_fileName OR LPFilebuffer is NULL");
	}
	FILE* file = (fopen(m_fileName, "rb"));
	if (file == NULL)
	{
		printf("error :%d", GetLastError());
		return FALSE;
	}

	// 从文件头跳转到偏移0x3C位置
	if (fseek(file, 0x3C, SEEK_SET) != 0) {
		perror("fseek failed");
		fclose(file);
		return FALSE;
	}
	//读到e_lfannew的值
	//LONG e_lfannew = 0;
	//if (fread(&e_lfannew, sizeof(LONG), 1, file) != 1) {
	//	perror("fread failed");
	//	fclose(file);
	//	return FALSE;
	//}
	从文件开始跳到可选头的imagebase的位置
	//fseek(file, e_lfannew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + 0x38, SEEK_SET);
	//DWORD sizeofimage = 0;
	//fread(&sizeofimage, sizeof(DWORD), 1, file);
	fseek(file, 0, SEEK_END);//到文件尾部
	DWORD fileSize = ftell(file);//获得文件的大小
	fseek(file, 0, SEEK_SET);//返回文件头部
	*LPFilebuffer = malloc(fileSize);
	if (*LPFilebuffer == NULL)
	{
		perror("malloc failed");
		fclose(file);
		free(*LPFilebuffer);

		return FALSE;
	}
	memset(*LPFilebuffer, 0, fileSize);
	fread(*LPFilebuffer, 1, fileSize, file);//将文件读取到内存中
	fclose(file);
	file = NULL;
	return TRUE;
}

//获得imagebuffer
BOOL StrechFileBuffer(__in char* LPFilebuffer, __inout char** LPImageBuffer)
{
	if (LPFilebuffer == NULL)
	{
		perror("Filebuffer is NULL");
		return FALSE;
	}
	PIMAGE_DOS_HEADER pDos =(PIMAGE_DOS_HEADER) LPFilebuffer;
	PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)(LPFilebuffer + pDos->e_lfanew + sizeof(DWORD));
	DWORD sizeofimage = *(PDWORD)(LPFilebuffer + pDos->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + 0x38);
	//根据imagebase申请拉伸后的内存
	char* pImagebuffer = malloc(sizeofimage);
	if (pImagebuffer == NULL)
	{
		perror("malloc failed");
		return FALSE;
	}
	memset(pImagebuffer, 0, sizeofimage);

	/
	/*已经将PE文件写到内存中了.但是需要分开拷贝,从最后的节开始拷贝数据*/
	
	//看看是多少位的程序
	WORD magic = *(WORD*)(LPFilebuffer + pDos->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER));

	//跳到最后一个节区信息结构列表
	WORD NumberOfSections = pFileHeader->NumberOfSections;
	PIMAGE_SECTION_HEADER PLastSectionTable =(PIMAGE_SECTION_HEADER) (char*)pFileHeader +sizeof(IMAGE_FILE_HEADER)+ (pFileHeader->SizeOfOptionalHeader) + ((NumberOfSections -1) * sizeof(IMAGE_SECTION_HEADER));
	
	// 从最后一个节区开始向前拷贝
	PIMAGE_SECTION_HEADER currentSection = PLastSectionTable; // 获取当前节区的指针
	for (size_t i = pFileHeader->NumberOfSections; i > 0; i--, currentSection--) {
		// 从文件中获取源地址和目标地址
		char* src = LPFilebuffer + currentSection->PointerToRawData; // 文件中的数据
		char* dest = pImagebuffer + currentSection->VirtualAddress; // 内存中的目标地址

		// 计算拷贝的大小
		size_t sizeToCopy = currentSection->SizeOfRawData > currentSection->Misc.VirtualSize
			? currentSection->SizeOfRawData
			: currentSection->Misc.VirtualSize;
		// 拷贝数据
		memcpy(dest, src, sizeToCopy);
	}

	//拷贝pe头和节表
	size_t sizeToCopy = 0;
	if (magic == 0X10B)
	{
		PIMAGE_OPTIONAL_HEADER32 Poptional =(PIMAGE_OPTIONAL_HEADER32) (LPFilebuffer + pDos->e_lfanew + sizeof(DWORD)) + sizeof(IMAGE_FILE_HEADER);
		sizeToCopy = Poptional->SizeOfHeaders;
	}
	else
	{
		PIMAGE_OPTIONAL_HEADER64 Poptional = (PIMAGE_OPTIONAL_HEADER64)(LPFilebuffer + pDos->e_lfanew + sizeof(DWORD)) + sizeof(IMAGE_FILE_HEADER);
		sizeToCopy = Poptional->SizeOfHeaders;
	}
	memcpy(pImagebuffer, LPFilebuffer, sizeToCopy);

	*LPImageBuffer = pImagebuffer;
	
	
	return TRUE;
}


//恢复到flieBuffer状态
BOOL RestoreImageToFile( __in char* LPImageBuffer, __inout char** LPFilebuffer, __inout DWORD* BufferSize)
{
	if (LPFilebuffer == NULL || LPImageBuffer == NULL)
	{
		perror("LPFilebuffer OR LPImageBuffer is NULL");
		return FALSE;
	}
	DWORD sizeOfHeader = 0;//头部文件对齐的大小
	DWORD sizeOfRawDatas = 0;//所有节需要的内存对齐大小
	PIMAGE_DOS_HEADER pDos =(PIMAGE_DOS_HEADER) LPImageBuffer;
	PIMAGE_FILE_HEADER pFileHeader =(PIMAGE_FILE_HEADER) (LPImageBuffer + pDos->e_lfanew + sizeof(DWORD));
	PIMAGE_SECTION_HEADER pFirstSectionHeader = (PIMAGE_SECTION_HEADER)((char*)pFileHeader + sizeof(IMAGE_FILE_HEADER) + pFileHeader->SizeOfOptionalHeader);
	
	PIMAGE_OPTIONAL_HEADER32 poptionalHeader32 = (PIMAGE_OPTIONAL_HEADER32)((char*)pFileHeader+sizeof(IMAGE_FILE_HEADER));
	PIMAGE_OPTIONAL_HEADER64 poptionalHeader64 = (PIMAGE_OPTIONAL_HEADER64)((char*)poptionalHeader32);
	
	//用于保存每个节区的节区FOA 和 文件对齐的大小.这样我就不需要遍历2次了.因为我现在还不知道要申请多大的一块内存
	PIMAGE_SECTION_HEADER pCurrentSectionHeader = pFirstSectionHeader;// 保存初始的指针位置
	
	for (size_t i = 0; i < pFileHeader->NumberOfSections; i++) {
		sizeOfRawDatas += pCurrentSectionHeader->SizeOfRawData;
		pCurrentSectionHeader++;
	}
	pCurrentSectionHeader--;//不 -- ,将会越界访问
	//开始为保存为文件 申请内存
	//读一下magic,便于看使用哪个可选头结构体
	WORD Magic = *(WORD*)((char*)pFileHeader + sizeof(IMAGE_FILE_HEADER));
	if (Magic == 0x10b)
	{
		sizeOfHeader = poptionalHeader32->SizeOfHeaders;
	}
	else
	{
		sizeOfHeader = poptionalHeader64->SizeOfHeaders;
	}
	//终于开始申请内存了
	char* pFileBuffer = (char*)malloc(sizeOfHeader + sizeOfRawDatas);
	if (pFileBuffer == NULL)
	{
		perror("pFileBuffer is faild");
		return FALSE;

	}
	memset(pFileBuffer, 0, sizeOfHeader + sizeOfRawDatas);
	for (size_t i = pFileHeader->NumberOfSections; i >0 ; i--)
	{
		char* source = (LPImageBuffer)+pCurrentSectionHeader->VirtualAddress;//获取到在内存中的位置
		char* dst = pFileBuffer + pCurrentSectionHeader->PointerToRawData;//获取到应该在文件中的位置
		DWORD copySize = pCurrentSectionHeader->SizeOfRawData;//文件对齐后的大小
		memcpy(dst, source, copySize);
		pCurrentSectionHeader--;
	}

	//复制整个头和节表
	memcpy(pFileBuffer, LPImageBuffer, sizeOfHeader);
	*LPFilebuffer = pFileBuffer;
	*BufferSize = sizeOfHeader + sizeOfRawDatas;
	return TRUE;
}
//保存到文件
BOOL StoringFile(__in char* SaveFilePath, __in char* FileBuffer ,DWORD BufferSize)
{
	if (SaveFilePath == NULL || FileBuffer == NULL)
	{
		perror("SaveFilePath or FileBuffer is NULL");
		return FALSE;
	}
	FILE* file = fopen(SaveFilePath,"r");
	{
		if (file) {
			// 文件已经存在
			fclose(file);
			printf("文件 '%s' 已存在,是否覆盖?(y/n): ", SaveFilePath);

			char response;
			scanf(" %c", &response); // 读取用户输入
			if (response != 'Y' && response != 'y') {
				printf("操作取消\n");
				return FALSE;
			}
		}

	}
	FILE* pFile = fopen(SaveFilePath, "wb");
	if (!pFile) {
		perror("无法打开文件");
		return FALSE;
	}
	// 写入数据到文件
	size_t elementsWritten = fwrite(FileBuffer, BufferSize, 1 , pFile);

	if (elementsWritten != BufferSize) {
//这里这样判断会出现问题,即使写入成功,也会导致进入这里 
		perror("写入错误");
		fclose(pFile);
		return FALSE;
	}

	// 关闭文件
	fclose(pFile);

	printf("数据已成功保存到二进制文件\n");

	return TRUE;
}


///
//测试拉伸文件,然后恢复文件,最后保存
BOOL TestLoadAndSave(__in char* m_fileName, __in char* SaveFilePath)
{
	char* Filebuffer = NULL;
	char* NewFielBuffer = NULL;
	CHAR* ImageBuffer = NULL;
	DWORD size = 0;
	do
	{
		if (!GetFileBuffer(m_fileName, &Filebuffer))break;
		if (!StrechFileBuffer(Filebuffer, &ImageBuffer))break;
		if (!RestoreImageToFile(ImageBuffer, &NewFielBuffer, &size))break;
		if (!StoringFile(SaveFilePath, NewFielBuffer, size))break;

	} while (FALSE);
	
	free(Filebuffer);
	free(ImageBuffer);
	free(NewFielBuffer);
	return TRUE;
}

///
//测试添加E8 E9 SHELLCODE 在节的空白区添加shellcode
BOOL AddShellCodeInEmpty(__in char* LPImageBuffer,__in char* Shellcode,DWORD SizeofShellcode)
{
	if (LPImageBuffer == NULL || Shellcode == NULL || SizeofShellcode==0)
	{
		perror("LPImageBuffer or Shellcode or SizeofShellcode is error");
	}
	
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)LPImageBuffer;
	PIMAGE_FILE_HEADER pFileHeader =(PIMAGE_FILE_HEADER) (LPImageBuffer + pDos->e_lfanew+sizeof(DWORD));
	PIMAGE_SECTION_HEADER pFirstSectionHeader = (PIMAGE_SECTION_HEADER)((char*)pFileHeader + sizeof(IMAGE_FILE_HEADER) + pFileHeader->SizeOfOptionalHeader);
	//尝试在节区某个空白区添加代码
	
	int EmptySize = 0;
	DWORD minSize = 0;
	BOOL FindIt = FALSE;
	//遍历节表
	PIMAGE_SECTION_HEADER pCurrent = pFirstSectionHeader;
	for (size_t i = 0; i < pFileHeader->NumberOfSections; i++)
	{
		if (pCurrent->Misc.VirtualSize < pCurrent->SizeOfRawData && (pCurrent->SizeOfRawData - pCurrent->Misc.VirtualSize) >= SizeofShellcode)
		{
			FindIt = TRUE;
			break;
		}
		pCurrent++;
	}
	if (FindIt==TRUE)//如果找到了
	{
		if ((pCurrent->Characteristics & 0x60000020) != 0x60000020)
		{
			//说明不是代码区,需要修改一下属性
			pCurrent->Characteristics |= 0x60000020;
		}
		//硬编码这一块写的非常烂,毫无兼容性,完全就是垃圾
        //硬编码这一块写的非常烂,毫无兼容性,完全就是垃圾
        //硬编码这一块写的非常烂,毫无兼容性,完全就是垃圾
		PIMAGE_OPTIONAL_HEADER32 pOptional = (PIMAGE_OPTIONAL_HEADER32)(char*)pFileHeader + sizeof(IMAGE_FILE_HEADER);//在使用 EOP和imagebase时,32位和64位是相同的
		///修正E8 //754A1060  是messagebox的地址
		//offect=要跳转的地址 减去 e8 下一条指令的地址
		DWORD offect = 0X754A1060 - (pOptional->ImageBase + pCurrent->VirtualAddress + pCurrent->Misc.VirtualSize + 0XD);
		*((PDWORD)&Shellcode[9]) = offect;
		//修复e9 要跳转的地址为oep
		offect = (pOptional->AddressOfEntryPoint + pOptional->ImageBase) - (pOptional->ImageBase + pCurrent->VirtualAddress + pCurrent->Misc.VirtualSize + 0x12);
		*((PDWORD)&Shellcode[14])= offect;
		memcpy(LPImageBuffer + pCurrent->VirtualAddress + pCurrent->Misc.VirtualSize, Shellcode, SizeofShellcode);

		//设置新的oep
		DWORD NewAddressOfPoint = pCurrent->VirtualAddress+ pCurrent->Misc.VirtualSize;
		pOptional->AddressOfEntryPoint = NewAddressOfPoint;
	
	}
	else
	{
		//很可惜没有找到
		//现在我们可以使用 新增节,扩大节 合并节 这些操作了
	}
	return TRUE;
}

BOOL TestAddShellCode(__in char* m_fileName, __in char* SaveFilePath)
{
	char* Filebuffer = NULL;
	char* NewFielBuffer = NULL;
	CHAR* ImageBuffer = NULL;
	DWORD size = 0;
	char shellcode[] = { 0X6A, 0X00,0X6A,0X00,0X6A,0X00,0X6A,0X00,0XE8,0X00,0X00,0X00,0X00,0XE9,0X00,0X00,0X00,0X00 };
	DWORD SizeofShellcode = sizeof(shellcode);
	do
	{
		if (!GetFileBuffer(m_fileName, &Filebuffer))break;
		if (!StrechFileBuffer(Filebuffer, &ImageBuffer))break;
		if (!AddShellCodeInEmpty(ImageBuffer, shellcode, SizeofShellcode))break;

		if (!RestoreImageToFile(ImageBuffer, &NewFielBuffer, &size))break;
		if (!StoringFile(SaveFilePath, NewFielBuffer, size))break;

	} while (FALSE);

	free(Filebuffer);
	free(ImageBuffer);
	free(NewFielBuffer);
	return TRUE;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值