参考:Revival_S
特别是里面的坑,要好好看看参考,感谢大佬
头文件:
DWORD toLoardPE(PVOID* pFileBuffer, PSTR file_path){
FILE *fp;
DWORD FileSize;
PVOID pFileBufferTemp;
fp = fopen(file_path, "rb");
if(!fp){
printf("读取文件失败!\n");
return 0;
}
fseek(fp, 0, SEEK_END);
FileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
pFileBufferTemp = malloc(FileSize);
if(!pFileBufferTemp){
printf("读取文件开辟内存失败\n");
return 0;
}
DWORD n = fread(pFileBufferTemp, FileSize, 1, fp);
*pFileBuffer = pFileBufferTemp;
pFileBufferTemp = NULL;
fclose(fp);
return FileSize;
}
DWORD Align(int add, int alignment){
if(add % alignment == 0){
return add;
}
return ((add / alignment) + 1) * alignment;
}
DWORD Rva2Foa(PVOID pFileBuffer, DWORD dwRva){
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
if(!pFileBuffer){
printf("从磁盘读取文件为空!\n");
return 0;
}
if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE){
printf("(Rva2Foa)没有MZ标志!\n");
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
if(*(PDWORD)((DWORD)pDosHeader + pDosHeader->e_lfanew) != IMAGE_NT_SIGNATURE){
printf("(Rva2Foa)没有PE标志!\n");
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_SECTION_HEADER pSectionHeaderTemp = pSectionHeader;
PIMAGE_SECTION_HEADER pNextSectionHeaderTemp = pSectionHeader + 1;
if(dwRva <= pOptionHeader->SizeOfHeaders){
return dwRva;
}else{
for(int n=1; n < pPEHeader->NumberOfSections; n++, pSectionHeaderTemp++, pNextSectionHeaderTemp++){
if((dwRva >= pSectionHeaderTemp->VirtualAddress) && (dwRva < (pNextSectionHeaderTemp->VirtualAddress)))
return dwRva - pSectionHeaderTemp->VirtualAddress + pSectionHeaderTemp->PointerToRawData;
}
}
if (dwRva >= pSectionHeaderTemp->VirtualAddress && dwRva < pOptionHeader->SizeOfImage)
{
return pSectionHeaderTemp->PointerToRawData + dwRva - pSectionHeaderTemp->VirtualAddress;
}
printf("RVA TO FOA Failed!\n");
return 0;
}
DWORD AddSection(PSTR file_path, PVOID* pFileBuffer, DWORD FileSize, PVOID* pNewFileBuffer){
int isUpHeader = 0;
//DWORD FileSize = toLordPE(file_path, pFileBuffer);
DWORD FileTotal = FileSize + 0x1000;
printf("%x\n",*pFileBuffer);
*pNewFileBuffer = malloc(FileTotal);
printf("%x\n",pNewFileBuffer);
printf("%x\n",*pNewFileBuffer);
if(!pNewFileBuffer){
printf("新增节内存分配失败!\n");
return 0;
}
memset(*pNewFileBuffer, 0, FileTotal);
memcpy(*pNewFileBuffer, *pFileBuffer, FileSize);
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
//printf("1\n");
printf("%x\n",*((PWORD)*pNewFileBuffer));
if (*((PWORD)*pNewFileBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("没有MZ标志!\n");
//free(*pNewFileBuffer);
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)*pNewFileBuffer;
if (*((PDWORD)((DWORD)(*pNewFileBuffer) + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
//printf("%x\n",pDosHeader->e_lfanew);
//printf("%x\n",*((PDWORD)((DWORD)(*pNewFileBuffer) + pDosHeader->e_lfanew)));
printf("没有PE标志!\n");
//free(*pNewFileBuffer);
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(*pNewFileBuffer) + 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);
PIMAGE_SECTION_HEADER pSectionHeaderTemp = pSectionHeader;
for (DWORD i = 0; i < pPEHeader->NumberOfSections; i++, pSectionHeaderTemp++)
{
// for结束后,pSectionHeaderTemp指向最后一个节表的后面
//printf("%x\n",i);
}
// pLastSectionHeaderTemp 指向最后一个节表
PIMAGE_SECTION_HEADER pLastSectionHeaderTemp = pSectionHeaderTemp-1;
/*
PBYTE Temp = (PBYTE)pSectionHeaderTemp;
printf("%x\n",*(Temp+0));
printf("%x\n",*(Temp+1));
printf("%x\n",*(Temp+2));
printf("%x\n",*(Temp+3));
*/
// 节表后有没有多余空间
// 多余空间是不是0
if((DWORD)pSectionHeaderTemp + IMAGE_SIZEOF_SECTION_HEADER * 2 <= (pOptionHeader->SizeOfHeaders + (DWORD)(*pNewFileBuffer))){
PBYTE pSTemp = (PBYTE)pSectionHeaderTemp;
for(i = 0; i < (IMAGE_SIZEOF_SECTION_HEADER * 2); i++, pSTemp++){
if(*pSTemp){
// printf("%x\n",*(pSTemp+0));
printf("节表后面有数据,不能插入节表,尝试头抬升!\n");
// UpHeader(&pFileBuffer, &pNewFileBuffer);
isUpHeader = 1;
break;
}
}
printf("节表后有足够空间,且数据为0\n");
}else{
printf("节表后没有多余空间,尝试头抬升!\n");
isUpHeader = 1;
// UpHeader();
}
if(isUpHeader){
if((DWORD)pNTHeader - (DWORD)*pNewFileBuffer - sizeof(IMAGE_DOS_HEADER) >= IMAGE_SIZEOF_SECTION_HEADER * 2){
printf("抬升头\n");
memcpy((PVOID)((DWORD)*pNewFileBuffer + sizeof(IMAGE_DOS_HEADER)), pNTHeader, (DWORD)pSectionHeaderTemp - (DWORD)pNTHeader);
pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER);
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(*pNewFileBuffer) + 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);
pSectionHeaderTemp = pSectionHeader;
for (DWORD i = 0; i < pPEHeader->NumberOfSections; i++, pSectionHeaderTemp++)
{
// for结束后,pSectionHeaderTemp指向最后一个节表的后面
//printf("%x\n",i);
}
// pLastSectionHeaderTemp 指向最后一个节表
pLastSectionHeaderTemp = pSectionHeaderTemp-1;
if (*((PDWORD)((DWORD)(*pNewFileBuffer) + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("(抬升后)没有PE标志!\n");
return 0;
}
printf("抬升成功\n");
memset(pSectionHeaderTemp, 0, IMAGE_SIZEOF_SECTION_HEADER * 2);
}else{
printf("(DOS Sub)没有足够的空间插入节表,不可以头抬升!\n");
return 0;
}
}
printf("插入节表\n");
memcpy(pSectionHeaderTemp, ".tttt", 8);
pSectionHeaderTemp->Misc.VirtualSize = 0x1000;
// pSectionHeaderTemp->VirtualAddress = pOptionHeader->SizeOfImage;
DWORD z = pLastSectionHeaderTemp->Misc.VirtualSize > pLastSectionHeaderTemp->SizeOfRawData ? pLastSectionHeaderTemp->Misc.VirtualSize : pLastSectionHeaderTemp->SizeOfRawData;
pSectionHeaderTemp->VirtualAddress = pLastSectionHeaderTemp->VirtualAddress + Align(z, pOptionHeader->SectionAlignment);
pSectionHeaderTemp->SizeOfRawData = Align(0x1000, pOptionHeader->FileAlignment);
pSectionHeaderTemp->PointerToRawData = pLastSectionHeaderTemp->PointerToRawData + pLastSectionHeaderTemp->SizeOfRawData;
pSectionHeaderTemp->Characteristics = 0xe0000060;
// 修改节表数量
pPEHeader->NumberOfSections++;
// 修改SizeOfImage(按内存对齐)
pOptionHeader->SizeOfImage += Align(0x1000, pOptionHeader->SectionAlignment);
return FileTotal;
}
BOOL Memory2File(PVOID pNewFileBuffer, DWORD size, PSTR write_path){
FILE *fp;
fp = fopen(write_path, "wb");
if(!fp){
printf("(MemoryToFile)写入失败!\n");
return 0;
}
printf("存盘成功\n");
fwrite(pNewFileBuffer, size, 1, fp);
fclose(fp);
return 1;
}
主程序:
#include<stdio.h>
#include<windows.h>
#include "toolfunc.h"
PSTR file_path = "C:\\Users\\lolol\\Desktop\\3.exe";
PSTR write_path = "C:\\Users\\lolol\\Desktop\\in.exe";
int main(){
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_DATA_DIRECTORY pDataDirectory = NULL;
PIMAGE_IMPORT_DESCRIPTOR pImportTable = NULL;
PVOID pFileBuffer = NULL;
PVOID pNewFileBuffer = NULL;
DWORD FileSize = toLoardPE(&pFileBuffer, file_path);
DWORD FileTotal = AddSection(file_path, &pFileBuffer, FileSize, &pNewFileBuffer);
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
pDataDirectory = pOptionHeader->DataDirectory;
pDataDirectory = pDataDirectory + 1; // 导入表目录
// 导入表
pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + Rva2Foa(pFileBuffer, pDataDirectory->VirtualAddress));
int NumOfImport = 0; //导入表个数
int SizeOfImport = 0; //导入表长度
// 判断导入表最保险的是全部为0才结束,但其实不可能没有dll名,这里就只用INT表和 dll名是否都为0 作为结束条件
while(pImportTable->OriginalFirstThunk && pImportTable->Name)
{
NumOfImport++;
pImportTable++;
}
// 注入前的导入表大小
SizeOfImport = NumOfImport * sizeof(IMAGE_IMPORT_DESCRIPTOR);
//printf("导入表大小:%d\n",SizeOfImport);
free(pFileBuffer);
pDosHeader = (PIMAGE_DOS_HEADER)pNewFileBuffer;
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNewFileBuffer + pDosHeader->e_lfanew + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
PIMAGE_SECTION_HEADER pSectionHeaderTemp = pSectionHeader;
for(size_t i=1; i<pPEHeader->NumberOfSections; i++, pSectionHeaderTemp++){}
pDataDirectory = (PIMAGE_DATA_DIRECTORY)pOptionHeader->DataDirectory;
pDataDirectory = pDataDirectory + 1; // 导入表目录
// 导入表
pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNewFileBuffer + Rva2Foa(pNewFileBuffer, pDataDirectory->VirtualAddress));
// 下面开始构造新节内容,内容按顺序排列如下:
// IMAGE_IMPORT_BY_NAME 结构,30字节
// dll 名称,30字节
// OriginalFirstThunk 指向的INT表,8 字节 (只用一个函数)
// FirstThunk 指向的IAT表,8 字节
// 原导入表本身,SizeOfImport 字节
// 新增的导入表,20字节(sizeof(IMAGE_IMPORT_DESCRIPTOR)==20字节 )
// IMAGE_IMPORT_BY_NAME.Name,(IMAGE_IMPORT_BY_NAME.Hint默认为0)
memcpy((PVOID)((DWORD)pNewFileBuffer + pSectionHeaderTemp->PointerToRawData + 2), "ExportFunction", sizeof("ExportFunction"));
// dll Name
memcpy((PVOID)((DWORD)pNewFileBuffer + pSectionHeaderTemp->PointerToRawData + 30), "testDLL.dll", sizeof("testDLL.dll"));
// INT的内容
memcpy((PVOID)((DWORD)pNewFileBuffer + pSectionHeaderTemp->PointerToRawData + 30 + 30), &pSectionHeaderTemp->VirtualAddress, 4);
// IAT的内容
memcpy((PVOID)((DWORD)pNewFileBuffer + pSectionHeaderTemp->PointerToRawData + 30 + 30 + 8), &pSectionHeaderTemp->VirtualAddress, 4);
// 把之前的导入表内容拷贝过来
memcpy((PVOID)((DWORD)pNewFileBuffer + pSectionHeaderTemp->PointerToRawData + 30 + 30 + 8 + 8), pImportTable, SizeOfImport);
// 把导入表目录的VirtalAddress修改正确
pDataDirectory->VirtualAddress = pSectionHeaderTemp->VirtualAddress + 30 + 30 + 8 + 8;
// 把导入表目录的Size修改正确
pDataDirectory->Size += sizeof(IMAGE_IMPORT_DESCRIPTOR);
// 注入导入表
IMAGE_IMPORT_DESCRIPTOR NewImportTable = {0};
// INT
NewImportTable.OriginalFirstThunk = pSectionHeaderTemp->VirtualAddress + 30 + 30;
// IAT
NewImportTable.FirstThunk = pSectionHeaderTemp->VirtualAddress + 30 + 30 + 8;
// DLL NAME
NewImportTable.Name = pSectionHeaderTemp->VirtualAddress + 30;
// 把要注入的导入表放到之前导入表的后面
memcpy((PVOID)((DWORD)pNewFileBuffer + pSectionHeaderTemp->PointerToRawData + 30 + 30 + 8 + 8 + SizeOfImport), &NewImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR));
Memory2File(pNewFileBuffer, FileTotal, write_path);
return 0;
}