最近想写一个软件壳,需要给PE文件增加一个区段(Section),来执行一些初始化的工作。只要先学习一下PE文件的格式和结构,有个大概了解后,我想就能很容易写出相关代码。网上有很多PE格式的介绍,这里就不多介绍,直入主题。
增加的执行代码有两个地方可以放,一个是现有PE文件区段在数据对齐时有一些空隙,这样的空隙一般只能存放比较小块的代码,优点是对原有的PE文件数据改动比较小,大小也不会改变;另一个就是增加一个新的区段,这样可以放任意你想放置的代码,发挥的空间也大一些。本文的方法是先判断是否有足够的空隙来存放代码,如果没有,就增加一个Section来存放。
下面这张图,详细说明这个过程
相关代码如下,加了简要的注释
#pragma once
#ifdef UNICODE
typedef fstream tfstream;
#else
typedef wfstream twfstream;
#endif // UNICODE
class CPEUtil
{
protected:
vector<char> m_vBuf;
public:
class CHeader
{
public:
CHeader(char* pBase)
{
Reset(pBase);
}
~CHeader()
{
}
void Reset(char* pBase)
{
pDosHeader = (IMAGE_DOS_HEADER*)pBase;
pNTHeader = (IMAGE_NT_HEADERS*)(pBase + pDosHeader->e_lfanew);
pOp = &pNTHeader->OptionalHeader;
}
public:
IMAGE_DOS_HEADER* pDosHeader;
IMAGE_NT_HEADERS* pNTHeader;
IMAGE_OPTIONAL_HEADER* pOp;
};
public:
CPEUtil();
~CPEUtil();
bool Load(LPCTSTR szFile);
bool Save(LPCTSTR szFile);
bool AddCode(byte* pCode, DWORD dwSize);
DWORD Rva2Fva(DWORD dwRva);
DWORD AlignUp(DWORD x, DWORD v);
};
View Code
#include "stdafx.h"
#include "PEUtil.h"
#include <assert.h>
CPEUtil::CPEUtil()
{
}
CPEUtil::~CPEUtil()
{
}
DWORD CPEUtil::AlignUp(DWORD x, DWORD v)
{
if (x%v == 0)
return x;
return x + v - x%v;
}
bool CPEUtil::Load(LPCTSTR szFile)
{
tfstream f(szFile, ios::in | ios::binary);
if (!f.is_open())
return false;
f.seekg(0, ios::end);
m_vBuf.assign(f.tellg(), 0);
f.seekg(0, ios::beg);
f.read(m_vBuf.data(), m_vBuf.size());
f.close();
return true;
}
bool CPEUtil::Save(LPCTSTR szFile)
{
if (m_vBuf.empty())
return false;
tfstream f(szFile, ios::out | ios::binary);
if (!f.is_open())
return false;
f.write(m_vBuf.data(), m_vBuf.size());
f.close();
return true;
}
bool CPEUtil::AddCode(byte * pCode, DWORD dwSize)
{
CHeader h(m_vBuf.data());
DWORD dwBase = 0;
auto pSec = IMAGE_FIRST_SECTION(h.pNTHeader);
if (h.pNTHeader->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
return false;
// 找空隙
for (size_t i = 0; i < h.pNTHeader->FileHeader.NumberOfSections; i++, pSec++)
{
if (pSec->SizeOfRawData > 0 &&
pSec->SizeOfRawData > (pSec->Misc.VirtualSize + dwSize))
{
dwBase = pSec->VirtualAddress + pSec->Misc.VirtualSize;
break;
}
}
if (!dwBase)
{
// 空隙不够大,添加一个新的区段
pSec = IMAGE_FIRST_SECTION(h.pNTHeader) +h.pNTHeader->FileHeader.NumberOfSections;
memset(pSec, 0, sizeof(pSec));
pSec->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE;
strcpy_s((char*)pSec->Name, sizeof(pSec->Name), ".add");
auto pSecPrev = pSec - 1;
pSec->SizeOfRawData = AlignUp(dwSize, h.pOp->FileAlignment);
pSec->PointerToRawData = AlignUp(pSecPrev->PointerToRawData + pSecPrev->SizeOfRawData, h.pOp->FileAlignment);
pSec->VirtualAddress = AlignUp(pSecPrev->VirtualAddress + max(pSecPrev->SizeOfRawData, pSecPrev->Misc.VirtualSize), h.pOp->SectionAlignment);
dwBase = pSec->VirtualAddress;
//
m_vBuf.insert(m_vBuf.end(), pSec->SizeOfRawData, 0);
h.Reset(m_vBuf.data());
pSec = IMAGE_FIRST_SECTION(h.pNTHeader) + h.pNTHeader->FileHeader.NumberOfSections;
h.pNTHeader->FileHeader.NumberOfSections += 1; // 增加一个区段
h.pOp->SizeOfImage += AlignUp(pSec->SizeOfRawData, h.pOp->SectionAlignment); // 修改映象文件大小
}
byte* pWrite = (byte*)(m_vBuf.data() + Rva2Fva(dwBase));
DWORD dwJmp = h.pNTHeader->OptionalHeader.AddressOfEntryPoint - dwBase - dwSize;
memcpy(pWrite, pCode, dwSize-sizeof(DWORD)); // pCode 最后5个字节为 jmp 00000000 (0xe9,0x00,0x00,0x00,0x00),作跳转用
memcpy(pWrite + dwSize - sizeof(DWORD), &dwJmp, sizeof(DWORD));
pSec->Misc.VirtualSize += dwSize;
pSec->Characteristics |= IMAGE_SCN_MEM_EXECUTE;
h.pNTHeader->OptionalHeader.AddressOfEntryPoint = dwBase;
return true;
}
DWORD CPEUtil::Rva2Fva(DWORD dwRva)
{
CHeader h(&m_vBuf[0]);
auto pSec = IMAGE_FIRST_SECTION(h.pNTHeader);
pSec += h.pNTHeader->FileHeader.NumberOfSections-1;
assert(dwRva <= (pSec->VirtualAddress + pSec->SizeOfRawData));
for (size_t i = 0; i < h.pNTHeader->FileHeader.NumberOfSections ; i++, pSec--)
{
if (dwRva >= pSec->VirtualAddress)
return pSec->PointerToRawData + dwRva - pSec->VirtualAddress;
}
return 0;
}
PEUtil.cpp
测试用例:
PETest.rar(加载一个dll,并调用导出函数)
原文链接: https://www.cnblogs.com/qyy1415/p/pe_add_code.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/227562
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!