前言
理解了前面的,这个新增节就很简单了,无非就是看满足不满足条件,不满足了怎么办,以及满足了之后应该怎么去新增,怎么去改一些地方可以让程序能够正确的跑起来
课堂
有时所有节的空白区可能都不够存放我们要添加的代码,所以我们自己新增足够大的节来添加代码
新增节条件
判断方法:SizeOfHeader - (DOS + 垃圾数据 + PE 标记 + 标准 PE 头 + 可选 PE 头 + 已存在节表) >= 2 个节表的大小
这里要至少要两个节表大小空间的原因是:首先肯定要有一整个节表的大小,其次有时 windows 会根据一个结构后面是否有多个 0x00 来判断这个结构是否结束,故最后一个节表后面还要补跟节表宽度一样的 40 个 0x00,但海东老师的例子也可以看出这个条件并不是必须的,但如果没有满足规定的格式要求,不知道什么时候就不好使了,所以我们新增节表时还是按照标准规定来
新增节
如果满足添加节表的条件,此时我们可以将已有的一个节表的 40 字节信息复制一份紧挨着最后一个节表的末尾(节表之间必须要挨着!这是规定),然后再往后的 40 字节全部补 0x00,接下来就是根据新增节的信息,去修改对应节表的字段值即可
然后罗列一下需要修改的的值
-
修改标准 PE 头中 NumberOfSections 字段(节的数量)
-
修改 SizeOfImage 的大小(原有值 + 新增节的大小,最后还要内存对齐)
-
在文件的最后,新增节(添加时节的大小如果设置为内存对齐的整数倍,后面就不用再担心对齐的事)
-
然后就是修改复制下来的节表的属性,1.首先的话就是 Name,这个按照 ASCII 码随便取,最好长度限制在 8 字节内,2.然后是 Misc.VirtualSize,如果此时我们还不知道添加的数据长度(没对齐前),那么直接就按照对齐后的大小写即可,比如我们要新增节大小为 0x1000(考虑了内存对齐),那么不管里面要用多少字节数据,VirtualSize 的值就按照 0x1000 写,3.VirtualAddress,内存起始偏移地址,我们通过上一个节表的 VirtualAddress + VirtualSize 内存对齐后,得到上一个节内存对齐后的结尾位置,所以新增节表的 VirtualAddress 就是这个值(千万不能用 SizeOfRawData 来判断,因为这个节的 VirtualSize 可能大于 SizeOfRawData,因为包含未初始化数据,那么此时在内存中应该按照 VirtualAddress + VirtualSize 内存对齐后的得到的值来存储),4.PointerToRawData,文件对齐后的文件地址,我们可以通过上一个节表的 PointerToRawData + SizeOfRawData 计算得到此值,5.Characteristics,按照我们想要的属性来修改即可(可读、可写、可执行等),6.
-
SizeOfHeaders 的值不要随便改变,因为如果这个值变了,后面的节都要跟着往后或者往前跟着变,但是这些节当中凡是涉及到地址的计算相关的就会改变,比如说我们昨天加的 E8 和 E9 后面的值,是通过其他的地址计算出来的,如果 SizeOfHeaders 变了,节地址跟着变,那么这些值也要改变,所以代价很高,不建议修改
一些特殊情况
节表后面紧跟着就是编译器自己填的一些数据
有些程序会在节表到节的空白区之间添加一些信息,由于添加的新节表一定要与原来的节表紧挨着,但是我们又不知道程序的这些信息是否有用、是否影响程序的正常运行,所以此时我们不能轻易修改覆盖这些内容,那么我们如果要添加新节表就需要想办法:我们知道程序的 DOS 头到 PE 签名之间有一处区域 DOS Stub,不影响程序的运行,数据也是程序的一些说明信息,对我们来说就是垃圾数据,所以我们可以将 NT 头到节表末尾这一部分整体上移,把 Dos Stub 这块数据覆盖了,接着修改 DOS 头中的 e_lfanew 字段的值为上移后 PE 签名的地址即可,那么此时下面就会空出来一部分,我们就可以先将这部分全部修改成 0x00,再往这片区域新增节表即可
整体前移数据后还不够
如果向上覆盖 DOS Stub 之后,还不够新增节表的大小,那么我们就采用扩大最后一个节的方式,将添加的代码加到最后一个节扩大的空间中,这样可以保证不影响上面的所有地址
手动增节
这个会演示两种,第一种是节表后面没有编译器写的杂乱的东西的
第二种是有的,这种情况就选择上移出空间就行,然后再继续写节表的内容
这个我也不一张张截图演示了,跟上海东老师一步一步做就行
作业
1.就自己跟上做就行
2.项目的结构
main 的代码
#include <iostream>
#include <windows.h>
#include "Fuction.h"
int main()
{
char* FilePath = (char*)"D:/Everything333.exe"; //打开的PE文件绝对路径
char* SavePath = (char*)"D:/FakeEverything.exe"; //保存的路径
char* FileBufferPoint = ReadPeFile(FilePath);
char* ImageBufferPoint = CopyFileBufferToImageBuffer(FileBufferPoint);
char* NewImageBuffuerPoint = AddSection(ImageBufferPoint);
int flag = AddShellCodeToSection(NewImageBuffuerPoint, 5);
if (!flag) {
printf("shellcode注入失败\n");
return 0;
}
char* NewBufferPoint = CopyImageBufferToNewBuffer(NewImageBuffuerPoint);
int flag_2 = MemeryToFile(NewBufferPoint, SavePath);
if (flag_2) {
printf("全部成功,程序已在对应路径生成\n");
}
else {
printf("失败,再检查检查\n");
}
free(FileBufferPoint);
free(ImageBufferPoint);
free(NewBufferPoint);
free(NewImageBuffuerPoint);
return 0;
}
头文件
#pragma once
int PeFileSize(char* FilePath);
char* ReadPeFile(char* FilePath);
char* CopyFileBufferToImageBuffer(char* FileBufferPoint);
char* CopyImageBufferToNewBuffer(char* ImageBufferPoint);
int MemeryToFile(char* NewBufferPoint, char* SavePath);
int AddShellCodeToSection(char* ImageBufferPoint, int SectionNum);
int ImageAddressToFileAddress(char* FileBufferPoint, int ImageAddress);
char* AddSection(char* ImageBufferPoint);
功能文件
#include "Fuction.h"
#include <cstdio>
#include <atomic>
//这个模块里面写的就是PE所要用到功能的集合,统一写在了这里
//给变量换个名字,写起来更方便一点
typedef unsigned int DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
//这个是shellcode的代码
BYTE shellcode[] = {
0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,
0xE8,0x00,0x00,0x00,0x00,
0xE9,0x00,0x00,0x00,0x00
};
//这个就是一些PE里面固定的值
#define MZ 0x5A4D
#define PE 0x4550
#define IMAGE_SIZEOF_SHORT_NAME 8
#define MessageBox_Address 0x758BA000//这个是Everything2.exe的
#define Example_Add_Section_Size 0x1000
//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; //特征值
};
//可选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; //该节特征属性
};
//OK至此所有用到的结构体就都定义完了,这个海东老师的课件里面都有,气死但他不给代码
int PeFileSize(char* FilePath) {
//PeFileSize:计算文件在硬盘上的大小
//参数说明:
//FilePath:指向文件的绝对路径
//返回值说明:
//读取成功返回文件在硬盘上的大小,读取失败则返回0
FILE* pf = fopen(FilePath, "rb");
if (pf == NULL) {
perror("打开文件错误");
fclose(pf);
return 0;
}
fseek(pf, 0, 2);
int length = ftell(pf);
fseek(pf, 0, 0);
fclose(pf);
printf("已经成功读取该文件的大小\n");
return length;
}
char* ReadPeFile(char* FilePath) {
//ReadPeFile:将可执行文件从硬盘读取到FileBuffer
//参数说明:
//FilePath:指向文件的绝对路径
//返回值说明:
//读取成功返回FileBuffer的首地址,读取失败则返回0
FILE* pf = fopen(FilePath, "rb");
if (pf == NULL) {
perror("打开文件错误");
fclose(pf);
return 0;
}
int length = PeFileSize(FilePath);
char* ptr_1 = (char*)malloc(sizeof(char) * length);
if (ptr_1 == NULL) {
perror("File堆内存分配失败");
fclose(pf);
return 0;
}
memset(ptr_1, 0, sizeof(char) * length);
int flag = fread(ptr_1, length, 1, pf);
if (flag == NULL) {
perror("读取数据失败,请检查文件路径");
fclose(pf);
free(ptr_1);
return 0;
}
fclose(pf);
//这里之所以没有free(ptr),原因是咱们下面还要用到这块堆的内存,所以可以在main函数结束之前释放掉就行
printf("已成功将可执行文件从硬盘读取到FileBuffer\n");
return ptr_1;
}
char* CopyFileBufferToImageBuffer(char* FileBufferPoint) {
//CopyFileBufferToImageBuffer:将可执行文件从FileBuffer读取到ImageBuffer
//参数说明:
//FileBufferPoint:指向可执行文件在FileBuffer的地址
//返回值说明:
//读取成功返回ImageBuffer的首地址,读取失败则返回0
_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*)FileBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(FileBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
int size = _image_optional_header->SizeOfImage;
char* ptr_2 = (char*)malloc(size);
if (ptr_2 == NULL) {
perror("Image堆内存分配失败");
return 0;
}
memset(ptr_2, 0, size);
for (unsigned int i = 0; i < _image_optional_header->SizeOfHeaders; i++) {
*(ptr_2 + i) = *(FileBufferPoint + i);
}
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
char* temp_1 = FileBufferPoint + _image_section_header->PointerToRawData;
char* temp_2 = ptr_2 + _image_section_header->VirtualAddress;
for (unsigned int j = 0; j < _image_section_header->SizeOfRawData; j++) {
*(temp_2 + j) = *(temp_1 + j);
}
_image_section_header++;
}
printf("已成功将可执行文件从FileBuffer读取到ImageBuffer\n");
return ptr_2;
}
char* CopyImageBufferToNewBuffer(char* ImageBufferPoint) {
//CopyImageBufferToNewBuffer:将可执行文件从ImageBuffer读取到NewBuffer(其实也就是FileBuffer)
//参数说明:
//ImageBufferPoint:指向可执行文件在ImageBuffer的地址
//返回值说明:
//读取成功返回NewBuffer(其实也就是FileBuffer)的首地址,读取失败则返回0
_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*)ImageBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(ImageBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
int ImageSectionSize = 0;
_IMAGE_SECTION_HEADER* _image_section_header_temp = _image_section_header;
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
ImageSectionSize += _image_section_header_temp->PointerToRawData;
_image_section_header_temp++;
}
char* ptr_3 = (char*)malloc(_image_optional_header->SizeOfHeaders + ImageSectionSize);
if (ptr_3 == NULL) {
perror("NewBuffer堆内存分配失败");
return 0;
}
memset(ptr_3, 0, _image_optional_header->SizeOfHeaders + ImageSectionSize);
for (unsigned int i = 0; i < _image_optional_header->SizeOfHeaders; i++) {
*(ptr_3 + i) = *(ImageBufferPoint + i);
}
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
char* temp_1 = ImageBufferPoint + _image_section_header->VirtualAddress;
char* temp_2 = ptr_3 + _image_section_header->PointerToRawData;
for (unsigned int j = 0; j < _image_section_header->SizeOfRawData; j++) {
*(temp_2 + j) = *(temp_1 + j);
}
_image_section_header++;
}
printf("已成功将可执行文件从ImageBuffer读取到NewBuffer\n");
return ptr_3;
}
int MemeryToFile(char* NewBufferPoint, char* SavePath) {
//MemeryTOFile:将可执行文件从NewBuffer读取到硬盘
//参数说明:
//NewBufferPoint:指向NewBuffer的首地址
//SavePath:指向另存为文件的绝对路径
//返回值说明:
//读取成功返回1,读取失败则返回0
_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*)NewBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(NewBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
int ImageSectionSize = 0;
_IMAGE_SECTION_HEADER* _image_section_header_temp = _image_section_header;
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
ImageSectionSize += _image_section_header_temp->PointerToRawData;
_image_section_header_temp++;
}
int size = _image_optional_header->SizeOfHeaders + ImageSectionSize;
FILE* pf = fopen(SavePath, "wb");
if (pf == NULL) {
perror("打开文件错误");
fclose(pf);
return 0;
}
int flag = fwrite(NewBufferPoint, size, 1, pf);
if (flag == NULL) {
perror("存文件出现错误,请检查文件路径是否有效");
free(NewBufferPoint);
fclose(pf);
return 0;
}
fclose(pf);
return 1;
}
int ImageAddressToFileAddress(char* FileBufferPoint, int ImageAddress) {
//ImageAddressToFileAddress:将ImageBuffer里面的节地址转换为对应的FileBuffer的节地址
//参数说明:
//FileBufferPoint:指向FileBuffer的首地址
//ImageAddress:传入ImageBuffer里面的节地址
//返回值说明:
//转换成功返回节地址,地址不在节内或在空白区则返回0
_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*)FileBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(FileBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
int flag = 0;
if (_image_section_header->VirtualAddress > ImageAddress - _image_optional_header->ImageBase) {
return 0;
}
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
if (ImageAddress - _image_optional_header->ImageBase >= _image_section_header->VirtualAddress && ImageAddress - _image_optional_header->ImageBase < _image_section_header->VirtualAddress + _image_section_header->Misc.VirtualSize) {
flag = 1;
break;
}
else {
_image_section_header++;
}
}
if (flag == 0) {
return 0;
}
int TempAddress = ImageAddress - _image_optional_header->ImageBase - _image_section_header->VirtualAddress;
return _image_section_header->PointerToRawData + TempAddress;
}
int AddShellCodeToSection(char* ImageBufferPoint, int SectionNum) {
//AddShellCodeToSection:将shellcode注入到ImageBuffer里面的任意节
//参数说明:
//ImageBufferPoint:指向ImageBuffer的首地址
//SectionNum:要注入的节的位置
//返回值说明:
//注入成功返回1,反之则返回0
_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*)ImageBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(ImageBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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 (SectionNum < 0 || SectionNum > _image_file_header->NumberOfSections) {
printf("输入的节不存在,请重新输入\n");
return 0;
}
_IMAGE_SECTION_HEADER* temp_image_section_header = _image_section_header + SectionNum - 1;
if ((int)(temp_image_section_header->SizeOfRawData - temp_image_section_header->Misc.VirtualSize) < sizeof(shellcode) / sizeof(shellcode[0])) {
printf("该节空间不足,无法加壳");
return 0;
}
char* ShellCodePoint = ImageBufferPoint + temp_image_section_header->VirtualAddress;
for (int i = 0; i < sizeof(shellcode) / sizeof(shellcode[0]); i++) {
*(ShellCodePoint + i) = shellcode[i];
}
DWORD E8Address = (DWORD)ShellCodePoint - (DWORD)ImageBufferPoint + _image_optional_header->ImageBase + 8;
DWORD E8Data = MessageBox_Address - (E8Address + 5);
*(DWORD*)(ShellCodePoint + 9) = E8Data;
DWORD E9Address = E8Address + 5;
DWORD E9Data = _image_optional_header->ImageBase + _image_optional_header->AddressOfEntryPoint - (E9Address + 5);
*(DWORD*)(ShellCodePoint + 14) = E9Data;
_image_optional_header->AddressOfEntryPoint = (DWORD)(ShellCodePoint - ImageBufferPoint);
temp_image_section_header->Characteristics = temp_image_section_header->Characteristics | 0x60000020;
return 1;
}
char* AddSection(char* ImageBufferPoint) {
//AddSection:给ImageBuffer
//参数说明:
//ImageBufferPoint:指向ImageBuffer的首地址
//返回值说明:
//成功添加则返回NewImageBuffer的地址
_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*)ImageBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(ImageBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
//这里就给一个添加0x1000h作为示例
char* NewImageBuffuerPoint = (char*)malloc(_image_optional_header->SizeOfImage + Example_Add_Section_Size);
if (NewImageBuffuerPoint == NULL) {
perror("Image堆内存分配失败");
return 0;
}
memset(NewImageBuffuerPoint,0 ,_image_optional_header->SizeOfImage + Example_Add_Section_Size);
memcpy(NewImageBuffuerPoint, ImageBufferPoint, _image_optional_header->SizeOfImage);
_image_dos_header = (_IMAGE_DOS_HEADER*)NewImageBuffuerPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(NewImageBuffuerPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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) {
perror("空间不足,无法新增节表");
return 0;
}
for (int i = 0; i < 80;i++) {
if (*((char*)(_image_section_header + _image_file_header->NumberOfSections)) != 0x00) {
perror("剩余空间存在非0,无法新增节表,请选择前移或者合并末尾节");
return 0;
}
}
DWORD original_SizeOfImage = _image_optional_header->SizeOfImage;
_image_optional_header->SizeOfImage += Example_Add_Section_Size;
_IMAGE_SECTION_HEADER* NewSectionPoint = _image_section_header + _image_file_header->NumberOfSections;
for (int i = 0; i < 40;i++) {
*((char*)NewSectionPoint + i) = *((char*)_image_section_header + i);
}
_image_file_header->NumberOfSections++;
char* name = (char*)NewSectionPoint->Name;
char* newName = (char*)".newsec";
strncpy(name, newName, IMAGE_SIZEOF_SHORT_NAME);
NewSectionPoint->Misc.VirtualSize = IMAGE_SIZEOF_SHORT_NAME;
NewSectionPoint->VirtualAddress = original_SizeOfImage;
NewSectionPoint->PointerToRawData = (NewSectionPoint - 1)->PointerToRawData + (NewSectionPoint - 1)->SizeOfRawData;
NewSectionPoint->SizeOfRawData = Example_Add_Section_Size + 0x200;
NewSectionPoint->Characteristics = 0x60000020;
return NewImageBuffuerPoint;
}
3.这个其实和第二个就差不多,我单独再写个代码,就不贴 main 和头文件了,直接给功能函数了
#include "Fuction.h"
#include <cstdio>
#include <atomic>
//这个模块里面写的就是PE所要用到功能的集合,统一写在了这里
//给变量换个名字,写起来更方便一点
typedef unsigned int DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
//这个是shellcode的代码
BYTE shellcode[] = {
0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,
0xE8,0x00,0x00,0x00,0x00,
0xE9,0x00,0x00,0x00,0x00
};
//这个就是一些PE里面固定的值
#define MZ 0x5A4D
#define PE 0x4550
#define IMAGE_SIZEOF_SHORT_NAME 8
#define MessageBox_Address 0x758BA000//这个是Everything2.exe的
#define Example_Add_Section_Size 0x1000
//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; //特征值
};
//可选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; //该节特征属性
};
//OK至此所有用到的结构体就都定义完了,这个海东老师的课件里面都有,气死但他不给代码
int PeFileSize(char* FilePath) {
//PeFileSize:计算文件在硬盘上的大小
//参数说明:
//FilePath:指向文件的绝对路径
//返回值说明:
//读取成功返回文件在硬盘上的大小,读取失败则返回0
FILE* pf = fopen(FilePath, "rb");
if (pf == NULL) {
perror("打开文件错误");
fclose(pf);
return 0;
}
fseek(pf, 0, 2);
int length = ftell(pf);
fseek(pf, 0, 0);
fclose(pf);
printf("已经成功读取该文件的大小\n");
return length;
}
char* ReadPeFile(char* FilePath) {
//ReadPeFile:将可执行文件从硬盘读取到FileBuffer
//参数说明:
//FilePath:指向文件的绝对路径
//返回值说明:
//读取成功返回FileBuffer的首地址,读取失败则返回0
FILE* pf = fopen(FilePath, "rb");
if (pf == NULL) {
perror("打开文件错误");
fclose(pf);
return 0;
}
int length = PeFileSize(FilePath);
char* ptr_1 = (char*)malloc(sizeof(char) * length);
if (ptr_1 == NULL) {
perror("File堆内存分配失败");
fclose(pf);
return 0;
}
memset(ptr_1, 0, sizeof(char) * length);
int flag = fread(ptr_1, length, 1, pf);
if (flag == NULL) {
perror("读取数据失败,请检查文件路径");
fclose(pf);
free(ptr_1);
return 0;
}
fclose(pf);
//这里之所以没有free(ptr),原因是咱们下面还要用到这块堆的内存,所以可以在main函数结束之前释放掉就行
printf("已成功将可执行文件从硬盘读取到FileBuffer\n");
return ptr_1;
}
char* CopyFileBufferToImageBuffer(char* FileBufferPoint) {
//CopyFileBufferToImageBuffer:将可执行文件从FileBuffer读取到ImageBuffer
//参数说明:
//FileBufferPoint:指向可执行文件在FileBuffer的地址
//返回值说明:
//读取成功返回ImageBuffer的首地址,读取失败则返回0
_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*)FileBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(FileBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
int size = _image_optional_header->SizeOfImage;
char* ptr_2 = (char*)malloc(size);
if (ptr_2 == NULL) {
perror("Image堆内存分配失败");
return 0;
}
memset(ptr_2, 0, size);
for (unsigned int i = 0; i < _image_optional_header->SizeOfHeaders; i++) {
*(ptr_2 + i) = *(FileBufferPoint + i);
}
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
char* temp_1 = FileBufferPoint + _image_section_header->PointerToRawData;
char* temp_2 = ptr_2 + _image_section_header->VirtualAddress;
for (unsigned int j = 0; j < _image_section_header->SizeOfRawData; j++) {
*(temp_2 + j) = *(temp_1 + j);
}
_image_section_header++;
}
printf("已成功将可执行文件从FileBuffer读取到ImageBuffer\n");
return ptr_2;
}
char* CopyImageBufferToNewBuffer(char* ImageBufferPoint) {
//CopyImageBufferToNewBuffer:将可执行文件从ImageBuffer读取到NewBuffer(其实也就是FileBuffer)
//参数说明:
//ImageBufferPoint:指向可执行文件在ImageBuffer的地址
//返回值说明:
//读取成功返回NewBuffer(其实也就是FileBuffer)的首地址,读取失败则返回0
_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*)ImageBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(ImageBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
int ImageSectionSize = 0;
_IMAGE_SECTION_HEADER* _image_section_header_temp = _image_section_header;
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
ImageSectionSize += _image_section_header_temp->PointerToRawData;
_image_section_header_temp++;
}
char* ptr_3 = (char*)malloc(_image_optional_header->SizeOfHeaders + ImageSectionSize);
if (ptr_3 == NULL) {
perror("NewBuffer堆内存分配失败");
return 0;
}
memset(ptr_3, 0, _image_optional_header->SizeOfHeaders + ImageSectionSize);
for (unsigned int i = 0; i < _image_optional_header->SizeOfHeaders; i++) {
*(ptr_3 + i) = *(ImageBufferPoint + i);
}
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
char* temp_1 = ImageBufferPoint + _image_section_header->VirtualAddress;
char* temp_2 = ptr_3 + _image_section_header->PointerToRawData;
for (unsigned int j = 0; j < _image_section_header->SizeOfRawData; j++) {
*(temp_2 + j) = *(temp_1 + j);
}
_image_section_header++;
}
printf("已成功将可执行文件从ImageBuffer读取到NewBuffer\n");
return ptr_3;
}
int MemeryToFile(char* NewBufferPoint, char* SavePath) {
//MemeryTOFile:将可执行文件从NewBuffer读取到硬盘
//参数说明:
//NewBufferPoint:指向NewBuffer的首地址
//SavePath:指向另存为文件的绝对路径
//返回值说明:
//读取成功返回1,读取失败则返回0
_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*)NewBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(NewBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
int ImageSectionSize = 0;
_IMAGE_SECTION_HEADER* _image_section_header_temp = _image_section_header;
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
ImageSectionSize += _image_section_header_temp->PointerToRawData;
_image_section_header_temp++;
}
int size = _image_optional_header->SizeOfHeaders + ImageSectionSize;
FILE* pf = fopen(SavePath, "wb");
if (pf == NULL) {
perror("打开文件错误");
fclose(pf);
return 0;
}
int flag = fwrite(NewBufferPoint, size, 1, pf);
if (flag == NULL) {
perror("存文件出现错误,请检查文件路径是否有效");
free(NewBufferPoint);
fclose(pf);
return 0;
}
fclose(pf);
return 1;
}
int ImageAddressToFileAddress(char* FileBufferPoint, int ImageAddress) {
//ImageAddressToFileAddress:将ImageBuffer里面的节地址转换为对应的FileBuffer的节地址
//参数说明:
//FileBufferPoint:指向FileBuffer的首地址
//ImageAddress:传入ImageBuffer里面的节地址
//返回值说明:
//转换成功返回节地址,地址不在节内或在空白区则返回0
_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*)FileBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(FileBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
int flag = 0;
if (_image_section_header->VirtualAddress > ImageAddress - _image_optional_header->ImageBase) {
return 0;
}
for (int i = 0; i < _image_file_header->NumberOfSections; i++) {
if (ImageAddress - _image_optional_header->ImageBase >= _image_section_header->VirtualAddress && ImageAddress - _image_optional_header->ImageBase < _image_section_header->VirtualAddress + _image_section_header->Misc.VirtualSize) {
flag = 1;
break;
}
else {
_image_section_header++;
}
}
if (flag == 0) {
return 0;
}
int TempAddress = ImageAddress - _image_optional_header->ImageBase - _image_section_header->VirtualAddress;
return _image_section_header->PointerToRawData + TempAddress;
}
int AddShellCodeToSection(char* ImageBufferPoint, int SectionNum) {
//AddShellCodeToSection:将shellcode注入到ImageBuffer里面的任意节
//参数说明:
//ImageBufferPoint:指向ImageBuffer的首地址
//SectionNum:要注入的节的位置
//返回值说明:
//注入成功返回1,反之则返回0
_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*)ImageBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(ImageBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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 (SectionNum < 0 || SectionNum > _image_file_header->NumberOfSections) {
printf("输入的节不存在,请重新输入\n");
return 0;
}
_IMAGE_SECTION_HEADER* temp_image_section_header = _image_section_header + SectionNum - 1;
if ((int)(temp_image_section_header->SizeOfRawData - temp_image_section_header->Misc.VirtualSize) < sizeof(shellcode) / sizeof(shellcode[0])) {
printf("该节空间不足,无法加壳");
return 0;
}
char* ShellCodePoint = ImageBufferPoint + _image_optional_header->SizeOfImage - Example_Add_Section_Size;
for (int i = 0; i < sizeof(shellcode) / sizeof(shellcode[0]); i++) {
*(ShellCodePoint + i) = shellcode[i];
}
DWORD E8Address = (DWORD)ShellCodePoint - (DWORD)ImageBufferPoint + _image_optional_header->ImageBase + 8;
DWORD E8Data = MessageBox_Address - (E8Address + 5);
*(DWORD*)(ShellCodePoint + 9) = E8Data;
DWORD E9Address = E8Address + 5;
DWORD E9Data = _image_optional_header->ImageBase + _image_optional_header->AddressOfEntryPoint - (E9Address + 5);
*(DWORD*)(ShellCodePoint + 14) = E9Data;
_image_optional_header->AddressOfEntryPoint = (DWORD)(ShellCodePoint - ImageBufferPoint);
temp_image_section_header->Characteristics = temp_image_section_header->Characteristics | 0x60000020;
return 1;
}
char* AddSection(char* ImageBufferPoint) {
//AddSection:给ImageBuffer添加一个节
//参数说明:
//ImageBufferPoint:指向ImageBuffer的首地址
//返回值说明:
//成功添加则返回NewImageBuffer的地址
_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*)ImageBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(ImageBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
//这里就给一个添加0x1000h作为示例
char* NewImageBuffuerPoint = (char*)malloc(_image_optional_header->SizeOfImage + Example_Add_Section_Size);
if (NewImageBuffuerPoint == NULL) {
perror("Image堆内存分配失败");
return 0;
}
memset(NewImageBuffuerPoint,0 ,_image_optional_header->SizeOfImage + Example_Add_Section_Size);
memcpy(NewImageBuffuerPoint, ImageBufferPoint, _image_optional_header->SizeOfImage);
_image_dos_header = (_IMAGE_DOS_HEADER*)NewImageBuffuerPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(NewImageBuffuerPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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) {
perror("空间不足,无法新增节表");
return 0;
}
for (int i = 0; i < 80;i++) {
if (*((char*)(_image_section_header + _image_file_header->NumberOfSections)) != 0x00) {
perror("剩余空间存在非0,无法新增节表,请选择前移或者合并末尾节");
return 0;
}
}
DWORD original_SizeOfImage = _image_optional_header->SizeOfImage;
_image_optional_header->SizeOfImage += Example_Add_Section_Size;
_IMAGE_SECTION_HEADER* NewSectionPoint = _image_section_header + _image_file_header->NumberOfSections;
for (int i = 0; i < 40;i++) {
*((char*)NewSectionPoint + i) = *((char*)_image_section_header + i);
}
_image_file_header->NumberOfSections++;
char* name = (char*)NewSectionPoint->Name;
char* newName = (char*)".newsec";
strncpy(name, newName, IMAGE_SIZEOF_SHORT_NAME);
NewSectionPoint->Misc.VirtualSize = IMAGE_SIZEOF_SHORT_NAME;
NewSectionPoint->VirtualAddress = original_SizeOfImage;
NewSectionPoint->PointerToRawData = (NewSectionPoint - 1)->PointerToRawData + (NewSectionPoint - 1)->SizeOfRawData;
NewSectionPoint->SizeOfRawData = Example_Add_Section_Size + 0x200;
NewSectionPoint->Characteristics = 0x60000020;
return NewImageBuffuerPoint;
}
char* AddLastSection(char* ImageBufferPoint) {
//AddSection:给ImageBuffer的最后一个节扩展
//参数说明:
//ImageBufferPoint:指向ImageBuffer的首地址
//返回值说明:
//成功添加则返回NewImageBuffer的地址
_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*)ImageBufferPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(ImageBufferPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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);
//这里就给一个添加0x1000h作为示例
char* NewImageBuffuerPoint = (char*)malloc(_image_optional_header->SizeOfImage + Example_Add_Section_Size);
if (NewImageBuffuerPoint == NULL) {
perror("Image堆内存分配失败");
return 0;
}
memset(NewImageBuffuerPoint, 0, _image_optional_header->SizeOfImage + Example_Add_Section_Size);
memcpy(NewImageBuffuerPoint, ImageBufferPoint, _image_optional_header->SizeOfImage);
_image_dos_header = (_IMAGE_DOS_HEADER*)NewImageBuffuerPoint;
//下面这个别忘记了还有一个PE标记的大小,为4个字节
_image_file_header = (_IMAGE_FILE_HEADER*)(NewImageBuffuerPoint + _image_dos_header->e_lfanew + sizeof(PE));
_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 original_SizeOfImage = _image_optional_header->SizeOfImage;
_image_optional_header->SizeOfImage += Example_Add_Section_Size;
_IMAGE_SECTION_HEADER* LastSectionPoint = _image_section_header + _image_file_header->NumberOfSections - 1;
LastSectionPoint->Misc.VirtualSize = _image_optional_header->SizeOfImage - LastSectionPoint->VirtualAddress;
LastSectionPoint->SizeOfRawData = LastSectionPoint->Misc.VirtualSize + 0x200;
LastSectionPoint->Characteristics = 0x60000020;
return NewImageBuffuerPoint;
}
累死,加油写吧