移动导出表,移动重定位表【滴水逆向三期51笔记+作业源码】

前面章节我们了解了PE文件中的导出表和重定位表,今天我们来学习如何来移动导出表和重定位表。

一.为什么要移动各种表?

首先,这些表都是由编译器生成的,里面存储了非常重要的信息,在程序启动的时候,系统会根据这些表的内容来做一些初始化的工作,比如将用到的dll中的函数地址存储到IAT表(后续我们将会学习)中,为了保护程序,我们可以对exe二进制进行加密操作,但是问题是:各种表的信息,与代码和数据混在一起(存在于各个节中)如果进行加密的话,系统在初始化的时候就会出问题。
学会移动各种表,是对程序加密解密的基础

二.移动导出表

这里给出移动导出表的基本思路,在文章后面会贴出源码
1.首先,我们在文件中新增一个节,我们可以将导出表等信息移动到导出表中
2.将函数地址表移动到新节(也就是AddressOfFunctions所指向的内容)长度:NumberOfFunctions*4 注意函数地址表中存储的是函数地址,因为我们没有移动函数,所以我们在移动导出表后无需修正
3.复制函数导出序号表到新节(也就是AddressOfNameOrdinals所指向的内容)长度:NumberOfNames*2 注意导出序号表中存储的就是导出序号,移动导出表后无需修正
4.复制函数名称表移动到新节(也就是AddressOfNames所指向的内容)长度:NumberOfNames*4 注意函数名称表中存储的是地址,指向函数名称字符串,这里在复制函数名字符串后立即修正函数名称表
5.复制所有函数名字符串长度=字符串长度
6.复杂IMAGE_EXPORT_DIRECTORY结构
7.修复IMAGE_EXPORT_DIRECTORY结构中的AddressOfFunctions,AddressOfOrdinals,AddressOfNames字段
8.修复数据目录表IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_EXPORT]中的VirsualAddress字段,使其指向我们移动后的导出表

三.移动导出表源码

PEFunction.h:
#include <stdio.h>
#include <windows.h>
#include <string.h>
//*************打开文件函数(将文件二进制读取到FileBuffer) ******************
//该函数需要一个char类型的指针,指向想要打开的文件路径
//该函数返回一个char类型的指针,指向FileBuffer
//该函数完成文件的打开,并且将文件的二进制读取到FIleBuffer
//该函数读取完成后会将文件关闭,避免出现误操作
//该函数会通过移动文件指针获取文件大小
//获取的文件大小用于动态申请内存 
//该函数会动态申请内存,用于存放FileBuffer
//***************************************************************************
char* ReadToFileBuffer(char* filename);




//***************************************获取文件大小函数*********************************
//该函数返回文件大小 
//****************************************************************************************
int SizeOfFile(char* filename);





//*****************************获取PE导出表数据函数**************************
//该函数需要一个指针,指向FileBuffer
//该函数在找到导出表之前,需要定义DOS结构指针,标准PE头结构指针和可选PE头指针,以方便找到导出表
//该函数会在控制台输出函数地址表,函数名称表和函数导出序号表 
//***************************************************************************
void ShowExportDirectory(char* FileBuffer);





//*****************************RVA转换为FOA函数******************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,为要转换的RVA
//该函数返回一个整数,为转换后的FOA地址
//***************************************************************************
int RVAToFOA(IN LPVOID pFileBuffer, IN DWORD dwRva);





//*************************根据函数名称查找函数地址函数**********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByName(char* filename);





//*************************根据函数序号查找函数地址函数**********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByOrdinal(char* filename);





//******************************打印PE重定位表函数***************************
//该函数需要一个指针,指向FIleBuffer
//该函数会在控制台打印出重定位表信息(重定位表偏移,重定位表大小,但不打印重定位表具体项
//***************************************************************************
void ShowBaseRelocation(char* FileBuffer);






//**************************************新增节函数***************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个指针,表示FileBuffer大小 
//该函数需要一个字符串,为原文件文件名 
//该函数完成在PE文件中新增一个节
//该函数在新增节之前,PE头部是否足够新增一个节表
//若PE文件头部内存不够新增一个节表,该函数将会提升所有头部,将DOSstob覆盖掉,并且让e_lfanew指向下一个字节 
//该函数会生成一个exe文件,存放于调用该函数的程序源目录下  
//该函数返回一个指针,指向新增节后的FileBuffer 
//****************************************************************************************
char* AddNewSection(char* FileBuffer,int SizeOfFileBuffer);




//*****************************覆盖DOSstob,抬升NT头和原有节表****************************
//该函数需要一个指针,指向需要改动的FileBuffer
//该函数将FileBuffer中的DOSstob覆盖
//该函数将PE头部中,DOS头以后的内容提升到DOSstob的位置 
//抬升成功后会将最后两个节表的数据全初始化为0 
//若头部抬升失败,则返回0 
//若抬升成功,则返回1 
//****************************************************************************************
int UpFile(char* FileBuffer);




//******************************计算文件对齐后的值函数************************************						
//Align:计算对齐后的值					
//参数说明:								
//x  需要进行对齐的值								
//Alignment 对齐大小						
//返回值说明:							
//返回x进行Alignment值对齐后的值								
//****************************************************************************************	
int Align(int x, int Alignment);




//**************************************移动导出表****************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整形参数,表示FileBuffer大小 
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向NewFileBuffer
//****************************************************************************************
char* RemoveExportDirectory(char* FileBuffer,int SizeOfFileBuffer);
PEFunction.c:
/**************************************************************/ 
//*********************自编PE函数库****************************/
#include "PEFunction.h"
//********打开文件函数(将文件二进制读取到FileBuffer) *******
//函数说明:
//该函数需要一个char类型的指针,指向想要打开的文件路径
//该数返回一个char类型的指针,指向FileBuffer
//该函数完成文件的打开,并且将文件的二进制读取到FIleBuffer
//该函数读取完成后会将文件关闭,避免出现误操作
//该函数会通过移动文件指针获取文件大小
//获取的文件大小用于动态申请内存 
//该函数会动态申请内存,用于存放FileBuffer
//********************************************************* 
char* ReadToFileBuffer(char* filename){
	FILE* fp;
	char* FileBuffer=NULL;
	int length;
	if((fp=fopen(filename,"rb"))==NULL){
		printf("%s打开失败!",filename);
		exit(0);
	}else{
		printf("文件打开成功,正在计算文件大小...\n");
	}
	fseek(fp,0,SEEK_END);
	length=ftell(fp);
	fseek(fp,0,SEEK_SET);
	printf("文件大小:%d字节\n正在申请FileBuffer内存...\n",length);
	FileBuffer=(char*)malloc(length);
	if(FileBuffer!=NULL){
		printf("FileBuffer内存申请成功。准备向FileBuffer写入数据...\n");
	}
	if((fread(FileBuffer,length,1,fp))==0){
		printf("写入数据失败!\n");
		exit(0);
	}else{
		printf("写入数据成功。\n");
	}
	if(fclose(fp)){
		printf("文件关闭失败!\n");
		exit(0);
	}else{
		printf("文件关闭成功。\n");
	}
	return FileBuffer;
}




//***************************************获取文件大小函数*********************************
//该函数返回文件大小 
//****************************************************************************************
int SizeOfFile(char* filename){
	FILE* fp;
	char* FileBuffer=NULL;
	int length;
	if((fp=fopen(filename,"rb"))==NULL){
		printf("%s打开失败!",filename);
		exit(0);
	}else{
		printf("文件打开成功,正在计算文件大小...\n");
	}
	fseek(fp,0,SEEK_END);
	length=ftell(fp);
	fseek(fp,0,SEEK_SET);
	return length;
}





