滴水三期:day41.2-PE阶段所有代码汇总(PE文件分析器基本C代码)

一、代码汇总

1.功能如下

  1. 打印PE头字段
  2. 打印节表
  3. 将文件读入到FileBuffer,FileBuffer到ImageBuffer到newBuffer,最后存盘
  4. RVA转FOA、FOA转RVA
  5. 向代码区空白区添加代码
  6. 向任何区空白区添加代码
  7. 新增一个节,并添加代码
  8. 扩大最后一个节,并添加代码
  9. 合并节
  10. 返回对齐后的大小
  11. 打印数据目录
  12. 打印导出表
  13. 按名字、序号找导出函数地址信息
  14. 打印重定位表
  15. 移动导出表
  16. 移动重定位表
  17. 修复重定位表
  18. 打印程序运行前的导入表、INT表、IAT表、函数名称表等
  19. 打印绑定导入表
  20. 导入表注入

2.代码

有些函数功能的验证需要额外的一些操作,见具体章节即可。下面代码中文件绝对地址换成你自己的就可以了。

本人使用环境:使用VC6.0编写,使用VMware虚拟机搭建的Windows32位XP系统,notepad.exe为系统自带程序,ipmsg.exe是网上下载的飞鸽软件,Winhex、OllyDBG、LordPE等均为网上下载的软件,在C盘下的DLL就是XP系统自带,其他的DLL就是上述软件目录下的(全部都是滴水三期海东老师上课所讲的内容,建议从头开始看)

#include "stdafx.h"
#include <stdlib.h>
#include <string.h>

typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef unsigned char BYTE;

//宏定义MZ标记和PE标记,方便后面判断
#define MZ 0x5A4D
#define PE 0x4550
#define IMAGE_SIZEOF_SHORT_NAME 8
#define MessageBox_Address 0x77D36476 //宏定义记事本的MessageBox内存地址,后面学API就可以计算得到了

//shellcode:定义要添加的硬编码全局变量,确定的写好,不确定的先用0x00填充,后面计算完再改
BYTE shellcode[] = {
	0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,
	0xE8,0x00,0x00,0x00,0x00,
	0xE9,0x00,0x00,0x00,0x00
};

//DOS头
struct _IMAGE_DOS_HEADER {
	WORD e_magic;  //MZ标记
	WORD e_cblp;
	WORD e_cp;
	WORD e_crlc;
	WORD e_cparhdr;
	WORD e_minalloc;
	WORD e_maxalloc;
	WORD e_ss;
	WORD e_sp;
	WORD e_csum;
	WORD e_ip;
	WORD e_cs;
	WORD e_lfarlc;
	WORD e_ovno;
	WORD e_res[4];
	WORD e_oemid;
	WORD e_oeminfo;
	WORD e_res2[10];
	DWORD e_lfanew;  //PE文件真正开始的偏移地址
};

//标准PE头
struct _IMAGE_FILE_HEADER {
	WORD Machine;  //文件运行平台
	WORD NumberOfSections;  //节数量
	DWORD TimeDateStamp;  //时间戳
	DWORD PointerToSymbolTable;
	DWORD NumberOfSymbols;
	WORD SizeOfOptionalHeader;  //可选PE头大小
	WORD Characteristics;  //特征值
};

//数据目录
struct _IMAGE_DATA_DIRECTORY{
    DWORD VirtualAddress;
    DWORD Size;
};

//可选PE头
struct _IMAGE_OPTIONAL_HEADER {
	WORD Magic;  //文件类型
	BYTE MajorLinkerVersion;
	BYTE MinorLinkerVersion;
	DWORD SizeOfCode;   //代码节文件对齐后的大小
	DWORD SizeOfInitializedData;  //初始化数据文件对齐后的大小
	DWORD SizeOfUninitializedData;  //未初始化数据文件对齐后大小
	DWORD AddressOfEntryPoint;  //程序入口点(偏移量)
	DWORD BaseOfCode;  //代码基址
	DWORD BaseOfData;  //数据基址
	DWORD ImageBase;   //内存镜像基址
	DWORD SectionAlignment;  //内存对齐粒度
	DWORD FileAlignment;  //文件对齐粒度
	WORD MajorOperatingSystemVersion;
	WORD MinorOperatingSystemVersion;
	WORD MajorImageVersion;
	WORD MinorImageVersion;
	WORD MajorSubsystemVersion;
	WORD MinorSubsystemVersion;
	DWORD Win32VersionValue;
	DWORD SizeOfImage;  //文件装入虚拟内存后大小
	DWORD SizeOfHeaders;  //DOS、NT头和节表大小
	DWORD CheckSum;  //校验和
	WORD Subsystem;
	WORD DllCharacteristics;
	DWORD SizeOfStackReserve;  //预留堆栈大小
	DWORD SizeOfStackCommit;  //实际分配堆栈大小
	DWORD SizeOfHeapReserve;  //预留堆大小
	DWORD SizeOfHeapCommit;  //实际分配堆大小
	DWORD LoaderFlags;
	DWORD NumberOfRvaAndSizes;  //目录项数目
	_IMAGE_DATA_DIRECTORY DataDirectory[16]; //数据目录
};

//NT头
struct _IMAGE_NT_HEADERS {
	DWORD Signature;  //PE签名
	_IMAGE_FILE_HEADER FileHeader;
	_IMAGE_OPTIONAL_HEADER OptionalHeader;
};

//节表
struct _IMAGE_SECTION_HEADER{
	BYTE Name[IMAGE_SIZEOF_SHORT_NAME];  //节表名
	union{
		DWORD PhysicalAddress;
		DWORD VirtualSize;  //内存中未对齐大小
	}Misc;
	DWORD VirtualAddress;  //该节在内存中偏移地址
	DWORD SizeOfRawData;  //该节在硬盘上文件对齐后大小
	DWORD PointerToRawData;  //该节在硬盘上文件对齐后偏移地址
	DWORD PointerToRelocations;
	DWORD PointerToLinenumbers;
	WORD NumberOfRelocations;
	WORD NumberOfLinenumbers;
	DWORD Characteristics;  //该节特征属性
};

//导出表
struct _IMAGE_EXPORT_DIRECTORY{						
    DWORD Characteristics;  //未使用		
    DWORD TimeDateStamp;  //时间戳		
    WORD MajorVersion;  //未使用		
    WORD MinorVersion;	//未使用		
    DWORD Name;  //指向该导出表文件名字符串  *
    DWORD Base;  //导出函数起始序号  *
    DWORD NumberOfFunctions;  //所有导出函数的个数  *		
    DWORD NumberOfNames;  //以函数名字导出的函数个数  *
    DWORD AddressOfFunctions;  //导出函数地址表RVA  *					
    DWORD AddressOfNames;  //导出函数名称表RVA  *						
    DWORD AddressOfNameOrdinals;  //导出函数序号表RVA  *						
};

//重定位表
struct _IMAGE_BASE_RELOCATION{
	DWORD VirtualAddress;
	DWORD SizeOfBlock;
    //具体项
};

//导入表
struct _IMAGE_IMPORT_DESCRIPTOR{							
    union{							
        DWORD Characteristics;           							
        DWORD OriginalFirstThunk;  //RVA,指向IMAGE_THUNK_DATA结构数组(INT表)
    };							
    DWORD TimeDateStamp;  //时间戳	
    DWORD ForwarderChain;              							
    DWORD Name;  //RVA,指向dll名字字符串存储地址
    DWORD FirstThunk;  //RVA,指向IMAGE_THUNK_DATA结构数组(IAT表)
};//导入表有很多个这种结构(成员全为0,表示结束)

//INT表中元素指向的函数名称表
struct _IMAGE_IMPORT_BY_NAME{							
    WORD Hint;  //可能为空(编译器决定);如果不为空,表示函数在导出表中的索引	
    BYTE Name[1];  //函数名称,以0结尾	
};	

//INT表
struct _IMAGE_THUNK_DATA32{								
    union{								
        BYTE ForwarderString;								
        DWORD Function;								
        DWORD Ordinal;  //序号		
        _IMAGE_IMPORT_BY_NAME* AddressOfData;  //RVA,指向IMAGE_IMPORT_BY_NAME		
    };								
};

//绑定导入表
struct _IMAGE_BOUND_IMPORT_DESCRIPTOR{						
    DWORD TimeDateStamp;  //时间戳					
    WORD OffsetModuleName;	//DLL的名字RVA(加第一个结构中RVA才是字符串真正RVA,详见下面)	
    WORD NumberOfModuleForwarderRefs;  //这个绑定导入表结构后面还有几个_IMAGE_BOUND_FORWARDER_REF这种结构					
};  //绑定导入表有很多这种结构或者_IMAGE_BOUND_FORWARDER_REF这种结构,最后如果有sizeof(_IMAGE_BOUND_IMPORT_DESCRIPTOR)个0,表示绑定导入表结束
struct _IMAGE_BOUND_FORWARDER_REF{			
    DWORD TimeDateStamp;  //时间戳		
    WORD OffsetModuleName;  //对应DLL的名字
    WORD Reserved;  //保留(未使用)	
};



/*计算文件大小函数
参数:文件绝对路径
返回值:返回文件大小(单位字节)
*/
int compute_file_size(char* filePath){
	FILE* fp = fopen(filePath,"rb");
    if(!fp){
		printf("打开文件失败");
		exit(0);
	}
    fseek(fp,0,2);
	int size = ftell(fp);
	//fseek(fp,0,0); 单纯计算文件大小,就不需要还原指针了
	fclose(fp);
	return size;
}

/*计算一个数按照某对齐粒度对齐后的值函数
参数:一个数,对齐粒度
返回值:此数对齐后的值,返回0表示参数不合法
*/
DWORD alignment(DWORD num,DWORD align_num){  //用int也行
    if((int)num <= 0 || (int)align_num <= 0){
        printf("输入的数据不合法\n");
        return 0;
    }
	if(num % align_num == 0){
		return num;
	}else{
		return align_num * (num / align_num + 1);
	}
}

/*将文件读入FileBuffer函数
参数:文件绝对路径
返回值:FileBuffer起始地址
*/
char* to_FileBuffer(char* filePath){
    FILE* fp = fopen(filePath,"rb");
    if(!fp){
		printf("打开文件失败");
		exit(0);
	}
    int size = compute_file_size(filePath);

	char* mp = (char*)malloc(sizeof(char) * size);  //分配内存空间
    if(!mp){
        printf("分配空间失败");
        fclose(fp);
        exit(0);
    }

    int isSucceed = fread(mp,size,1,fp);
    if(!isSucceed){
        printf("读取数据失败");
        free(mp);
        fclose(fp);
        exit(0);
    }

    fclose(fp);
    return mp;
}

