PE文件(六)新增节-添加代码

本节的目的是在所有节的空白区都不够存放我们要添加的代码时,教会我们新增一个足够大的节来添加代码

添加节

一.判断是最后节表后到节表部分结束否有足够的空间可以添加一个节表:新增节需要新增一个节表来记录此节信息

注意:如果节表后有足够的空间但是紧接节表有数据(非0x),就要谨慎行事,因为这些数据可能是有用数据

判断方法:SizeOfHeader - (DOS + 垃圾数据 + PE标记 + 标准PE头 + 可选PE头 + 已存在节表) >= 2个节表的大小(80个字节大小)

注意:windows会根据一个结构体后面是否有至少一个同结构体大小以上的0x00来判断这个结构体是否结束,所以最后一个节表后面通常需要填补同节表宽度的0以防系统误判

二.当满足添加节表的条件时,我们可以将已有的一个节表的40字节信息复制一份紧挨着最后一个节表的末尾(节表与节表之间时连续的),然后再定义之后的40字节都是0,之后再根据新增节的信息,去修改对应节表的字段值

三.修改数据:

1.修改PE头中NumberOfSections字段(节的数量)为我们添加节以后节的总数

2.修改SizeOfImage的大小:原有值 + 新增节的大小(注意内存对齐)

3.修正新增节表的属性:

Name:按照ASCII码自定义名字,最好长度限制在8字节内

Misc.VirtualSize:内存起始偏移地址,我们通过上一个节表的VirtualAddress + VirtualSize的值再进行内存对齐后得到上一个节的结尾位置,作为新增节的内存起始偏移地址。但我们在实际操作中选择VirtualSize和SizeOfRawData中大者取值

举例:

我们有时候发现文件内存中未对齐的大小确实比文件中对齐的大小大,这是由于节中包含初始化数据的缘故。比如notepad.exe文件的第二个节.data中,内存中未对齐的大小为0x1BA8,文件中对齐后的大小为0x600。因此我们可以发现,第三个节在文件起始中应该按照上一个节在文件中对齐后的大小往后接着存放,即0x7200 + 0x600 = 0x7800,所以第三个节的PointerToRawData为0x7800。而第三个节在内存起始中应该按照上一个节在内存中对齐后的大小往后接着存放而不是再按照上一个节的文件中对齐大小挨着存放了,这是因为此时VirtualSize比SizeOfRawData大,即0x8000 + 0x1BA8 = 0x9BA8,对齐后为0xA000,因此第三个节内存偏移为0xA000

SizeOfRawData:根据文件对齐粒度来修正这个值。如果上面设定了VirtualSize的值为0x1000,说明这个节的这0x1000字节都是有用数据,那么此节在硬盘上时也应该有这0x1000字节的数据,此时需要根据文件对齐粒度来修正这个值。如果为0x200或者0x1000,就不用修改0x1000,因为已经满足是文件对齐的整数倍了

PointerToRawData:文件对齐后的文件地址,我们可以通过上一个节表的PointerToRawData + SizeOfRawData计算得到此值

Characteristics:按照我们想要的属性来修改即可(可读、可写、可执行等)

如图所示:

注意:修改SizeOfHeaders的值代价很高,所以不能随便改变。因为如果这个值变大或变小了,后面的节都要跟着往后或者往前跟着改变,其中的数据地址也会随之改变,比如这些节当中涉及到相关计算地址的数值就需要重新计算了。其他诸多类似的修改都是一个繁琐的过程,会加重我们的工作量。比如说我们上节课作业中E8和E9后面的值,是通过其他的地址计算出来的。如果SizeOfHeaders改变了,节地址也会随之改变,因此这些值也要改变。

特殊情况

在众多程序中,有一些程序在最后一个节表后有一些信息(这些信息我们无法知晓是否有用),所以我们不可轻易修改这些信息。但是我们要添加的新节表一定要与原来的节表连续紧挨着,所以在这种情况下为了不覆盖有用的信息,我们就要考虑整体上移NT头和节表

已知程序的DOS头到PE签名之间有一处区域叫做DOS Stub。该区域存储的是程序的一些说明信息相关的数据,这些数据不会影响程序的运行,并且对我们来说是垃圾数据,所以我们可以将NT头到节表末尾这一部分整体上移,把Dos Stub这块数据覆盖了,但原来节表末尾的数据不进行修改。这时我们修改DOS头中的e_lfanew字段的值为上移后PE签名的地址。此时节表末尾和原节表末尾的信息之间就会空出来一部分,我们将这部分全部初始化以后,就可以往这片空白区域新增节表了。

