构造新的节表,存放导入表结构,在这之后构造INT、IAT、IMAGE_IMPORT_BY_NAME结构。同时注意FOA到RVA的转化。
导入表注入
1.创建新节表并移动导入表copy(不需要修复)
2.创建导入表之后添加一个新导入表(在新表之后添加一个导入表大小的0作为导入表的结束标志)
3.追加INT和IAT表
4.构造IMAGE_IMPORT_BY_NAME结构
5.赋值
6.修正IMAGE_DATA_DIRECTORY的VirtualAddress 和Size
RVATOFOA
1.定位节表
2. 判断是否在文件头中 RVA小于最后一个节表的 末尾
ReadPEFile
1.文件流读取
2.计算文件的大小
3.分配内存
4.文件读取到内存中
(AddNewSection)
1.定位节表位置
2.定位最后一个节表的末尾
3.判断是否足够两个节表位置
4.新增节表并修改节表的属性、节区后添加空白区
//5.分配空间得到新句柄并将内存复制
ImportInject
1.原来导入表全部copy到新增节//导入表的数量计算 需要ImportTable地址进行循环
2.追加一个导入表 追加导入表结束标志(一个导入表的大小)
3.追加INT和IAT表
4.IMAGE_IMPORT_BY_NAME结构
5.将IMAGE_IMPORT_BY_NAME结构的RVA赋值给INT和IAT表中的第一项(IAT有INT的值得到)
6.分配空间存储DLL名称字符串 并将该字符串的RVA赋值给Name属性
7.修正IMAGE_DATA_DIRECTORY结构的VirtualAddress和Size
#include
#include
#include
DWORD RVATOFOA(DWORD RVA,LPVOID pFileBuffer)
{
DWORD FOA = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
if(RVA <= pOptionalHeader->SizeOfHeaders)
return RVA;
for(;RVA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);pSectionHeader++);//定位到所在节
FOA = RVA - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
return FOA;
}
DWORD FOATORVA(DWORD FOA,LPVOID pFileBuffer)
{
DWORD RVA = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
PIMAGE_FILE_HEADER pFileHeader = NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
if(FOA <= pOptionalHeader->SizeOfHeaders)
return FOA;
for(;FOA > (pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);pSectionHeader++);//定位到所在节
RVA = FOA - pSectionHeader->PointerToRawData + pSectionHeader->VirtualAddress ;
return RVA;
}
LPVOID ReadPEFile(LPSTR lpszFile)//读取文件
{
FILE *pFile = NULL;//文件流
DWORD fileSize = 0;//文件大小
LPVOID pFileBuffer = NULL;//文件存储的缓冲区
//打开文件
pFile = fopen(lpszFile,"rb");
if(!pFile)
{
printf("无法打开exe文件!");
return NULL;
}
//读取文件的大小
//SEEK_SET: 文件开头SEEK_CUR: 当前位置;SEEK_END: 文件结尾
fseek(pFile,0L,SEEK_END);//fseek用于得到文件位置指针当前位置相对于文件首的偏移字节数
fileSize = ftell(pFile);
fseek(pFile,0L,SEEK_SET);
//分配缓冲区 pFileBuffer缓冲区的
pFileBuffer = malloc(fileSize);
if(!pFileBuffer)
{
printf("分配文件失败!");
fclose(pFile);
return NULL;
}
//将文件读入缓冲区
size_t n = fread(pFileBuffer,fileSize,1,pFile);
if(!n)
{
printf("读取数据失败!");
free(pFileBuffer);
fclose(pFile);
return NULL;
}
//关闭文件
fclose(pFile);
return pFileBuffer;
}
//导入表注入
VOID ImportInject(LPVOID pFileBuffer)
{
PIMAGE_DOS_HEADER pDosHeader = NULL;//DOS头
PIMAGE_NT_HEADERS pNtHeaders = NULL;//NT头
PIMAGE_FILE_HEADER pFileHeader = NULL;//标准PE头
PIMAGE_OPTIONAL_HEADER pOptionalHeader = NULL;//拓展PE头
PIMAGE_SECTION_HEADER pSectionHeader = NULL;//节表
PIMAGE_SECTION_HEADER pNewSec = NULL;//新节表结构
PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; //导出表结构体
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
DWORD dwNumberOfDll = 0;
//判断是否有足够的空间添加节表
if ((pOptionalHeader->SizeOfHeaders - ((DWORD)pSectionHeader - (DWORD)pFileBuffer + pFileHeader->NumberOfSections * 40)) < 80)
{
printf("空间不足");
return FALSE;
}
//新增节表结构
pNewSec = (PIMAGE_SECTION_HEADER)(pSectionHeader + pFileHeader->NumberOfSections);
//修改节表内容
memcpy(pNewSec->Name,".import",8);//修改节表名
PIMAGE_SECTION_HEADER upSecHeader = (PIMAGE_SECTION_HEADER)(pSectionHeader + pFileHeader->NumberOfSections-1);
if(upSecHeader->Misc.VirtualSize > upSecHeader->SizeOfRawData)//修改节表VrituallAddress
{
pNewSec->VirtualAddress = upSecHeader->VirtualAddress + upSecHeader->Misc.VirtualSize;
}else{
pNewSec->VirtualAddress = upSecHeader->VirtualAddress + upSecHeader->SizeOfRawData;
}
pNewSec->SizeOfRawData = 0x1000;//新增的节区的大小
pNewSec->PointerToRawData = upSecHeader->PointerToRawData + upSecHeader->SizeOfRawData;//文件中的偏移
pNewSec->Characteristics = 0xc0000040;//修改属性(可执行)
//在新增节表后增加40个字节的空白区
memset(pNewSec+1, 0, 40);
//修改NT头属性
pFileHeader->NumberOfSections += 1;//修改NumberOfSection数量
pOptionalHeader->SizeOfImage += 0x1000;//修改SizeOfImage大小
LPVOID NewBuffer = malloc(pOptionalHeader->SizeOfImage);//申请内存
memset(NewBuffer, 0, pOptionalHeader->SizeOfImage);//初始化内存
memcpy(NewBuffer, pFileBuffer,pOptionalHeader->SizeOfImage);//复制内存
//遍历得到模块的个数
PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + RVATOFOA(pOptionalHeader->DataDirectory[1].VirtualAddress,pFileBuffer));
while(pImportTable->Name)
{
dwNumberOfDll++;//导入表的数量
pImportTable++;
}
printf("导入表的数量:%d\n",dwNumberOfDll);
pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pFileBuffer + RVATOFOA(pOptionalHeader->DataDirectory[1].VirtualAddress,pFileBuffer));//指向导入表的位置
//原来导入表copy到新增节
LPVOID pNewSecAddr = (LPVOID)((DWORD)NewBuffer + pNewSec->PointerToRawData);//定位节表的位置
/*memcpy(pNewSecAddr,pImportTable,sizeof(IMAGE_IMPORT_DESCRIPTOR)*dwNumberOfDll);//复制导入表的内容
printf("%x\n",pNewSecAddr);*/
PIMAGE_IMPORT_DESCRIPTOR ImportEnd = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pNewSecAddr + 20 * dwNumberOfDll);//定位复制后的导入表之后
/*printf("%x\n",InsertImport);
printf("%x\n",sizeof(PIMAGE_IMPORT_DESCRIPTOR));*/
int i = 0;
while((pImportTable+i) -> OriginalFirstThunk){
memcpy(pNewSecAddr, (LPVOID)(pImportTable+i), 20);
pNewSecAddr = (LPVOID)((DWORD)pNewSecAddr + 20);
i++;
}//复制两个导入表
pNewSecAddr = (LPVOID)((DWORD)NewBuffer + pNewSec->PointerToRawData);//定位节表的位置
//新增一个导入表
memset(ImportEnd,0,20);
//设置导入表的成员
ImportEnd->ForwarderChain = 0;
ImportEnd->TimeDateStamp = 0;
//设置导入结束标记 为一个导入表结构的0
LPVOID pInsertEnd = (LPVOID)((DWORD)ImportEnd + 20);
memset(pInsertEnd,0,20);
//追加INT
PIMAGE_THUNK_DATA pINT = (PIMAGE_THUNK_DATA)((DWORD)pInsertEnd + 20);
//设置INT结束标志
memset(pINT + 1,0,sizeof(PIMAGE_THUNK_DATA));
//设置IMPORT_BY_NAME
PIMAGE_IMPORT_BY_NAME pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD)pINT + 8);//定位INT表之后 只需要一个函数
pImportByName->Hint = 0;
strcpy((char*)pImportByName->Name,"ExportFunction");//设置函数名
//设置INT表中得到值
*((PDWORD)pINT) = FOATORVA((DWORD)pImportByName - (DWORD)NewBuffer,NewBuffer);
//设置IAT表
PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)((DWORD)pImportByName + 3 + strlen("ExportFunction"));
memcpy(pIAT,pINT,8);
//dll名称字符串
LPVOID DllName = (LPVOID)((DWORD)pIAT + 8);
strcpy(DllName,"InjectDll.dll");
//设置导入表属性
ImportEnd->FirstThunk = FOATORVA((DWORD)pIAT - (DWORD)NewBuffer,NewBuffer);
ImportEnd->OriginalFirstThunk = FOATORVA((DWORD)pINT - (DWORD)NewBuffer,NewBuffer);
ImportEnd->Name = FOATORVA((DWORD)DllName - (DWORD)NewBuffer,NewBuffer);
//更新目录表导入表的位置
pDosHeader = (PIMAGE_DOS_HEADER)NewBuffer;
pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNtHeaders + 4);
pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
pOptionalHeader->DataDirectory[1].VirtualAddress = FOATORVA((DWORD)pNewSecAddr - (DWORD)NewBuffer,NewBuffer);
FILE* fp = fopen("D:\\test\\HelloWorld.exe","wb+");//读入w文件流
fwrite(NewBuffer,pOptionalHeader->SizeOfImage,1,fp);
fclose(fp);
return;
}
int main()
{
LPSTR lpszFile = "D:\\test\\HelloWorld.exe";
LPVOID pFileBuffer = ReadPEFile(lpszFile);
if(pFileBuffer)
{
printf("读取文件成功!\n");
}
ImportInject(pFileBuffer);
return 0;
}