// FileToImage.cpp: implementation of the FileToImage class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FileToImage.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <winnt.h>
#include <malloc.h>

#define FILEPATH_IN "E:\\达人\\Jmp\\Debug\\Jmp.exe"
#define FILEPATH_OUT "E:\\达人\\Jmp\\Debug\\NewJmp.exe"
#define SHELLCODELENGTH 0x12
#define MESSAGEBOXADDR 0x00401066

//声明全局变量
extern BYTE shellCode[] =
{
					0x6A,00,0x6A,00,0x6A,00,0x6A,00,
					0xE8,00,00,00,00,
					0xE9,00,00,00,00
};
//文件写入内存开始

int FileLength(FILE* fp)
{
	int fileSize = 0;
	fseek(fp,0,SEEK_END);
	fileSize = ftell(fp);
	fseek(fp,0,SEEK_SET);  //指针归位
	return fileSize;
}

//创建一个函数
//两个参数  文件路径,返回的文件地址
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* PFileBuffer)
{
	FILE* pFile = NULL;		//文件指针
	DWORD fileSize = 0;		//文件大小
	LPVOID pTempFileBuffer = NULL;		//malloc 返回指针(缓冲区指针)


	//打开文件
	pFile = fopen(lpszFile,"rb+");
	//打开失败返回
	if(!pFile)
	{
		printf("无法打开 EXE 文件");
		return 0;
	}

	//读取文件大小
	FileLength(pFile);

	//分配缓冲空间
	pTempFileBuffer = malloc(fileSize);

	//失败返回方法
	if(!pTempFileBuffer)
	{
		printf("缓冲区分配失败");
		fclose(pFile);  //关闭文件指针
		return 0;
	}


	//将缓冲器分配好之后,将文件数据读取到缓冲区
	size_t n = fread(pTempFileBuffer,fileSize,1,pFile);   //size_t = unsigned int  fread(分配好的地址*,读取次数,每次读取大小,文件地址*)
	//失败返回
	if(!n)
	{
		printf("读取数据失败\n");
		free(pTempFileBuffer);   //释放分配好的内存
		fclose(pFile);	 //关闭文件指针
		return 0;
	}

	//关闭文件
	*PFileBuffer = pTempFileBuffer;    //将文件内存地址  赋值  给OUT参数
	pTempFileBuffer = NULL;		//指针清空
	free(pFile);		//释放文件指针
	return fileSize;	//返回文件大小


//文件读入内存结束
}



/**
	FileBuffer 复制到 ImageBuffer
	两个参数  IN LPVOIE  FileBuffer指针, OUT LPVOID* ImageBuffer
  */
DWORD CopyfFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer)
{
	//PE
	PIMAGE_DOS_HEADER pDosHeader = NULL;	//DOS头
	PIMAGE_NT_HEADERS pNTHeader = NULL;		//NT头
	PIMAGE_FILE_HEADER pPEHeader = NULL;	//标准PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;	//可选PE头
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;	//节表
	LPVOID pTempImageBuffer = NULL;		//ImageBudder 临时指针


	//判断传入的缓冲区指针是否有效
	if(!pFileBuffer)
	{
		printf("缓冲区指针无效");
		return 0;
	}

	//判断指针内容是否合法
	if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标记指针");
		return 0;
	}

	//将传入的 FileBuffer 赋值给 pDosHeader
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	//判断是否是有效的PE头
	if(*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		return 0;
	}

	//众头归位
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
	pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);

	//申请空间
	pTempImageBuffer = malloc(pOptionHeader->SizeOfImage+0x1000);

	//判断是否申请成功
	if(!pTempImageBuffer)
	{
		printf("空间申请失败\n");
		return 0;
	}

	//初始化新的缓冲区
	memset(pTempImageBuffer,0,pOptionHeader->SizeOfImage);
	//根据SizeOfHeaders 先复制头
	memcpy(pTempImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
	//再for循环 复制节
	PIMAGE_SECTION_HEADER ptempSectionHeader = pSectionHeader;	//节表临时地址
	for(int i=0;i<pPEHeader->NumberOfSections;i++,ptempSectionHeader++)
	{
		memcpy((void*)((DWORD)pTempImageBuffer+ptempSectionHeader->VirtualAddress),(void*)((DWORD)pDosHeader+ptempSectionHeader->PointerToRawData),ptempSectionHeader->SizeOfRawData);
	}

	//返回参数  ImageBuffer 地址指针
	*pImageBuffer = pTempImageBuffer;
	pTempImageBuffer = NULL;
	//返回文件拉伸后大小
	return pOptionHeader->SizeOfImage;
}