//**********************获取PE导出表数据函数************************************************
//该函数需要一个指针,指向FileBuffer
//该函数在找到导出表之前,需要定义DOS结构指针,标准PE头结构指针和可选PE头指针,以方便找到导出表
//该函数会在控制台输出函数地址表,函数名称表和函数导出序号表 
//********************************************************************************************
void ShowExportDirectory(char* FileBuffer){
	IMAGE_DOS_HEADER* pDosHeader=NULL;
	IMAGE_FILE_HEADER* pFileHeader=NULL;
	IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
	IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
	pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
	if(*((PDWORD)((DWORD)FileBuffer + pDosHeader->e_lfanew))!= IMAGE_NT_SIGNATURE){
		printf("不是有效的PE标志!\n");
	}else{
		printf("检测到有效的PE标志。\n");
	}
	pFileHeader=(IMAGE_FILE_HEADER*)(FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
	pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
	printf("导出表RVA:%x\n",pOptionalHeader->DataDirectory[0].VirtualAddress);
	printf("导出表大小:%x字节\n",pOptionalHeader->DataDirectory[0].Size);
	printf("导出表FOA:%d\n",RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
	printf("*******************************导出表*********************************\n");
	printf("TimeDataStamp(经加密):%d\n",pExportDirectory->TimeDateStamp);
	printf("Name(导出表文件名字符串):%s\n",FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->Name));
	printf("Base(函数起始序号):%d\n",pExportDirectory->Base);
	printf("NumberOfFunction(导出函数总数):%d\n",pExportDirectory->NumberOfFunctions);
	printf("NumberOfNames(以名称导出函数的总数):%d\n",pExportDirectory->NumberOfNames);
	printf("*****************************函数地址表********************************\n");
	int i=0;
	char* AddressOfFunction;
	AddressOfFunction=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions));
	for(i=0;i<pExportDirectory->NumberOfFunctions;i++){
		printf("下标:%d     函数地址:0x%x\n",i,*(PWORD)((DWORD)AddressOfFunction+i*4));
	}
	printf("*****************************函数名称表********************************\n");
	int* AddressOfNames=NULL;
	char* name=NULL;
	AddressOfNames=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNames));
	for(i=0;i<pExportDirectory->NumberOfNames;i++){
		name=(char*)(FileBuffer+RVAToFOA(FileBuffer,*AddressOfNames));
		printf("下标:%d     函数名称:%s\n",i,name);
		AddressOfNames++;
	}
	printf("*******************************函数序号表*******************************\n");
	char *AddressOfNameOrdinals=NULL;
	char *Ordinal=NULL;
	AddressOfNameOrdinals=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNameOrdinals));
	for(i=0;i<pExportDirectory->NumberOfNames;i++){
		Ordinal=(int*)(FileBuffer+RVAToFOA(FileBuffer,*AddressOfNameOrdinals));
		printf("下标:%d      函数序号(加Base):%d\n",i,*(AddressOfNameOrdinals+i*2)+pExportDirectory->Base);
	} 
}
//*************************RVA转换为FOA函数*************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,为要转换的RVA
//该函数返回一个整数,为转换后的FOA地址
//******************************************************************
int RVAToFOA(IN LPVOID pFileBuffer, IN DWORD dwRva)
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	PIMAGE_SECTION_HEADER pNextSectionHeader = NULL;
	//DOS头
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;	// 强转 DOS_HEADER 结构体指针
	//PE头
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4);	//NT头地址 + 4 为 FileHeader 首址
	//可选PE头	
	pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中
	if (dwRva < pOptionalHeader->SizeOfHeaders)	//偏移小于头的大小,内存偏移则为文件偏移
	{
		return dwRva;
	}
    //首个节表
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
	//下一个节表
	pNextSectionHeader = pSectionHeader + 1;
	//循环遍历节表
	int i;
	for (i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++, pNextSectionHeader++)//注意这里i从1开始 i < NumberOfSections
	{	//注意这里的pSectionHeader已经是加了基址的,不是偏移, 是绝对地址。而dwRva是偏移地址
		if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pNextSectionHeader->VirtualAddress)//大于当前节的内存偏移而小于下一节的内存偏移
		{	//则dwRva属于当前节,则dwRva - VirtualAddress为dwRva基于当前节的偏移。此偏移加上当前节的文件起始偏移地址 则为dwRva在文件中的偏移
			DWORD PointerToRawData = pSectionHeader->PointerToRawData;
			DWORD VirtualAddress = pSectionHeader->VirtualAddress;
			DWORD aa = pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress;
			return pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress ;
		}
	}	//出循环后pSectionHeader指向最后一个节表
	//大于当前节(最后一节)的内存偏移且小于内存映射大小
	if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pOptionalHeader->SizeOfImage)
	{	//同上return
		return pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress;
	}
	else //大于内存映射大小
	{
		printf("dwRva大于内存映射大小\n");
		return -1;
	}
}
//*************************根据函数名称查找函数地址函数***********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//****************************************************************************
void GetAddressOfFunctionByName(char* filename){
	char* FileBuffer=NULL;
	char inname[5];
	int i;
	FileBuffer=ReadToFileBuffer(filename);
	IMAGE_DOS_HEADER* pDosHeader=NULL;
	IMAGE_FILE_HEADER* pFileHeader=NULL;
	IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
	IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
	pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
	if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
		exit(0);
	}
	pFileHeader=(IMAGE_FILE_HEADER*)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
	pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
	int* AddressOfNames=NULL;
	char* name=NULL;
	AddressOfNames=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNames));
	
	printf("请输入您需要查找的函数名:");
	scanf("%s",inname);
	printf("正在查找中...\n");
	for(i=0;i<pExportDirectory->NumberOfNames;i++){
	name=(int*)(FileBuffer+RVAToFOA(FileBuffer,RVAToFOA(FileBuffer,*AddressOfNames)));
		if(!(strcmp("Plus",name))){
			printf("下标为%d的函数名符合。\n",i);
			break;
		}
		AddressOfNames++;
	}
	char* Ordinal=NULL;
	Ordinal=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNameOrdinals)+i*2);
	char* AddressOfFunction=NULL;
	AddressOfFunction=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions)+*Ordinal*4);
	printf("Ordinal(函数导出序号(未加Base)):%d    AddressOfFunction:0x%x",*Ordinal,*(PWORD)((DWORD)AddressOfFunction));
}
//************************根据函数序号查找函数地址函数***********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByOrdinal(char* filename){
	char* FileBuffer=NULL;
	int InOrdinal=0;
	IMAGE_DOS_HEADER* pDosHeader=NULL;
	IMAGE_FILE_HEADER* pFileHeader=NULL;
	IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
	IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
	FileBuffer=ReadToFileBuffer(filename);
	char* AddressOfFunction;
	pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
	if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到PE标志。");
	}else{
		printf("未检测到PE标志!\n");
		exit(0);
	}
	pFileHeader=(IMAGE_FILE_HEADER*)(FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
	
	pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
	printf("请输入您需要查找的函数导出序号:");
	scanf("%d",&InOrdinal);
	InOrdinal=InOrdinal-pExportDirectory->Base;
	AddressOfFunction=(char*)FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions+InOrdinal*4);
	printf("函数导出序号(未加Base):%d       函数地址:0x%x",InOrdinal,*(PWORD)((DWORD)AddressOfFunction));
}
//*************************打印PE重定位表函数*********************************************
//该函数需要一个指针,指向FIleBuffer
//该函数会在控制台打印出重定位表信息(重定位表偏移,重定位表大小,但不打印重定位表具体项*/
//****************************************************************************************
void ShowBaseRelocation(char* FileBuffer){
	int i=1;
	IMAGE_DOS_HEADER* pDosHeader=NULL;
	IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
	IMAGE_BASE_RELOCATION* pBaseRelocation=NULL;
	pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
	if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
		exit(0);
	}
	pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)FileBuffer+pDosHeader->e_lfanew+24);
	pBaseRelocation=(IMAGE_BASE_RELOCATION*)((DWORD)FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[5].VirtualAddress));
	printf("%x",pOptionalHeader->DataDirectory[5].VirtualAddress);
	while(pBaseRelocation->VirtualAddress&&pBaseRelocation->SizeOfBlock){
		printf("************                 第%d块                 ************\n",i);
		printf("VirtulaAddress(重定位表在文件中的偏移):0x%x\n",RVAToFOA(FileBuffer,pBaseRelocation->VirtualAddress));
		printf("Size(该块重定位表的大小):%d字节\n",pBaseRelocation->SizeOfBlock);
		printf("重定位表具体项数目:%d\n\n",(pBaseRelocation->SizeOfBlock-8)/2);
		pBaseRelocation = (IMAGE_BASE_RELOCATION*)(pBaseRelocation->SizeOfBlock + (DWORD)pBaseRelocation);
		i++;
	}
}
//**************************************新增节函数***************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,表示FileBuffer大小 
//该函数需要一个字符串,位原文件文件名 
//该函数完成在PE文件中新增一个节
//该函数在新增节之前,PE头部是否足够新增一个节表
//若PE文件头部内存不够新增一个节表,该函数将会提升所有头部,将DOSstob覆盖掉,并且让e_lfanew指向下一个字节 
//该函数会生成一个exe文件,存放于调用该函数的程序源目录下 
//该函数返回一个指针,指向新增节后的FileBuffer 
//****************************************************************************************
char* AddNewSection(char* FileBuffer,int SizeOfFileBuffer){
	printf("新增节执行中...\n");
	int choose1;
	unsigned char ShellCode[100];
	int AddressOfShellCode=0;
	PIMAGE_DOS_HEADER pDosHeader=NULL;
	PIMAGE_FILE_HEADER pFileHeader=NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
	PIMAGE_SECTION_HEADER pSectionHeader=NULL;
	PIMAGE_SECTION_HEADER pNewSectionHeader=NULL;
	int i,j;
	char* NewFileBuffer=NULL;
	pDosHeader=(PIMAGE_DOS_HEADER)FileBuffer;
	if(*(PDWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n"); 
	}else{
		printf("未检测到有效的PE标志!\n");
		return 0;
	}
	pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
	for(i=1;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
		printf("移动节表指针中...\n");
		printf("%s",pSectionHeader->Name); 
	}
	pNewSectionHeader=pSectionHeader+1;
	for(i=0;i<IMAGE_SIZEOF_SECTION_HEADER*2;i++){
		if((*(PWORD)((DWORD)pNewSectionHeader+i))!=0){
			printf("%x",*(PWORD)((DWORD)pNewSectionHeader+i));
			printf("PE文件头部内存空间不足,需要覆盖DOSstob抬升头部,以保证足够的空间新增节表!\n");
			if(UpFile){
				printf("更新头部指针中...\n");
				pDosHeader=(PIMAGE_DOS_HEADER)FileBuffer;
				pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
				pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
				pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pOptionalHeader->SizeOfHeaders);
				for(i=1;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
					printf("移动节表指针中...\n");
				}
				pNewSectionHeader=pSectionHeader+1;
				break;
			}else{
				printf("抬升失败!\n");
				return 0;
			}
		}else{
			printf("检测数据中...\n");
			
		}
	}
	if(i==IMAGE_SIZEOF_SECTION_HEADER*2){
		printf("数据检测完毕,未检测到数据,将新增节...\n");
	}
	strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
	printf("******                         请选择是否添加ShellCode                         ******\n");
	printf("******                         0:不添加ShellCode                              ******\n");
	printf("******                         1:添加ShellCode                                 ******\n");

	printf("请输入您的选择:");
	scanf("%d",&choose1);
	switch (choose1){
		case 0:{
			strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
			pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode);
			pNewSectionHeader->VirtualAddress=pOptionalHeader->SizeOfImage;
			printf("FileAligment:%x\n",pOptionalHeader->FileAlignment);
			pNewSectionHeader->SizeOfRawData=Align(sizeof(ShellCode),pOptionalHeader->FileAlignment);
			pNewSectionHeader->PointerToRawData = SizeOfFileBuffer;
//			pNewSectionHeader->PointerToRawData = pSectionHeader->SizeOfRawData+pSectionHeader->PointerToRawData;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
			pNewSectionHeader->PointerToRelocations = 0;
			pNewSectionHeader->PointerToLinenumbers = 0;
			pNewSectionHeader->NumberOfRelocations = 0;
			pNewSectionHeader->NumberOfLinenumbers = 0;
			pNewSectionHeader->Characteristics = 0x60000020;
			pFileHeader->NumberOfSections++;
			printf("SectionAlignment: %x\nSizeOfImage:%x\n", pOptionalHeader->SectionAlignment, pOptionalHeader->SizeOfImage);
			pOptionalHeader->SizeOfImage += Align(sizeof(ShellCode), pOptionalHeader->SectionAlignment);
			printf("SizeOfImage:%x\n", pOptionalHeader->SizeOfImage);
			int SizeOfNewBuffer=SizeOfFileBuffer+pNewSectionHeader->SizeOfRawData;
			NewFileBuffer=(char*)malloc(SizeOfNewBuffer);
			memcpy(NewFileBuffer, FileBuffer, SizeOfFileBuffer);
			memset((void *)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), 0, pNewSectionHeader->SizeOfRawData);
			FILE* fp=NULL;
//			if((fp=(fopen("新增节程序.exe","wb")))==NULL){
//				printf("文件新建失败!\n");
//				exit(0);
//			}else{
//				printf("文件新建成功,正在写入数据...\n");
//				if(fwrite(NewFileBuffer,SizeOfNewBuffer,1,fp)){
//					printf("数据写入成功。\n");
//				}else{
//					printf("数据写入失败!\n");
//					exit(0);
//				}
//			}
//			if(!fclose(fp)){
//				printf("文件保存成功。\n");
//			}else{
//				printf("文件保存失败!");
//				exit(0); 
//			}
			return  NewFileBuffer;
			break;
		}
		case 1:{
			int CallShellCode;
			int JmpShellCode;
			strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
			pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode);
			pNewSectionHeader->VirtualAddress=pOptionalHeader->SizeOfImage;
			printf("FileAligment:%x\n",pOptionalHeader->FileAlignment);
			pNewSectionHeader->SizeOfRawData=Align(sizeof(ShellCode),pOptionalHeader->FileAlignment);
			pNewSectionHeader->PointerToRawData = pSectionHeader->SizeOfRawData+pSectionHeader->PointerToRawData;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
			pNewSectionHeader->PointerToRelocations = 0;
			pNewSectionHeader->PointerToLinenumbers = 0;
			pNewSectionHeader->NumberOfRelocations = 0;
			pNewSectionHeader->NumberOfLinenumbers = 0;
			pNewSectionHeader->Characteristics = 0x60000020;
			pFileHeader->NumberOfSections++;
			printf("SectionAlignment: %x\nSizeOfImage:%x\n", pOptionalHeader->SectionAlignment, pOptionalHeader->SizeOfImage);
			pOptionalHeader->SizeOfImage += Align(sizeof(ShellCode), pOptionalHeader->SectionAlignment);
			printf("SizeOfImage:%x\n", pOptionalHeader->SizeOfImage);
			int SizeOfNewBuffer=SizeOfFileBuffer+pNewSectionHeader->SizeOfRawData;
			NewFileBuffer=(int*)malloc(SizeOfNewBuffer);
			DWORD OddAddressOfEntryPoint = pOptionalHeader->AddressOfEntryPoint;
			pOptionalHeader->AddressOfEntryPoint = pNewSectionHeader->VirtualAddress;
			memcpy(NewFileBuffer, FileBuffer, SizeOfFileBuffer);
			memset((void *)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), 0, pNewSectionHeader->SizeOfRawData);
			printf("请输入ShellCode硬编码:\n");
			printf("!!!特别注意:在输入硬编码后,应输入E8和该ShellCode执行时内存中的地址,程序会自动转换!!!暂时只支持输入100字节以内的硬编码\n");
			for(i=0,j=0;i<100;i++){
				scanf("%x ",ShellCode[i]);
				if(ShellCode[i]==0xE8){
					j=i+1;
				}
				if(i=j+4){
					CallShellCode=*(int*)(ShellCode[j]);
					CallShellCode = CallShellCode - (pOptionalHeader->ImageBase + pNewSectionHeader->VirtualAddress + j-1 + 5);
					*(int*)ShellCode[j] = CallShellCode;
				}
				if(i=j+9){
					JmpShellCode = OddAddressOfEntryPoint - (pNewSectionHeader->VirtualAddress + j+5 + 5);
					*(int*)ShellCode[j+5] = JmpShellCode;
				}
			}
			memcpy((void*)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), ShellCode, sizeof(ShellCode));