/*FileBuffer到ImageBuffer函数
参数:FileBuffer起始地址
返回值:ImageBuffer起始地址
*/
char* fileBuffer_to_ImageBuffer(char* fileBufferp){

	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	DWORD sizeofImage = _image_optional_header->SizeOfImage;
	char* imageBufferp = (char*)malloc(sizeofImage);
	if(NULL == imageBufferp){
        printf("动态申请ImageBuffer内存失败\n");
        exit(0);
    }
	for(DWORD i = 0;i < sizeofImage;i++){
		*(imageBufferp + i) = 0x00;
	}

	//strncpy(imageBufferp,fileBufferp,_image_optional_header->SizeOfHeaders); 因为imageBufferp,fileBufferp值会变,所以这个方法不太好
	for(i = 0;i < _image_optional_header->SizeOfHeaders;i++){
		*(imageBufferp + i) = *(fileBufferp + i);
	}

	for(i = 0;i < _image_file_header->NumberOfSections;i++){
		for(DWORD j = 0;j < _image_section_header->SizeOfRawData;j++){
			*(imageBufferp + _image_section_header->VirtualAddress + j) = *(fileBufferp + 
				_image_section_header->PointerToRawData + j);
		}
		_image_section_header++;
	}

	return imageBufferp;
}

/*计算NewBuffer大小函数
参数:NewBuffer起始地址
返回值:unsigned int类型(单位:字节)
*/
DWORD compute_NewBuffer_size(char* newBufferp){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)newBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(newBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	_IMAGE_SECTION_HEADER* last_image_section_header = _image_section_header + _image_file_header->NumberOfSections - 1;
	DWORD sizeofNewBuffer = last_image_section_header->PointerToRawData + last_image_section_header->SizeOfRawData;
	return sizeofNewBuffer;
}

/*ImageBuffer到NewBuffer函数
参数:ImageBuffer起始地址
返回值:NewBuffer起始地址
*/
char* imageBuffer_to_NewBuffer(char* imageBufferp){
	
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//重新计算newBuffer需要大小
	/*方法一:SizeOfHEADER + 所有节的SizeOfRawData之和
	int sizeofSections = 0;  
	_IMAGE_SECTION_HEADER* _image_section_header_temp = _image_section_header;
	for(DWORD i = 0;i < _image_file_header->NumberOfSections;i++){
		sizeofSections += _image_section_header_temp->SizeOfRawData;
		_image_section_header_temp++;
	}
	char* newBufferp = (char*)malloc(_image_optional_header->SizeOfHeaders + sizeofSections);
	*/
	
	//方法二:使用最后一个节的文件偏移地址 + 最后一个节对齐后的大小
	DWORD size = compute_NewBuffer_size(imageBufferp);
	char* newBufferp = (char*)malloc(size);
	if(NULL == newBufferp){
        printf("NewBuffer内存分配失败\n");
        exit(0);
    }
	for(DWORD i = 0;i < size;i++){
		*(newBufferp + i) = 0x00;
	}
	
	
	for(i = 0;i < _image_optional_header->SizeOfHeaders;i++){
		*(newBufferp + i) = *(imageBufferp + i);
	}
	
	for(i = 0;i < _image_file_header->NumberOfSections;i++){
		for(DWORD j = 0;j < _image_section_header->SizeOfRawData;j++){ //不用VirtualSize因为害怕会多复制覆盖下一个节
			*(newBufferp + _image_section_header->PointerToRawData + j) = *(imageBufferp + 
				_image_section_header->VirtualAddress + j);
		}
		_image_section_header++;
	}

	return newBufferp;
}	

/*NewBuffer存盘函数
参数:需要写出数据的内存首地址,保存绝对路径,写出的数据大小(单位:字节)
返回值:成功返回1,失败返回0
*/
int save_to_disk(char* newBufferp,char* storagePath,DWORD size){
	FILE* fp = fopen(storagePath,"wb");
	if(!fp){
		printf("打开文件失败");
		return 0;
	}
	int isSucceed = fwrite(newBufferp,size,1,fp);
	if(!isSucceed){
        free(newBufferp);
        fclose(fp);
        return 0;
    }
	fclose(fp);
	return 1;
}

/*虚拟内存偏移地址->文件偏移地址函数
参数:FileBuffer起始地址,RVA地址值
返回值:RVA对应的FOA,返回0则表示非法RVA
*/
DWORD RVA_to_FOA(char* fileBufferp,DWORD RVA){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + 
		_image_file_header->SizeOfOptionalHeader);

	bool flag = 0; //用来判断最终RVA值是否在节中的非空白区
	if(RVA < _image_section_header->VirtualAddress)
		return RVA;
	for(int i = 0;i < _image_file_header->NumberOfSections;i++){
		if(RVA >= _image_section_header->VirtualAddress 
			&& RVA < _image_section_header->VirtualAddress + _image_section_header->Misc.VirtualSize){
			flag = 1;
			break;
		}else{
			_image_section_header++;
		}
	}
	if(!flag)
		return 0;
	DWORD mem_offset_from_section = RVA - _image_section_header->VirtualAddress;
	return _image_section_header->PointerToRawData + mem_offset_from_section;	
}

/*文件偏移地址函数->虚拟内存偏移地址
参数:FileBuffer起始地址,FOA地址值
返回值:FOA对应的RVA,返回0则表示非法FOA
*/
DWORD FOA_to_RVA(char* fileBufferp,DWORD FOA){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + 
		_image_file_header->SizeOfOptionalHeader);

	bool flag = 0;//用来判断最终FOA值是否在节中的非空白区
	if(FOA < _image_section_header->PointerToRawData)
		return FOA;
	for(DWORD i = 0;i < _image_file_header->NumberOfSections;i++){
		DWORD tempSize = (_image_section_header->Misc.VirtualSize < _image_section_header->SizeOfRawData ? _image_section_header->Misc.VirtualSize : _image_section_header->SizeOfRawData);
		if(FOA >= _image_section_header->PointerToRawData && FOA < _image_section_header->PointerToRawData + tempSize){
			flag = 1;
			break;
		}
		_image_section_header++;
	}

	if(!flag)
		return 0;
	DWORD file_offset_from_section = FOA - _image_section_header->PointerToRawData;
	return _image_section_header->VirtualAddress + file_offset_from_section;	
}

/*打印PE头各字段函数
参数:要打印的PE文件绝对路径
返回值:无
*/
void PE_header_print(char* filePath){
	char* fileBufferp = to_FileBuffer(filePath);  //将文件读入内存并返回FileBuffer首地址
	
	//定义各个结构结构体指针,方便查找数据
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_NT_HEADERS* _image_nt_header = NULL;

	//打印DOS头
	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	printf("**********************DOS头**********************\n");
	if(_image_dos_header->e_magic != MZ){
		printf("此文件不满足MZ标记,不再继续分析");
		exit(0);
	}
	printf("e_magic:%04X\n",_image_dos_header->e_magic);  //%04X表示输出格式为宽度为4不够用0补的十六进制
	printf("e_lfanew:%08X\n",_image_dos_header->e_lfanew);

	//打印PE签名
	_image_nt_header = (_IMAGE_NT_HEADERS*)((char*)fileBufferp + _image_dos_header->e_lfanew);
	printf("\n**********************PE签名**********************\n");
	if(_image_nt_header->Signature != PE){
		printf("不是有效的PE标记");
		exit(0);
	}
	printf("Signature:%08X\n",_image_nt_header->Signature);

	//打印标准PE头
	_image_file_header = (_IMAGE_FILE_HEADER*)((char*)_image_nt_header + 4);
	printf("\n**********************标准PE头**********************\n");
	printf("Machine:%04X\n",_image_file_header->Machine);
	printf("NumberOfSections:%04X\n",_image_file_header-> NumberOfSections);
	printf("TimeDateStamp:%08X\n",_image_file_header->TimeDateStamp);
	printf("SizeOfOptionalHeader:%04X\n",_image_file_header->SizeOfOptionalHeader);
	printf("Characteristics:%04X\n",_image_file_header-> Characteristics);

	//打印可选PE头
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_nt_header + 24);
	printf("\n**********************可选PE头**********************\n");
	printf("Magic:%04X\n",_image_optional_header->Magic);
	printf("SizeOfCode:%08X\n",_image_optional_header->SizeOfCode);
	printf("SizeOfInitializedData:%08X\n",_image_optional_header-> SizeOfInitializedData);
	printf("SizeOfUninitializedData:%08X\n",_image_optional_header->SizeOfUninitializedData);
	printf("AddressOfEntryPoint:%08X\n",_image_optional_header->AddressOfEntryPoint);
	printf("BaseOfCode:%08X\n",_image_optional_header-> BaseOfCode);
	printf("BaseOfData:%08X\n",_image_optional_header->BaseOfData);
	printf("ImageBase:%08X\n",_image_optional_header-> ImageBase);
	printf("SectionAlignment:%08X\n",_image_optional_header->SectionAlignment);
	printf("FileAlignment:%08X\n",_image_optional_header->FileAlignment);
	printf("SizeOfImage:%08X\n",_image_optional_header->SizeOfImage);
	printf("SizeOfHeaders:%08X\n",_image_optional_header-> SizeOfHeaders);
	printf("CheckSum:%08X\n",_image_optional_header->CheckSum);
	printf("SizeOfStackReserve:%08X\n",_image_optional_header->SizeOfStackReserve);
	printf("SizeOfStackCommit:%08X\n",_image_optional_header->SizeOfStackCommit);
	printf("SizeOfHeapReserve:%08X\n",_image_optional_header->SizeOfHeapReserve);
	printf("SizeOfHeapCommit:%08X\n",_image_optional_header->SizeOfHeapCommit);

	//别忘了释放分配的内存mp
	free(fileBufferp);
}

/*打印节表各字段函数
参数:要打印的PE文件绝对路径
返回值:无
*/
void section_table_print(char* filePath){
  	char* mp = to_FileBuffer(filePath);
	
  	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)mp;  //指向dos头开始
	_image_file_header = (_IMAGE_FILE_HEADER*)(mp + _image_dos_header->e_lfanew + 4); //指向标准PE头开始地址
	int numberOfSections = _image_file_header->NumberOfSections;  //节的数量
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_file_header + 20 + _image_file_header->SizeOfOptionalHeader);  //指向节表开始位置

	printf("\n**********************节表**********************\n");
	char temp[9] = "";  //初始化一个9字节的char数组,默认初始值为'\0',为了正确输出节名
	for(int i = 0;i < numberOfSections;i++){
		printf("---------节表%d---------\n",i+1);
		char* name = (char*)_image_section_header->Name;
		strncpy(temp,name,IMAGE_SIZEOF_SHORT_NAME);  //strncpy函数是截取指定长度字符串复制
		/*这里也可以自己写
		for(int j = 0;;j++){
			if(_image_section_header->Name[j] != '\0' && j < IMAGE_SIZEOF_SHORT_NAME)
				temp[j] = _image_section_header->Name[j];
			else{
				temp[++j] = '\0';
				break;
			}
		}*/
		printf("Name:%s\n",temp);
		printf("VirtualSize:%08X\n",_image_section_header->Misc.VirtualSize);
		printf("VirtualAddress:%08X\n",_image_section_header->VirtualAddress);
		printf("SizeOfRawData:%08X\n",_image_section_header->SizeOfRawData);
		printf("PointerToRawData:%08X\n",_image_section_header->PointerToRawData);
		printf("Characteristics:%08X\n",_image_section_header->Characteristics);
		_image_section_header = _image_section_header++;
	}
}

