脱壳与加壳-加壳-4-修复dll文件的重定位表
1 先将一个dll文件load到内存,然后找到dll文件的第一个区段也就是我们的代码段加数据段也就是壳代码
2 然后将这个dll的第一个区段复制到加壳程序的最后一个区段
3 由于ImageBase发生变化 需要修复重定位表,要修复重定位表就得获取重定位表的信息,两种方案:1 读取未加入到内存的dll文件 拿到重定位表信息 2 拿到载入到内存当中的dll文件重定位表信息
4 拿到重定位表容易,但是修复比较困难,因为要修复的是在FileBuff中的重定位表
修复重定位表
代码实现
//exe.cpp
#include"Exe.h"
CPeUtil::CPeUtil()
{
FileBuff = NULL;
pDosHeader = NULL;
pNtHeader = NULL;
pOptionHeader = NULL;
pFileHeader = NULL;
}
CPeUtil::~CPeUtil()
{
if (FileBuff)
{
delete[] FileBuff;
}
}
BOOL CPeUtil::LoadFile(const char* path)
{
//打开文件,获得文件句柄
HANDLE hFile = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//获得文件大小
FileSize = GetFileSize(hFile, 0);
//给FileBuff开辟空间来存储文件内容
FileBuff = new char[FileSize];
//读取文件到缓冲区
DWORD RealRead = 0;
BOOL IfSuccess = ReadFile(hFile, FileBuff, FileSize, &RealRead, NULL);
if (IfSuccess == FALSE)
{
MessageBoxA(0, "打开文件失败", "报错", MB_OK);
return FALSE;
}
CloseHandle(hFile);
return TRUE;
}
BOOL CPeUtil::InitFileInfo()
{
pDosHeader = (PIMAGE_DOS_HEADER)FileBuff;
pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + FileBuff);
pFileHeader = &pNtHeader->FileHeader;
pOptionHeader = &pNtHeader->OptionalHeader;
return 0;
}
DWORD CPeUtil::GetAlignSize(DWORD RealSize, DWORD AlignSize)
{
if (RealSize % AlignSize == 0)
{
return RealSize;
}
else
{
return (RealSize / AlignSize + 1) * AlignSize;
}
}
PIMAGE_SECTION_HEADER CPeUtil::GetLastSection()
{
PIMAGE_SECTION_HEADER FirstSection = IMAGE_FIRST_SECTION(pNtHeader);
FirstSection = FirstSection + pFileHeader->NumberOfSections - 1;
return FirstSection;
}
BOOL CPeUtil::SaveFile(const char* path)
{
HANDLE hFile = CreateFileA(path, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD RealInput = 0;
BOOL ret = WriteFile(hFile, FileBuff, FileSize, &RealInput, NULL);
CloseHandle(hFile);
return TRUE;
}
BOOL CPeUtil::InsertSection(const char* SectionName, DWORD ShellCodeSize, char* ShellCodeBuff, DWORD dwAttribute)
{
//1 先要判断区段表后面 是否足够存放两个区段头的地址
DWORD k = pFileHeader->NumberOfSections;
k *= sizeof(IMAGE_SECTION_HEADER);//区段数*每个区段头的大小=整个区段头有多大
k = k + 504; //总的区段头的大小+可选PE头的结尾位置的地址
//利用文件对齐来计算剩余的值
DWORD FileAlignment = pOptionHeader->FileAlignment;
DWORD Surplus = FileAlignment - k % FileAlignment;
//Surplus就是剩下的内容了
if (Surplus < 2 * sizeof(IMAGE_SECTION_HEADER))
{
MessageBoxA(0, "区段剩余内存不够", "报错", MB_OK);
return 0;
}
//2 创建新的缓冲区来存放新的PE文件,因为这里假设添加了ShellCode进去
//这里需要注意的是需要注意对齐值的应用,获取对齐后的PE文件大小
DWORD newFileSize = GetAlignSize(FileSize + ShellCodeSize, pOptionHeader->FileAlignment);
//3 创建新的缓冲区来存放PE文件
char* newFileBuff = new char[newFileSize];
memcpy_s(newFileBuff, newFileSize, FileBuff, FileSize);
FileSize = newFileSize;
delete[] FileBuff;
FileBuff = newFileBuff;
//4更新PE文件信息
InitFileInfo();
//5给新增的区段添加区段头
PIMAGE_SECTION_HEADER LastSection = GetLastSection();
LastSection++;//也就是新添加的区段的首个区段
//给新区段头设置属性
//设置区段内存大小,省事直接安装内存大小对齐
LastSection->Misc.VirtualSize = GetAlignSize(ShellCodeSize, pOptionHeader->SectionAlignment);
//设置名称
strcpy_s((char*)LastSection->Name, 8, SectionName);
//设置区段文件大小
LastSection->SizeOfRawData = GetAlignSize(ShellCodeSize, pOptionHeader->FileAlignment);
//设置偏移值,在内存中的偏移值
PIMAGE_SECTION_HEADER PreLastSectionHeader = GetLastSection();
//新加的区段的内存中的偏移=上一个区段内存中的偏移+内存中的大小对齐后的值
LastSection->VirtualAddress = PreLastSectionHeader->VirtualAddress
+ GetAlignSize(PreLastSectionHeader->Misc.VirtualSize, pOptionHeader->SectionAlignment);
//设置文件中的偏移
LastSection->PointerToRawData = PreLastSectionHeader->PointerToRawData +
+PreLastSectionHeader->SizeOfRawData;
LastSection->Characteristics = dwAttribute;
//修改Section数量
pFileHeader->NumberOfSections++;
//修改整个PE文件在内存中的大小
pOptionHeader->SizeOfImage += GetAlignSize(ShellCodeSize, pOptionHeader->SectionAlignment);
//将壳代码放到新的区段
char* SectionAddr = GetLastSection()->PointerToRawData + FileBuff;
memcpy(SectionAddr, ShellCodeBuff, ShellCodeSize);
return TRUE;
}
BOOL CPeUtil::EncodeSections()
{
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
int key = 0x51;
//进行异或来加密
char* pData = FileBuff + (DWORD)pSectionHeader->PointerToRawData;
//pData指向文件偏移中的区段的首地址