思路:
是我自己想的,也许不会,也许别人已经做过了,但是不是重点,哈,我现在想将两个exe文件合并成为一个exe文件,那么就需要四个exe,现在说下这四个exe文件的作用
分别是A.exe D.exe tmpA.exe tmpB.exe
A.exe的作用是将tmpA.exe和tmpB.exe文件写入到D.exe当中去,这里tmpA.exe和tmpB.exe我们是不知道源码的,但是D.exe和A.exe是知道的,
D.exe的源码是这样的:
// PE文件捆绑.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<Windows.h>
#include<iostream>
#include<ImageHlp.h>
using namespace std;
#pragma comment(lib,"ImageHlp.lib")
char* strFileTarget="D:\\D.exe";
int gSectionNum=0;
int gSectionAlign=0;
int gFileAlign=0;
char* gFileA="D:\\tmpA.exe";
char* gFileB="D:\\tmpB.exe";
char* gExeBufferA=NULL;
char* gExeBufferB=NULL;
int gdwFileSizeA=0;
int gdwFileSizeB=0;
//函数名称:getAlign
//函数描述:根据固有对其值和将要对其的大小,返回应有大小
int getAlign(int Align,int target)
{
if(target<Align)
{
return Align;
}
else if(target%Align)
{
return (target/Align+1)*Align;
}
else
{
return target;
}
}
//函数结束
//函数名称:fileToStream
//函数描述:根据固有对其值和将要对其的大小,返回应有大小
char* fileTostream(char* srcExePathA,char* srcExePathB)
{
//开始读取第一个文件
HANDLE hFileA=CreateFile(srcExePathA,GENERIC_ALL,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0);
DWORD dwTmp=0;
if(hFileA==INVALID_HANDLE_VALUE)
{
int errNum=GetLastError();
MessageBox(NULL,"对不起,文件打开失败",0,0);
return 0;
}
gdwFileSizeA=GetFileSize(hFileA,0);
gExeBufferA=new char[gdwFileSizeA+1];
memset(gExeBufferA,0,gdwFileSizeA+1);
ReadFile(hFileA,gExeBufferA,gdwFileSizeA,&dwTmp,NULL);
CloseHandle(hFileA);
//开始读取第二个文件
HANDLE hFileB=CreateFile(srcExePathB,GENERIC_ALL,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0);
if(hFileB==INVALID_HANDLE_VALUE)
{
MessageBox(NULL,"对不起,文件打开失败",0,0);
return 0;
}
gdwFileSizeB=GetFileSize(hFileB,0);
gExeBufferB=new char[gdwFileSizeB+1];
memset(gExeBufferB,0,gdwFileSizeB+1);
ReadFile(hFileB,gExeBufferB,gdwFileSizeB,&dwTmp,NULL);
CloseHandle(hFileB);
}
//函数结束
//函数名称:editTarget
//函数描述:编辑目标exe文件,将待捆绑文件作为数据放在新
// 区块中
void editTarget()
{
//尝试打开文件
HANDLE hFile=CreateFile(strFileTarget,GENERIC_ALL,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hFile)
{
int srrNum=GetLastError();
MessageBox(NULL,"文件打开失败",0,0);
return ;
}
//获得文件大小
DWORD dwFileSize=GetFileSize(hFile,0);
//尝试映射到内存
HANDLE hMap=CreateFileMapping(hFile,NULL,PAGE_EXECUTE_READWRITE,0,dwFileSize+getAlign(512,gdwFileSizeA)+getAlign(512,gdwFileSizeB),0);
if(INVALID_HANDLE_VALUE==hMap)
{
MessageBox(NULL,"文件映射失败",0,0);
return ;
}
LPVOID lpBase=MapViewOfFile(hMap,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
//获得文件的DOS头部
PIMAGE_DOS_HEADER pDosHeader=(PIMAGE_DOS_HEADER)lpBase;
//检测DOS头部,是否是PE文件
if(pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
{
MessageBox(NULL,"非PE文件",0,0);
return ;
}
//获得文件的NT头部,需要注意的是pDosHeader需要进行强制类型转换,pDosHeader转成DWORD
PIMAGE_NT_HEADERS pNtHeader=(PIMAGE_NT_HEADERS)((DWORD)pDosHeader+pDosHeader->e_lfanew);
if(pNtHeader->Signature!=IMAGE_NT_SIGNATURE)
{
MessageBox(NULL,"非PE文件",0,0);
return ;
}
//记录区块的数目
gSectionNum=pNtHeader->FileHeader.NumberOfSections;
//记录内存对其值
gSectionAlign=pNtHeader->OptionalHeader.SectionAlignment;
//记录文件对其值
gFileAlign=pNtHeader->OptionalHeader.FileAlignment;
//移动文件指针,方便我们进行读取区块信息
SetFilePointer(hFile,pDosHeader->e_lfanew +sizeof(IMAGE_NT_HEADERS),0,0);
IMAGE_SECTION_HEADER LastSection={0};
DWORD dwTmp;
//开始读取区块信息,当然只记录最后一个区块的信息
for(int i=0;i<gSectionNum;i++)
{
ReadFile(hFile,&LastSection,sizeof(IMAGE_SECTION_HEADER),&dwTmp,NULL);
}
//将exeA的文件内容写入到newA区块当中去,新建一个区块,A
IMAGE_SECTION_HEADER SectionA={0};
memcpy(SectionA.Name,".NewA",5);
SectionA.Characteristics=IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_MEM_EXECUTE;
SectionA.PointerToRawData=LastSection.PointerToRawData+LastSection.SizeOfRawData;
SectionA.SizeOfRawData=getAlign(gFileAlign,gdwFileSizeA);
SectionA.Misc.VirtualSize=gdwFileSizeA;
SectionA.VirtualAddress=LastSection.VirtualAddress+getAlign(gSectionAlign,LastSection.Misc.VirtualSize);
//写入新的区块,移动文件指针
SetFilePointer(hFile,pDosHeader->e_lfanew+sizeof(IMAGE_NT_HEADERS)+(pNtHeader->FileHeader.NumberOfSections)*sizeof(IMAGE_SECTION_HEADER),0,0);
WriteFile(hFile,&SectionA,sizeof(IMAGE_SECTION_HEADER),&dwTmp,NULL);
pNtHeader->FileHeader.NumberOfSections++;
//向区块中写入数据,移动文件指针
SetFilePointer(hFile,SectionA.PointerToRawData,0,0);
//首先写入大小
WriteFile(hFile,gExeBufferA,gdwFileSizeA,&dwTmp,NULL);
//修改镜像大小
pNtHeader->OptionalHeader.SizeOfCode+=gdwFileSizeA;
pNtHeader->OptionalHeader.SizeOfImage+=gdwFileSizeA;
//开始进行第二个文件的内容写入
IMAGE_SECTION_HEADER SectionB={0};
SectionB.Misc.VirtualSize=gdwFileSizeB;
memcpy(SectionB.Name,".NewB",5);
SectionB.Characteristics=IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_MEM_EXECUTE;
SectionB.PointerToRawData=SectionA.PointerToRawData+SectionA.SizeOfRawData;
SectionB.SizeOfRawData=getAlign(gFileAlign,gdwFileSizeB);
SectionB.Misc.VirtualSize=gdwFileSizeB;
SectionB.VirtualAddress=SectionA.VirtualAddress+getAlign(gSectionAlign,gdwFileSizeB);
//写入新的区块信息,移动文件指针
SetFilePointer(hFile,pDosHeader->e_lfanew+sizeof(IMAGE_NT_HEADERS)+(pNtHeader->FileHeader.NumberOfSections)*sizeof(IMAGE_SECTION_HEADER),0,0);
WriteFile(hFile,&SectionB,sizeof(IMAGE_SECTION_HEADER),&dwTmp,0);
pNtHeader->FileHeader.NumberOfSections++;
//向区块中写入数据
SetFilePointer(hFile,SectionB.PointerToRawData,0,0);
WriteFile(hFile,gExeBufferB,gdwFileSizeB,&dwTmp,0);
//修改镜像大小
pNtHeader->OptionalHeader.SizeOfCode+=gdwFileSizeA;
pNtHeader->OptionalHeader.SizeOfImage+=gdwFileSizeA;
CloseHandle(hFile);
MessageBox(NULL,"写入成功",0,0);
}
//函数结束
int _tmain(int argc, _TCHAR* argv[])
{
fileTostream(gFileA,gFileB);
editTarget();
return 0;
}
而A.exe的源码是这样的:
// tmpB.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<Windows.h>
//函数名称:getAlign
//函数描述:根据固有对其值和将要对其的大小,返回应有大小
int getAlign(int Align,int target)
{
if(target<Align)
{
return Align;
}
else if(target%Align)
{
return (target/Align+1)*Align;
}
else
{
return target;
}
}
//函数结束
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hFile=:: GetModuleHandle (NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
int a=GetLastError();
return 0;
}
LPVOID lpBase=(LPVOID)hFile;
PIMAGE_DOS_HEADER pDosHeader=(PIMAGE_DOS_HEADER)lpBase;
if(pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
{
MessageBox(NULL,"对不起不是有效的额PE文件",0,0);
return 0;
}
//读取区块的名字
PIMAGE_NT_HEADERS pNtHeader=(PIMAGE_NT_HEADERS)((DWORD)pDosHeader+pDosHeader->e_lfanew);
if(pNtHeader->Signature!=IMAGE_NT_SIGNATURE)
{
MessageBoxA(NULL,"对不起,不是有效的PE文件",0,0);
return 0;
}
//移动文件指针,读取特定的区块内容,
int a=pNtHeader->FileHeader.NumberOfSections;
LPVOID lpSectionsHeader=(LPVOID)((DWORD)pDosHeader+pDosHeader->e_lfanew+sizeof(IMAGE_NT_HEADERS));
PIMAGE_SECTION_HEADER pSectionA=(PIMAGE_SECTION_HEADER)((DWORD)lpSectionsHeader+7*(sizeof(IMAGE_SECTION_HEADER)));
if(strcmp((char*)pSectionA->Name,".NewA")!=0)
{
return 0;
}
//移动指针,获得该区块中文件大小
char* tmpA=new char[pSectionA->Misc.VirtualSize];
memset(tmpA,0,pSectionA->Misc.VirtualSize);
memcpy(tmpA,(char*)((DWORD)pDosHeader+pSectionA->VirtualAddress),pSectionA->Misc.VirtualSize);
DWORD dwTmp=0;
HANDLE hFileA=CreateFileA("heheA.exe",GENERIC_ALL,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
WriteFile(hFileA,tmpA,pSectionA->Misc.VirtualSize,&dwTmp,NULL);
CloseHandle(hFileA);
STARTUPINFO si;
PROCESS_INFORMATION pi;
LPTSTR szCmdline=NULL;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
CreateProcessA("heheA.exe",NULL,NULL,NULL,false,0,NULL,NULL,&si,&pi);
//开始获取第二个文件的内容
PIMAGE_SECTION_HEADER pSectionB=(PIMAGE_SECTION_HEADER)((DWORD)lpSectionsHeader+8*sizeof(IMAGE_SECTION_HEADER));
//开始获取文件大小
DWORD dwFileSizeB=pSectionB->Misc.VirtualSize;
char* FileBBuffer=new char[dwFileSizeB+1];
memset(FileBBuffer,0,dwFileSizeB+1);
memcpy(FileBBuffer,(void*)((DWORD)pDosHeader+pSectionB->VirtualAddress),dwFileSizeB);
HANDLE hFileB=CreateFile("heheB.exe",GENERIC_ALL,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFileB==INVALID_HANDLE_VALUE)
{
return 0;
}
WriteFile(hFileB,FileBBuffer,dwFileSizeB,&dwTmp,NULL);
CloseHandle(hFileB);
if(CreateProcess("heheB.exe",NULL,NULL,NULL,false,0,NULL,NULL,&si,&pi))
{
return 0;
}
DeleteFile("heheA.exe");
DeleteFile("heheB.exe");
}
即,将tmpA.exe的数据写入到D.exe的NewA的区块当中去,tmpB.exe的数据内容写入到newB的区块当中去,然后呢,在D.exe执行时查找自己的IMAGE_SECTION_HEADER
中是否有newA和NewB区块,如果有则将其写入到一个新的文件当中去,CreateFile,创建成功之后CreateProcess即可,最后最好再DeleteFile,就更完美了
哈哈,自己瞎写的,大神飘过即可