//			FILE* fp=NULL;
//			if((fp=(fopen("新增节程序.exe","wb")))==NULL){
//				printf("文件新建失败!\n");
//				exit(0);
//			}else{
//				printf("文件新建成功,正在写入数据...\n");
//				if(fwrite(fp,SizeOfNewBuffer,1,NewFileBuffer)){
//					printf("数据写入成功。\n");
//				}else{
//					printf("数据写入失败!\n");
//					exit(0);
//				}
//			}
			return NewFileBuffer;
			break;
		}
	}
	
}
//*****************************覆盖DOSstob,抬升NT头和原有节表****************************
//该函数需要一个指针,指向需要改动的FileBuffer
//该函数将FileBuffer中的DOSstob覆盖
//该函数将PE头部中,DOS头以后的内容提升到DOSstob的位置 
//抬升成功后会将最后两个节表的数据全初始化为0 
//若头部抬升失败,则返回0 
//若抬升成功,则返回1 
//****************************************************************************************
int UpFile(char* FileBuffer){
	PIMAGE_DOS_HEADER pDosHeader=NULL;
	PIMAGE_NT_HEADERS32 pNTHeader=NULL; 
	PIMAGE_FILE_HEADER pFileHeader=NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
	PIMAGE_SECTION_HEADER pSectionHeader=NULL;
	char* pNewSectionHeader=NULL;
	int i;
	pDosHeader=(PIMAGE_DOS_HEADER)((DWORD)FileBuffer);
	pNTHeader=(PIMAGE_NT_HEADERS32)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
	if(*(PDWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
		return 0;
	}
	pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((DWORD)FileBuffer+20);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
	for(i=0;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
		printf("移动节表指针中...\n");
	}
	pNewSectionHeader=pSectionHeader+1;
	if ((DWORD)FileBuffer + sizeof(IMAGE_DOS_HEADER) - (DWORD)pNTHeader >= IMAGE_SIZEOF_SECTION_HEADER * 2)
		{
			printf("可抬升NT头\n抬升PE头部中...\n");
			//开始拷贝,将NT头拷贝到DOS头结束之后,长度为NT头开始到最后一个节表结束时的长度,即pNewSectionHeader
			memcpy((void*)((DWORD)FileBuffer + sizeof(IMAGE_DOS_HEADER)), pNTHeader, (DWORD)pNewSectionHeader - (DWORD)pNTHeader);
			//拷贝后重置e_lfanew位置
			printf(" e_lfanew: %x\n", pDosHeader->e_lfanew);
			pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER);
			printf("e_lfanew: %x\n", pDosHeader->e_lfanew);
			//抬升后更新所有被抬升的头指针
			//NT头
			pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)FileBuffer + pDosHeader->e_lfanew);
			//PE头
			pFileHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);	//NT头地址 + 4 为 FileHeader 首址
			//可选PE头	
			pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中
			//首个节表
			pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
			for(i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++)	//注意这里i从1开始 i < NumberOfSections
			{}	//出循环后pSectionHeader指向最后一个节表				
			pNewSectionHeader = pSectionHeader + 1;
			//验证代码,判断是否是有效的PE标志
			if (*((PDWORD)((DWORD)FileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)	//基址pFileBuffer + lfanew 为 NTHeader首址
			{
				printf("抬升后验证失败,不是有效的PE标志\n");
				return ;
			}
			printf("抬升成功!\n");
			//抬升成功后将最后一个节表后两个节表位置的空间置零
			memset(pNewSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER * 2);
		}
		return 1;
}
//******************************计算文件对齐后的值函数************************************						
//Align:计算对齐后的值					
//参数说明:								
//x  需要进行对齐的值								
//Alignment 对齐大小						
//返回值说明:							
//返回x进行Alignment值对齐后的值								
//****************************************************************************************	
int Align(int x, int Alignment)
{
	if (x%Alignment==0)
	{
		return x;
	}
	else
	{
		return (1 + (x / Alignment)) * Alignment;
	}
}