/*打印指定PE文件的数据目录函数
参数:指定可执行文件绝对路径
返回值:无
*/
void data_directory_print(char* filePath){
	char* fileBufferp = to_FileBuffer(filePath);
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);

	char* tableNameArr[16] = {
		"IMAGE_DIRECTORY_ENTRY_EXPORT(导出表)",
		"IMAGE_DIRECTORY_ENTRY_IMPORT(导入表)",
		"IMAGE_DIRECTORY_ENTRY_RESOURCE(资源表)",
		"IMAGE_DIRECTORY_ENTRY_EXCEPTION(异常信息表)",
		"IMAGE_DIRECTORY_ENTRY_SECURITY(安全证书表)",
		"IMAGE_DIRECTORY_ENTRY_BASERELOC(重定位表)",
		"IMAGE_DIRECTORY_ENTRY_DEBUG(调试信息表)",
		"IMAGE_DIRECTORY_ENTRY_COPYRIGHT(版权所有表)",
		"IMAGE_DIRECTORY_ENTRY_GLOBALPTR(全局指针表)",
		"IMAGE_DIRECTORY_ENTRY_TLS(TLS表)",
		"IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG(加载配置表)",
		"IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT(绑定导入表)",
		"IMAGE_DIRECTORY_ENTRY_IAT(IAT表)",
		"IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT(延迟导入表)",
		"IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR(COM信息表)",
		"保留"
	  };

	//定位到数据目录结构起始地址
	_IMAGE_DATA_DIRECTORY* _image_data_directory = _image_optional_header->DataDirectory;
	printf("\n**********************数据目录**********************\n");
	for(DWORD i = 0;i < _image_optional_header->NumberOfRvaAndSizes;i++){
		printf("%s\nVirtualSize:%08X  Size:%08X\n\n",tableNameArr[i],_image_data_directory->VirtualAddress,_image_data_directory->Size);
		_image_data_directory++;
	}
}

/*打印导出表函数
参数:指定可执行文件绝对路径
返回值:无
*/
void exportTable_print(char* filePath){
	char* fileBufferp = to_FileBuffer(filePath);
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
	_IMAGE_EXPORT_DIRECTORY* _image_export_directory = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)_image_optional_header->DataDirectory;
	if(_image_data_directory->VirtualAddress == 0){
		printf("此PE文件没有导出表");
		getchar();
		exit(0);
	}

	//打印导出表
	_image_export_directory = (_IMAGE_EXPORT_DIRECTORY*)(RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress) + (DWORD)fileBufferp);
	char* name = (char*)(RVA_to_FOA(fileBufferp,_image_export_directory->Name) + (DWORD)fileBufferp);
	printf("**********************导出表(ExportTable)**********************\n");
	printf("Name:%08X --> %s\n",_image_export_directory->Name,name);
	printf("Base:%08X\n",_image_export_directory->Base);
	printf("NumberOfFunctions:%08X\n",_image_export_directory->NumberOfFunctions);
	printf("NumberOfNames:%08X\n",_image_export_directory->NumberOfNames);
	printf("AddressOfFunctions:%08X\n",_image_export_directory->AddressOfFunctions);
	printf("AddressOfNames:%08X\n",_image_export_directory->AddressOfNames);
	printf("AddressOfNameOrdinals:%08X\n\n",_image_export_directory->AddressOfNameOrdinals);

	//打印函数地址表
	DWORD* functionAddressTable = (DWORD*)(RVA_to_FOA(fileBufferp,_image_export_directory->AddressOfFunctions) + (DWORD)fileBufferp);
	printf("**********************函数地址表(FunctionAddressTable)**********************\n");
	for(DWORD i = 0;i < _image_export_directory->NumberOfFunctions;i++){
		printf("%08X\n",*(functionAddressTable + i));
	}

	//打印函数序号表(别忘了加Base)
	WORD* functionOrdinalsTable = (WORD*)(RVA_to_FOA(fileBufferp,_image_export_directory->AddressOfNameOrdinals) + (DWORD)fileBufferp);
	printf("\n**********************函数序号表(FunctionOrdinalsTable)**********************\n");
	for(i = 0;i < _image_export_directory->NumberOfNames;i++){
		printf("%04X\n",*(functionOrdinalsTable + i) + _image_export_directory->Base);
	}

	//打印函数名称表(别忘了转FOA)
	DWORD* functionNameTable = (DWORD*)(RVA_to_FOA(fileBufferp,_image_export_directory->AddressOfNames) + (DWORD)fileBufferp);
	printf("\n**********************函数名称表(FunctionNameTable)**********************\n");
	for(i = 0;i < _image_export_directory->NumberOfNames;i++){
		printf("%08X --> %s\n",*(functionNameTable + i),(char*)(RVA_to_FOA(fileBufferp,*(functionNameTable + i)) + (DWORD)fileBufferp));
	}
}

/*打印重定位表函数
参数:指定可执行文件绝对路径
返回值:无
*/
void relocationTable_print(char* filePath){
	char* fileBufferp = to_FileBuffer(filePath);

	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
	_IMAGE_BASE_RELOCATION* _image_base_relocation = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	//指向数据目录结构体数组的第6个结构体
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)(_image_optional_header->DataDirectory + 5);

	//判断是否有重定位表
	if(_image_data_directory->VirtualAddress == 0){
		printf("此PE文件没有重定位表");
		getchar();
		exit(0);
	}

	//找到重定位表
	_image_base_relocation = (_IMAGE_BASE_RELOCATION*)(RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress) + fileBufferp);

	//打印重定位表
	printf("\n**********************重定位表**********************\n");
	for(int i = 0;_image_base_relocation->VirtualAddress != 0;i++){
		printf("---------第%d块---------\n",i + 1);
		printf("VirtualAddress:%08X   SizeOfBlock:%08X\n",_image_base_relocation->VirtualAddress,_image_base_relocation->SizeOfBlock);
		printf("类型\tRVA\n");
		for(DWORD j = 0;j < (_image_base_relocation->SizeOfBlock - 8) / 2;j++){
			//这里使用右移12位的方式打印2字节宽度的高4位
			if((*((WORD*)((char*)_image_base_relocation + 8 + j * 2)) >> 12) == 0){
				printf("%d\n",*((WORD*)((char*)_image_base_relocation + 8 + j * 2)) >> 12);
				continue;
			}
			//这里用与运算把高4位变成0后输出2字节宽度的值,即为低12位的值(别忘了还要加VirtualAddress)
			printf("%d\t%08X\n",*((WORD*)((char*)_image_base_relocation + 8 + j * 2)) >> 12,_image_base_relocation->VirtualAddress + (*((WORD*)((BYTE*)_image_base_relocation + 8 + j * 2)) & 0x0FFF));	
		}
		_image_base_relocation = (_IMAGE_BASE_RELOCATION*)((char*)_image_base_relocation + _image_base_relocation->SizeOfBlock);
	}
}

/*打印导入表、INT表、运行前IAT表、函数名称或序号
参数:需要打印的PE文件绝对路径
返回值:无
*/
void importTable_print(char* filePath){
	char* fileBufferp = to_FileBuffer(filePath);

	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
	_IMAGE_IMPORT_DESCRIPTOR* _image_import_descriptor = NULL;
	_IMAGE_THUNK_DATA32* _image_thunk_data32 = NULL;  //指向INT表或IAT表
	_IMAGE_IMPORT_BY_NAME* _image_import_by_name = NULL;  //指向函数名称表


	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)(_image_optional_header->DataDirectory + 1);
	_image_import_descriptor = (_IMAGE_IMPORT_DESCRIPTOR*)(fileBufferp + RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress));

	printf("\n**********************导出表**********************\n");
	while(1){
		//根据导入表结构中是否为全0判断导入表是否结束
		for(int i = 0;i < sizeof(*_image_import_descriptor);i++){
			if(*((char*)_image_import_descriptor + i) != 0){
				break;
			}
		}
		if(i == sizeof(*_image_import_descriptor))
			break;

		//打印导出表
		char* dllName = fileBufferp + RVA_to_FOA(fileBufferp,_image_import_descriptor->Name);
		printf("\nName:%08X--->%s\n",_image_import_descriptor->Name,dllName);
		printf("TimeDateStamp:%08X\n",_image_import_descriptor->TimeDateStamp);
		printf("OriginalFirstThunk:%08X\n",_image_import_descriptor->OriginalFirstThunk);
		printf("FirstThunk:%08X\n",_image_import_descriptor->FirstThunk);

		//打印INT表和函数名
		printf("-----------------INT表-----------------\n");
		if(_image_import_descriptor->OriginalFirstThunk != 0){
			_image_thunk_data32 = (_IMAGE_THUNK_DATA32*)(fileBufferp + RVA_to_FOA(fileBufferp,_image_import_descriptor->OriginalFirstThunk));
			while(*((DWORD*)_image_thunk_data32) != 0){  //直接把INT表中元素当成DWORD来判断即可
				if((_image_thunk_data32->Ordinal & 0x80000000) == 0x80000000){
					printf("(以序号方式导出)序号:%d\n",_image_thunk_data32->Ordinal & 0x7FFFFFFF);
				}else{
					_image_import_by_name = (_IMAGE_IMPORT_BY_NAME*)(fileBufferp + RVA_to_FOA(fileBufferp,_image_thunk_data32->Ordinal));
					printf("(以函数名方式导出)函数名RVA:%08X--->(hint:%04X)%s\n",_image_thunk_data32->Function,_image_import_by_name->Hint,_image_import_by_name->Name);
				}
				_image_thunk_data32++;
			}
		}else{
			printf("无INT表\n");
		}

		//打印运行前的IAT表
		printf("-----------------运行前IAT表-----------------\n");
		_image_thunk_data32 = (_IMAGE_THUNK_DATA32*)(fileBufferp + RVA_to_FOA(fileBufferp,_image_import_descriptor->FirstThunk));
		while(*((DWORD*)_image_thunk_data32) != 0){
			if((_image_thunk_data32->Ordinal & 0x80000000) == 0x80000000){
				printf("(以序号方式导出)序号:%d\n",_image_thunk_data32->Ordinal & 0x7FFFFFFF);
			}else{
				_image_import_by_name = (_IMAGE_IMPORT_BY_NAME*)(fileBufferp + RVA_to_FOA(fileBufferp,_image_thunk_data32->Ordinal));
				printf("(以函数名方式导出)函数名RVA:%08X--->(hint:%04X)%s\n",_image_thunk_data32->Function,_image_import_by_name->Hint,_image_import_by_name->Name);
			}
			_image_thunk_data32++;
		}

		printf("\n");
		//导出表后移一个结构
		_image_import_descriptor++;
	}  //在这里加断点可以方便导出表一个结构一个结构的打印

}