/**
	ImageBuffer 复制到 FileBuffer
	两个传入参数  IN LPSTR  FileBuffer指针, OUT LPVOID* ImageBuffer
	一个传出参数  PFileBuffer 文件路径
 */
DWORD CopyImageBufferToFileBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pFileBuffer)
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;	//DOS头
	PIMAGE_NT_HEADERS pNTHeader = NULL;		//NT头
	PIMAGE_FILE_HEADER pPEHeader = NULL;	//PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;		//可选PE头
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;	//节表部分
	LPVOID pTempFileBuffer = NULL;	//TempFileBuffer

	//文件内存地址的合法性
	if(!pImageBuffer)
	{
		printf("文件的内存地址不正确\n");
		return 0;
	}
	//判断是否为可执行文件
	if(*((PWORD)pImageBuffer)!=IMAGE_DOS_SIGNATURE)
	{
		printf("不是标准的MZ文件\n");
		return 0;
	}
	//是否为标准PE头
	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
	if(*(((PDWORD)pImageBuffer+pDosHeader->e_lfanew))!=IMAGE_NT_SIGNATURE)
	{
		printf("不是标准的PE文件\n");
		return 0;
	}

	//众头归位
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
	pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader)+4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeader)+IMAGE_SIZEOF_FILE_HEADER);
	pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pOptionHeader) + pPEHeader->SizeOfOptionalHeader);

	//分配空间
	FILE* fp = fopen(FILEPATH_IN,"rb+");
	pTempFileBuffer = malloc(FileLength(fp));	//文件临时地址使用
	if(!pTempFileBuffer)
	{
		printf("TempFileBuffer 空间分配失败\n");
		return 0;
	}

	//初始化空间
	memset(pTempFileBuffer,0,pOptionHeader->SizeOfImage);
	//头部转移
	memcpy(pTempFileBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
	//节内容转移
	PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
	for(int z=0;z<pPEHeader->NumberOfSections;z++,pTempSectionHeader++)
	{
		memcpy((void*)((DWORD)pTempFileBuffer+pTempSectionHeader->PointerToRawData),(void*)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress),pTempSectionHeader->SizeOfRawData);
	}

	//返回FileBuffer地址
	*pFileBuffer = pTempFileBuffer;
	pTempFileBuffer = NULL;
	free(fp);

	//返回文件大小
	return pOptionHeader->SizeOfImage;
}




//存盘  将数据写入文件
/*
	文件FileBuffer,文件路径
*/
BOOL WriteToFile(IN LPVOID pFileBuffer,IN LPSTR FilePath)
{

	FILE* fp = NULL;

	//参数合理化
	if(!pFileBuffer)
	{
		printf("缓冲区文件有误\n");
		return 0;
	}
	if(!FilePath)
	{
		printf("文件路径有问题\n");
		return 0;
	}

	//创建一个二进制文件
	fp = fopen(FilePath,"Wb");

	//判断二进制文件是否创建
	if(!fp)
	{
		printf("文件创建失败\n");
		return 0;
	}

	//存入文件
	int Size_File = FileLength(fp);
	size_t x = fwrite(pFileBuffer,Size_File,1,fp);

	//判断文件是否写入
	if(!x)
	{
		printf("文件写入失败\n");
		return 0;
	}
	//初始化
	free(fp);
	return 1;
}