//**************************************移动导出表****************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整形参数,表示FileBuffer大小 
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向NewFileBuffer
//****************************************************************************************
char* RemoveExportDirectory(char* FileBuffer,int SizeOfFileBuffer){
	printf("******                         移动导出表程序                         ******\n"); 
	char* NewFileBuffer=NULL;
	int offset=0;
	int i;
	PIMAGE_DOS_HEADER pDosHeader=NULL;
	PIMAGE_FILE_HEADER pFileHeader=NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
	PIMAGE_SECTION_HEADER pSectionHeader=NULL;
	PIMAGE_EXPORT_DIRECTORY pExportDirectory=NULL; 
	NewFileBuffer=AddNewSection(FileBuffer,SizeOfFileBuffer);
	pDosHeader=(PIMAGE_DOS_HEADER)NewFileBuffer;
	int* AddressOfFunctions;
	char* AddressOfNameOrdinals;
	int* AddressOfNames;
	if(*(PWORD)((DWORD)NewFileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
	}
	pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)NewFileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+RVAToFOA(NewFileBuffer,pFileHeader->SizeOfOptionalHeader));
	pExportDirectory=(PIMAGE_EXPORT_DIRECTORY)((char*)NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));
	AddressOfFunctions=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfFunctions));
	AddressOfNameOrdinals=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNameOrdinals));
	AddressOfNames=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNames));
	for(i=1;i<pFileHeader->NumberOfSections;i++){
		pSectionHeader++;
	}
	printf("移动函数地址表中...\n");
	memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfFunctions,pExportDirectory->NumberOfFunctions*4);
	pExportDirectory->AddressOfFunctions=(DWORD)pSectionHeader->VirtualAddress+offset;
	offset=pExportDirectory->NumberOfFunctions*4;
	//移动测试: 
	printf("函数地址表移动测试:\n");
//	printf("%x\n",*AddressOfFunctions);
//	printf("%x\n",*(PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData));
//	AddressOfFunctions=(char*)(NewFileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions));
//	printf("%x",*AddressOfFunctions);
	for(i=0;i<pExportDirectory->NumberOfFunctions;i++){
		printf("下标:%d     函数地址:0x%x\n",i,*(PWORD)((DWORD)AddressOfFunctions+i*4));
	}
	printf("函数地址表移动成功。\n");
	printf("移动函数导出序号表中...\n");
	memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfNameOrdinals,pExportDirectory->NumberOfNames*2);
	pExportDirectory->AddressOfNameOrdinals=pSectionHeader->VirtualAddress+offset;
	offset+=pExportDirectory->NumberOfNames*2;
	printf("函数导出序号表移动测试:\n");
	for(i=0;i<pExportDirectory->NumberOfNames;i++){
		AddressOfNameOrdinals=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNameOrdinals+i*2));
		printf("下标:%d   函数导出序号:0x%x\n",i,*AddressOfNameOrdinals);
	}
	printf("函数导出序号表移动成功。\n");
	offset+=pExportDirectory->NumberOfNames*4;
	printf("移动函数名称表中...\n");
	memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfNames,pExportDirectory->NumberOfNames*4);
	offset+=pExportDirectory->NumberOfNames*2;
	printf("函数名称表移动成功。\n");
	//移动函数名称字符串
	int p=0;
	for (i = 0; i < pExportDirectory->NumberOfNames; i++){
		AddressOfNames=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNames));
		char* Name=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,*(AddressOfNames+i)));
		memcpy((PVOID)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset + p),Name, strlen(Name)+1);
		printf("下标:%d,函数名:%s\n", i, (char*)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset + p));
		p += strlen(Name)+1;
		AddressOfNames += 1;
	}
	printf("函数名称移动成功。\n");
	offset+=p;
	printf("导出表长度:%d\n",sizeof(IMAGE_EXPORT_DIRECTORY));
	//拷贝导出表到新表
	pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = pSectionHeader->VirtualAddress + offset;
	memcpy((PVOID)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset), pExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY));
	offset+=sizeof(IMAGE_SECTION_HEADER);
	printf("%x",pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	return NewFileBuffer;
}
main.c:
#include <stdio.h>
int main(int argc, char** argv) {
	char filename1[50];
	char filename2[50];
	printf("******               欢迎使用移动导出表程序               ******\n");
	printf("请输入想要操作的文件路径:");
	scanf("%s",filename1);
	char* FileBuffer=NULL;
	char* NewFileBuffer=NULL;
	int length;
	int* plength=&length; 
	FileBuffer=ReadToFileBuffer(filename1);
	length=SizeOfFile(filename1);
	NewFileBuffer=RemoveExportDirectory(FileBuffer,length);
	printf("请输入您想要保存的文件名称:");
	scanf("%d",filename2);
	FILE* fp;
	if((fp=fopen(filename2,"wb"))==NULL){
		printf("文件新建失败!\n");
		exit(0);
	}else{
		printf("文件新建成功,正在写入数据...\n");
	}
	if(fwrite(NewFileBuffer,length+1000,1,fp)){
		printf("数据写入成功。\n");
	}else{
		printf("数据写入失败!\n");
		exit(0);
	}
	free(FileBuffer);
	free(NewFileBuffer);
	return 0;
}

四.移动重定位表源码:

PEFunction.h:
#include <stdio.h>
#include <windows.h>
#include <string.h>
//*************打开文件函数(将文件二进制读取到FileBuffer) ******************
//该函数需要一个char类型的指针,指向想要打开的文件路径
//该函数返回一个char类型的指针,指向FileBuffer
//该函数完成文件的打开,并且将文件的二进制读取到FIleBuffer
//该函数读取完成后会将文件关闭,避免出现误操作
//该函数会通过移动文件指针获取文件大小
//获取的文件大小用于动态申请内存 
//该函数会动态申请内存,用于存放FileBuffer
//***************************************************************************
char* ReadToFileBuffer(char* filename);




//***************************************获取文件大小函数*********************************
//该函数返回文件大小 
//****************************************************************************************
int SizeOfFile(char* filename);





//*****************************获取PE导出表数据函数**************************
//该函数需要一个指针,指向FileBuffer
//该函数在找到导出表之前,需要定义DOS结构指针,标准PE头结构指针和可选PE头指针,以方便找到导出表
//该函数会在控制台输出函数地址表,函数名称表和函数导出序号表 
//***************************************************************************
void ShowExportDirectory(char* FileBuffer);





//*****************************RVA转换为FOA函数******************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,为要转换的RVA
//该函数返回一个整数,为转换后的FOA地址
//***************************************************************************
int RVAToFOA(IN LPVOID pFileBuffer, IN DWORD dwRva);





//*************************根据函数名称查找函数地址函数**********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByName(char* filename);





//*************************根据函数序号查找函数地址函数**********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByOrdinal(char* filename);





//******************************打印PE重定位表函数***************************
//该函数需要一个指针,指向FIleBuffer
//该函数会在控制台打印出重定位表信息(重定位表偏移,重定位表大小,但不打印重定位表具体项
//***************************************************************************
void ShowBaseRelocation(char* FileBuffer);






//**************************************新增节函数***************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个指针,表示FileBuffer大小 
//该函数需要一个字符串,为原文件文件名 
//该函数完成在PE文件中新增一个节
//该函数在新增节之前,PE头部是否足够新增一个节表
//若PE文件头部内存不够新增一个节表,该函数将会提升所有头部,将DOSstob覆盖掉,并且让e_lfanew指向下一个字节 
//该函数会生成一个exe文件,存放于调用该函数的程序源目录下  
//该函数返回一个指针,指向新增节后的FileBuffer 
//****************************************************************************************
char* AddNewSection(char* FileBuffer,int SizeOfFileBuffer);




//*****************************覆盖DOSstob,抬升NT头和原有节表****************************
//该函数需要一个指针,指向需要改动的FileBuffer
//该函数将FileBuffer中的DOSstob覆盖
//该函数将PE头部中,DOS头以后的内容提升到DOSstob的位置 
//抬升成功后会将最后两个节表的数据全初始化为0 
//若头部抬升失败,则返回0 
//若抬升成功,则返回1 
//****************************************************************************************
int UpFile(char* FileBuffer);




//******************************计算文件对齐后的值函数************************************						
//Align:计算对齐后的值					
//参数说明:								
//x  需要进行对齐的值								
//Alignment 对齐大小						
//返回值说明:							
//返回x进行Alignment值对齐后的值								
//****************************************************************************************	
int Align(int x, int Alignment);




//**************************************移动导出表****************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整形参数,表示FileBuffer大小 
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向NewFileBuffer
//****************************************************************************************
char* RemoveExportDirectory(char* FileBuffer,int SizeOfFileBuffer);




//*************************************移动重定位表***************************************
//该函数需要一个指针,指向FileBuffer 
//该函数需要一个整形参数,表示FileBuffer的大小 
//该函数将在原来节表的基础上新增一个节,用于存放移动后的重定位表
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向移动重定位表后的地址 
//****************************************************************************************
char* RemoveBaseRelocation(char* FileBuffer,int SizeOfFileBuffer); 
PEFuncion.c:
/**************************************************************/ 
//*********************自编PE函数库****************************/
#include "PEFunction.h"
//********打开文件函数(将文件二进制读取到FileBuffer) *******
//函数说明:
//该函数需要一个char类型的指针,指向想要打开的文件路径
//该数返回一个char类型的指针,指向FileBuffer
//该函数完成文件的打开,并且将文件的二进制读取到FIleBuffer
//该函数读取完成后会将文件关闭,避免出现误操作
//该函数会通过移动文件指针获取文件大小
//获取的文件大小用于动态申请内存 
//该函数会动态申请内存,用于存放FileBuffer
//********************************************************* 
char* ReadToFileBuffer(char* filename){
	FILE* fp;
	char* FileBuffer=NULL;
	int length;
	if((fp=fopen(filename,"rb"))==NULL){
		printf("%s打开失败!",filename);
		exit(0);
	}else{
		printf("文件打开成功,正在计算文件大小...\n");
	}
	fseek(fp,0,SEEK_END);
	length=ftell(fp);
	fseek(fp,0,SEEK_SET);
	printf("文件大小:%d字节\n正在申请FileBuffer内存...\n",length);
	FileBuffer=(char*)malloc(length);
	if(FileBuffer!=NULL){
		printf("FileBuffer内存申请成功。准备向FileBuffer写入数据...\n");
	}
	if((fread(FileBuffer,length,1,fp))==0){
		printf("写入数据失败!\n");
		exit(0);
	}else{
		printf("写入数据成功。\n");
	}
	if(fclose(fp)){
		printf("文件关闭失败!\n");
		exit(0);
	}else{
		printf("文件关闭成功。\n");
	}
	return FileBuffer;
}