/*打印绑定导入表
参数:需要打印的PE文件绝对路径
返回值:无
*/
void boundImportTable_print(char* filePath){
	char* fileBufferp = to_FileBuffer(filePath);

	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
	_IMAGE_BOUND_IMPORT_DESCRIPTOR* _image_bound_import_descriptor = NULL;
	_IMAGE_BOUND_FORWARDER_REF* _image_bound_forwarder_ref = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)(_image_optional_header->DataDirectory + 11);  //指向绑定导入表数据目录项
	if(_image_data_directory->VirtualAddress == 0){
		printf("此文件没有绑定导入表");
		getchar();
		exit(0);
	}

	_image_bound_import_descriptor = (_IMAGE_BOUND_IMPORT_DESCRIPTOR*)(fileBufferp + RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress));
	DWORD bound_import_table_RVA = (DWORD)_image_data_directory->VirtualAddress; //记录下绑定导入表起始RVA

	//打印绑定导入表
	printf("\n***************绑定导入表***************\n");
	while(1){
		//根据绑定导入表结构中是否为全0判断绑定导入表是否结束
		for(int i = 0;i < sizeof(*_image_bound_import_descriptor);i++){
			if(*((char*)_image_bound_import_descriptor) != 0){
				break;
			}
		}
		if(i == sizeof(*_image_bound_import_descriptor)){
			break;
		}

		printf("OffsetModuleName:%04X--->%s\n",_image_bound_import_descriptor->OffsetModuleName,fileBufferp + RVA_to_FOA(fileBufferp,_image_bound_import_descriptor->OffsetModuleName + bound_import_table_RVA));
		printf("TimeDateStamp:%08X\n",_image_bound_import_descriptor->TimeDateStamp);
		printf("NumberOfModuleForwarderRefs:%04X\n",_image_bound_import_descriptor->NumberOfModuleForwarderRefs);
		
		//打印_IMAGE_BOUND_FORWARDER_REF结构
		if(_image_bound_import_descriptor->NumberOfModuleForwarderRefs != 0){
			printf("-----ModuleForwarders-----\n");
			for(i = 0;(WORD)i < _image_bound_import_descriptor->NumberOfModuleForwarderRefs;i++){
				_image_bound_forwarder_ref = (_IMAGE_BOUND_FORWARDER_REF*)(_image_bound_import_descriptor + 1 + i);	
				printf("OffsetModuleName:%04X--->%s\n",_image_bound_forwarder_ref->OffsetModuleName,fileBufferp + RVA_to_FOA(fileBufferp,_image_bound_forwarder_ref->OffsetModuleName + bound_import_table_RVA));
				printf("TimeDateStamp:%08X\n",_image_bound_forwarder_ref->TimeDateStamp);
				printf("Reserved(未使用):%04X\n\n",_image_bound_forwarder_ref->Reserved);
			}
		}
		
		printf("\n");
		_image_bound_import_descriptor = (_IMAGE_BOUND_IMPORT_DESCRIPTOR*)(_image_bound_import_descriptor + 1 + _image_bound_import_descriptor->NumberOfModuleForwarderRefs);
	}
	
}

/*向第一个节.text中注入shellcode函数(在ImageBuffer中)
参数:要注入的可执行文件的ImageBuffer起始地址
返回值:0则注入失败,1则注入成功
*/
int add_shellcode(char* imageBufferp){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;
	_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;

	_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//用SizeofRawData - VirtualSize判断空白区是否存的下shellcode:这里要考虑到一个问题:我们使用的是secp->VirtualAddress + secp->Misc.VirtualSize来确定内存中此节的空白区的偏移起始地址,这个算法是没错的,但是还记得前面将FileBuffer装载到ImageBuffer时我们复制每个节的长度是按照SizeOfRawData复制的,而且ImageBuffer到NewBuffer也是每个节按照SizeOfRawData复制的。那么如果某一个节的VirtualSize>SizeOfRawData,就会出现我们添加代码的地方确实在节装入内存时的空白区,但是最后ImageBuffer到NewBuffer时,复制的时候只复制了这个节开始的SizeOfRawData个字节,我们加的代码并没有复制进去,就可能出现问题,所以干脆直接要求SizeOfRawData > VirtualSize才能注入
	if((int)(_image_section_header->SizeOfRawData - _image_section_header->Misc.VirtualSize) < sizeof(shellcode) / sizeof(shellcode[0])){
		printf("此节空白区大小不够,添加失败");
		return 0;
	}

	//将shellcode注入到节空白区
	char* shellcodep = imageBufferp + _image_section_header->VirtualAddress + _image_section_header->Misc.VirtualSize;
	char* newOEP = shellcodep;  //此shellcode注入起始地址即为新的OEP地址
	memcpy(shellcodep,shellcode,sizeof(shellcode) / sizeof(shellcode[0])); //注意memcpy函数不改变传入的指针的值!!

	//修改call MessageBox的硬编码E8后面的4字节
	DWORD E8_fill_value = MessageBox_Address - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0xD);
	*(DWORD*)(shellcodep + 9) = E8_fill_value;

	//修改jmp 原OEP的硬编码E9后面的4字节
	DWORD E9_fill_value = _image_optional_header->AddressOfEntryPoint + _image_optional_header->ImageBase - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0x12);
	*(DWORD*)(shellcodep + 14) = E9_fill_value;

	//修改OEP指向shellcode
	_image_optional_header->AddressOfEntryPoint = (DWORD)(newOEP - imageBufferp);
	
	return 1;
}

/*向任意节的空白区中注入shellcode函数(在ImageBuffer中)
参数:要注入的可执行文件的ImageBuffer起始地址,要注入第几个节
返回值:0为注入失败、1为注入成功
*/
int add_shellcode_to_specific_section(char* imageBufferp,int section_num){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//判断输入的节是否合法,并定位到指定节的节表起始地址
	if(section_num <= 0 || section_num > _image_file_header->NumberOfSections){
		printf("输入的节不存在");
		return 0;
	}
	_IMAGE_SECTION_HEADER* target_image_section_header = _image_section_header + section_num - 1;

	//用SizeofRawData - VirtualSize判断空白区是否存的下shellcode(当SizeofRawData < VirtualSize时,这种特殊情况,我们就当做空白区大小不够处理)
	if((int)(target_image_section_header->SizeOfRawData - target_image_section_header->Misc.VirtualSize) < (int)(sizeof(shellcode) / sizeof(shellcode[0]))){
		printf("此节空白区大小不够,添加失败");
		return 0;
	}

	//将shellcode注入到节空白区
	char* shellcodep = imageBufferp + target_image_section_header->VirtualAddress + target_image_section_header->Misc.VirtualSize;
	char* newOEP = shellcodep;  //此shellcode注入起始地址即为新的OEP地址
	memcpy(shellcodep,shellcode,sizeof(shellcode) / sizeof(shellcode[0])); //注意memcpy函数不改变传入的指针的值!!

	//修改call MessageBox的硬编码E8后面的4字节
	DWORD E8_fill_value = MessageBox_Address - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0xD);
	*(DWORD*)(shellcodep + 9) = E8_fill_value;

	//修改jmp 原OEP的硬编码E9后面的4字节
	DWORD E9_fill_value = _image_optional_header->AddressOfEntryPoint + _image_optional_header->ImageBase - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0x12);
	*(DWORD*)(shellcodep + 14) = E9_fill_value;

	//修改OEP指向shellcode
	_image_optional_header->AddressOfEntryPoint = (DWORD)(newOEP - imageBufferp);

	//修改该节的特征值使之可读、可写、可执行
	target_image_section_header->Characteristics = target_image_section_header->Characteristics | 0x60000020;

	return 1;
}

/*向新增节中注入shellcode函数(在ImageBuffer中)
参数:要注入的可执行文件的ImageBuffer起始地址
返回值:0为注入失败、1为注入成功
*/
int add_shellcode_to_new_section(char* imageBufferp){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//定位到新节表起始地址
	_IMAGE_SECTION_HEADER* target_image_section_header = _image_section_header + _image_file_header->NumberOfSections - 1;

	//判断新节是否存的下shellcode
	if((int)(target_image_section_header->Misc.VirtualSize) < (int)(sizeof(shellcode) / sizeof(shellcode[0]))){
		printf("新节大小不够,添加失败");
		return 0;
	}

	//将shellcode注入到新节
	char* shellcodep = imageBufferp + target_image_section_header->VirtualAddress;
	char* newOEP = shellcodep;  //此shellcode注入起始地址即为新的OEP地址
	memcpy(shellcodep,shellcode,sizeof(shellcode) / sizeof(shellcode[0])); //注意memcpy函数不改变传入的指针的值!!

	//修改call MessageBox的硬编码E8后面的4字节
	DWORD E8_fill_value = MessageBox_Address - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0xD);
	*(DWORD*)(shellcodep + 9) = E8_fill_value;

	//修改jmp 原OEP的硬编码E9后面的4字节
	DWORD E9_fill_value = _image_optional_header->AddressOfEntryPoint + _image_optional_header->ImageBase - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0x12);
	*(DWORD*)(shellcodep + 14) = E9_fill_value;

	//修改OEP指向shellcode
	_image_optional_header->AddressOfEntryPoint = (DWORD)(newOEP - imageBufferp);

	return 1;
}

/*计算最小公倍数函数
参数:传入要计算的两个数
返回值:两数的最小公倍数
*/
int least_common_multiple(int a,int b){
	if(a <= 0 || b <= 0)
  		return -1;
	int max = (a > b ? a : b);
	  while(1){
		  if(max % a == 0 && max % b == 0){
			  break;
		  }
		  max++;
	  }
	return max;
}

/*在文件最后新增节函数(在ImageBuffer中)
参数:要新增节的可执行文件的ImageBuffer起始地址
返回值:新增节后的NewImageBuffer内存的起始地址
*/
char* add_one_section(char* imageBufferp){
  	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	//定义原来的ImageBuffer几个指针(因为要用到几个值用于创建新的NewImageBuffer内存)
	_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);

	//先计算添加新节后的NewImageBuffer的大小,并初始化内存
	int expand_value = least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment);//这里为了方便直接把新节大小设为文件对齐粒度和内存对齐粒度的最小公倍数即可
	char* newImageBufferp = (char*)malloc(_image_optional_header->SizeOfImage + expand_value);
	for(int i = 0;i < (int)_image_optional_header->SizeOfImage + expand_value;i++){
		*(newImageBufferp + i) = 0x00;
	}
	memcpy(newImageBufferp,imageBufferp,_image_optional_header->SizeOfImage);//不改变指针哦
	_image_dos_header = (_IMAGE_DOS_HEADER*)newImageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(newImageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//判断节表末尾是否有空间新增节表
	if(_image_optional_header->SizeOfHeaders - _image_dos_header->e_lfanew - 4 - 20 - _image_file_header->SizeOfOptionalHeader - 
		_image_file_header->NumberOfSections * 40 < 80){
		printf("空间不足,无法新增节表");
		getchar();
		exit(0);
	}
	for(i = 0;i < 80;i++){
		if(*((char*)(_image_section_header + _image_file_header->NumberOfSections)+ i) != 0){
			printf("节表后80字节数据不全为0x00,有文件数据,无法新增节表");
			getchar();
			exit(0);
		}
	}

	//新增节
	DWORD original_SizeOfImage = _image_optional_header->SizeOfImage; //记录下原来的SizeOfImage
	_image_optional_header->SizeOfImage += expand_value;

	//新增节表
	_IMAGE_SECTION_HEADER* _image_section_header_new = (_IMAGE_SECTION_HEADER*)(char*)_image_section_header + _image_file_header->NumberOfSections;
	for(i = 0;i < 40;i++){
		*((char*)_image_section_header_new + i) = *((char*)_image_section_header + i);
	}
	_image_file_header->NumberOfSections++;

	//修改新增节表信息
	char* name = (char*)_image_section_header_new->Name;
	char* newName = ".newsec";
	strncpy(name,newName,IMAGE_SIZEOF_SHORT_NAME);
	_image_section_header_new->Misc.VirtualSize = expand_value;
	_image_section_header_new->VirtualAddress = original_SizeOfImage;
	_image_section_header_new->SizeOfRawData = expand_value;
	_image_section_header_new->PointerToRawData = (_image_section_header_new - 1)->PointerToRawData + (_image_section_header_new - 1)->SizeOfRawData;
	_image_section_header_new->Characteristics = 0x60000020;

	return newImageBufferp;
}