//空白区添加代码
VOID TestAddCodeInCodeSec()
{
	LPVOID NewFileBuffer = NULL;
	LPVOID pFileBuffer = NULL;		//文件地址
	LPVOID pImageBuffer = NULL;		//内存地址
	LPVOID pNewBuffer = NULL;		//新地址
	PIMAGE_DOS_HEADER pDosHeader = NULL;	//Dos头地址
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;	//可选PE头地址
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;	//节表位置
	PBYTE codeBegin = NULL;	//添加代码开始位置
	BOOL isOK = FALSE;	//判断
	DWORD size = 0;		//大小

	//file -->  FileBuffer
	ReadPEFile(FILEPATH_IN,&pFileBuffer);
	if(!pFileBuffer)
	{
		printf("文件-->缓冲区失败");
		return ;
	}

	//FileBuffer --> ImageBuffer
	CopyfFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
	if(!pImageBuffer)
	{
		printf("FileBuffer-->ImageBuffer 失败");
		free(pFileBuffer);
		return ;
	}

	//判断是否有在足够的缓冲区
	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
	//可选PE头
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew)+4+IMAGE_SIZEOF_FILE_HEADER);
	//节表
	pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer+pDosHeader->e_lfanew)+4+IMAGE_SIZEOF_FILE_HEADER+IMAGE_SIZEOF_NT_OPTIONAL32_HEADER);
	//判断
		//文件拉伸后大小 - Misc大小 < 添加的代码大小
	if(((pSectionHeader->SizeOfRawData)-(pSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH){
		printf("文件位置不够\n");
		free(pFileBuffer);
		free(pImageBuffer);
	}

	//代码复制
	codeBegin = (PBYTE)(DWORD)pImageBuffer + pSectionHeader->VirtualAddress+pSectionHeader->SizeOfRawData;
	memcpy(codeBegin,shellCode,SHELLCODELENGTH);

	//修正E8
	//有三张图  file image runImage
	DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader->ImageBase+((DWORD)codeBegin+0xD - (DWORD)pImageBuffer)));
	*(PDWORD)(codeBegin+0x9) = callAddr;  //把这个值赋给 codeBegin+0x9位置
	//修正E9
	DWORD JmpAddr = ((pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint) - (pOptionHeader->ImageBase + ((DWORD)codeBegin+0x12 - (DWORD)pImageBuffer)));
	*(PDWORD)(codeBegin+0xE) = JmpAddr;
	//修改OEP
	pOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pImageBuffer;

	//ImageBuffer --> NewBuffer
	CopyImageBufferToFileBuffer(pImageBuffer,&NewFileBuffer);
	if(size==0 || !NewFileBuffer)
	{
		printf("ToNewFileBuffer失败");
		free(pFileBuffer);
		free(pImageBuffer);
		return ;
	}

	//存盘
	isOK = WriteToFile(NewFileBuffer,FILEPATH_OUT);
	if(isOK)
	{
		printf("存盘成功");
		return ;
	}

	//释放内存
	free(pFileBuffer);
	free(pImageBuffer);

	return ;
}


//添加一个
/*
*	需修改:节表个数;总代码数;节表新增节;修改新增节的属性(名字,代码大小,内存中开始地址,文件中大小,文件开始地址);增加数据
*/
VOID TestAddSectionCode()
{
	LPVOID pFileBuffer = NULL;     //文件Buffer
	LPVOID pImageBuffer = NULL;		//内存Buffer
	PIMAGE_DOS_HEADER pDosHeader = NULL;	//DOSHeader
	PIMAGE_FILE_HEADER pPEHeader = NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;

	//file -->  FileBuffer
	ReadPEFile(FILEPATH_IN,&pFileBuffer);
	if(!pFileBuffer)
	{
		printf("文件-->缓冲区失败");
		return ;
	}

	//FileBuffer --> ImageBuffer
	CopyfFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
	if(!pImageBuffer)
	{
		printf("FileBuffer-->ImageBuffer 失败");
		free(pFileBuffer);
		return ;
	}

	//众头归位
	pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
	pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pDosHeader+pDosHeader->e_lfanew) + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeader)+IMAGE_SIZEOF_FILE_HEADER);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + (DWORD)pPEHeader->SizeOfOptionalHeader);

	//判断空间是否充足

	//节末
	PIMAGE_SECTION_HEADER AddSection = NULL;
	PIMAGE_SECTION_HEADER MySection = NULL;
	//最后一个节表的最末端
	MySection = AddSection = (PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader + (pPEHeader->NumberOfSections*IMAGE_SIZEOF_SECTION_HEADER));
	//添加节
	memcpy((LPDWORD)MySection,(LPDWORD)pSectionHeader,IMAGE_SIZEOF_SECTION_HEADER);


	MySection--;
	AddSection->Name[0]='.';
	AddSection->Name[1]='a';
	AddSection->Name[2]='d';
	AddSection->Name[3]='d';
	//节大小
	AddSection->Misc.VirtualSize = 0x1000;
	//内存地址
	AddSection->VirtualAddress = MySection->SizeOfRawData + MySection->VirtualAddress;
	//文件拉伸大小
	AddSection->SizeOfRawData = 0x1000;
	//文件中的位置
	AddSection->PointerToRawData = MySection->SizeOfRawData + MySection->PointerToRawData;
	//节的个数
	pPEHeader->NumberOfSections += 1;
	//代码总数
	pOptionHeader->SizeOfImage += 0x1000;


	//释放内存
	free(pFileBuffer);
	free(pImageBuffer);

	return ;
}

 

10-05 13:22