//***************************************获取文件大小函数*********************************
//该函数返回文件大小 
//****************************************************************************************
int SizeOfFile(char* filename){
	FILE* fp;
	char* FileBuffer=NULL;
	int length;
	if((fp=fopen(filename,"rb"))==NULL){
		printf("%s打开失败!",filename);
		exit(0);
	}else{
		printf("文件打开成功,正在计算文件大小...\n");
	}
	fseek(fp,0,SEEK_END);
	length=ftell(fp);
	fseek(fp,0,SEEK_SET);
	return length;
}





//**********************获取PE导出表数据函数************************************************
//该函数需要一个指针,指向FileBuffer
//该函数在找到导出表之前,需要定义DOS结构指针,标准PE头结构指针和可选PE头指针,以方便找到导出表
//该函数会在控制台输出函数地址表,函数名称表和函数导出序号表 
//********************************************************************************************
void ShowExportDirectory(char* FileBuffer){
	IMAGE_DOS_HEADER* pDosHeader=NULL;
	IMAGE_FILE_HEADER* pFileHeader=NULL;
	IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
	IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
	pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
	if(*((PDWORD)((DWORD)FileBuffer + pDosHeader->e_lfanew))!= IMAGE_NT_SIGNATURE){
		printf("不是有效的PE标志!\n");
	}else{
		printf("检测到有效的PE标志。\n");
	}
	pFileHeader=(IMAGE_FILE_HEADER*)(FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
	pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
	printf("导出表RVA:%x\n",pOptionalHeader->DataDirectory[0].VirtualAddress);
	printf("导出表大小:%x字节\n",pOptionalHeader->DataDirectory[0].Size);
	printf("导出表FOA:%d\n",RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
	printf("*******************************导出表*********************************\n");
	printf("TimeDataStamp(经加密):%d\n",pExportDirectory->TimeDateStamp);
	printf("Name(导出表文件名字符串):%s\n",FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->Name));
	printf("Base(函数起始序号):%d\n",pExportDirectory->Base);
	printf("NumberOfFunction(导出函数总数):%d\n",pExportDirectory->NumberOfFunctions);
	printf("NumberOfNames(以名称导出函数的总数):%d\n",pExportDirectory->NumberOfNames);
	printf("*****************************函数地址表********************************\n");
	int i=0;
	char* AddressOfFunction;
	AddressOfFunction=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions));
	for(i=0;i<pExportDirectory->NumberOfFunctions;i++){
		printf("下标:%d     函数地址:0x%x\n",i,*(PWORD)((DWORD)AddressOfFunction+i*4));
	}
	printf("*****************************函数名称表********************************\n");
	int* AddressOfNames=NULL;
	char* name=NULL;
	AddressOfNames=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNames));
	for(i=0;i<pExportDirectory->NumberOfNames;i++){
		name=(char*)(FileBuffer+RVAToFOA(FileBuffer,*AddressOfNames));
		printf("下标:%d     函数名称:%s\n",i,name);
		AddressOfNames++;
	}
	printf("*******************************函数序号表*******************************\n");
	char *AddressOfNameOrdinals=NULL;
	char *Ordinal=NULL;
	AddressOfNameOrdinals=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNameOrdinals));
	for(i=0;i<pExportDirectory->NumberOfNames;i++){
		Ordinal=(int*)(FileBuffer+RVAToFOA(FileBuffer,*AddressOfNameOrdinals));
		printf("下标:%d      函数序号(加Base):%d\n",i,*(AddressOfNameOrdinals+i*2)+pExportDirectory->Base);
	} 
}
//*************************RVA转换为FOA函数*************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,为要转换的RVA
//该函数返回一个整数,为转换后的FOA地址
//******************************************************************
int RVAToFOA(IN LPVOID pFileBuffer, IN DWORD dwRva)
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_FILE_HEADER pFileHeader = NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	PIMAGE_SECTION_HEADER pNextSectionHeader = NULL;
	//DOS头
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;	// 强转 DOS_HEADER 结构体指针
	//PE头
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pFileBuffer + pDosHeader->e_lfanew + 4);	//NT头地址 + 4 为 FileHeader 首址
	//可选PE头	
	pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中
	if (dwRva < pOptionalHeader->SizeOfHeaders)	//偏移小于头的大小,内存偏移则为文件偏移
	{
		return dwRva;
	}
    //首个节表
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
	//下一个节表
	pNextSectionHeader = pSectionHeader + 1;
	//循环遍历节表
	int i;
	for (i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++, pNextSectionHeader++)//注意这里i从1开始 i < NumberOfSections
	{	//注意这里的pSectionHeader已经是加了基址的,不是偏移, 是绝对地址。而dwRva是偏移地址
		if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pNextSectionHeader->VirtualAddress)//大于当前节的内存偏移而小于下一节的内存偏移
		{	//则dwRva属于当前节,则dwRva - VirtualAddress为dwRva基于当前节的偏移。此偏移加上当前节的文件起始偏移地址 则为dwRva在文件中的偏移
			DWORD PointerToRawData = pSectionHeader->PointerToRawData;
			DWORD VirtualAddress = pSectionHeader->VirtualAddress;
			DWORD aa = pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress;
			return pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress ;
		}
	}	//出循环后pSectionHeader指向最后一个节表
	//大于当前节(最后一节)的内存偏移且小于内存映射大小
	if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pOptionalHeader->SizeOfImage)
	{	//同上return
		return pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress;
	}
	else //大于内存映射大小
	{
		printf("dwRva大于内存映射大小\n");
		return -1;
	}
}
//*************************根据函数名称查找函数地址函数***********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//****************************************************************************
void GetAddressOfFunctionByName(char* filename){
	char* FileBuffer=NULL;
	char inname[5];
	int i;
	FileBuffer=ReadToFileBuffer(filename);
	IMAGE_DOS_HEADER* pDosHeader=NULL;
	IMAGE_FILE_HEADER* pFileHeader=NULL;
	IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
	IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
	pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
	if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
		exit(0);
	}
	pFileHeader=(IMAGE_FILE_HEADER*)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
	pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
	int* AddressOfNames=NULL;
	char* name=NULL;
	AddressOfNames=(int*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNames));
	
	printf("请输入您需要查找的函数名:");
	scanf("%s",inname);
	printf("正在查找中...\n");
	for(i=0;i<pExportDirectory->NumberOfNames;i++){
	name=(int*)(FileBuffer+RVAToFOA(FileBuffer,RVAToFOA(FileBuffer,*AddressOfNames)));
		if(!(strcmp("Plus",name))){
			printf("下标为%d的函数名符合。\n",i);
			break;
		}
		AddressOfNames++;
	}
	char* Ordinal=NULL;
	Ordinal=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfNameOrdinals)+i*2);
	char* AddressOfFunction=NULL;
	AddressOfFunction=(char*)(FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions)+*Ordinal*4);
	printf("Ordinal(函数导出序号(未加Base)):%d    AddressOfFunction:0x%x",*Ordinal,*(PWORD)((DWORD)AddressOfFunction));
}
//************************根据函数序号查找函数地址函数***********************
//该函数需要一个指针,指向要打开的文件路径 
//该函数返回一个整数,指向得到的函数地址
//***************************************************************************
void GetAddressOfFunctionByOrdinal(char* filename){
	char* FileBuffer=NULL;
	int InOrdinal=0;
	IMAGE_DOS_HEADER* pDosHeader=NULL;
	IMAGE_FILE_HEADER* pFileHeader=NULL;
	IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
	IMAGE_EXPORT_DIRECTORY* pExportDirectory=NULL;
	FileBuffer=ReadToFileBuffer(filename);
	char* AddressOfFunction;
	pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
	if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到PE标志。");
	}else{
		printf("未检测到PE标志!\n");
		exit(0);
	}
	pFileHeader=(IMAGE_FILE_HEADER*)(FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)pFileHeader+20);
	
	pExportDirectory = (IMAGE_EXPORT_DIRECTORY*)(FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[0].VirtualAddress));
	printf("请输入您需要查找的函数导出序号:");
	scanf("%d",&InOrdinal);
	InOrdinal=InOrdinal-pExportDirectory->Base;
	AddressOfFunction=(char*)FileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions+InOrdinal*4);
	printf("函数导出序号(未加Base):%d       函数地址:0x%x",InOrdinal,*(PWORD)((DWORD)AddressOfFunction));
}
//*************************打印PE重定位表函数*********************************************
//该函数需要一个指针,指向FIleBuffer
//该函数会在控制台打印出重定位表信息(重定位表偏移,重定位表大小,但不打印重定位表具体项*/
//****************************************************************************************
void ShowBaseRelocation(char* FileBuffer){
	int i=1;
	IMAGE_DOS_HEADER* pDosHeader=NULL;
	IMAGE_OPTIONAL_HEADER32* pOptionalHeader=NULL;
	IMAGE_BASE_RELOCATION* pBaseRelocation=NULL;
	pDosHeader=(IMAGE_DOS_HEADER*)FileBuffer;
	if(*(PWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
		exit(0);
	}
	pOptionalHeader=(IMAGE_OPTIONAL_HEADER32*)((DWORD)FileBuffer+pDosHeader->e_lfanew+24);
	pBaseRelocation=(IMAGE_BASE_RELOCATION*)((DWORD)FileBuffer+RVAToFOA(FileBuffer,pOptionalHeader->DataDirectory[5].VirtualAddress));
	printf("%x",pOptionalHeader->DataDirectory[5].VirtualAddress);
	while(pBaseRelocation->VirtualAddress&&pBaseRelocation->SizeOfBlock){
		printf("************                 第%d块                 ************\n",i);
		printf("VirtulaAddress(重定位表在文件中的偏移):0x%x\n",RVAToFOA(FileBuffer,pBaseRelocation->VirtualAddress));
		printf("Size(该块重定位表的大小):%d字节\n",pBaseRelocation->SizeOfBlock);
		printf("重定位表具体项数目:%d\n\n",(pBaseRelocation->SizeOfBlock-8)/2);
		pBaseRelocation = (IMAGE_BASE_RELOCATION*)(pBaseRelocation->SizeOfBlock + (DWORD)pBaseRelocation);
		i++;
	}
}
//**************************************新增节函数***************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整数,表示FileBuffer大小 
//该函数需要一个字符串,位原文件文件名 
//该函数完成在PE文件中新增一个节
//该函数在新增节之前,PE头部是否足够新增一个节表
//若PE文件头部内存不够新增一个节表,该函数将会提升所有头部,将DOSstob覆盖掉,并且让e_lfanew指向下一个字节 
//该函数会生成一个exe文件,存放于调用该函数的程序源目录下 
//该函数返回一个指针,指向新增节后的FileBuffer 
//****************************************************************************************
char* AddNewSection(char* FileBuffer,int SizeOfFileBuffer){
	printf("新增节执行中...\n");
	int choose1;
	unsigned char ShellCode[100];
	int AddressOfShellCode=0;
	PIMAGE_DOS_HEADER pDosHeader=NULL;
	PIMAGE_FILE_HEADER pFileHeader=NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
	PIMAGE_SECTION_HEADER pSectionHeader=NULL;
	PIMAGE_SECTION_HEADER pNewSectionHeader=NULL;
	int i,j;
	char* NewFileBuffer=NULL;
	pDosHeader=(PIMAGE_DOS_HEADER)FileBuffer;
	if(*(PDWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n"); 
	}else{
		printf("未检测到有效的PE标志!\n");
		return 0;
	}
	pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
	for(i=1;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
		printf("移动节表指针中...\n");
		printf("%s",pSectionHeader->Name); 
	}
	pNewSectionHeader=pSectionHeader+1;
	for(i=0;i<IMAGE_SIZEOF_SECTION_HEADER*2;i++){
		if((*(PWORD)((DWORD)pNewSectionHeader+i))!=0){
			printf("%x",*(PWORD)((DWORD)pNewSectionHeader+i));
			printf("PE文件头部内存空间不足,需要覆盖DOSstob抬升头部,以保证足够的空间新增节表!\n");
			if(UpFile){
				printf("更新头部指针中...\n");
				pDosHeader=(PIMAGE_DOS_HEADER)FileBuffer;
				pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
				pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
				pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pOptionalHeader->SizeOfHeaders);
				for(i=1;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
					printf("移动节表指针中...\n");
				}
				pNewSectionHeader=pSectionHeader+1;
				break;
			}else{
				printf("抬升失败!\n");
				return 0;
			}
		}else{
			printf("检测数据中...\n");
			
		}
	}
	if(i==IMAGE_SIZEOF_SECTION_HEADER*2){
		printf("数据检测完毕,未检测到数据,将新增节...\n");
	}
	strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
	printf("******                         请选择是否添加ShellCode                         ******\n");
	printf("******                         0:不添加ShellCode                              ******\n");
	printf("******                         1:添加ShellCode                                 ******\n");

	printf("请输入您的选择:");
	scanf("%d",&choose1);
	switch (choose1){
		case 0:{
			strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
			pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode);
			pNewSectionHeader->VirtualAddress=pOptionalHeader->SizeOfImage;
			printf("FileAligment:%x\n",pOptionalHeader->FileAlignment);
			pNewSectionHeader->SizeOfRawData=Align(sizeof(ShellCode),pOptionalHeader->FileAlignment);
			pNewSectionHeader->PointerToRawData = SizeOfFileBuffer;
//			pNewSectionHeader->PointerToRawData = pSectionHeader->SizeOfRawData+pSectionHeader->PointerToRawData;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
			pNewSectionHeader->PointerToRelocations = 0;
			pNewSectionHeader->PointerToLinenumbers = 0;
			pNewSectionHeader->NumberOfRelocations = 0;
			pNewSectionHeader->NumberOfLinenumbers = 0;
			pNewSectionHeader->Characteristics = 0x60000020;
			pFileHeader->NumberOfSections++;
			printf("SectionAlignment: %x\nSizeOfImage:%x\n", pOptionalHeader->SectionAlignment, pOptionalHeader->SizeOfImage);
			pOptionalHeader->SizeOfImage += Align(sizeof(ShellCode), pOptionalHeader->SectionAlignment);
			printf("SizeOfImage:%x\n", pOptionalHeader->SizeOfImage);
			int SizeOfNewBuffer=SizeOfFileBuffer+pNewSectionHeader->SizeOfRawData;
			NewFileBuffer=(char*)malloc(SizeOfNewBuffer);
			memcpy(NewFileBuffer, FileBuffer, SizeOfFileBuffer);
			memset((void *)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), 0, pNewSectionHeader->SizeOfRawData);
			FILE* fp=NULL;
//			if((fp=(fopen("新增节程序.exe","wb")))==NULL){
//				printf("文件新建失败!\n");
//				exit(0);
//			}else{
//				printf("文件新建成功,正在写入数据...\n");
//				if(fwrite(NewFileBuffer,SizeOfNewBuffer,1,fp)){
//					printf("数据写入成功。\n");
//				}else{
//					printf("数据写入失败!\n");
//					exit(0);
//				}
//			}
//			if(!fclose(fp)){
//				printf("文件保存成功。\n");
//			}else{
//				printf("文件保存失败!");
//				exit(0); 
//			}
			return  NewFileBuffer;
			break;
		}
		case 1:{
			int CallShellCode;
			int JmpShellCode;
			strcpy((char*)pNewSectionHeader->Name, (char*)".NewSec");
			pNewSectionHeader->Misc.VirtualSize = sizeof(ShellCode);
			pNewSectionHeader->VirtualAddress=pOptionalHeader->SizeOfImage;
			printf("FileAligment:%x\n",pOptionalHeader->FileAlignment);
			pNewSectionHeader->SizeOfRawData=Align(sizeof(ShellCode),pOptionalHeader->FileAlignment);
			pNewSectionHeader->PointerToRawData = pSectionHeader->SizeOfRawData+pSectionHeader->PointerToRawData;//pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
			pNewSectionHeader->PointerToRelocations = 0;
			pNewSectionHeader->PointerToLinenumbers = 0;
			pNewSectionHeader->NumberOfRelocations = 0;
			pNewSectionHeader->NumberOfLinenumbers = 0;
			pNewSectionHeader->Characteristics = 0x60000020;
			pFileHeader->NumberOfSections++;
			printf("SectionAlignment: %x\nSizeOfImage:%x\n", pOptionalHeader->SectionAlignment, pOptionalHeader->SizeOfImage);
			pOptionalHeader->SizeOfImage += Align(sizeof(ShellCode), pOptionalHeader->SectionAlignment);
			printf("SizeOfImage:%x\n", pOptionalHeader->SizeOfImage);
			int SizeOfNewBuffer=SizeOfFileBuffer+pNewSectionHeader->SizeOfRawData;
			NewFileBuffer=(int*)malloc(SizeOfNewBuffer);
			DWORD OddAddressOfEntryPoint = pOptionalHeader->AddressOfEntryPoint;
			pOptionalHeader->AddressOfEntryPoint = pNewSectionHeader->VirtualAddress;
			memcpy(NewFileBuffer, FileBuffer, SizeOfFileBuffer);
			memset((void *)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), 0, pNewSectionHeader->SizeOfRawData);
			printf("请输入ShellCode硬编码:\n");
			printf("!!!特别注意:在输入硬编码后,应输入E8和该ShellCode执行时内存中的地址,程序会自动转换!!!暂时只支持输入100字节以内的硬编码\n");
			for(i=0,j=0;i<100;i++){
				scanf("%x ",ShellCode[i]);
				if(ShellCode[i]==0xE8){
					j=i+1;
				}
				if(i=j+4){
					CallShellCode=*(int*)(ShellCode[j]);
					CallShellCode = CallShellCode - (pOptionalHeader->ImageBase + pNewSectionHeader->VirtualAddress + j-1 + 5);
					*(int*)ShellCode[j] = CallShellCode;
				}
				if(i=j+9){
					JmpShellCode = OddAddressOfEntryPoint - (pNewSectionHeader->VirtualAddress + j+5 + 5);
					*(int*)ShellCode[j+5] = JmpShellCode;
				}
			}
			memcpy((void*)((DWORD)NewFileBuffer + pNewSectionHeader->PointerToRawData), ShellCode, sizeof(ShellCode));
//			FILE* fp=NULL;
//			if((fp=(fopen("新增节程序.exe","wb")))==NULL){
//				printf("文件新建失败!\n");
//				exit(0);
//			}else{
//				printf("文件新建成功,正在写入数据...\n");
//				if(fwrite(fp,SizeOfNewBuffer,1,NewFileBuffer)){
//					printf("数据写入成功。\n");
//				}else{
//					printf("数据写入失败!\n");
//					exit(0);
//				}
//			}
			return NewFileBuffer;
			break;
		}
	}
	
}
//*****************************覆盖DOSstob,抬升NT头和原有节表****************************
//该函数需要一个指针,指向需要改动的FileBuffer
//该函数将FileBuffer中的DOSstob覆盖
//该函数将PE头部中,DOS头以后的内容提升到DOSstob的位置 
//抬升成功后会将最后两个节表的数据全初始化为0 
//若头部抬升失败,则返回0 
//若抬升成功,则返回1 
//****************************************************************************************
int UpFile(char* FileBuffer){
	PIMAGE_DOS_HEADER pDosHeader=NULL;
	PIMAGE_NT_HEADERS32 pNTHeader=NULL; 
	PIMAGE_FILE_HEADER pFileHeader=NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
	PIMAGE_SECTION_HEADER pSectionHeader=NULL;
	char* pNewSectionHeader=NULL;
	int i;
	pDosHeader=(PIMAGE_DOS_HEADER)((DWORD)FileBuffer);
	pNTHeader=(PIMAGE_NT_HEADERS32)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
	if(*(PDWORD)((DWORD)FileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
		return 0;
	}
	pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)FileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((DWORD)FileBuffer+20);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pFileHeader->SizeOfOptionalHeader);
	for(i=0;i<pFileHeader->NumberOfSections;i++,pSectionHeader++){
		printf("移动节表指针中...\n");
	}
	pNewSectionHeader=pSectionHeader+1;
	if ((DWORD)FileBuffer + sizeof(IMAGE_DOS_HEADER) - (DWORD)pNTHeader >= IMAGE_SIZEOF_SECTION_HEADER * 2)
		{
			printf("可抬升NT头\n抬升PE头部中...\n");
			//开始拷贝,将NT头拷贝到DOS头结束之后,长度为NT头开始到最后一个节表结束时的长度,即pNewSectionHeader
			memcpy((void*)((DWORD)FileBuffer + sizeof(IMAGE_DOS_HEADER)), pNTHeader, (DWORD)pNewSectionHeader - (DWORD)pNTHeader);
			//拷贝后重置e_lfanew位置
			printf(" e_lfanew: %x\n", pDosHeader->e_lfanew);
			pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER);
			printf("e_lfanew: %x\n", pDosHeader->e_lfanew);
			//抬升后更新所有被抬升的头指针
			//NT头
			pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)FileBuffer + pDosHeader->e_lfanew);
			//PE头
			pFileHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);	//NT头地址 + 4 为 FileHeader 首址
			//可选PE头	
			pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);//SIZEOF_FILE_HEADER为固定值且不存在于PE文件字段中
			//首个节表
			pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader + pFileHeader->SizeOfOptionalHeader);
			for(i = 1; i < pFileHeader->NumberOfSections; i++, pSectionHeader++)	//注意这里i从1开始 i < NumberOfSections
			{}	//出循环后pSectionHeader指向最后一个节表				
			pNewSectionHeader = pSectionHeader + 1;
			//验证代码,判断是否是有效的PE标志
			if (*((PDWORD)((DWORD)FileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)	//基址pFileBuffer + lfanew 为 NTHeader首址
			{
				printf("抬升后验证失败,不是有效的PE标志\n");
				return ;
			}
			printf("抬升成功!\n");
			//抬升成功后将最后一个节表后两个节表位置的空间置零
			memset(pNewSectionHeader, 0, IMAGE_SIZEOF_SECTION_HEADER * 2);
		}
		return 1;
}
//******************************计算文件对齐后的值函数************************************						
//Align:计算对齐后的值					
//参数说明:								
//x  需要进行对齐的值								
//Alignment 对齐大小						
//返回值说明:							
//返回x进行Alignment值对齐后的值								
//****************************************************************************************	
int Align(int x, int Alignment)
{
	if (x%Alignment==0)
	{
		return x;
	}
	else
	{
		return (1 + (x / Alignment)) * Alignment;
	}
}
//**************************************移动导出表****************************************
//该函数需要一个指针,指向FileBuffer
//该函数需要一个整形参数,表示FileBuffer大小 
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向NewFileBuffer
//****************************************************************************************
char* RemoveExportDirectory(char* FileBuffer,int SizeOfFileBuffer){
	printf("******                         移动导出表程序                         ******\n"); 
	char* NewFileBuffer=NULL;
	int offset=0;
	int i;
	PIMAGE_DOS_HEADER pDosHeader=NULL;
	PIMAGE_FILE_HEADER pFileHeader=NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
	PIMAGE_SECTION_HEADER pSectionHeader=NULL;
	PIMAGE_EXPORT_DIRECTORY pExportDirectory=NULL; 
	NewFileBuffer=AddNewSection(FileBuffer,SizeOfFileBuffer);
	pDosHeader=(PIMAGE_DOS_HEADER)NewFileBuffer;
	int* AddressOfFunctions;
	char* AddressOfNameOrdinals;
	int* AddressOfNames;
	if(*(PWORD)((DWORD)NewFileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
	}
	pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)NewFileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+RVAToFOA(NewFileBuffer,pFileHeader->SizeOfOptionalHeader));
	pExportDirectory=(PIMAGE_EXPORT_DIRECTORY)((char*)NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress));
	AddressOfFunctions=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfFunctions));
	AddressOfNameOrdinals=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNameOrdinals));
	AddressOfNames=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNames));
	for(i=1;i<pFileHeader->NumberOfSections;i++){
		pSectionHeader++;
	}
	printf("移动函数地址表中...\n");
	memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfFunctions,pExportDirectory->NumberOfFunctions*4);
	pExportDirectory->AddressOfFunctions=(DWORD)pSectionHeader->VirtualAddress+offset;
	offset=pExportDirectory->NumberOfFunctions*4;
	//移动测试: 
	printf("函数地址表移动测试:\n");
