?
/*
添加任意代码到代码区
1、定义变量(PE文件各部分指针以及文件各状态指针)
2、判断传进来的缓冲区地址是否正确
3、判断是否遵守PE格式
4、获取DOS头、NT头、标准PE头、可选PE头、第一个节表信息
5、判断空间是否足够写入代码
6、将代码复制到空闲区
7、修正代码
8、ImageBuffer-->NewBuffer(CopyImageBufferToNewBuffer())
9、NewBuffer-->File(MemeryToFile())
10、释放内存(pFileBuffer,pImageBuffer,pNewBuffer)
*/
VOID TestAddCodeInCodeSec()
{
LPVOID pFileBuffer = NULL;
LPVOID pImageBuffer = NULL;
LPVOID pNewBuffer = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PBYTE CodeBegin = NULL;
BOOL isOK = FALSE;
DWORD size = 0;
//File-->FileBuffer
ReadPEFile(FILEPATH_IN,&pFileBuffer);
if (!pFileBuffer)
{
printf("File-->FileBuffer错误!");
return ;
}
//FileBuffer-->ImageBuffer
CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
if (!pImageBuffer)
{
printf("FileBuffer-->ImageBuffer错误!");
free(pFileBuffer);
return ;
}
//获取DOS头
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
//判断DOS头是否是可执行的文件
if(*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE标志\n");
return ;
}
//NT头地址
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
//标准PE头地址
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 0x04);
//可选PE头地址
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一个节表地址
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//判断代码段空闲区是否足够存储ShellCode代码
int tempDiffer = (pSectionHeader->SizeOfRawData) - (pSectionHeader->Misc.VirtualSize);
if (tempDiffer < SHELLCODELENGTH)
{
printf("代码区空闲空间不足!");
free(pFileBuffer);
free(pImageBuffer);
return ;
}
//将代码复制到空闲区
CodeBegin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);
memcpy(CodeBegin,ShellCode,SHELLCODELENGTH);
//(E8/E9)修正的地址(X) = 真正要跳转的地址 - (E8/E9)这条指令的下一行地址
DWORD CallAddr = MESSAGEBOXADDR
- (pOptionHeader->ImageBase + ((DWORD)(CodeBegin + 0x0D) - (DWORD)pImageBuffer));
/*真正要跳转的地址:MESSAGEBOXADDR,((DWORD)(CodeBegin + 0x0D)-(DWORD)pImageBuffer)是在ImageBuffer中的偏移地址,
E8这条指令的下一行地址:(pOptionHeader->ImageBase + ((DWORD)(CodeBegin + 0x0D)-(DWORD)pImageBuffer))*/
*(PDWORD)(CodeBegin+0x09) = CallAddr;
DWORD JmpAddr = (pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint)
- (pOptionHeader->ImageBase + ((DWORD)CodeBegin + SHELLCODELENGTH - (DWORD)pImageBuffer));
*(PDWORD)(CodeBegin+0x0E) = JmpAddr;
//修改OEP
pOptionHeader->AddressOfEntryPoint = (DWORD)CodeBegin - (DWORD)pImageBuffer;
//ImageBuffer-->NewBuffer
size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewBuffer);
if (size == 0 || !pNewBuffer)
{
printf("ImageBuffer-->FileBuffer错误!");
free(pFileBuffer);
free(pImageBuffer);
return ;
}
//NewBuffer-->File
isOK = MemeryToFile(pNewBuffer,size,FILEPATH_OUT);
if (isOK)
{
printf("successfully!");
return ;
}
//释放内存
free(pFileBuffer);
free(pImageBuffer);
free(pNewBuffer);
}
#include "stdafx.h"
#include <stdlib.h>
#include <windows.h>
//读取文件的路径
#define FILEPATH_IN "C:\\WINDOWS\\system32\\notepad.exe"
//写入文件的路径
#define FILEPATH_OUT "C:\\notepad1.exe"
#define SHELLCODELENGTH 0x12
#define MESSAGEBOXADDR 0x77D507EA
BYTE ShellCode[] =
{
0x6A,00,0x6A,00,0x6A,00,0x6A,00,
0xE8,00,00,00,00,
0xE9,00,00,00,00,
};
/*
File -> FileBuffer
1、定义变量(文件指针,文件大小,缓冲区首地址)
2、读取文件,并判断是否读取成功(if语句)
3、读取文件大小(ftell()+fseek())
4、分配缓冲区(malloc())
5、初始化缓冲区(memset())
6、将文件数据读取到缓冲区(fread())
7、关闭文件,并返回实际读取的大小,输出缓冲区首地址(fclose(pFile)+fileSize+pFileBuffer)
*/
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer)
{
FILE *pFile = NULL;
DWORD fileSize = 0; //文件大小
LPVOID pTempFileBuffer = NULL;//缓冲区首地址
pFile = fopen(lpszFile, "rb");//打开文件
if(!pFile)
{
printf("无法打开EXE文件! ");
return 0;
}
//读取文件大小
fseek(pFile, 0, SEEK_END); //将指针从开始的位置移动到末尾
fileSize = ftell(pFile); //获取数据大小
fseek(pFile, 0, SEEK_SET);
//分配缓冲区(申请内存)
pTempFileBuffer = malloc(fileSize);
if(!pTempFileBuffer)
{
printf(" 分配空间失败! ");
fclose(pFile);
return 0;
}
//初始化缓冲区
memset(pTempFileBuffer, 0 , fileSize);
//将文件数据读取到缓冲区
size_t n = fread(pTempFileBuffer, fileSize, 1, pFile); //将数据读取到缓冲区中
if(!n)
{
printf(" 读取数据失败! ");
free(pTempFileBuffer); //释放内存
fclose(pFile); //关闭文件
return 0;
}
*pFileBuffer = pTempFileBuffer;
//关闭文件
pTempFileBuffer = NULL;
fclose(pFile);
return fileSize;
}
/*
FileBuffer -> ImageBuffer
将缓冲区的文件进行拉伸
1、定义变量(PE文件各部分指针)
2、判断传进来的缓冲区地址是否正确(pFileBuffer)
3、判断是否遵守PE格式(IMAGE_DOS_SIGNATURE)
4、获取DOS头、NT头、标准PE头、可选PE头、第一个节表信息的指针(pDosHeader,pNTHeader,pPEHeader,pOptionHeader,pSectionHeader)
5、分配缓冲区(malloc())
6、初始化缓冲区(memset())
7、根据 SizeOfHeaders,先拷贝PE头(memcpy())
8、根据节表,循环拷贝节(for循环)
9、将拉伸后的数据首地址传出(*pImageBuffer)
*/
DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer)
{
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
LPVOID pTempImageBuffer = NULL;
//判断传入的值是否有效
if(!pFileBuffer)
{
printf("分配空间失败!");
return 0;
}
//判断是否为有效的MZ头
if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("不是有效的MZ头\n");
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
//判断是否为有效的PE标志
if(*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE标志\n");
return 0;
}
//NT头地址
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
//标准PE头地址
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 0x04);
//可选PE头地址
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一个节表地址
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + (pPEHeader->SizeOfOptionalHeader));
//申请缓冲区大小
pTempImageBuffer = malloc(pOptionHeader->SizeOfImage);
if(!pTempImageBuffer)
{
printf("分配空间失败");
return 0;
}
//初始化缓冲区
memset(pTempImageBuffer,0,pOptionHeader->SizeOfImage);
//根据 SizeOfHeaders,先拷贝头
memcpy(pTempImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
//根据节表,循环拷贝节
PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
for(int i=0;i<pPEHeader->NumberOfSections;i++)
{
memcpy((void*)((DWORD)pTempImageBuffer + pTempSectionHeader->VirtualAddress),
(void*)((DWORD)pFileBuffer + pTempSectionHeader->PointerToRawData),
pTempSectionHeader->SizeOfRawData);
pTempSectionHeader++;
}
//返回数据
*pImageBuffer = pTempImageBuffer;
pTempImageBuffer = NULL;
return pOptionHeader->SizeOfImage;
}
/*
ImageBuffer -> NewBuffer
1、定义变量(PE文件各部分指针)
2、判断传进来的缓冲区地址是否正确
3、判断是否遵守PE格式
4、获取DOS头、NT头、标准PE头、可选PE头、第一个节表信息
5、申请缓冲区大小(malloc())
6、初始化缓冲区(memset())
7、根据 SizeOfHeaders(DOS头+NT头+节表的大小),先拷贝PE头
8、根据节表,循环拷贝节
9、将新的数据后的数据首地址传出,并返回大小(return FileSize)
*/
DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer)
{
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
LPVOID pTempNewBuffer = NULL;
DWORD FileSize = NULL;
//判断传进来的缓冲区地址是否正确
if(!pImageBuffer)
{
printf("分配空间失败!");
return 0;
}
//判断是否遵守PE格式
if(*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("不是有效的MZ头\n");
return 0;
}
//获取DOS头
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
//判断DOS头是否是可执行的文件
if(*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE标志\n");
return 0;
}
//NT头地址
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
//标准PE头地址
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 0x04);
//可选PE头地址
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一个节表地址
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//申请缓冲区大小
FileSize = pOptionHeader->SizeOfImage;
pTempNewBuffer = malloc(FileSize);
if(!pTempNewBuffer)
{
printf("分配空间失败");
return 0;
}
//初始化缓冲区
memset(pTempNewBuffer,0,FileSize);
//根据节表,循环拷贝节
memcpy(pTempNewBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
for(int i=0;i<pPEHeader->NumberOfSections;i++)
{
memcpy((void*)((DWORD)pTempNewBuffer + pTempSectionHeader->PointerToRawData),
(void*)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress),
pTempSectionHeader->SizeOfRawData);
pTempSectionHeader++;
}
*pNewBuffer = pTempNewBuffer;
pTempNewBuffer = NULL;
return FileSize;
}
/*
存盘
1、定义变量(文件指针)
2、打开文件(fopen())
3、判断文件指针是否有效
4、文件写入(fwrite())
5、释放空间,存盘成功返回值TRUE
*/
BOOL MemeryToFile(IN LPVOID pMemBuffer,size_t size,LPSTR lpszFile)
{
//定义文件指针
FILE *fp = NULL;
//打开文件,文件使用方式为读写
fp = fopen(lpszFile, "wb+");
//判断指针是否有效
if (fp == NULL)
{
return FALSE;
}
//写入:将lpszFile(起始路径)中的文件写到pMemBuffer(目标路径)中去
fwrite(pMemBuffer, size, 1, fp);
//关闭文件
fclose(fp);
fp = NULL;
return TRUE;
}
/*
添加任意代码到代码区
1、定义变量(PE文件各部分指针以及文件各状态指针)
2、判断传进来的缓冲区地址是否正确
3、判断是否遵守PE格式
4、获取DOS头、NT头、标准PE头、可选PE头、第一个节表信息
5、判断空间是否足够写入代码
6、将代码复制到空闲区
7、修正代码
8、ImageBuffer-->NewBuffer(CopyImageBufferToNewBuffer())
9、NewBuffer-->File(MemeryToFile())
10、释放内存(pFileBuffer,pImageBuffer,pNewBuffer)
*/
VOID TestAddCodeInCodeSec()
{
LPVOID pFileBuffer = NULL;
LPVOID pImageBuffer = NULL;
LPVOID pNewBuffer = NULL;
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PBYTE CodeBegin = NULL;
BOOL isOK = FALSE;
DWORD size = 0;
//File-->FileBuffer
ReadPEFile(FILEPATH_IN,&pFileBuffer);
if (!pFileBuffer)
{
printf("File-->FileBuffer错误!");
return ;
}
//FileBuffer-->ImageBuffer
CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
if (!pImageBuffer)
{
printf("FileBuffer-->ImageBuffer错误!");
free(pFileBuffer);
return ;
}
//获取DOS头
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
//判断DOS头是否是可执行的文件
if(*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE标志\n");
return ;
}
//NT头地址
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
//标准PE头地址
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 0x04);
//可选PE头地址
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//第一个节表地址
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//判断代码段空闲区是否足够存储ShellCode代码
int tempDiffer = (pSectionHeader->SizeOfRawData) - (pSectionHeader->Misc.VirtualSize);
if (tempDiffer < SHELLCODELENGTH)
{
printf("代码区空闲空间不足!");
free(pFileBuffer);
free(pImageBuffer);
return ;
}
//将代码复制到空闲区
CodeBegin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);
memcpy(CodeBegin,ShellCode,SHELLCODELENGTH);
//(E8/E9)修正的地址(X) = 真正要跳转的地址 - (E8/E9)这条指令的下一行地址
DWORD CallAddr = MESSAGEBOXADDR
- (pOptionHeader->ImageBase + ((DWORD)(CodeBegin + 0x0D) - (DWORD)pImageBuffer));
/*真正要跳转的地址:MESSAGEBOXADDR,((DWORD)(CodeBegin + 0x0D)-(DWORD)pImageBuffer)是在ImageBuffer中的偏移地址,
E8这条指令的下一行地址:(pOptionHeader->ImageBase + ((DWORD)(CodeBegin + 0x0D)-(DWORD)pImageBuffer))*/
*(PDWORD)(CodeBegin+0x09) = CallAddr;
DWORD JmpAddr = (pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint)
- (pOptionHeader->ImageBase + ((DWORD)CodeBegin + SHELLCODELENGTH - (DWORD)pImageBuffer));
*(PDWORD)(CodeBegin+0x0E) = JmpAddr;
//修改OEP
pOptionHeader->AddressOfEntryPoint = (DWORD)CodeBegin - (DWORD)pImageBuffer;
//ImageBuffer-->NewBuffer
size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewBuffer);
if (size == 0 || !pNewBuffer)
{
printf("ImageBuffer-->FileBuffer错误!");
free(pFileBuffer);
free(pImageBuffer);
return ;
}
//NewBuffer-->File
isOK = MemeryToFile(pNewBuffer,size,FILEPATH_OUT);
if (isOK)
{
printf("successfully!");
return ;
}
//释放内存
free(pFileBuffer);
free(pImageBuffer);
free(pNewBuffer);
}
int main()
{
TestAddCodeInCodeSec();
return 0;
}
?