#include <winnt.h>
#include "stdafx.h"
#include "Globle.h"
#include <windows.h>
#include <malloc.h>
#define FILEPATH_IN "C:/ipmsg.exe"
#define FILEPATH_OUT "C:/ipmsg_new.exe"
#define SHELLCODELENGTH 0X12
//XP //演示的地址
//#define MESSAGEBOXADDR 0X77E5425F
//Win7 //这个宏要看自己机器的地址
#define MESSAGEBOXADDR 0x75BAEA89
//全局变量声明
BYTE shellCode[] =
{
0x6A,00,0x6A,00,0x6A,00,0x6A,00,
0xE8,00,00,00,00,
0XE9,00,00,00,00
};
//
//Construction/Destruction
//
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer)
{
FILE *pFile = NULL;
DWORD fileSize = 0;
LPVOID pTempFileBuffer;
//打开文件
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;
}
//将文件数据读取到缓冲区
size_t n = fread(pTempFileBuffer, fileSize, 1, pFile);
if(!n)
{
printf(" 读取数据失败! \n ");
free(pTempFileBuffer);
return 0;
}
*pFileBuffer = pTempFileBuffer;
pTempFileBuffer = NULL;
fclose(pFile);
return fileSize;
}
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 == NULL)
{
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;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
//可选PE头
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
//第一个节目录指针
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//根据SizeofImage申请新的空间
pTempImageBuffer = malloc(pOptionHeader->SizeOfImage);
if(!pTempImageBuffer)
{
printf(" 分配空间失败! ");
return 0;
}
//初始化新的缓冲区
memset(pTempImageBuffer,0,pOptionHeader->SizeOfImage);
//根据SizeOfHeaders 先copy头
memcpy(pTempImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
//根据节表 循环copy节
PIMAGE_SECTION_HEADER ptempSectionHeader = pSectionHeader;
for(int i=0; i<pPEHeader->NumberOfSections;i++,ptempSectionHeader++)
{
memcpy((void*)((DWORD)pTempImageBuffer + ptempSectionHeader->VirtualAddress),(void*)((DWORD)pDosHeader + ptempSectionHeader->PointerToRawData),ptempSectionHeader->SizeOfRawData);
}
*pImageBuffer = pTempImageBuffer;
pTempImageBuffer = NULL;
return pOptionHeader->SizeOfImage;
}
DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer, OUT LPVOID* pNewFileBuffer)
{
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 sizeOfFile = 0;
DWORD numberOfSection = 0;
if(pImageBuffer == NULL)
{
printf("ImageBuffer缓冲区指针无效");
return 0;
}
//判断是否是有效的MZ标志
if(*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("ImageBuffer中的数据没有有效的MZ标志\n");
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
//判断是否是有效的PE标志
if (*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
{
printf("ImageBuffer中的数据没有有效的PE标志\n");
return 0;
}
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer+pDosHeader->e_lfanew);
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
//可选PE头
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
//第一个节目录指针
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//计算文件需要的空间:最后一个节的文件偏移+节对齐后的长度
numberOfSection = pPEHeader->NumberOfSections;
pSectionHeader = pSectionHeader+(numberOfSection-1);
sizeOfFile = pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData;
//根据SizeOfImage申请新的空间
pTempNewbuffer = malloc(sizeOfFile);
if (!pTempNewbuffer)
{
printf("分配新空间失败!");
return 0;
}
//初始化新的缓冲区
memset(pTempNewbuffer, 0, sizeOfFile);
//根据SizeOfHearders 先Copy头
memcpy(pTempNewbuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
//根据节表 循环copy节
PIMAGE_SECTION_HEADER pTempSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
for (int i=0; i<pPEHeader->NumberOfSections;i++, pTempSectionHeader++)
{ //PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
memcpy((void*)((DWORD)pTempNewbuffer + pTempSectionHeader->PointerToRawData), (void*)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress), pTempSectionHeader->SizeOfRawData);
}
//返回数据
*pNewFileBuffer = pTempNewbuffer; //暂存的数据传给参数后释放
pTempNewbuffer = NULL;
return sizeOfFile; // 返回计算得到的分配内存的大小
}
//****************************************************************************
//MemeryTOFile:将内存中的数据复制到文件
//参数说明:
//pMemBuffer 内存中的数据的指针
//size 要复制的大小
//lpszFile 要存储的文件路径
//返回值说明:
//读取失败返回0 否则返回复制大小
//****************************************************************************
BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile)
{
FILE *fp = NULL;
fp = fopen(lpszFile, "wb");
if(fp == NULL)
{
return FALSE;
}
fwrite(pMemBuffer, size, 1, fp);
fclose(fp);
fp = NULL;
return TRUE;
}
//****************************************************************************
//RvaToFileOffset:将内存变异转换文件偏移
//参数说明:
//pFileBuffer FileBuffer指针
//dwRva RVA的值
//返回值说明
//返回转换后的FOA的值 如果失败返回0
//****************************************************************************
DWORD RavToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva)
{
return 0;
}
//测试函数:打印NT头
VOID TestPrintNTHeaders()
{
}
//测试函数 文件-->FileBuffer-->ImageBuffer-NewBuffer-->存盘
VOID TestPELoader()
{
}
//测试函数:向代码段空闲区添加代码
VOID TestAddCodeInCodeSec()
{
LPVOID pFileBuffer = NULL;
LPVOID pImageBuffer = NULL;
LPVOID pNewBuffer = NULL;
PIMAGE_DOS_HEADER pDosHeader = 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("文件-->缓冲区失败");
return;
}
//FileBuffer-->ImageBuffer
CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
if(!pImageBuffer)
{
printf("FileBuffer-->ImageBuffer");
free(pFileBuffer);
return;
}
//判断代码段空闲区是否足够存储ShellCode代码
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_NT_OPTIONAL32_HEADER);
if(((pSectionHeader->SizeOfRawData) - (pSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH)
{
printf("代码区空间不够");
free(pFileBuffer);
free(pImageBuffer);
}
//将代码复制到空闲区
codeBegin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);
memcpy(codeBegin,shellCode,SHELLCODELENGTH);
//修正E8
DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader->ImageBase+((DWORD)(codeBegin+0xD) - (DWORD)pImageBuffer)));
*(PDWORD)(codeBegin+9) = callAddr;
//修改E9
DWORD jmpAddr = ((pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint) - (pOptionHeader->ImageBase + ((DWORD)codeBegin+SHELLCODELENGTH- (DWORD)pImageBuffer)));
*(PDWORD)(codeBegin + 0xE) = jmpAddr;
//修改OEP
pOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pImageBuffer;
//ImageBuffer-NewBuffer
size = CopyImageBufferToNewBuffer(pImageBuffer,&pNewBuffer);
if(size==0 || !pNewBuffer)
{
printf("ImageBuffer-->NewBuffer失败");
free(pFileBuffer);
free(pImageBuffer);
return;
}
//NewBuffer-->文件
isOK = MemeryTOFile(pNewBuffer,size,FILEPATH_OUT);
if(isOK)
{
printf("存盘成功");
free(pFileBuffer);
free(pImageBuffer);
free(pNewBuffer);
return;
}
}
//测试函数 向数据段空白闲添加代码
VOID TestAddCodeInExpSec()
{
}
//测试函数:打印目录项
VOID TestPrintDricetory()
{
}
//测试函数:打印输出表
VOID TestPrintExport()
{
}
//测试函数:通过函数名获得地址 成功返回函数RVA 失败返回0
DWORD TestGetFunctionAddrByName(PSTR pszFunctionName)
{
return 0;
}
#if !defined(AFX_GLOBLE_H__6E197AFF_5DAE_4435_99CC_3760AFDFB99E__INCLUDED_)
#define AFX_GLOBLE_H__6E197AFF_5DAE_4435_99CC_3760AFDFB99E__INCLUDED_
#include <windows.h>
//全局变量声明
extern BYTE shellcode[];
//函数声明
//****************************************************************************
//ReadPEFile:将文件读取到缓冲区
//参数说明:
//lpszFile 文件路径
//pFileBuffer 缓冲区指针
//返回值说明
//读取失败返回0 否则返回实际读取的大小
//****************************************************************************
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer);
//****************************************************************************
//CopyFileBufferToImageBuffer:将文件从FileBuffer复制到ImageBuffer
//参数说明:
//pFileBuffer FileBuffer指针
//pImageBuffer ImageBuffer指针
//返回值说明:
//读取失败返回0 否则返回复制的大小
//****************************************************************************
DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer);
//CopyImageBuffertoNewBuffer:将ImageBuffer中的数据复制到新的缓冲区
//参数说明:
//PImageBuffer ImageBuffer指针
//pNewBuffer NewBuffer指针
//返回值说明:
//读取失败返回0 否则返回复制的大小
//****************************************************************************
DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer);
//****************************************************************************
//MemeryTOFile:将内存中的数据复制到文件
//参数说明:
//pMemBuffer 内存中的数据的指针
//size 要复制的大小
//lpszFile 要存储的文件路径
//返回值说明:
//读取失败返回0 否则返回复制大小
//****************************************************************************
BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile);
//****************************************************************************
//RvaToFileOffset:将内存变异转换文件偏移
//参数说明:
//pFileBuffer FileBuffer指针
//dwRva RVA的值
//返回值说明
//返回转换后的FOA的值 如果失败返回0
//****************************************************************************
DWORD RavToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva);
//测试函数:打印NT头
VOID TestPrintNTHeaders();
//测试函数 文件-->FileBuffer-->ImageBuffer-NewBuffer-->存盘
VOID TestPELoader();
//测试函数:向代码段空闲区添加代码
VOID TestAddCodeInCodeSec();
//测试函数 向数据段空白闲添加代码
VOID TestAddCodeInExpSec();
//测试函数:打印目录项
VOID TestPrintDricetory();
//测试函数:打印输出表
VOID TestPrintExport();
//测试函数:通过函数名获得地址 成功返回函数RVA 失败返回0
DWORD TestGetFunctionAddrByName(PSTR pszFunctionName);
#endif //
// PETool.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Globle.h"
int main(int argc, char* argv[])
{
//
//
TestAddCodeInCodeSec();
printf("Hello World!\n");
return 0;
}