// 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 ;
}