//	printf("%x\n",*AddressOfFunctions);
//	printf("%x\n",*(PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData));
//	AddressOfFunctions=(char*)(NewFileBuffer+RVAToFOA(FileBuffer,pExportDirectory->AddressOfFunctions));
//	printf("%x",*AddressOfFunctions);
	for(i=0;i<pExportDirectory->NumberOfFunctions;i++){
		printf("下标:%d     函数地址:0x%x\n",i,*(PWORD)((DWORD)AddressOfFunctions+i*4));
	}
	printf("函数地址表移动成功。\n");
	printf("移动函数导出序号表中...\n");
	memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfNameOrdinals,pExportDirectory->NumberOfNames*2);
	pExportDirectory->AddressOfNameOrdinals=pSectionHeader->VirtualAddress+offset;
	offset+=pExportDirectory->NumberOfNames*2;
	printf("函数导出序号表移动测试:\n");
	for(i=0;i<pExportDirectory->NumberOfNames;i++){
		AddressOfNameOrdinals=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNameOrdinals+i*2));
		printf("下标:%d   函数导出序号:0x%x\n",i,*AddressOfNameOrdinals);
	}
	printf("函数导出序号表移动成功。\n");
	offset+=pExportDirectory->NumberOfNames*4;
	printf("移动函数名称表中...\n");
	memcpy((PWORD)((DWORD)NewFileBuffer+pSectionHeader->PointerToRawData+offset),AddressOfNames,pExportDirectory->NumberOfNames*4);
	offset+=pExportDirectory->NumberOfNames*2;
	printf("函数名称表移动成功。\n");
	//移动函数名称字符串
	int p=0;
	for (i = 0; i < pExportDirectory->NumberOfNames; i++){
		AddressOfNames=(int*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,pExportDirectory->AddressOfNames));
		char* Name=(char*)((DWORD)NewFileBuffer+RVAToFOA(NewFileBuffer,*(AddressOfNames+i)));
		memcpy((PVOID)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset + p),Name, strlen(Name)+1);
		printf("下标:%d,函数名:%s\n", i, (char*)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset + p));
		p += strlen(Name)+1;
		AddressOfNames += 1;
	}
	printf("函数名称移动成功。\n");
	offset+=p;
	printf("导出表长度:%d\n",sizeof(IMAGE_EXPORT_DIRECTORY));
	//拷贝导出表到新表
	pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = pSectionHeader->VirtualAddress + offset;
	memcpy((PVOID)((DWORD)NewFileBuffer + pSectionHeader->PointerToRawData + offset), pExportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY));
	offset+=sizeof(IMAGE_SECTION_HEADER);
	printf("%x",pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	return NewFileBuffer;
}
//*************************************移动重定位表***************************************
//该函数需要一个指针,指向FileBuffer 
//该函数需要一个整形参数,表示FileBuffer的大小 
//该函数将在原来节表的基础上新增一个节,用于存放移动后的重定位表
//该函数将移动导出表到新节,节名称:.NewSec 
//该函数返回一个指针,指向移动重定位表后的地址 
//****************************************************************************************
char* RemoveBaseRelocation(char* FileBuffer,int SizeOfFileBuffer){
	char* NewFileBuffer=NULL;
	int offset=0;
	int i;
	int SizeOfRelocation=0; 
	PIMAGE_DOS_HEADER pDosHeader=NULL;
	PIMAGE_FILE_HEADER pFileHeader=NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionalHeader=NULL;
	PIMAGE_SECTION_HEADER pSectionHeader=NULL;
	PIMAGE_BASE_RELOCATION pBaseRelocation=NULL;
	NewFileBuffer=AddNewSection(FileBuffer,SizeOfFileBuffer);
	pDosHeader=(PIMAGE_DOS_HEADER)NewFileBuffer;
	if(*(PWORD)((DWORD)NewFileBuffer+pDosHeader->e_lfanew)==IMAGE_NT_SIGNATURE){
		printf("检测到有效的PE标志。\n");
	}else{
		printf("未检测到有效的PE标志!\n");
	}
	pFileHeader=(PIMAGE_FILE_HEADER)((DWORD)NewFileBuffer+pDosHeader->e_lfanew+4);
	pOptionalHeader=(PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+20);
	pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+RVAToFOA(NewFileBuffer,pFileHeader->SizeOfOptionalHeader));
	for(i=1;i<pFileHeader->NumberOfSections;i++){
		pSectionHeader++;
	}
	if (!pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
	{
		printf("该文件没有重定向表!\n");
		return;
	}
	pBaseRelocation=(PIMAGE_BASE_RELOCATION)(NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress ));
	while(pBaseRelocation->VirtualAddress&&pBaseRelocation->SizeOfBlock){
		SizeOfRelocation+=pBaseRelocation->SizeOfBlock;
		pBaseRelocation=(PDWORD)((DWORD)pBaseRelocation+pBaseRelocation->SizeOfBlock);
	}
	SizeOfRelocation+=8;
	//memcpy(PVOID((DWORD)pNewFileBuffer + pNewSectionHeader->PointerToRawData ), pRelocationTable, SizeOfRelocationTable);
	memcpy((PVOID)(NewFileBuffer+pSectionHeader->PointerToRawData),NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress),SizeOfRelocation);
	pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress=pSectionHeader->PointerToRawData;
	printf("重定位表移动成功。\n"); 
	//检测重定位表移动
	pBaseRelocation=(PIMAGE_BASE_RELOCATION)(NewFileBuffer+RVAToFOA(NewFileBuffer,pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress ));
	i=1;
	while(pBaseRelocation->VirtualAddress&&pBaseRelocation->SizeOfBlock){
		printf("******                                          第%d个块                                          ******\n",i);
		printf("VirtualAddress:0x%x\nSizeOfBlock:0x%x\n",pBaseRelocation->VirtualAddress,pBaseRelocation->SizeOfBlock);
		pBaseRelocation = (IMAGE_BASE_RELOCATION*)(pBaseRelocation->SizeOfBlock + (DWORD)pBaseRelocation);
		i++;
	}
	return NewFileBuffer;
}

