http://ift.tt/2AAEutK
// 手动加壳demo.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
#include <string.h>
typedef struct _StubConf
{
IMAGE_NT_HEADERS ntheader;
}STUBCONF;
class PeFile
{
public:
PeFile();
~PeFile();
bool OpenFile(const char*FilePath);
bool InitHdrs();
PIMAGE_SECTION_HEADER addSection(const char * secName, DWORD dwSecSzie);
PIMAGE_SECTION_HEADER getSection(const char* secName);
DWORD Size2ALi(DWORD dwSize, DWORD dwALi);
void peclose();
void setOpe(DWORD newOep);
LPVOID peGetProcAddress(const char* szFnName);
DWORD RVATOOFFSET(DWORD rva);
ULONG_PTR getfileBuff();
PIMAGE_NT_HEADERS getNtHeader();
PIMAGE_OPTIONAL_HEADER getOptionHeader();
void fixStubReloc(DWORD oldImageBase,
DWORD newImageBase,
DWORD oldSectionRva,
DWORD newSectionRva);
void setSecData(IMAGE_SECTION_HEADER* pScn, void* pSectionData, DWORD dwSectionSize);
bool saveas(const char *filepath);
private:
PIMAGE_DOS_HEADER m_pDosHdr;
PIMAGE_NT_HEADERS m_pNtHdr;
PIMAGE_OPTIONAL_HEADER m_pOpHdr;
PIMAGE_FILE_HEADER m_pFileHdr;
PIMAGE_SECTION_HEADER m_pFirSecHdr;
DWORD m_dwFile;
DWORD m_FileSize;
char* m_FileBuff;
};
PeFile::PeFile()
{
m_FileBuff = NULL;
}
PeFile::~PeFile()
{
peclose();
}
bool PeFile::OpenFile(const char*FilePath)
{
HANDLE hFile = CreateFileA(FilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("文件不存在");
CloseHandle(hFile);
return false;
}
DWORD dwHigh = 0;
m_FileSize = GetFileSize(hFile, &dwHigh);
m_FileBuff = new char[m_FileSize] {};
DWORD dwRealy = 0;
ReadFile(hFile, m_FileBuff, m_FileSize, &dwRealy, NULL);
CloseHandle(hFile);
if (dwRealy == m_FileSize)
{
printf("打开%s成功\n", FilePath);
}
return true;
}
bool PeFile::InitHdrs()
{
m_pDosHdr = (PIMAGE_DOS_HEADER)m_FileBuff;
if (m_pDosHdr->e_magic!=IMAGE_DOS_SIGNATURE)
{
printf("不是有效的PE文件\n");
return false;
}
m_pNtHdr =(PIMAGE_NT_HEADERS) (m_pDosHdr->e_lfanew + (ULONG_PTR)m_pDosHdr);
if (m_pNtHdr->Signature!=IMAGE_NT_SIGNATURE)
{
printf("不是有效的PE文件\n");
return false;
}
m_pFileHdr = (PIMAGE_FILE_HEADER)&m_pNtHdr->FileHeader;
m_pOpHdr = (PIMAGE_OPTIONAL_HEADER)&m_pNtHdr->OptionalHeader;
//然后是第一区段头
m_pFirSecHdr = IMAGE_FIRST_SECTION(m_pNtHdr);
return true;
}
//增加区段
PIMAGE_SECTION_HEADER PeFile::addSection(const char * secName, DWORD dwSecSzie)
{
DWORD dwNowNumbersOfSec = m_pFileHdr->NumberOfSections;
if (dwNowNumbersOfSec>=13)
{
return NULL;
}
if (m_FileBuff==NULL)
{
return NULL;
}
//对区段进行更改
PIMAGE_SECTION_HEADER pNewSec, pOldSec;
pOldSec = m_pFirSecHdr+ dwNowNumbersOfSec-1;
pNewSec = m_pFirSecHdr + dwNowNumbersOfSec;
//首先设置名字
memcpy(pNewSec->Name, secName, 8);
//然后就是设置各种大小
//需要设置virtualsize
//sizefoRawData
//virtualaddress
//PointerToRawData
//SizeOfImage
//文件的大小
//修改charactristics
//区段的个数
//
pNewSec->Misc.VirtualSize = dwSecSzie;
pNewSec->SizeOfRawData = Size2ALi(dwSecSzie, m_pOpHdr->FileAlignment);
//Pointer2RawData 肯定是上一个区段的P2RD+SORD
pNewSec->PointerToRawData = pOldSec->PointerToRawData + pOldSec->SizeOfRawData;
//virtuallAddress
//是上一个区段的地址加上对其后的大小
pNewSec->VirtualAddress = pOldSec->VirtualAddress + Size2ALi(pOldSec->SizeOfRawData, m_pOpHdr->SectionAlignment);
//
pNewSec->Characteristics = 0xE0000060;//默认设置为REW属性
++m_pFileHdr->NumberOfSections;
//设置映像的大小
m_pOpHdr->SizeOfImage = pNewSec->VirtualAddress + pNewSec->SizeOfRawData;
//扩充pe文件缓冲区
char *pNewBuff = new char[m_FileSize + pNewSec->SizeOfRawData]{};
memcpy(pNewBuff, m_FileBuff, m_FileSize);
delete[] m_FileBuff;
m_FileBuff = pNewBuff;
//重新初始化头部
InitHdrs();
//然后找到这个区段
pNewSec = m_pFirSecHdr + m_pFileHdr->NumberOfSections - 1;
//增加文件大小
m_FileSize += pNewSec->SizeOfRawData;
return pNewSec;
}
PIMAGE_SECTION_HEADER PeFile::getSection(const char* secName)
{
PIMAGE_SECTION_HEADER pSec = m_pFirSecHdr;
for (DWORD i = 0;i<m_pFileHdr->NumberOfSections;i++)
{
char szname[10] = {};
memcpy(szname, pSec->Name, 8);
szname[8] = 0;
if (strcmp(szname,secName)==0)
{
//说明找到了
return pSec;
}
pSec++;
}
return NULL;
}
DWORD PeFile::Size2ALi(DWORD dwSize, DWORD dwALi)
{
if (dwSize%dwALi==0)
{
return dwSize;
}
return (dwSize / dwALi + 1)*dwALi;
}
void PeFile::peclose()
{
if (m_FileBuff != NULL)
{
delete m_FileBuff;
m_FileBuff = NULL;
}
}
void PeFile::setOpe(DWORD newOep)
{
m_pOpHdr->AddressOfEntryPoint = newOep;
}
//遍历导出表
LPVOID PeFile::peGetProcAddress(const char* szFnName)
{
//遍历导出表
PIMAGE_EXPORT_DIRECTORY pExpDir =NULL;
pExpDir = (PIMAGE_EXPORT_DIRECTORY)(RVATOOFFSET(m_pOpHdr->DataDirectory[0].VirtualAddress) + (ULONG_PTR)m_pDosHdr);
//然后开始遍历导出表
char* pName = NULL;
DWORD * pEnt = (DWORD*)(RVATOOFFSET(pExpDir->AddressOfNames)+(ULONG_PTR)m_pDosHdr);
for (DWORD i =0;i<pExpDir->NumberOfNames;i++)
{
pName = (char*)(RVATOOFFSET(pEnt[i]) + (ULONG_PTR)m_pDosHdr);
if (strcmp(pName, szFnName)==0)
{
//说明找到名字了
//开始找导入名称序号表
WORD * pEot = (WORD*)(RVATOOFFSET(pExpDir->AddressOfNameOrdinals) + (ULONG_PTR)m_pDosHdr);
int or = pEot[i];
//然后找到地址
DWORD * pEat = (DWORD*)(RVATOOFFSET(pExpDir->AddressOfFunctions) + (ULONG_PTR)m_pDosHdr);
return (LPVOID)pEat[or];
}
}
return NULL;
}
DWORD PeFile::RVATOOFFSET(DWORD rva)
{
IMAGE_SECTION_HEADER* pScnHdr;
pScnHdr = m_pFirSecHdr;
for (int i = 0; i < m_pFileHdr->NumberOfSections; ++i) {
if (rva >= pScnHdr[i].VirtualAddress
&& rva < pScnHdr[i].VirtualAddress + pScnHdr[i].SizeOfRawData) {
return rva - pScnHdr[i].VirtualAddress + pScnHdr[i].PointerToRawData;
}
}
return -1;
}
ULONG_PTR PeFile::getfileBuff()
{
return (ULONG_PTR)m_FileBuff;
}
PIMAGE_NT_HEADERS PeFile::getNtHeader()
{
return m_pNtHdr;
}
PIMAGE_OPTIONAL_HEADER PeFile::getOptionHeader()
{
return m_pOpHdr;
}
void PeFile::fixStubReloc(DWORD oldImageBase, DWORD newImageBase, DWORD oldSectionRva, DWORD newSectionRva)
{
//
// 修复stub部分的重定位数据
// 地址是三段式的, 由 加载基址 + 段首RVA + 段内偏移
// stub是一个dll,它的代码要从dll中移植到exe中,默认加载基址发生了改变
// 然后stub将被当成一个新区段被移植到exe中的新区段中,段首RVA也发生了
// 改变, 因此 , 需要将那些使用了VA地址的代码修正.
// 那些使用了VA地址的代码的地址都被保存到了重定位表中
// 修复的过程,就相当于遍历重定位表,将重定位项修正.
//
IMAGE_BASE_RELOCATION* pRelTab;
pRelTab = (IMAGE_BASE_RELOCATION*)
(RVATOOFFSET(m_pOpHdr->DataDirectory[5].VirtualAddress) + getfileBuff());
/*!
* \brief 重定位块的偏移结构
*/
struct TypeOffset {
WORD Offset : 12; // (1) 大小为12Bit的重定位偏移
WORD Type : 4; // (2) 大小为4Bit的重定位信息类型值
};
while (pRelTab->SizeOfBlock != 0) {
TypeOffset* tofs;
DWORD count;
count = (pRelTab->SizeOfBlock - 8) / 2;
tofs = (TypeOffset*)(pRelTab + 1);
for (DWORD i = 0; i < count; ++i) {
if (tofs[i].Type == 3) {
SIZE_T* pFixVa = (SIZE_T*)(RVATOOFFSET(tofs[i].Offset + pRelTab->VirtualAddress) + getfileBuff());
// 替换加载基址
*pFixVa -= oldImageBase; // 默认加载基址
*pFixVa += newImageBase; // 新的加载基址
// 替换段首RVA
*pFixVa -= oldSectionRva; // 旧的区段段首RVA
*pFixVa += newSectionRva; // 新的区段段首RVA
}
}
// 找到下一个重定位块
pRelTab = (IMAGE_BASE_RELOCATION*)
((SIZE_T)pRelTab + pRelTab->SizeOfBlock);
}
}
void PeFile::setSecData(IMAGE_SECTION_HEADER* pScn, void* pSectionData, DWORD dwSectionSize)
{
memcpy(m_FileBuff + pScn->PointerToRawData,
pSectionData,
dwSectionSize);
}
bool PeFile::saveas(const char *filepath)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
hFile = CreateFileA(filepath,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("文件不存在");
return false;
}
DWORD size;
WriteFile(hFile, m_FileBuff, m_FileSize, &size, NULL);
CloseHandle(hFile);
return true;
}
int main()
{
printf("输入加壳程序的路径:");
char path[MAX_PATH] = {};
gets_s(path, MAX_PATH);
PeFile pePacked;
PeFile peStub;
pePacked.OpenFile(path);
if (!peStub.OpenFile("stub.dll"))
{
printf("打开stub dll 失败\n");
system("pasue");
return -1;
}
if (!pePacked.InitHdrs())
{
system("pause");
return -1;
}
if (!peStub.InitHdrs())
{
system("pause");
return -1;
}
PIMAGE_SECTION_HEADER pStubSec = peStub.getSection(".text");
if (pStubSec==NULL)
{
printf("获取stub 的 .text段失败\n");
system("pause");
return -1;
}
//然后就是对区段进行增加
PIMAGE_SECTION_HEADER pNewSec = pePacked.addSection("demo", pStubSec->SizeOfRawData);
if (pNewSec ==NULL)
{
printf("添加区段失败\n");
system("pause");
return -1;
}
//对区段增加玩之后,就是吧stub的text段中的数据全部拷贝的新的区段中
//但是在拷贝前,还需要做
/*
更改oep
" 拷贝数据
保存文件
*/
STUBCONF *pSutbConf = NULL;
DWORD dwStubConfRva =(DWORD) peStub.peGetProcAddress("g_StubConf");
if (dwStubConfRva == 0)
{
printf("g_StubConf 查找失败\n");
system("pause");
return -1;
}
pSutbConf = (STUBCONF*)(peStub.RVATOOFFSET(dwStubConfRva) + peStub.getfileBuff());
//对结构体进行赋值
pSutbConf->ntheader = *pePacked.getNtHeader();
//然后就是获取stub的入口函数
DWORD dwNewOep = (DWORD)peStub.peGetProcAddress("GetStart");
dwNewOep -= pStubSec->VirtualAddress;
dwNewOep += pNewSec->VirtualAddress;
pePacked.setOpe(dwNewOep);
//去除被加壳程序的重定位项
pePacked.getOptionHeader()->DllCharacteristics &= (~0x40);
//修复重定位项
peStub.fixStubReloc(peStub.getOptionHeader()->ImageBase,
pePacked.getOptionHeader()->ImageBase,
pStubSec->VirtualAddress,
pNewSec->VirtualAddress);
//拷贝stub.dll的代码段到被加壳程序的新区段中
pePacked.setSecData(pNewSec, (void*)(pStubSec->PointerToRawData + peStub.getfileBuff()),
pStubSec->SizeOfRawData);
pePacked.saveas("ergouzi.exe");
pePacked.peclose();
system("pause");
return 0;
}
The post 手工加壳Demo- C++Version appeared first on cole.
http://ift.tt/eA8V8J reverse engineering, pack, shell pack December 06, 2017 at 01:36PM
评论
发表评论