/*扩大最后一个节函数(在ImageBuffer中)
参数:要扩大节的可执行文件的ImageBuffer起始地址
返回值:扩大节后的NewImageBuffer内存的起始地址
*/
char* expand_last_section(char* imageBufferp){
  	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);

	//计算扩大多少,并初始化NewImageBuffer
	int expand_value = least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment);//这里为了方便直接把需要扩大的大小设为文件对齐粒度和内存对齐粒度的最小公倍数即可
	char* newImageBufferp = (char*)malloc(_image_optional_header->SizeOfImage + expand_value);
	for(int i = 0;i < (int)_image_optional_header->SizeOfImage + expand_value;i++){
		*(newImageBufferp + i) = 0x00;
	}
	memcpy(newImageBufferp,imageBufferp,_image_optional_header->SizeOfImage);//不改变指针哦
	_image_dos_header = (_IMAGE_DOS_HEADER*)newImageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(newImageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//修改SizeofImage:原来的SizeOfImage + Ex(因为原来的SizeOfImage是内存对齐的整数倍,Ex也是通过内存对齐和文件对齐的最小公倍数算出来的,所以相加一定还是内存对齐的整数倍)
	DWORD original_SizeOfImage = _image_optional_header->SizeOfImage; //记录下原来的SizeOfImage
	_image_optional_header->SizeOfImage += expand_value;

	//修改节表信息
	_IMAGE_SECTION_HEADER* _image_section_header_last = _image_section_header + _image_file_header->NumberOfSections - 1;
	_image_section_header_last->Misc.VirtualSize = original_SizeOfImage - _image_section_header_last->VirtualAddress + expand_value;
	_image_section_header_last->SizeOfRawData = _image_section_header_last->Misc.VirtualSize;

	//修改节属性,保证可执行
	_image_section_header_last->Characteristics = _image_section_header_last->Characteristics | 0x60000020;
	
	return newImageBufferp;
}

/*向扩大的节中注入shellcode函数(在ImageBuffer中)
参数:要注入的可执行文件的ImageBuffer起始地址
返回值:0表示注入失败,1表示注入成功
*/
int add_shellcode_to_expanded_section(char* imageBufferp){
  	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//判断是否存的下shellcode,这里直接在Ex区域内注入,不考虑原来的空白区
	if((int)(least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment)) < (int)(sizeof(shellcode) / sizeof(shellcode[0]))){
		printf("新节大小不够,添加失败");
		return 0;
	}

	//将shellcode注入到Ex
	char* shellcodep = imageBufferp + _image_optional_header->SizeOfImage - least_common_multiple(_image_optional_header->FileAlignment,_image_optional_header->SectionAlignment);
	char* newOEP = shellcodep;  //此shellcode注入起始地址即为新的OEP地址
	memcpy(shellcodep,shellcode,sizeof(shellcode) / sizeof(shellcode[0])); //注意memcpy函数不改变传入的指针的值!!

	//修改call MessageBox的硬编码E8后面的4字节
	DWORD E8_fill_value = MessageBox_Address - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0xD);
	*(DWORD*)(shellcodep + 9) = E8_fill_value;

	//修改jmp 原OEP的硬编码E9后面的4字节
	DWORD E9_fill_value = _image_optional_header->AddressOfEntryPoint + _image_optional_header->ImageBase - ((shellcodep - imageBufferp + _image_optional_header->ImageBase) + 0x12);
	*(DWORD*)(shellcodep + 14) = E9_fill_value;

	//修改OEP指向shellcode
	_image_optional_header->AddressOfEntryPoint = (DWORD)(newOEP - imageBufferp);

	return 1;
}

/*合并节函数(在ImageBuffer中)
参数:需要合并节的可执行文件ImageBuffer起始地址
返回值:合并后的ImageBuffer起始地址(因为合并节后并不改变ImageBuffer内存大小,所以返回void也行)
*/
char* merge_section(char* imageBufferp){
  	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)imageBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(imageBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//修改合并节的节表字段
	_image_section_header->Misc.VirtualSize = _image_optional_header->SizeOfImage - _image_section_header->VirtualAddress;
	_image_section_header->SizeOfRawData = _image_section_header->Misc.VirtualSize;
	for(int i = 1;i < _image_file_header->NumberOfSections;i++){
		_image_section_header->Characteristics = _image_section_header->Characteristics | (_image_section_header + i)->Characteristics;
	}

	/*前面提到过节表末尾应该跟40个0x00,但是如果修改了,文件就打不开了?不知道原因是啥
	for(i = 0;i < 40 * _image_file_header->NumberOfSections;i++){
		*((char*)(_image_section_header + 1) + i) = 0x00;
	}*/

	//修改NumberOfSections字段
	_image_file_header->NumberOfSections = 1;

	return imageBufferp;
}

/*按名字查找导出函数地址
参数:PE文件的FileBuffer起始地址,函数名字符串指针
返回值:该导出函数的RVA(如果想返回FOA也可以,代码都在下面)
*/
DWORD GetFunctionAddrByName(char* fileBufferp,char* funcName){
  	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
  	_IMAGE_EXPORT_DIRECTORY* _image_export_directory = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)_image_optional_header->DataDirectory;
	if(_image_data_directory->VirtualAddress == 0){
		printf("此PE文件没有导出表,没有函数导出");
		getchar();
		exit(0);
	}
	_image_export_directory = (_IMAGE_EXPORT_DIRECTORY*)(RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress) + (DWORD)fileBufferp);

	//先遍历函数名称表
	DWORD* functionNameTable = (DWORD*)(RVA_to_FOA(fileBufferp,_image_export_directory->AddressOfNames) + (DWORD)fileBufferp);
	bool flag = 0;
	for(DWORD index = 0;index < _image_export_directory->NumberOfNames;index++){
		char* nameTemp = (char*)(RVA_to_FOA(fileBufferp,*functionNameTable) + (DWORD)fileBufferp);
		if(strcmp(nameTemp,funcName) == 0){  //小贴士:strcmp执行完,参数值并不改变
			flag = 1;
			break;
		}
		functionNameTable++;
	}
	if(!flag){
		printf("没有此导出函数");
		getchar();
		exit(0); 
	}

	//再找函数序号表对应下标index中的值funcIndex
	WORD* functionOrdinalsTable = (WORD*)(RVA_to_FOA(fileBufferp,_image_export_directory->AddressOfNameOrdinals) + (DWORD)fileBufferp);
	WORD funcIndex = *(functionOrdinalsTable + index);

	//最后找函数地址表下标为funcIndex中的值
	DWORD* functionAddressTable = (DWORD*)(RVA_to_FOA(fileBufferp,_image_export_directory->AddressOfFunctions) + (DWORD)fileBufferp);

	//返回该导出函数RVA
	return *(functionAddressTable + funcIndex);
	//return RVA_to_FOA(fileBufferp,*(functionAddressTable + funcIndex));
}

/*按序号查找导出函数地址信息函数
参数:PE文件的FileBuffer起始地址,函数名字符串指针
返回值:该导出函数的RVA(如果想返回FOA也可以,代码都在下面)
*/
DWORD GetFunctionAddrByOrdinals(char* fileBufferp,DWORD ordinal){
  	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
  	_IMAGE_EXPORT_DIRECTORY* _image_export_directory = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)_image_optional_header->DataDirectory;
	if(_image_data_directory->VirtualAddress == 0){
		printf("此PE文件没有导出表,没有函数导出");
		getchar();
		exit(0);
	}
	_image_export_directory = (_IMAGE_EXPORT_DIRECTORY*)(RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress) + (DWORD)fileBufferp);

	//判断导出序号是否在范围内
	if(ordinal - _image_export_directory->Base > _image_export_directory->NumberOfFunctions - 1){  //因为ordinal用的WORD类型,所以<0的情况不用考虑
		printf("导出序号不合法");
		getchar();
		exit(0);
	}

	//定位到函数地址表起始地址
	DWORD* functionAddressTable = (DWORD*)(RVA_to_FOA(fileBufferp,_image_export_directory->AddressOfFunctions) + (DWORD)fileBufferp);

	//返回该序号导出函数的RVA
	return *(functionAddressTable + (ordinal - _image_export_directory->Base));
	//return RVA_to_FOA(fileBufferp,*(functionAddressTable + (ordinal - _image_export_directory->Base)));
}

/*在文件最后新增节函数(直接在FileBuffer中操作)
参数:要新增节的可执行文件的FileBuffer起始地址
返回值:新增节后的NewFileBuffer内存的起始地址
*/
char* add_one_section_inFileBuffer(char* fileBufferp){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

    //定义原来的FileBuffer几个指针(因为要用到几个值用于创建新的NewFileBuffer内存)
	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + 
		_image_file_header->SizeOfOptionalHeader);

	//先计算添加新节后的NewFileBuffer的大小,并初始化内存
	DWORD expand_value = 0x1000; //这里0x1000字节足够了,要视情况而定
	DWORD fileBufferSize = (_image_section_header + _image_file_header->NumberOfSections - 1)->PointerToRawData + (_image_section_header + _image_file_header->NumberOfSections - 1)->SizeOfRawData;
	char* newFileBufferp = (char*)malloc(fileBufferSize + expand_value);
	for(DWORD i = 0;i < fileBufferSize + expand_value;i++){
		*(newFileBufferp + i) = 0x00;
	}
	memcpy(newFileBufferp,fileBufferp,fileBufferSize);//不改变指针哦
	_image_dos_header = (_IMAGE_DOS_HEADER*)newFileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(newFileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//判断节表末尾是否有空间新增节表
	if(_image_optional_header->SizeOfHeaders - _image_dos_header->e_lfanew - 4 - 20 - _image_file_header->SizeOfOptionalHeader - 
		_image_file_header->NumberOfSections * 40 < 80){
		printf("空间不足,无法新增节表");
		getchar();
		exit(0);
	}
	for(i = 0;i < 80;i++){
		if(*((char*)(_image_section_header + _image_file_header->NumberOfSections)+ i) != 0){
			printf("节表后80字节数据不全为0x00,有文件数据,无法新增节表");
			getchar();
			exit(0);
		}
	}
	
	//新增节
	DWORD original_SizeOfImage = _image_optional_header->SizeOfImage; //记录下原来的SizeOfImage
	_image_optional_header->SizeOfImage += expand_value;

	//新增节表
	_IMAGE_SECTION_HEADER* _image_section_header_new = (_IMAGE_SECTION_HEADER*)(char*)_image_section_header + _image_file_header->NumberOfSections;
	for(i = 0;i < 40;i++){
		*((char*)_image_section_header_new + i) = *((char*)_image_section_header + i);
	}
	_image_file_header->NumberOfSections++;

	//修改新增节表信息
	char* name = (char*)_image_section_header_new->Name;
	char* newName = ".newsec";
	strncpy(name,newName,IMAGE_SIZEOF_SHORT_NAME);
	_image_section_header_new->Misc.VirtualSize = expand_value;
	_image_section_header_new->VirtualAddress = original_SizeOfImage;
	_image_section_header_new->SizeOfRawData = expand_value;
	_image_section_header_new->PointerToRawData = fileBufferSize;
	//修改节属性,保证可执行,这里最保险的办法就是把每个节的属性全包括(这里的错误找了好久!!前面学习过程中都是满足可读可执行就可以了,即0x60000020,但这里不行!必须把所有节的属性都包含,0xC0000040才行)
	for(i = 0,_image_section_header_new->Characteristics = 0x00000000;i < _image_file_header->NumberOfSections;i++){
		_image_section_header_new->Characteristics = _image_section_header_new->Characteristics | (_image_section_header + i)->Characteristics;
	}

	return newFileBufferp;
}