main.c:

#include <stdio.h>

int main(int argc, char** argv) {
	char filename1[50];
	char filename2[50];
	char* FileBuffer=NULL;
	char* NewFileBuffer=NULL;
	int length;
	FILE* fp;
	printf("请输入您想要操作的文件名:");
	scanf("%s",filename1);
	FileBuffer=ReadToFileBuffer(filename1);
	length=SizeOfFile(filename1);
	NewFileBuffer=RemoveBaseRelocation(FileBuffer,length);
	printf("请输入您想要保存的文件名:");
	if((fp=fopen(filename2,"wb"))==NULL){
		printf("新建文件失败!\n");
		exit(0); 
	}else{
		printf("新建文件成功。\n");
	}
	memcpy(fp,NewFileBuffer,length+1000);
	if(
	fclose(!fp)){
		printf("数据写入成功。");
	}else{
		printf("文件写入失败!");
		exit(0); 
	}
	free(FileBuffer);
	free(NewFileBuffer);
	return 0;
}

文章中若有语法错误或理解错误,还请大家指出来,我会非常虚心地学习,希望大家共同进步!

第1讲:2015-01-12(进制01) 第2讲:2015-01-13(进制02) 第3讲:2015-01-14(数据宽度-逻辑运算03) 第4讲:2015-01-15(通用寄存器-内存读写04) 第5讲:2015-01-16(内存寻址-堆栈05) 第6讲:2015-01-19(EFLAGS寄存器06) 第7讲:2015-01-20(JCC) 第8讲:2015-01-21(堆栈图) 第8讲:2015-01-21(宝马问题) 第9讲:2015-01-22(堆栈图2) 第10讲:2015-01-23(C语言01_后半段) 第10讲:2015-01-23(C语言完整版) 第11讲:2015-01-26(C语言02_数据类型) 第12讲:2015-01-27(C语言03_数据类型_IF语句) 第13讲:2015-01-28(C语言04_IF语句逆向分析上) 第14讲:2015-01-28(C语言04_IF语句逆向分析下) 第15讲:2015-01-29(C语言04_正向基础) 第16讲:2015-01-30(C语言05_循环语句) 第17讲:2015-02-02(C语言06_参数_返回值_局部变量_数组反汇编) 第18讲:2015-02-02(2015-01-30课后练习) 第19讲:2015-02-03(C语言07_多维数组) 第20讲:2015-02-03(2015-02-02课后练习) 第21讲:2015-02-04(C语言08_结构体) 第22讲:2015-02-05(C语言09_字节对齐_结构体数组) 第23讲:2015-02-06(C语言10_Switch语句反汇编) 第24讲:2015-02-26(C语言11_指针1) 第25讲:2015-02-27(C语言11_指针2) 第26讲:2015-02-28(C语言11_指针3) 第27讲:2015-02-28(C语言11_指针4) 第28讲:2015-03-02(C语言11_指针5) 第29讲:2015-03-03(C语言11_指针6) 第30讲:2015-03-04(C语言11_指针7) 第31讲:2015-03-06(C语言11_指针8) 第32讲:2015-03-09(位运算) 第33讲:2015-03-10(内存分配_文件读写) 第34讲:2015-03-11(PE头解析_手动) 第35讲:2015-03-12(PE头字段说明) 第36讲:2015-03-13(PE节) 第37讲:2015-03-16(FileBuffer转ImageBuffer) 第38讲:2015-03-17(代码节空白区添加代码) 第39讲:2015-03-18(任意节空白区添加代码) 第40讲:2015-03-19(新增节添加代码) 第41讲:2015-03-20(扩大节-合并节-数据目录) 第42讲:2015-03-23(静态连接库-动态链接库) 第43讲:2015-03-24(导出) 第44讲:2015-03-25(重定位) 第45讲:2015-03-26(移动导出-重定位) 第46讲:2015-03-27(IAT) 第47讲:2015-03-27(导入) 第48讲:2015-03-30(绑定导入) 第49讲:2015-03-31(导入注入) 第50讲:2015-04-01(C++ this指针 类 上) 第51讲:2015-04-01(C++ this指针 类 下) 第52讲:2015-04-02(C++ 构造-析构函数 继承) 第53讲:2015-04-03(C++ 权限控制) 第54讲:2015-04-07(C++ 虚函数) 第55讲:2015-04-08(C++ 动态绑定-多态-上) 第56讲:2015-04-08(C++ 动态绑定-多态-下) 第57讲:2015-04-09(C++ 模版) 第58讲:2015-04-10(C++ 引用-友元-运算符重载) 第59讲:2015-04-13(C++ new-delete-Vector) 第60讲:2015-04-14(C++Vector实现) 第61讲:2015-04-15(C++) 第62讲:2015-04-16(C++实现) 第63讲:2015-04-16(C++二叉树) 第64讲:2015-04-17(C++二叉树实现) 第65讲:2015-04-20(Win32 宽字符) 第66讲:2015-04-21(Win32 事件-消息-消息处理函数) 第67讲:2015-04-22(Win32 ESP寻址-定位回调函数-条件断点) 第68讲:2015-04-23(Win32 子窗口-消息处理函数定位) 第69讲:2015-04-24(Win32 资源文件-消息断点) 第70讲:2015-04-27(Win32 提取图标-修改标题) 第71讲:2015-04-28(Win32 通用控件-VM_NOTIFY) 第72讲:2015-04-29(Win32 PE查看器-项目要求) 项目一:PE查看器 开发周期(5天) 需求文档 第73讲:2015-05-07(Win32 创建线程) 第74讲:2015-05-08(Win32 线程控制_CONTEXT) 第75讲:2015-05-11(Win32 临界区) 第76讲:2015-05-12(Win32 互斥体) 第77讲:2015-05-13(Win32 事件) 第78讲:2015-05-14(Win32 信号量) 第79讲:2015-05-15(Win32 线程同步与线程互斥) 第80讲:2015-05-18(Win32 进程创建_句柄) 第81讲:2015-05-20(Win32 以挂起形式创建进程) 第82讲:2015-05-21(Win32 加密壳_项目说明) 项目二:加密壳 开发周期(5天) 需求文档 第83讲:2015-05-28(Win32 枚举窗口_鼠标键盘事件) 第84讲:2015-05-29(Win32 CE练习) 第85讲:2015-06-01(Win32 OD练习) 第86讲:2015-06-03(Win32 ShellCode_远程线程注入) 第87讲:2015-06-04(Win32 加载EXE_模块隐藏) 第88讲:2015-06-09(Win32 IAT_HOOK) 第89讲:2015-06-10(Win32 InlineHook) 第90讲:2015-06-11(Win32 进程通信) 第91讲:2015-06-11(Win32 进程监控_项目说明) 项目三:进程监控 开发周期(5天) 需求文档 第92讲:2015-06-15(硬编码_01) 第93讲:2015-06-16(硬编码_02) 第94讲:2015-06-17(硬编码_03) 第95讲:2015-06-18(硬编码_04) 第96讲:2015-06-19(硬编码_05)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shad0w-2023

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值