脱壳与加壳-加壳-1-手工实现添加区段
给壳代码开辟空间来存放壳代码
方法1:在空白的区段头到区段的位置添加区段头
在区段的最后一个后面开辟新的区段
步骤
1 读取文件
2 创建buff存放PE文件镜像
3 解析PE(DOS头、NT头、可选PE头、标准PE头)
4 添加区段、修改相关PE某些字段值
5 将壳代码写入新区段
6 保存文件
代码实现
1 读取文件
//打开文件,获得文件句柄
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;
2 存放Buff
New一个buff来存放原来的文件
3 解析PE头
存放PE头的一些属性
pDosHeader = (PIMAGE_DOS_HEADER)FileBuff;
pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + FileBuff);
pFileHeader = &pNtHeader->FileHeader;
pOptionHeader = &pNtHeader->OptionalHeader;
return 0;
4 添加区段修改相关属性
//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;
//将壳代码放到新区段
return 0;
5 保存Buff到文件里面
代码实现
//.h文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<Windows.h>
#include<iostream>
#include<string>
class CPeUtil
{
public:
CPeUtil();
~CPeUtil();
BOOL LoadFile(const char*path);//加载PE文件
BOOL InitFileInfo();//初始化
BOOL InsertSection(const char*SectionName,DWORD ShellCodeSize,char* ShellCodeBuff,DWORD dwAttribute);//添加区段函数,分别是区段名字,壳代码大小,壳代码指针,区段属性
DWORD GetAlignSize(DWORD RealSize,DWORD AlignSize);
PIMAGE_SECTION_HEADER GetLastSection();
private:
char *FileBuff;
DWORD FileSize;
PIMAGE_DOS_HEADER pDosHeader;
PIMAGE_NT_HEADERS pNtHeader;
PIMAGE_OPTIONAL_HEADER pOptionHeader;
PIMAGE_FILE_HEADER pFileHeader;
};
#include"main.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);
//将壳代码放到新区段
//保存Buff到PE里面
SaveFile("a");
return 0;
}