/*扩大最后一个节函数(直接在FileBuffer中操作)
参数:要扩大节的可执行文件的FileBuffer起始地址
返回值:扩大节后的NewFileBuffer内存的起始地址
*/
char* expand_last_section_inFileBuffer(char* fileBufferp){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);

	//计算扩大多少,并初始化NewFileBuffer
	int expand_value = 0x1000;//这里为了方便直接把需要扩大的大小设为文件对齐粒度和内存对齐粒度的最小公倍数即可,如果不够再改
	char* newFileBufferp = (char*)malloc(_image_optional_header->SizeOfImage + expand_value);
	for(int i = 0;i < (int)_image_optional_header->SizeOfImage + expand_value;i++){
		*(newFileBufferp + i) = 0x00;
	}
	memcpy(newFileBufferp,fileBufferp,_image_optional_header->SizeOfImage);//不改变指针哦
	_image_dos_header = (_IMAGE_DOS_HEADER*)newFileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(newFileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);

	//修改SizeofImage:原来的SizeOfImage + Ex(因为原来的SizeOfImage是内存对齐的整数倍,Ex也是通过内存对齐和文件对齐的最小公倍数算出来的,所以相加一定还是内存对齐的整数倍)
	DWORD original_SizeOfImage = _image_optional_header->SizeOfImage; //记录下原来的SizeOfImage
	_image_optional_header->SizeOfImage += expand_value;

	//修改节表信息
	_IMAGE_SECTION_HEADER* _image_section_header_last = _image_section_header + _image_file_header->NumberOfSections - 1;
	_image_section_header_last->Misc.VirtualSize = original_SizeOfImage - _image_section_header_last->VirtualAddress + expand_value;
	_image_section_header_last->SizeOfRawData = _image_section_header_last->Misc.VirtualSize;

	//修改节属性,保证可执行,这里最保险的办法就是把每个节的属性全包括(这里的错误找了好久!!前面学习过程中都是满足可读可执行就可以了,即0x60000020,但这里不行!必须把所有节的属性都包含,0xC0000040才行)
	for(i = 0;i < _image_file_header->NumberOfSections - 1;i++){
		_image_section_header_last->Characteristics = _image_section_header_last->Characteristics | (_image_section_header + i)->Characteristics;
	}

	return newFileBufferp;
}

/*将PE文件导出表移到新增节中函数
参数:PE文件的FileBuffer首地址
返回值:新增节并且移动导出表后的NewFileBuffer首地址
*/
char* move_ExportTable(char* fileBufferp){
	//新增节
  	char* newFileBufferp = add_one_section_inFileBuffer(fileBufferp);
	
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;
	_IMAGE_EXPORT_DIRECTORY* _image_export_directory = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)newFileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(newFileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)_image_optional_header->DataDirectory;
	if(_image_data_directory->VirtualAddress == 0){
		printf("此PE文件没有导出表");
		getchar();
		exit(0);
	}
	_image_export_directory = (_IMAGE_EXPORT_DIRECTORY*)(RVA_to_FOA(newFileBufferp,_image_data_directory->VirtualAddress) + newFileBufferp);

	//复制函数地址表到新节中
	char* functionAddressTablep = RVA_to_FOA(newFileBufferp,_image_export_directory->AddressOfFunctions) + newFileBufferp;
	char* newSectionp = (_image_section_header + _image_file_header->NumberOfSections - 1)->PointerToRawData + newFileBufferp;  //newSectionp指向:向新节中复制的位置
	char* funcAddressTable_in_newSectionp = newSectionp;//把函数地址表在新节中的首地址记下来,后面要用
	memcpy(newSectionp,functionAddressTablep,_image_export_directory->NumberOfFunctions * 4);

	//复制函数序号表到新节中
	char* functionOrdinalTablep = RVA_to_FOA(newFileBufferp,_image_export_directory->AddressOfNameOrdinals) + newFileBufferp;
	newSectionp += _image_export_directory->NumberOfFunctions * 4;
	char* funcOrdinalTable_in_newSectionp = newSectionp;//把函数序号表在新节中的首地址记下来,后面要用
	memcpy(newSectionp,functionOrdinalTablep,_image_export_directory->NumberOfNames * 2);

	//复制函数名称表到新节中
	char* functionNameTablep = RVA_to_FOA(newFileBufferp,_image_export_directory->AddressOfNames) + newFileBufferp;
	newSectionp += _image_export_directory->NumberOfNames * 2;
	char* funcNameTable_in_newSectionp = newSectionp;//把函数名称表在新节中的首地址记下来,后面要用
	memcpy(newSectionp,functionNameTablep,_image_export_directory->NumberOfNames * 4);

	//复制函数名称字符串到新节中,每复制一个就修改函数名称表中的对应地址值RVA
	newSectionp += _image_export_directory->NumberOfNames * 4;
	DWORD* funcNameTable_in_newSectionp_temp = (DWORD*)funcNameTable_in_newSectionp;//用于修改新节中的函数名称表中地址值
	for(DWORD i = 0;i < _image_export_directory->NumberOfNames;i++){
		char* nameStr = (char*)(RVA_to_FOA(newFileBufferp,*(DWORD*)functionNameTablep) + newFileBufferp);
		memcpy(newSectionp,nameStr,strlen(nameStr) + 1);//字符串结尾的\0别忘了复制
		*funcNameTable_in_newSectionp_temp = FOA_to_RVA(newFileBufferp,(DWORD)(newSectionp - newFileBufferp));//修改对应的函数名称表中的地址值
		newSectionp += (strlen(nameStr) + 1);
		functionNameTablep = (char*)((DWORD*)functionNameTablep + 1);
		funcNameTable_in_newSectionp_temp++;
	}

	//复制导出表到新节中
	memcpy(newSectionp,(char*)_image_export_directory,40);

	//修正新节中导出表的成员值
	((_IMAGE_EXPORT_DIRECTORY*)newSectionp)->AddressOfFunctions = FOA_to_RVA(newFileBufferp,(DWORD)(funcAddressTable_in_newSectionp - newFileBufferp));
	((_IMAGE_EXPORT_DIRECTORY*)newSectionp)->AddressOfNameOrdinals = FOA_to_RVA(newFileBufferp,(DWORD)(funcOrdinalTable_in_newSectionp - newFileBufferp));
	((_IMAGE_EXPORT_DIRECTORY*)newSectionp)->AddressOfNames = FOA_to_RVA(newFileBufferp,(DWORD)(funcNameTable_in_newSectionp - newFileBufferp));

	//修正导出表数据目录中的成员
	_image_data_directory->VirtualAddress = FOA_to_RVA(newFileBufferp,(DWORD)(newSectionp - newFileBufferp));

	return newFileBufferp;
}

/*将PE文件重定位表移到新增节中函数
参数:PE文件的FileBuffer首地址
返回值:新增节并且移动重定位表后的NewFileBuffer首地址
*/
char* move_RelocationTable(char* fileBufferp){
	//新增节
  	char* newFileBufferp = add_one_section_inFileBuffer(fileBufferp);

	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header = NULL;
	_IMAGE_BASE_RELOCATION* _image_base_relocation = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)newFileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(newFileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_section_header = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header + _image_file_header->SizeOfOptionalHeader);
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)(_image_optional_header->DataDirectory + 5);
	if(_image_data_directory->VirtualAddress == 0){
		printf("此PE文件没有重定位表");
		getchar();
		exit(0);
	}
	_image_base_relocation = (_IMAGE_BASE_RELOCATION*)(RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress) + newFileBufferp);

	//复制重定位表到新节中
	_IMAGE_BASE_RELOCATION* _image_base_relocation_temp = _image_base_relocation;
	char* newSectionp = (_image_section_header + _image_file_header->NumberOfSections - 1)->PointerToRawData + newFileBufferp;  //newSectionp指向:向新节中复制的位置
	int size = 0; //计算重定位表的大小
	for(int num = 0;_image_base_relocation_temp->VirtualAddress != 0;num++){
		size += _image_base_relocation_temp->SizeOfBlock;
		_image_base_relocation_temp = (_IMAGE_BASE_RELOCATION*)((char*)_image_base_relocation_temp + _image_base_relocation_temp->SizeOfBlock);
	}
	size += 8; //还要加上重定位表结束标记的8字节
	memcpy(newSectionp,(char*)_image_base_relocation,size);

	//修正重定位表数据目录的成员
	_image_data_directory->VirtualAddress = FOA_to_RVA(newFileBufferp,newSectionp - newFileBufferp);

	return newFileBufferp;
}

/*修改ImageBase后修复重定位表函数
参数:要修复重定位表的PE文件的FileBuffer
返回值:无
*/
void repair_RelocationTable(char* fileBufferp){
  	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
  	_IMAGE_FILE_HEADER* _image_file_header = NULL;
  	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
  	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
  	_IMAGE_BASE_RELOCATION* _image_base_relocation = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	//指向数据目录结构体数组的第6个结构体
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)(_image_optional_header->DataDirectory + 5);
	//判断是否有重定位表
	if(_image_data_directory->VirtualAddress == 0){
		printf("此PE文件没有重定位表");
		getchar();
		exit(0);
	}
	//找到重定位表
	_image_base_relocation = (_IMAGE_BASE_RELOCATION*)(RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress) + fileBufferp);

	//手动修改ImageBase(这里可以先查一下原ImageBase(0x20000000)是多少,方便修改)
	DWORD original_ImageBase = _image_optional_header->ImageBase;
	_image_optional_header->ImageBase = 0x30000000;
	int offset = (int)(_image_optional_header->ImageBase - original_ImageBase);//现ImageBase比原ImageBase可能大也可能小,所以设置为有符号整型类型

	//根据重定位表中每个块的具体项去修复
	while(_image_base_relocation->VirtualAddress != 0){
		for(DWORD j = 0;j < (_image_base_relocation->SizeOfBlock - 8) / 2;j++){
			//这里使用右移12位的方式2字节宽度的高4位
			if((*((WORD*)((char*)_image_base_relocation + 8 + j * 2)) >> 12) == 0){
				continue;
			}
			//这里用与运算把高4位变成0后输出2字节宽度的值,即为低12位的值(别忘了还要加该块VirtualAddress)
			DWORD* repairAddress = (DWORD*)(fileBufferp + RVA_to_FOA(fileBufferp,_image_base_relocation->VirtualAddress + (*((WORD*)((BYTE*)_image_base_relocation + 8 + j * 2)) & 0x0FFF)));
			*repairAddress += offset;
		}
		_image_base_relocation = (_IMAGE_BASE_RELOCATION*)((char*)_image_base_relocation + _image_base_relocation->SizeOfBlock);
	}
}

