PE 移动导出表

移动各种表的原因:

PE 移动导出表

实现代码如下:

void MoveExportTable(PVOID pFileBuffer,PDWORD OldBufferSize,PVOID* pNewBuffer){
	PIMAGE_DOS_HEADER pImageDosHeader = NULL;
	PIMAGE_FILE_HEADER pImageFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER32 pImageOptionalHeader = NULL;
	PIMAGE_SECTION_HEADER pImageSectionHeaderGroup = NULL;
	PIMAGE_SECTION_HEADER NewSec = NULL;

	PIMAGE_EXPORT_DIRECTORY EXPORT_TABLE = NULL;
	PIMAGE_EXPORT_DIRECTORY EXPORT_TABLE_NewBuffer = NULL;

	PDWORD AddressFunctionName;
	DWORD RVA = 0;
	DWORD FOA = 0;
	PDWORD pTempAddress;

	int FunNameLen = 0;

	char FunName[10] = {0};

	int i = 0;
	int j = 0;
	DWORD all_num = 0;


	DWORD isOk;
	DWORD NewLength=0;
	PVOID LastSection = NULL;
	PVOID CodeSection = NULL;

	pImageDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageDosHeader + pImageDosHeader->e_lfanew + 4);
	pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pImageFileHeader + sizeof(IMAGE_FILE_HEADER));
	pImageSectionHeaderGroup = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader + pImageFileHeader->SizeOfOptionalHeader);
	
	/*
	第一步:新增节
	*/

	//判断是否可以容纳相应的节表
	isOk = (DWORD)pImageOptionalHeader->SizeOfHeaders - ((DWORD)pImageDosHeader->e_lfanew + IMAGE_SIZEOF_FILE_HEADER + pImageFileHeader->SizeOfOptionalHeader + 40*pImageFileHeader->NumberOfSections);
	if(isOk < 80){
		printf("空间太小 无法进行添加!");
		return;
	}

	//申请对应的内存大小的空间
	NewLength += *OldBufferSize + 0x1000;
	*pNewBuffer = (PVOID)malloc(NewLength);
	ZeroMemory(*pNewBuffer,NewLength);

	//拷贝之前内存空间 到 当前新生成的内存空间
	memcpy(*pNewBuffer,pFileBuffer,*OldBufferSize);

	//获取新的空间中的PE结构体
	pImageDosHeader = (PIMAGE_DOS_HEADER)(*pNewBuffer);
	pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageDosHeader + pImageDosHeader->e_lfanew + 4);
	pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pImageFileHeader + sizeof(IMAGE_FILE_HEADER));
	pImageSectionHeaderGroup = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader + pImageFileHeader->SizeOfOptionalHeader);
	
	// pImageFileHeader->NumberOfSections修改
	pImageFileHeader->NumberOfSections = pImageFileHeader->NumberOfSections + 1;
	
	// pImageOptionalHeader->SizeOfImage修改
	pImageOptionalHeader->SizeOfImage = (DWORD)pImageOptionalHeader->SizeOfImage + 0x1000;
	
	// 复制代码段的节数据到 当前最后一个节数据后面
	CodeSection = (PVOID)(&pImageSectionHeaderGroup[0]);
	LastSection = (PVOID)(DWORD)(&pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-1]);
	memcpy(LastSection,CodeSection,40);
	
	//修正相关属性
 	NewSec = (PIMAGE_SECTION_HEADER)LastSection;
	strcpy(NewSec,".NewSec");
	NewSec->Misc.VirtualSize = 0x1000;
	NewSec->SizeOfRawData = 0x1000;
	
	NewSec->VirtualAddress = pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].VirtualAddress 
		+ pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].SizeOfRawData;
	
	NewSec->PointerToRawData = pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].PointerToRawData 
		+ pImageSectionHeaderGroup[pImageFileHeader->NumberOfSections-2].SizeOfRawData;

	//修改大小长度
	*OldBufferSize = NewLength;

	//获取导出表的地址
	RVA_TO_FOA(*pNewBuffer,pImageOptionalHeader->DataDirectory[0].VirtualAddress,&FOA);
	EXPORT_TABLE = (PIMAGE_EXPORT_DIRECTORY)((DWORD)*pNewBuffer + (DWORD)FOA);

	/*
	第二步:复制AddressOfFunctions
	长度:NumberOfFunctions*4		
	*/
	printf("AddressOfFunctions个数: %d 每个占4字节\n", EXPORT_TABLE->NumberOfFunctions);
	RVA_TO_FOA(*pNewBuffer,EXPORT_TABLE->AddressOfFunctions,&FOA);
	memcpy((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData,
		(PVOID)((DWORD)*pNewBuffer + FOA),
		((DWORD)EXPORT_TABLE->NumberOfFunctions)*4);

	/*
	第三步:复制AddressOfNameOrdinals				
	长度:NumberOfNames*2			
	*/
	printf("AddressOfNameOrdinals个数: %d 每个占2字节\n", EXPORT_TABLE->NumberOfNames);

	RVA_TO_FOA(*pNewBuffer, EXPORT_TABLE->AddressOfNameOrdinals,&FOA);
	memcpy((PVOID)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4),
		(PVOID)((DWORD)*pNewBuffer + FOA),
		((DWORD)EXPORT_TABLE->NumberOfNames)*2);

	/*
	第四步:复制AddressOfNames
	长度:NumberOfNames*4		
	*/
	printf("AddressOfNames个数: %d 每个占4字节\n", EXPORT_TABLE->NumberOfNames);
	RVA_TO_FOA(*pNewBuffer, EXPORT_TABLE->AddressOfNames,&FOA);

	memcpy((PVOID)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2),
		(PVOID)((DWORD)*pNewBuffer + FOA),
		(DWORD)EXPORT_TABLE->NumberOfNames*4);

	/*
	第五步:复制所有的函数名
	长度不确定,复制时直接修复AddressOfNames
	*/

	for(j=0;j<EXPORT_TABLE->NumberOfNames;j++){
		//获得函数名称表的RVA,将其转换为FOA
		printf("%x\n", EXPORT_TABLE->AddressOfNames);
		RVA_TO_FOA(*pNewBuffer, EXPORT_TABLE->AddressOfNames,&FOA);

		// 每个函数的RVA转换为FOA
		RVA_TO_FOA(*pNewBuffer, *(PDWORD)((DWORD)*pNewBuffer + (DWORD)FOA), &FOA);
		
		//获取当前函数名称的偏移地址,将当前的函数名称的偏移地址 + pNewBuffer 得到对应的内存地址
		AddressFunctionName = (PDWORD)(*(PDWORD)((DWORD)*pNewBuffer + (DWORD)FOA + (DWORD)all_num));
		printf("%d\n",all_num);
		//printf("%x",AddressFunctionName);

		//通过strcpy来获取当前地址保存的函数名称
		strcpy(FunName,&AddressFunctionName);
		//printf("%s",FunName);

		//得到当前函数名称的长度
		FunNameLen = strlen(FunName) + 1; //最后结尾需要+1,原因\0 空字节
		
		//拿到函数的长度和名称之后需要进行复制
		memcpy((PVOID)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData
			+ ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 
			+ ((DWORD)EXPORT_TABLE->NumberOfNames)*2 
			+ ((DWORD)EXPORT_TABLE->NumberOfNames)*4 
			+ (DWORD)all_num) //这里到时候加循环来进行偏移复制
			
			,((PVOID)&AddressFunctionName)
			,FunNameLen);
		
		//接下来需要进行修复

		//过程:每次复制完 还需要修复下之前刚复制AddressOfNames中的对应的地址 让它里面的值 保存为当前复制的函数地址
		
		//通过all_num来进行偏移 从而获得当前的地址是指向第j个函数的地址
		pTempAddress = (PDWORD)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + (DWORD)all_num);

		//上面获得的地址是VA 还需要减去pNewBuffer变成FOA 然后再转换为RVA 最后存储到新复制的函数名称表对应的地址当中
		FOA_TO_RVA(*pNewBuffer
			,((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + ((DWORD)EXPORT_TABLE->NumberOfNames)*4 + (DWORD)all_num) -(DWORD)*pNewBuffer
			,&RVA);

		printf("%d\n", ((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + ((DWORD)EXPORT_TABLE->NumberOfNames)*4 + (DWORD)all_num) -(DWORD)*pNewBuffer);


		
		//修改当前pTempAddress指向的地址中的值,修改为之前每个函数名称的的地址
		*pTempAddress = RVA;
		
		// all_num用来保存复制函数名称的时候一共用了多少个字节
		all_num += FunNameLen;
	}

	/*
	第六步:复制IMAGE_EXPORT_DIRECTORY结构				
	*/
	memcpy((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2 + ((DWORD)EXPORT_TABLE->NumberOfNames)*4 + (DWORD)all_num
		,EXPORT_TABLE
		,40
		);

	
	/*
	第七步:修复IMAGE_EXPORT_DIRECTORY结构中的

	AddressOfFunctions					
	AddressOfNameOrdinals										
	AddressOfNames					
	*/
	EXPORT_TABLE_NewBuffer = (PIMAGE_EXPORT_DIRECTORY)((DWORD)*pNewBuffer + (DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 
		+ ((DWORD)EXPORT_TABLE->NumberOfNames)*2 
		+ ((DWORD)EXPORT_TABLE->NumberOfNames)*4 
		+ (DWORD)all_num);
	
	//将新的缓冲区中的三个表中存储的地址都进行修改为上面移动好的位置
	FOA_TO_RVA(*pNewBuffer,(DWORD)NewSec->PointerToRawData,&RVA);
	EXPORT_TABLE_NewBuffer->AddressOfFunctions = RVA;
	FOA_TO_RVA(*pNewBuffer,(DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4,&RVA);
	EXPORT_TABLE_NewBuffer->AddressOfNameOrdinals = RVA;
	FOA_TO_RVA(*pNewBuffer,(DWORD)NewSec->PointerToRawData + ((DWORD)EXPORT_TABLE->NumberOfFunctions)*4 + ((DWORD)EXPORT_TABLE->NumberOfNames)*2,&RVA);
	EXPORT_TABLE_NewBuffer->AddressOfNames = RVA;
	
	/*
	第八步:修复目录项中的值,指向新的IMAGE_EXPORT_DIRECTORY						
	*/
	
	FOA_TO_RVA(*pNewBuffer,(DWORD)EXPORT_TABLE_NewBuffer - (DWORD)*pNewBuffer,&RVA);
	pImageOptionalHeader->DataDirectory[0].VirtualAddress = RVA;
}

PE 移动导出表

PE 移动导出表

上一篇:DELL Inspiron3501 PE认不到硬盘解决方案


下一篇:PE可执行文件的镶入式程序后门开发