作业

代码实现新增一个节,并添加代码

#include<stdio.h>
#include<Windows.h>
#include<string.h>
DWORD ReadPEFileSize(const char* lpszFile) //将一个文件的硬盘内存数据d大小
{
	FILE* pFile = NULL;
	pFile = fopen(lpszFile, "rb");
	DWORD FileSize = 0;
	if (!pFile)
	{
		printf("无法打开EXE文件");
		return 0;
	}
	fseek(pFile, 0, SEEK_END);
	FileSize = ftell(pFile);
	return FileSize;
}
char* ReadPEFile(const char* lpszFile)
{
	FILE* pFile = NULL;
	pFile = fopen(lpszFile, "rb");
	DWORD FileSize = ReadPEFileSize(lpszFile);
	fseek(pFile, 0, SEEK_SET);
	char* pFileBuffer = NULL;
	pFileBuffer = (char*)malloc(sizeof(char) * FileSize);
	if (!pFileBuffer)
	{
		printf("分配空间失败");
		fclose(pFile);
		return 0;
	}
	size_t i = fread(pFileBuffer, FileSize, 1, pFile);
	if (!i)
	{
		printf("读取数据失败!");
		free(pFileBuffer);
		fclose(pFile);
		return 0;
	}
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((char*)pFileBuffer + pDosHeader->e_lfanew); //(char*)pFileBuffer只有此处转换为了char*类型,之后加减是为char的大小为一个单位进行加减
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效MZ标志,结束\n");
		free(pFileBuffer);
		fclose(pFile);
		return 0;
	}
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志,打印结束\n");
		free(pFileBuffer);
		pFileBuffer = NULL;
		return 0;
	}
	fclose(pFile);
	return pFileBuffer;
}
BOOL shellcode(const char* newBuffer, const char* lpszFile, DWORD size)
{
	char shellcode[18] = { 0x6A, 0x00, 0x6A, 0x00, 0x6A,0x00, 0x6A, 0x00, 0xE8, 0x00,  0x00,  0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00 };
	char* pFileBuffer = ReadPEFile(lpszFile); //获取自定义文件内存缓冲区指针
	if (pFileBuffer == NULL)
	{
		printf("缓冲区指针无效\n");
		return FALSE;
	}
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; //获取自定义文件内存缓冲区DOS头指针
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((char*)pFileBuffer + pDosHeader->e_lfanew); //获取NT头指针
	PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((char*)pNTHeader + 4);//获取标准PE头指针
	PIMAGE_OPTIONAL_HEADER pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((char*)pFileHeader + 20);//获取可选PE头指针
	PIMAGE_SECTION_HEADER pSecHeader = (PIMAGE_SECTION_HEADER)((char*)pOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取文件节表指针
	if (pOptionHeader->SizeOfHeaders - pDosHeader->e_lfanew - 4 - 20 - pFileHeader->SizeOfOptionalHeader >= 2 * pFileHeader->SizeOfOptionalHeader)
	{
		printf("节表后剩余空间足够添加一个新的节表\n");
	}
	else
	{
		printf("节表后剩余空间不足以添加一个新的节表,结束\n");
		return FALSE;
	}
	PIMAGE_SECTION_HEADER pSecHeaderEnd = (PIMAGE_SECTION_HEADER)((char*)pSecHeader + pFileHeader->NumberOfSections * 40);
	memcpy(pSecHeaderEnd, pSecHeader, 40);
	memset(((char*)pSecHeaderEnd + 40), 0, 40); //此时已经新增了一个节表
	PIMAGE_SECTION_HEADER pSecHeaderLast = (PIMAGE_SECTION_HEADER)((char*)pSecHeader + (pFileHeader->NumberOfSections - 1) * 40);//获取新增节上一个节指针
	pFileHeader->NumberOfSections += 1;
	pOptionHeader->SizeOfImage += pOptionHeader->SectionAlignment;
	strcpy((char*)pSecHeaderEnd->Name, (char*)".shel");
	pSecHeaderEnd->PointerToRawData = pSecHeaderLast->PointerToRawData + pSecHeaderLast->SizeOfRawData;
	char* pSecHeaderEndBuffer = (char*)pDosHeader + pSecHeaderEnd->PointerToRawData;
	pSecHeaderEnd->Misc.VirtualSize = sizeof(shellcode);
	pSecHeaderEnd->SizeOfRawData = pOptionHeader->FileAlignment;
	DWORD Alignment = pOptionHeader->SectionAlignment - pSecHeaderLast->Misc.VirtualSize % pOptionHeader->SectionAlignment;
	pSecHeaderEnd->VirtualAddress = pSecHeaderLast->VirtualAddress + pSecHeaderLast->Misc.VirtualSize + Alignment; //获取上个节对齐以后添加节的地址
	DWORD NewFileSize = pSecHeaderEnd->PointerToRawData + pSecHeaderEnd->SizeOfRawData; //获取新的申请的文件内存大小
	char* pNewFileBuffer = (char*)malloc(NewFileSize); //重新申请一块大的内存
	if (pNewFileBuffer == NULL) // 判断内存是否生成成功
	{
		printf("缓冲区指针无效\n");
		return FALSE;
	}
	memset(pNewFileBuffer, 0, NewFileSize);
	memcpy(pNewFileBuffer, pDosHeader, (NewFileSize - pSecHeaderEnd->SizeOfRawData));
	PIMAGE_DOS_HEADER pNewDosHeader = (PIMAGE_DOS_HEADER)pNewFileBuffer;
	PIMAGE_NT_HEADERS pNewNTHeader = (PIMAGE_NT_HEADERS)((char*)pNewFileBuffer + pNewDosHeader->e_lfanew); //获取NT头指针
	PIMAGE_FILE_HEADER pNewFileHeader = (PIMAGE_FILE_HEADER)((char*)pNewNTHeader + 4);//获取标准PE头指针
	PIMAGE_OPTIONAL_HEADER pNewOptionHeader = (PIMAGE_OPTIONAL_HEADER)((char*)pNewFileHeader + 20);//获取可选PE头指针
	PIMAGE_SECTION_HEADER pNewSecHeader = (PIMAGE_SECTION_HEADER)((char*)pNewOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取文件节表指针
	pNewSecHeader += pNewFileHeader->NumberOfSections - 1; //指向最后一个节表
	char* pNewSecBuffer = (char*)pNewDosHeader + pNewSecHeader->PointerToRawData;
	DWORD NewShellcodePoint = (DWORD)pNewOptionHeader->ImageBase + (DWORD)pNewSecHeader->VirtualAddress + 0xD;//指向虚拟内存中E8下一条指令地址
	DWORD MessageAddress = (DWORD)0x77D507EA - NewShellcodePoint; //获取E8指令所要的相对地址
	*(DWORD*)(shellcode + 9) = MessageAddress;
	NewShellcodePoint += 0x5; //获取虚拟内存中E9下一条指令地址
	DWORD EnterAdderss = (DWORD)pNewOptionHeader->ImageBase + (DWORD)pNewOptionHeader->AddressOfEntryPoint - (DWORD)NewShellcodePoint; //获取E9所需要虚拟内存相对地址
	*(DWORD*)(shellcode + 14) = EnterAdderss;
	memcpy(pNewSecBuffer, shellcode, sizeof(shellcode)); //将预备shellcode添加至空白区
	pNewOptionHeader->AddressOfEntryPoint = (DWORD)pNewSecHeader->VirtualAddress; //修改程序入口为添加代码处
	FILE* NewFile = fopen(newBuffer, "wb");
	DWORD Success = fwrite(pNewFileBuffer, NewFileSize, 1, NewFile);
	if (!Success)
	{
		printf("存盘失败");
	}
	free(pFileBuffer);
	return TRUE;
}
int main(int argc, char* argv[])
{
	const char* lpszFile = "C:\\Users\\扶摇\\Desktop\\复件 NOTEPAD.exe";
	const char* NewlpszFile = "C:\\Users\\扶摇\\Desktop\\NewNOTEPAD.exe";
	DWORD size = ReadPEFileSize(lpszFile);
	if (!shellcode(NewlpszFile, lpszFile, size))
	{
		printf("注入shellcode失败\n");
	}
	return 0;
}

上述代码利用xp的notepad实现,其节表最后新增节后应再初始化40个0,由于此40个0覆盖了原来存在有效数据,所以程序运行失败。但针对本次练习,该代码没有任何问题

通过上移PE头节表等数据,使上题代码生成程序正常运行

#include<stdio.h>
#include<Windows.h>
#include<string.h>
DWORD ReadPEFileSize(const char* lpszFile) //将一个文件的硬盘内存数据d大小
{
	FILE* pFile = NULL;
	pFile = fopen(lpszFile, "rb");
	DWORD FileSize = 0;
	if (!pFile)
	{
		printf("无法打开EXE文件");
		return 0;
	}
	fseek(pFile, 0, SEEK_END);
	FileSize = ftell(pFile);
	return FileSize;
}
char* ReadPEFile(const char* lpszFile)
{
	FILE* pFile = NULL;
	pFile = fopen(lpszFile, "rb");
	DWORD FileSize = ReadPEFileSize(lpszFile);
	fseek(pFile, 0, SEEK_SET);
	char* pFileBuffer = NULL;
	pFileBuffer = (char*)malloc(sizeof(char) * FileSize);
	if (!pFileBuffer)
	{
		printf("分配空间失败");
		fclose(pFile);
		return 0;
	}
	size_t i = fread(pFileBuffer, FileSize, 1, pFile);
	if (!i)
	{
		printf("读取数据失败!");
		free(pFileBuffer);
		fclose(pFile);
		return 0;
	}
	IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pFileBuffer;
	IMAGE_NT_HEADERS* pNTHeader = (IMAGE_NT_HEADERS*)((char*)pFileBuffer + pDosHeader->e_lfanew); //(char*)pFileBuffer只有此处转换为了char*类型,之后加减是为char的大小为一个单位进行加减
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效MZ标志,结束\n");
		free(pFileBuffer);
		fclose(pFile);
		return 0;
	}
	if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志,打印结束\n");
		free(pFileBuffer);
		pFileBuffer = NULL;
		return 0;
	}
	fclose(pFile);
	return pFileBuffer;
}
BOOL shellcode(const char* newBuffer, const char* lpszFile, DWORD size)
{
	char shellcode[18] = { 0x6A, 0x00, 0x6A, 0x00, 0x6A,0x00, 0x6A, 0x00, 0xE8, 0x00,  0x00,  0x00, 0x00, 0xE9, 0x00, 0x00, 0x00, 0x00 };
	char* pFileBuffer = ReadPEFile(lpszFile); //获取自定义文件内存缓冲区指针
	if (pFileBuffer == NULL)
	{
		printf("缓冲区指针无效\n");
		return FALSE;
	}
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; //获取自定义文件内存缓冲区DOS头指针
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((char*)pFileBuffer + pDosHeader->e_lfanew); //获取NT头指针
	PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((char*)pNTHeader + 4);//获取标准PE头指针
	PIMAGE_OPTIONAL_HEADER pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((char*)pFileHeader + 20);//获取可选PE头指针
	PIMAGE_SECTION_HEADER pSecHeader = (PIMAGE_SECTION_HEADER)((char*)pOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取文件节表指针
	char* flag = (char*)pDosHeader + 64;
	memcpy(flag, (char*)pNTHeader, 4 + 20 + pFileHeader->SizeOfOptionalHeader + pFileHeader->NumberOfSections * 40);
	DWORD memsize = (DWORD)((char*)pDosHeader + pDosHeader->e_lfanew) - (DWORD)((char*)pDosHeader + 64);
	memset((char*)(pSecHeader + pFileHeader->NumberOfSections - 1), 0, memsize);
	pDosHeader->e_lfanew = 64;
	pNTHeader = (PIMAGE_NT_HEADERS)((char*)pDosHeader + pDosHeader->e_lfanew); //获取上移后NT头指针
	pFileHeader = (PIMAGE_FILE_HEADER)((char*)pNTHeader + 4);//获取上移后标准PE头指针
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((char*)pFileHeader + 20);//获取上移后可选PE头指针
	pSecHeader = (PIMAGE_SECTION_HEADER)((char*)pOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取上移后文件节表指针
	if (pOptionHeader->SizeOfHeaders - pDosHeader->e_lfanew - 4 - 20 - pFileHeader->SizeOfOptionalHeader >= 2 * pFileHeader->SizeOfOptionalHeader)
	{
		printf("节表后剩余空间足够添加一个新的节表\n");
	}
	else
	{
		printf("节表后剩余空间不足以添加一个新的节表,结束\n");
		return FALSE;
	}
	PIMAGE_SECTION_HEADER pSecHeaderEnd = (PIMAGE_SECTION_HEADER)((char*)pSecHeader + pFileHeader->NumberOfSections * 40);
	memcpy(pSecHeaderEnd, pSecHeader, 40);
	memset(((char*)pSecHeaderEnd + 40), 0, 40); //此时已经新增了一个节表
	PIMAGE_SECTION_HEADER pSecHeaderLast = (PIMAGE_SECTION_HEADER)((char*)pSecHeader + (pFileHeader->NumberOfSections - 1) * 40);//获取新增节上一个节指针
	pFileHeader->NumberOfSections += 1;
	pOptionHeader->SizeOfImage += pOptionHeader->SectionAlignment;
	strcpy((char*)pSecHeaderEnd->Name, (char*)".shel");
	pSecHeaderEnd->PointerToRawData = pSecHeaderLast->PointerToRawData + pSecHeaderLast->SizeOfRawData;
	char* pSecHeaderEndBuffer = (char*)pDosHeader + pSecHeaderEnd->PointerToRawData;
	pSecHeaderEnd->Misc.VirtualSize = sizeof(shellcode);
	pSecHeaderEnd->SizeOfRawData = pOptionHeader->FileAlignment;
	DWORD Alignment = pOptionHeader->SectionAlignment - pSecHeaderLast->Misc.VirtualSize % pOptionHeader->SectionAlignment;
	pSecHeaderEnd->VirtualAddress = pSecHeaderLast->VirtualAddress + pSecHeaderLast->Misc.VirtualSize + Alignment; //获取上个节对齐以后添加节的地址
	DWORD NewFileSize = pSecHeaderEnd->PointerToRawData + pSecHeaderEnd->SizeOfRawData; //获取新的申请的文件内存大小	char* pFileBuffer = ReadPEFile(lpszFile); //获取自定义文件内存缓冲区指针
	if (pFileBuffer == NULL)
	{
		printf("缓冲区指针无效\n");
		return FALSE;
	}
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; //获取自定义文件内存缓冲区DOS头指针
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((char*)pFileBuffer + pDosHeader->e_lfanew); //获取NT头指针
	PIMAGE_FILE_HEADER pFileHeader = (PIMAGE_FILE_HEADER)((char*)pNTHeader + 4);//获取标准PE头指针
	PIMAGE_OPTIONAL_HEADER pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((char*)pFileHeader + 20);//获取可选PE头指针
	PIMAGE_SECTION_HEADER pSecHeader = (PIMAGE_SECTION_HEADER)((char*)pOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取文件节表指针
	DWORD memsize = (DWORD)((char*)pDosHeader + pDosHeader->e_lfanew) - (DWORD)((char*)pDosHeader + 64);
	pDosHeader->e_lfanew = 64;
	memset((char*)pDosHeader + 64, 0, memsize);
	memcpy((char*)pDosHeader + 64, (char*)pNTHeader, 4 + 20 + pFileHeader->SizeOfOptionalHeader + pFileHeader->NumberOfSections * 40);
	pNTHeader = (PIMAGE_NT_HEADERS)((char*)pDosHeader + pDosHeader->e_lfanew); //获取上移后NT头指针
	pFileHeader = (PIMAGE_FILE_HEADER)((char*)pNTHeader + 4);//获取上移后标准PE头指针
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER)((char*)pFileHeader + 20);//获取上移后可选PE头指针
	pSecHeader = (PIMAGE_SECTION_HEADER)((char*)pOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取上移后文件节表指针
	PIMAGE_SECTION_HEADER pSecHeaderLast = (PIMAGE_SECTION_HEADER)((char*)pSecHeader + (pFileHeader->NumberOfSections - 1) * 40);//获取新增节上一个节指针
	if (pOptionHeader->SizeOfHeaders - pDosHeader->e_lfanew - 4 - 20 - pFileHeader->SizeOfOptionalHeader >= 2 * pFileHeader->SizeOfOptionalHeader)
	{
		printf("节表后剩余空间足够添加一个新的节表\n");
	}
	else
	{
		printf("节表后剩余空间不足以添加一个新的节表,结束\n");
		return FALSE;
	}
	PIMAGE_SECTION_HEADER pSecHeaderEnd = (PIMAGE_SECTION_HEADER)((char*)pSecHeader + pFileHeader->NumberOfSections * 40);
	memcpy(pSecHeaderEnd, pSecHeader, 40);
	memset((char*)pSecHeaderEnd + 40, 0, 40); //此时将节表后初始化40个0,表示节表结束
	pFileHeader->NumberOfSections += 1;
	strcpy((char*)pSecHeaderEnd->Name, (char*)".mov");
	pSecHeaderEnd->PointerToRawData = pSecHeaderLast->PointerToRawData + pSecHeaderLast->SizeOfRawData;
	pSecHeaderEnd->Misc.VirtualSize = 0x2000;
	pSecHeaderEnd->SizeOfRawData = Alige(0x1000, pOptionHeader->FileAlignment);
	pSecHeaderEnd->VirtualAddress = pSecHeaderLast->VirtualAddress + Alige(pSecHeaderLast->Misc.VirtualSize, pOptionHeader->SectionAlignment); //获取上个节对齐以后添加节的地址
	pOptionHeader->SizeOfImage = pOptionHeader->SizeOfImage + Alige(pSecHeaderLast->Misc.VirtualSize, pOptionHeader->SectionAlignment);
	DWORD NewFileSize = pSecHeaderEnd->PointerToRawData + pSecHeaderEnd->SizeOfRawData;
	char* pNewFileBuffer = (char*)malloc(NewFileSize); //重新申请一块大的内存
	if (pNewFileBuffer == NULL) // 判断内存是否生成成功
	{
		printf("缓冲区指针无效\n");
		return FALSE;
	}
	memset(pNewFileBuffer, 0, NewFileSize);
	memcpy(pNewFileBuffer, pDosHeader, (NewFileSize - pSecHeaderEnd->SizeOfRawData));
	PIMAGE_DOS_HEADER pNewDosHeader = (PIMAGE_DOS_HEADER)pNewFileBuffer;
	PIMAGE_NT_HEADERS pNewNTHeader = (PIMAGE_NT_HEADERS)((char*)pNewFileBuffer + pNewDosHeader->e_lfanew); //获取NT头指针
	PIMAGE_FILE_HEADER pNewFileHeader = (PIMAGE_FILE_HEADER)((char*)pNewNTHeader + 4);//获取标准PE头指针
	PIMAGE_OPTIONAL_HEADER pNewOptionHeader = (PIMAGE_OPTIONAL_HEADER)((char*)pNewFileHeader + 20);//获取可选PE头指针
	PIMAGE_SECTION_HEADER pNewSecHeader = (PIMAGE_SECTION_HEADER)((char*)pNewOptionHeader + pFileHeader->SizeOfOptionalHeader); // 获取文件节表指针
	pNewSecHeader += pNewFileHeader->NumberOfSections - 1; //指向最后一个节表
	char* pNewSecBuffer = (char*)pNewDosHeader + pNewSecHeader->PointerToRawData;
	DWORD NewShellcodePoint = (DWORD)pNewOptionHeader->ImageBase + (DWORD)pNewSecHeader->VirtualAddress + 0xD;//指向虚拟内存中E8下一条指令地址
	DWORD MessageAddress = (DWORD)0x77D507EA - NewShellcodePoint; //获取E8指令所要的相对地址
	*(DWORD*)(shellcode + 9) = MessageAddress;
	NewShellcodePoint += 0x5; //获取虚拟内存中E9下一条指令地址
	DWORD EnterAdderss = (DWORD)pNewOptionHeader->ImageBase + (DWORD)pNewOptionHeader->AddressOfEntryPoint - (DWORD)NewShellcodePoint; //获取E9所需要虚拟内存相对地址
	*(DWORD*)(shellcode + 14) = EnterAdderss;
	memcpy(pNewSecBuffer, shellcode, sizeof(shellcode)); //将预备shellcode添加至空白区
	pNewOptionHeader->AddressOfEntryPoint = (DWORD)pNewSecHeader->VirtualAddress; //修改程序入口为添加代码处
	FILE* NewFile = fopen(newBuffer, "wb");
	DWORD Success = fwrite(pNewFileBuffer, NewFileSize, 1, NewFile);
	if (!Success)
	{
		printf("存盘失败");
	}
	free(pFileBuffer);
	return TRUE;
}
int main(int argc, char* argv[])
{
	const char* lpszFile = "C:\\Users\\扶摇\\Desktop\\复件 NOTEPAD.exe";
	const char* NewlpszFile = "C:\\Users\\扶摇\\Desktop\\NewNOTEPAD.exe";
	DWORD size = ReadPEFileSize(lpszFile);
	if (!shellcode(NewlpszFile, lpszFile, size))
	{
		printf("注入shellcode失败\n");
	}
	return 0;
}

经测试,上述代码成功注入shellcode并可正常运行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值