/*导入表注入函数
参数:需要注入的程序FileBuffer起始地址,要注入的DLL名字,要使用到的DLL函数名
返回值:返回注入后的NewFileBuffer起始地址
*/
char* importTable_injectDll(char* fileBufferp,char* dllName,char* API){
	_IMAGE_DOS_HEADER* _image_dos_header = NULL;
	_IMAGE_FILE_HEADER* _image_file_header = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header = NULL;
	_IMAGE_DATA_DIRECTORY* _image_data_directory = NULL;
	_IMAGE_IMPORT_DESCRIPTOR* _image_import_descriptor = NULL;

	_image_dos_header = (_IMAGE_DOS_HEADER*)fileBufferp;
	_image_file_header = (_IMAGE_FILE_HEADER*)(fileBufferp + _image_dos_header->e_lfanew + 4);
	_image_optional_header = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header + 20);
	_image_data_directory = (_IMAGE_DATA_DIRECTORY*)(_image_optional_header->DataDirectory + 1); //导入表数据目录
    if(_image_data_directory->VirtualAddress == 0){
        printf("此文件没有导入表");
        getchar();
        exit(0);
    }
	_image_import_descriptor = (_IMAGE_IMPORT_DESCRIPTOR*)(fileBufferp + RVA_to_FOA(fileBufferp,_image_data_directory->VirtualAddress));
	
	//先选择把导入表移动到新增节的方式,如果无法新增节,就选择扩大节再移动的方式
	char* newFileBufferp = add_one_section_inFileBuffer(fileBufferp); //新增节(0x1000)
	if(newFileBufferp == 0){
		printf("程序无法新增节,采用扩大最后一个节的方式\n");
		newFileBufferp = expand_last_section_inFileBuffer(fileBufferp);  //如果程序没法新增节,就选择扩大最后一个节,并将导入表移动到最后一个节
		if(newFileBufferp == 0){
			printf("注入失败\n");
			getchar();
			exit(0);
		}
	}
	_IMAGE_DOS_HEADER* _image_dos_header_new = NULL;
	_IMAGE_FILE_HEADER* _image_file_header_new = NULL;
	_IMAGE_OPTIONAL_HEADER* _image_optional_header_new = NULL;
	_IMAGE_SECTION_HEADER* _image_section_header_new = NULL;
	_IMAGE_DATA_DIRECTORY* _image_data_directory_new = NULL;
	_IMAGE_IMPORT_DESCRIPTOR* _image_import_descriptor_new = NULL;
	_IMAGE_THUNK_DATA32* _INT_new = NULL;  //INT表
	_IMAGE_THUNK_DATA32* _IAT_new = NULL;  //IAT表
	_IMAGE_IMPORT_BY_NAME* _image_import_by_name_new = NULL;  //函数名称表


	_image_dos_header_new = (_IMAGE_DOS_HEADER*)newFileBufferp;
	_image_file_header_new = (_IMAGE_FILE_HEADER*)(newFileBufferp + _image_dos_header_new->e_lfanew + 4);
	_image_optional_header_new = (_IMAGE_OPTIONAL_HEADER*)((char*)_image_file_header_new + 20);
	_image_section_header_new = (_IMAGE_SECTION_HEADER*)((char*)_image_optional_header_new + _image_file_header_new->SizeOfOptionalHeader);
	_image_data_directory_new = (_IMAGE_DATA_DIRECTORY*)(_image_optional_header_new->DataDirectory + 1); //导入表数据目录
	_image_import_descriptor_new = (_IMAGE_IMPORT_DESCRIPTOR*)(newFileBufferp + RVA_to_FOA(newFileBufferp,_image_data_directory_new->VirtualAddress));

	//由于新增节大小为0x1000,且扩大最后一个节大小也为0x1000,所以无论哪一种方法都可以从NewFileBuffer倒数第0x1000的位置开始存储
	char* moveStartp = newFileBufferp + compute_NewBuffer_size(newFileBufferp) - 0x1000;
	//char* moveStartp = newFileBufferp + (_image_section_header_new + _image_file_header_new->NumberOfSections - 1)->PointerToRawData; //如果是新增节,在新增节起始地址开始复制即可
	DWORD moveStartAddress = (DWORD)moveStartp; //记录一下存储起始地址,后面计算VirtualAddress要用到
	
	//移动导入表
	while(1){
		//根据导入表结构中是否为全0判断导入表是否结束
		for(int i = 0;i < sizeof(*_image_import_descriptor_new);i++){
			if(*((char*)_image_import_descriptor_new + i) != 0){
				break;
			}
		}
		if(i == sizeof(*_image_import_descriptor_new))
			break;

		memcpy(moveStartp,_image_import_descriptor_new,sizeof(*_image_import_descriptor_new));
		moveStartp += sizeof(*_image_import_descriptor_new);
		_image_import_descriptor_new++;
	}
	
	//新增一个导入表结构
	_IMAGE_IMPORT_DESCRIPTOR* new_importTablep = (_IMAGE_IMPORT_DESCRIPTOR*)moveStartp;
	moveStartp += (2 * sizeof(*_image_import_descriptor_new)); //别忘了全0结束

	//新增一个8字节的INT表和IAT表
	_INT_new = (_IMAGE_THUNK_DATA32*)moveStartp;
	moveStartp += 8;  //正常来说应该计算一下注入DLL中有多少个被使用的函数,再决定INT、IAT表有多大
	_IAT_new = (_IMAGE_THUNK_DATA32*)moveStartp;
	moveStartp += 8;

	//修正新增导入表结构中的OriginalFirstThunk和FirstThunk
	new_importTablep->OriginalFirstThunk = FOA_to_RVA(newFileBufferp,(DWORD)_INT_new - (DWORD)newFileBufferp); 
	new_importTablep->FirstThunk = FOA_to_RVA(newFileBufferp,(DWORD)_IAT_new - (DWORD)newFileBufferp);
	
	//新增一个IMAGE_IMPORT_BY_NAME结构
	_image_import_by_name_new = (_IMAGE_IMPORT_BY_NAME*)moveStartp;
	_image_import_by_name_new->Hint = 0;
	strncpy((char*)_image_import_by_name_new->Name,API,strlen(API) + 1);
	moveStartp += (2 + strlen(API) + 1);

	//修改INT表和IAT表(运行前)中的元素值
	_INT_new->Function = FOA_to_RVA(newFileBufferp,(DWORD)_image_import_by_name_new - (DWORD)newFileBufferp);
	_IAT_new->Function = FOA_to_RVA(newFileBufferp,(DWORD)_image_import_by_name_new - (DWORD)newFileBufferp);

	//存储DLL名称字符串
	char* dllNamep = moveStartp;
	strncpy(dllNamep,dllName,strlen(dllName) + 1);
	moveStartp += (strlen(dllName) + 1);

	//DLL名称字符串RVA赋值给导入表结构中的Name
	new_importTablep->Name = FOA_to_RVA(newFileBufferp,(DWORD)dllNamep - (DWORD)newFileBufferp);

	//修正导入表数据目录中的VirtualAddress和Size
	_image_data_directory_new->Size = _image_data_directory->Size + 20;
	_image_data_directory_new->VirtualAddress = FOA_to_RVA(newFileBufferp,moveStartAddress - (DWORD)newFileBufferp);

	return newFileBufferp;
}

int main(int argc,char* argv[]){
	//说明:如果要执行下面某个功能函数,先把其他的功能全部注释掉即可
	
	
	//---------------------------------------打印PE文件结构---------------------------------------
	/*//由于不是每个PE文件都有所有的表,所以在验证时可以使用下面推荐的PE文件进行验证
  	char* filePath = "D:/LordPE/16Edit.DLL";
	//char* filePath = "D:/C-language/file/notepad.exe";
	//char* filePath = "D:/IPMsg/ipmsg.exe";
	//char* filePath = "C:/WINDOWS/vmmreg32.dll";

	//打印PE头各字段(PE文件都有)
	PE_header_print(filePath);
	
	//打印节表各字段(PE文件都有)
	section_table_print(filePath);
	
	//打印数据目录(PE文件都有)
	data_directory_print(filePath);
	
	//打印导出表("D:/LordPE/16Edit.DLL")
	exportTable_print(filePath);
	
	//打印重定位表("C:/WINDOWS/vmmreg32.dll")
	relocationTable_print(filePath);
	
	//打印导入表、INT表、运行前IAT表、函数名称或序号("D:/IPMsg/ipmsg.exe")
	importTable_print(filePath);
	
	//打印绑定导入表("D:/C-language/file/notepad.exe")
	boundImportTable_print(filePath);*/
	//------------------------------------------结束------------------------------------------
	


	//-------------------将文件读入到FileBuffer,FileBuffer到ImageBuffer到newBuffer,最后存盘--------------------
	/*char* filePath = "D:/C-language/file/notepad.exe";
    char* storagePath = "D:/C-language/file/notepad_copy.exe"; //保存路径
	char* fileBufferp = to_FileBuffer(filePath);
	char* imageBufferp = fileBuffer_to_ImageBuffer(fileBufferp);
	char* newBufferp = imageBuffer_to_NewBuffer(imageBufferp);
	int isSucceed = save_to_disk(newBufferp,storagePath,compute_NewBuffer_size(newBufferp)); 
	if(isSucceed){
		printf("存盘成功");
	}else{
		printf("存盘失败");
	}
	free(fileBufferp);
	free(imageBufferp);
	free(newBufferp);*/
	//------------------------------------------结束------------------------------------------



	//---------------------------------------RVA转FOA、FOA转RVA---------------------------------------
	/*char* filePath = "D:/C-language/file/notepad.exe";
	char* fileBufferp = to_FileBuffer(filePath);
	DWORD FOA = RVA_to_FOA(fileBufferp,0x00008008);
	printf("0x%08X\n",FOA); //0x00007208
	DWORD RVA = FOA_to_RVA(fileBufferp,0x00007208);
	printf("0x%08X\n",RVA); //0x00008008*/
	//------------------------------------------结束------------------------------------------



	//--------------------------向第一个节.text中注入shellcode函数--------------------------------
	/*char* filePath = "D:/C-language/file/notepad.exe";  //你要打开的PE文件绝对路径
    char* storagePath = "D:/C-language/file/notepad_add.exe"; //保存路径
	char* fileBufferp = to_FileBuffer(filePath);
	char* imageBufferp = fileBuffer_to_ImageBuffer(fileBufferp);
	if(!add_shellcode(imageBufferp)){
		printf("shellcode注入失败");
		return 0;
	}
	char* newBufferp = imageBuffer_to_NewBuffer(imageBufferp);
	int isSucceed = save_to_disk(newBufferp,storagePath,compute_NewBuffer_size(newBufferp));
	if(!isSucceed)
		printf("存盘失败");
	else
		printf("存盘成功");
    free(fileBufferp);
	free(imageBufferp);
	free(newBufferp);*/
	//------------------------------------------结束------------------------------------------



	//---------------------------向任意节的空白区中注入shellcode----------------------------
	/*char* filePath = "D:/C-language/file/notepad.exe";  //你要打开的PE文件绝对路径
    char* storagePath = "D:/C-language/file/notepad_add.exe"; //保存路径
	char* fileBufferp = to_FileBuffer(filePath);
	char* imageBufferp = fileBuffer_to_ImageBuffer(fileBufferp);
	if(!add_shellcode_to_specific_section(imageBufferp,3)){ //这这里修改在第几节注入
		printf("shellcode注入失败");
		getchar();
		return 0;
	}
	char* newBufferp = imageBuffer_to_NewBuffer(imageBufferp);
	int isSucceed = save_to_disk(newBufferp,storagePath,compute_NewBuffer_size(newBufferp));
	if(!isSucceed)
		printf("存盘失败");
	else
		printf("存盘成功");
    free(fileBufferp);
	free(imageBufferp);
	free(newBufferp);*/
	//------------------------------------------结束------------------------------------------



	//----------------------------扩大最后一个节并向扩大的节中注入shellcode---------------------------
	/*char* filePath = "D:/IPMsg/ipmsg.exe";  //你要打开的PE文件绝对路径
    char* storagePath = "D:/IPMsg/ipmsg_new.exe"; //保存路径
	//char* filePath = "D:/C-language/file/notepad.exe";  //你要打开的PE文件绝对路径
    //char* storagePath = "D:/C-language/file/notepad_new.exe"; //保存路径
	char* fileBufferp = to_FileBuffer(filePath);
	char* imageBufferp = fileBuffer_to_ImageBuffer(fileBufferp);
	char* newImageBufferp = add_one_section(imageBufferp);
	if(!add_shellcode_to_new_section(newImageBufferp)){
		printf("在新节中注入shellcode失败");
		getchar();
		return 0;
	}	
	char* newBufferp = imageBuffer_to_NewBuffer(newImageBufferp);
	DWORD size = compute_NewBuffer_size(newBufferp);
	int isSucceed = save_to_disk(newBufferp,storagePath,size);
	if(!isSucceed){
		printf("存盘失败");
    	getchar();
    }else
		printf("存盘成功");
	free(fileBufferp);
	free(imageBufferp);
	free(newImageBufferp);
	free(newBufferp);*/
	//------------------------------------------结束------------------------------------------



	//------------------------------------------合并节-----------------------------------------------
	/*char* filePath = "D:/C-language/file/notepad.exe";
    char* storagePath = "D:/C-language/file/notepad_merge.exe";
	//char* filePath = "D:/IPMsg/ipmsg.exe";
    //char* storagePath = "D:/IPMsg/ipmsg_merge.exe";
	char* fileBufferp = to_FileBuffer(filePath);
	char* imageBufferp = fileBuffer_to_ImageBuffer(fileBufferp);
	imageBufferp = merge_section(imageBufferp);
	char* newBufferp = imageBuffer_to_NewBuffer(imageBufferp);
	DWORD size = compute_NewBuffer_size(newBufferp);
	int isSucceed = save_to_disk(newBufferp,storagePath,size);
	if(!isSucceed){
		printf("存盘失败");
    	getchar();
    }else
		printf("存盘成功");
	free(fileBufferp);
	free(imageBufferp);
	free(newBufferp);*/
	//------------------------------------------结束------------------------------------------




	//--------------------------计算一个数按照某对齐粒度对齐后的值函数----------------------------
	//printf("%x",alignment(0x3700,0x1000)); //0x4000
	//------------------------------------------结束------------------------------------------



	//---------------------------------------按名字查找导出函数地址---------------------------------------
	/*char* filePath = "D:/LordPE/16Edit.DLL";  //选一个有导出表的PE文件
	char* funcName = "HEEnterWindowLoopInNewThread"; //使用LordPE看有哪些导出函数
	char* fileBufferp = to_FileBuffer(filePath);
	printf("%08X",GetFunctionAddrByName(fileBufferp,funcName));*/
	//------------------------------------------结束------------------------------------------



	//--------------------------------按序号查找导出函数地址信息--------------------------------------
	/*char* filePath = "D:/OllyICE_1.10/OllyDBG.EXE";  //选一个有导出表的PE文件
	char* fileBufferp = to_FileBuffer(filePath);	
	printf("%08X",GetFunctionAddrByOrdinals(fileBufferp,0xA5)); //使用LordPE看有哪些导出序号*/
	//------------------------------------------结束------------------------------------------



	

	//-----------------------------------将PE文件导出表移到新增节中------------------------------------	
	/*char* filePath = "D:/LordPE/16Edit.DLL";  //选一个有导出表的PE文件,选LordPE文件下的16Edit.DLL是因为这个DLL的导出函数比较少,方便我们验证是否可以正常解析
	char* storagePath = "D:/LordPE/16Edit_add.DLL";
	//char* filePath = "D:/OllyICE_1.10/OllyDBG.EXE"; //选ollyDBG.EXE是因为不光可以用LordPE解析其导出表验证是否成功;也可以直接双击运行,看移动导出表后能否正常运行,去验证是否成功
	//char* storagePath = "D:/OllyICE_1.10/OllyDBG_add.EXE";
	char* fileBufferp = to_FileBuffer(filePath);
	char* newFileBufferp = move_ExportTable(fileBufferp);
	DWORD size = compute_NewBuffer_size(newFileBufferp);
	int isSucceed = save_to_disk(newFileBufferp,storagePath,size);  //将移动导出表后的PE文件存盘
	if(!isSucceed){
		printf("存盘失败");
    	getchar();
    }else
		printf("存盘成功");
	free(fileBufferp);
	free(newFileBufferp);*/
	//------------------------------------------结束------------------------------------------



	//-----------------------------------将PE文件重定位表移到新增节中------------------------------------------
	/*char* filePath = "D:/WinHex/zlib1.dll";  //选一个有重定位表的PE文件,选WinHex文件下的zlib1.dll是因为这个DLL的重定位表的块比较少,且原节表后面有空余位置新增节表,方便我们验证是否可以正常解析
	char* storagePath = "D:/WinHex/zlib1_add.dll";
	//char* filePath = "D:/OllyICE_1.10/OllyDBG.EXE"; //选ollyDBG.EXE是因为不光可以用LordPE解析其导出表验证是否成功;也可以直接双击运行,看移动重定位表后能否正常运行,去验证是否成功
	//char* storagePath = "D:/OllyICE_1.10/OllyDBG_add.EXE";
	char* fileBufferp = to_FileBuffer(filePath);
	char* newFileBufferp = move_RelocationTable(fileBufferp);
	DWORD size = compute_NewBuffer_size(newFileBufferp);
	int isSucceed = save_to_disk(newFileBufferp,storagePath,size);  //将移动重定位表后的PE文件存盘
	if(!isSucceed){
		printf("存盘失败");
    	getchar();
    }else
		printf("存盘成功");
	free(fileBufferp);
	free(newFileBufferp);*/
	//------------------------------------------结束------------------------------------------

	

	//-----------------------------------修改ImageBase后修复重定位表------------------------------------
	/*char* filePath = "D:/LordPE/PROCS.DLL";  //选一个有重定位表的PE文件,选LordPE文件下的PROCS.DLL是因为这个DLL的重定位表的块比较少,方便我们验证是否可以正常解析
	char* fileBufferp = to_FileBuffer(filePath);
	repair_RelocationTable(fileBufferp);
	DWORD size = compute_NewBuffer_size(fileBufferp);
	char* storagePath = "D:/LordPE/PROCS_repair.DLL";
	int isSucceed = save_to_disk(fileBufferp,storagePath,size); //将修复重定位表后的PE文件存盘
	if(!isSucceed){
		printf("存盘失败");
    	getchar();
    }else
		printf("存盘成功");
	free(fileBufferp);*/
	//------------------------------------------结束------------------------------------------


	
	//-----------------------------------------导入表注入-------------------------------------------
	/*char* filePath = "D:/IPMsg/ipmsg.exe";
	char* fileBufferp = to_FileBuffer(filePath);
	char* dllName = "InjectDll.dll";
	char* API = "ExportFunction";  //如果有很多API,可以用数组传入,再去遍历,但这里可以偷个懒
	char* newFileBufferp = importTable_injectDll(fileBufferp,dllName,API);
	DWORD size = compute_NewBuffer_size(newFileBufferp);
	char* storagePath = "D:/IPMsg/ipmsg_inject.exe";
	int isSucceed = save_to_disk(newFileBufferp,storagePath,size);  //将注入后的PE文件存盘
	if(!isSucceed){
		printf("存盘失败");
    	getchar();
    }else
		printf("存盘成功");
	free(fileBufferp);
	free(newFileBufferp);*/
	//------------------------------------------结束------------------------------------------
	

	return 0;
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
[{"valie1":"日期","valie2":"品种","valie3":"燃料级别","valie4":"结算重量","valie5":"水分","valie6":"灰分","valie7":"低位热值","valie8":"占比"},{"valie1":"2023-07-01","valie2":"树根Z","valie3":"一级","valie4":"8.66","valie5":"29.9","valie6":"5","valie7":"2100","valie8":"0.72%"},{"valie1":"2023-07-01","valie2":"枝丫Z","valie3":"一级","valie4":"6.7","valie5":"41.2","valie6":"10","valie7":"2200","valie8":"0.56%"},{"valie1":"2023-07-01","valie2":"薪材S","valie3":"一级","valie4":"107.48","valie5":"44.24","valie6":"13.11","valie7":"1848.74","valie8":"8.99%"},{"valie1":"2023-07-01","valie2":"板皮S","valie3":"一级","valie4":"619.2","valie5":"32.61","valie6":"13.74","valie7":"2287.92","valie8":"51.76%"},{"valie1":"2023-07-01","valie2":"枝丫S","valie3":"一级","valie4":"414.92","valie5":"40.99","valie6":"28.17","valie7":"1502.87","valie8":"34.69%"},{"valie1":"2023-07-01","valie2":"边角余料S","valie3":"一级","valie4":"39.22","valie5":"54.03","valie6":"14.93","valie7":"1398.96","valie8":"3.28%"},{"valie1":"合计","valie2":"","valie3":"","valie4":"1196.18","valie5":"37.29","valie6":"18.64","valie7":"1945.14","valie8":"100%"},{"valie1":"2023-07-02","valie2":"树皮S","valie3":"一级","valie4":"39.56","valie5":"48.11","valie6":"12.69","valie7":"1561.51","valie8":"4.28%"},{"valie1":"2023-07-02","valie2":"枝丫S","valie3":"一级","valie4":"266.84","valie5":"38.62","valie6":"24.96","valie7":"1716.44","valie8":"28.89%"},{"valie1":"2023-07-02","valie2":"边角余料S","valie3":"一级","valie4":"39","valie5":"56.83","valie6":"5.24","valie7":"1478.41","valie8":"4.22%"},{"valie1":"2023-07-02","valie2":"枝丫Z","valie3":"一级","valie4":"31.14","valie5":"41.2","valie6":"10","valie7":"2200","valie8":"3.37%"},{"valie1":"2023-07-02","valie2":"薪材S","valie3":"一级","valie4":"133.6","valie5":"39.87","valie6":"15.09","valie7":"1912.4","valie8":"14.47%"},{"valie1":"2023-07-02","valie2":"板皮S","valie3":"一级","valie4":"395.54","valie5":"34.01","valie6":"14.45","valie7":"2202.4","valie8":"42.83%"},{"valie1":"2023-07-02","valie2":"边角余料Z","valie3":"二级","valie4":"17.9","valie5":"29.8","valie6":"3.09","valie7":"2866","valie8":"1.94%"},{"valie1":"合计","valie2":"","valie3":"","valie4":"923.58","valie5":"37.92","valie6":"16.74","valie7":"1974.8","valie8":"100%"}]juqery 对valie1统计返回需要跨几行
07-15

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值