305 lines
10 KiB
C++
305 lines
10 KiB
C++
#include "sandbox.h"
|
|
|
|
auto Sandbox::DumpPE() -> std::pair<std::unique_ptr<BYTE[]>, size_t> {
|
|
// 查找目标模块 - 这里我们使用主模块(通常是被分析的可执行文件)
|
|
std::shared_ptr<struct_moudle> targetModule = nullptr;
|
|
for (const auto& module : m_moduleList) {
|
|
if ((*module).name == "HUOJI.EXE") {
|
|
targetModule = module;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!targetModule) {
|
|
throw std::runtime_error("No modules found to dump");
|
|
}
|
|
|
|
// 计算虚拟内存大小
|
|
auto virtualMemorySize = getVirtualMemorySize(m_peInfo->peBuffer);
|
|
|
|
// 创建用于存储转储数据的缓冲区
|
|
auto resultBuffer = std::make_unique<BYTE[]>(virtualMemorySize);
|
|
|
|
// 从虚拟机内存中读取PE文件
|
|
uc_err err = uc_mem_read(m_ucEngine, m_peInfo->RecImageBase,
|
|
resultBuffer.get(), virtualMemorySize);
|
|
if (err != UC_ERR_OK) {
|
|
throw std::runtime_error("Failed to read memory during PE dump: " +
|
|
std::string(uc_strerror(err)));
|
|
}
|
|
|
|
// 确保PE头部的签名有效
|
|
auto* dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(resultBuffer.get());
|
|
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
throw std::runtime_error("Invalid DOS signature in dumped PE");
|
|
}
|
|
|
|
auto* ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(resultBuffer.get() +
|
|
dosHeader->e_lfanew);
|
|
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {
|
|
throw std::runtime_error("Invalid NT signature in dumped PE");
|
|
}
|
|
|
|
// 获取当前RIP/EIP作为新的入口点
|
|
uint64_t currentEntryPoint = 0;
|
|
if (this->GetCrossSectionExecution().size() > 0) {
|
|
currentEntryPoint = this->GetCrossSectionExecution()
|
|
[this->GetCrossSectionExecution().size() - 1] -
|
|
m_peInfo->RecImageBase;
|
|
}
|
|
|
|
PIMAGE_SECTION_HEADER sectionHeaders = nullptr;
|
|
WORD numberOfSections = 0;
|
|
|
|
// 处理32位或64位PE文件
|
|
if (m_peInfo->isX64) {
|
|
auto* optHeader64 =
|
|
&reinterpret_cast<PIMAGE_NT_HEADERS64>(ntHeaders)->OptionalHeader;
|
|
optHeader64->ImageBase = m_peInfo->RecImageBase;
|
|
if (currentEntryPoint != 0) {
|
|
// 修改入口点为当前执行位置
|
|
optHeader64->AddressOfEntryPoint =
|
|
static_cast<DWORD>(currentEntryPoint);
|
|
}
|
|
|
|
// 修改SizeOfImage
|
|
optHeader64->SizeOfImage = static_cast<DWORD>(AlignToSectionAlignment(
|
|
virtualMemorySize, optHeader64->SectionAlignment));
|
|
|
|
// 修改DllCharacteristics以移除ASLR标记
|
|
optHeader64->DllCharacteristics &=
|
|
~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
|
|
|
// 获取区段头信息
|
|
sectionHeaders = reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
reinterpret_cast<ULONG_PTR>(ntHeaders) +
|
|
sizeof(ntHeaders->Signature) + sizeof(ntHeaders->FileHeader) +
|
|
ntHeaders->FileHeader.SizeOfOptionalHeader);
|
|
numberOfSections = ntHeaders->FileHeader.NumberOfSections;
|
|
}
|
|
else {
|
|
auto* optHeader32 =
|
|
&reinterpret_cast<PIMAGE_NT_HEADERS32>(ntHeaders)->OptionalHeader;
|
|
optHeader32->ImageBase = static_cast<DWORD>(m_peInfo->RecImageBase);
|
|
|
|
if (currentEntryPoint != 0) {
|
|
// 修改入口点为当前执行位置
|
|
optHeader32->AddressOfEntryPoint =
|
|
static_cast<DWORD>(currentEntryPoint);
|
|
}
|
|
|
|
// 修改SizeOfImage
|
|
optHeader32->SizeOfImage = static_cast<DWORD>(AlignToSectionAlignment(
|
|
virtualMemorySize, optHeader32->SectionAlignment));
|
|
|
|
// 修改DllCharacteristics以移除ASLR标记
|
|
optHeader32->DllCharacteristics &=
|
|
~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
|
|
|
// 获取区段头信息
|
|
sectionHeaders = reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
|
reinterpret_cast<ULONG_PTR>(ntHeaders) +
|
|
sizeof(ntHeaders->Signature) + sizeof(ntHeaders->FileHeader) +
|
|
ntHeaders->FileHeader.SizeOfOptionalHeader);
|
|
numberOfSections = ntHeaders->FileHeader.NumberOfSections;
|
|
}
|
|
|
|
// 更新代码基址和大小
|
|
UpdateBaseOfCode(sectionHeaders, ntHeaders, numberOfSections,
|
|
static_cast<DWORD>(currentEntryPoint));
|
|
|
|
// 修复区段
|
|
FixSections(sectionHeaders, numberOfSections, virtualMemorySize);
|
|
|
|
// 创建一个ExportsMapper对象用于导入表修复
|
|
peconv::ExportsMapper exportsMap;
|
|
|
|
// 添加所有已加载模块到导出表映射中
|
|
for (const auto& module : m_moduleList) {
|
|
if (module->base == 0 || module->size == 0) {
|
|
continue;
|
|
}
|
|
|
|
// 创建临时缓冲区以存储模块内容
|
|
std::unique_ptr<BYTE[]> moduleBuffer =
|
|
std::make_unique<BYTE[]>(module->size);
|
|
|
|
// 从虚拟机内存读取模块内容
|
|
uc_err readErr = uc_mem_read(m_ucEngine, module->base,
|
|
moduleBuffer.get(), module->size);
|
|
if (readErr != UC_ERR_OK) {
|
|
printf(
|
|
"Warning: Could not read module %s for exports mapping: %s\n",
|
|
module->name, uc_strerror(readErr));
|
|
continue;
|
|
}
|
|
|
|
// 添加模块到导出表映射
|
|
exportsMap.add_to_lookup(module->name,
|
|
reinterpret_cast<HMODULE>(moduleBuffer.get()),
|
|
module->base);
|
|
}
|
|
// 这里有一个严重的问题,就懒得处理了:
|
|
// 壳里面吐出来的代码的导入表和壳的导入表不是同样一个.
|
|
// 这个修的是壳的 导入表,所以导入表 修 不 全
|
|
// 有个很简单的办法,需要搜索IAT结构,然后修改脱壳后的IAT的字段到壳的字段里面,然后再执行一次fix_imports
|
|
// 懒得写了,家庭作业.自己完成
|
|
bool importsFixed = peconv::fix_imports(
|
|
resultBuffer.get(), virtualMemorySize, exportsMap, nullptr);
|
|
if (importsFixed) {
|
|
printf("PE file imports fixed successfully\n");
|
|
}
|
|
else {
|
|
printf("Warning: Failed to fix PE file imports\n");
|
|
}
|
|
|
|
size_t out_size = 0;
|
|
|
|
// 重新计算校验和
|
|
if (m_peInfo->isX64) {
|
|
auto* optHeader64 =
|
|
&reinterpret_cast<PIMAGE_NT_HEADERS64>(ntHeaders)->OptionalHeader;
|
|
optHeader64->CheckSum =
|
|
CalculateChecksum(resultBuffer.get(), virtualMemorySize);
|
|
}
|
|
else {
|
|
auto* optHeader32 =
|
|
&reinterpret_cast<PIMAGE_NT_HEADERS32>(ntHeaders)->OptionalHeader;
|
|
optHeader32->CheckSum =
|
|
CalculateChecksum(resultBuffer.get(), virtualMemorySize);
|
|
}
|
|
|
|
printf(
|
|
"PE file dumped successfully from address: 0x%llx, size: %zu bytes\n",
|
|
m_peInfo->RecImageBase, virtualMemorySize);
|
|
printf("Entry point set to: 0x%llx (RVA: 0x%llx)\n",
|
|
m_peInfo->RecImageBase + currentEntryPoint, currentEntryPoint);
|
|
|
|
return { std::move(resultBuffer), virtualMemorySize };
|
|
}
|
|
|
|
// 修复区段信息
|
|
void Sandbox::FixSections(PIMAGE_SECTION_HEADER sectionHeaders,
|
|
WORD numberOfSections, size_t virtualMemorySize) {
|
|
if (numberOfSections == 0 || sectionHeaders == nullptr) {
|
|
return;
|
|
}
|
|
|
|
// 修复每个区段的信息
|
|
for (WORD i = 0; i < numberOfSections - 1; i++) {
|
|
auto& currentSection = sectionHeaders[i];
|
|
auto& nextSection = sectionHeaders[i + 1];
|
|
|
|
// 修复大小,使之与下一个区段的起始地址对齐
|
|
currentSection.SizeOfRawData =
|
|
nextSection.VirtualAddress - currentSection.VirtualAddress;
|
|
currentSection.PointerToRawData = currentSection.VirtualAddress;
|
|
currentSection.Misc.VirtualSize = currentSection.SizeOfRawData;
|
|
}
|
|
|
|
// 修复最后一个区段
|
|
auto& lastSection = sectionHeaders[numberOfSections - 1];
|
|
lastSection.SizeOfRawData =
|
|
static_cast<DWORD>(virtualMemorySize) - lastSection.VirtualAddress;
|
|
lastSection.PointerToRawData = lastSection.VirtualAddress;
|
|
lastSection.Misc.VirtualSize = lastSection.SizeOfRawData;
|
|
}
|
|
|
|
// 计算校验和
|
|
DWORD Sandbox::CalculateChecksum(const BYTE* peBuffer, size_t size) {
|
|
DWORD sum = 0;
|
|
const DWORD* ptr = reinterpret_cast<const DWORD*>(peBuffer);
|
|
const DWORD count = static_cast<DWORD>(size / sizeof(DWORD));
|
|
|
|
// 获取校验和字段的偏移
|
|
const auto dosHeader = (PIMAGE_DOS_HEADER)(peBuffer);
|
|
const auto ntHeaders = (PIMAGE_NT_HEADERS)(peBuffer + dosHeader->e_lfanew);
|
|
DWORD checksumOffset = dosHeader->e_lfanew +
|
|
FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
|
|
FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum);
|
|
|
|
// 计算总和,跳过校验和字段本身
|
|
for (DWORD i = 0; i < count; i++) {
|
|
// 跳过校验和字段
|
|
if ((i * sizeof(DWORD)) == checksumOffset ||
|
|
(i * sizeof(DWORD)) == checksumOffset + sizeof(DWORD) - 1) {
|
|
continue;
|
|
}
|
|
sum += ptr[i];
|
|
// 处理溢出
|
|
if (sum < ptr[i]) {
|
|
sum++;
|
|
}
|
|
}
|
|
|
|
// 完成计算
|
|
sum = (sum & 0xFFFF) + (sum >> 16);
|
|
sum = (sum & 0xFFFF) + (sum >> 16);
|
|
sum = sum + static_cast<DWORD>(size);
|
|
|
|
return sum;
|
|
}
|
|
|
|
// 按区段对齐大小进行对齐
|
|
DWORD Sandbox::AlignToSectionAlignment(size_t size, DWORD alignment) {
|
|
return static_cast<DWORD>(((size + alignment - 1) / alignment) * alignment);
|
|
}
|
|
|
|
// 更新代码基址和代码大小
|
|
void Sandbox::UpdateBaseOfCode(PIMAGE_SECTION_HEADER sectionHeader,
|
|
PIMAGE_NT_HEADERS ntHeaders,
|
|
WORD numberOfSections, DWORD entryPoint) {
|
|
if (sectionHeader == nullptr || ntHeaders == nullptr ||
|
|
numberOfSections == 0) {
|
|
return;
|
|
}
|
|
|
|
DWORD baseOfCode = 0;
|
|
DWORD sizeOfCode = 0;
|
|
bool foundSection = false;
|
|
|
|
// 寻找包含入口点的区段
|
|
for (WORD i = 0; i < numberOfSections; i++) {
|
|
auto& section = sectionHeader[i];
|
|
if (entryPoint >= section.VirtualAddress &&
|
|
entryPoint < (section.VirtualAddress + section.Misc.VirtualSize)) {
|
|
baseOfCode = section.VirtualAddress;
|
|
sizeOfCode = section.Misc.VirtualSize;
|
|
foundSection = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 如果没有找到包含入口点的区段,使用第一个可执行区段
|
|
if (!foundSection) {
|
|
for (WORD i = 0; i < numberOfSections; i++) {
|
|
auto& section = sectionHeader[i];
|
|
if (section.Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
|
baseOfCode = section.VirtualAddress;
|
|
sizeOfCode = section.Misc.VirtualSize;
|
|
foundSection = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 更新NT头部信息
|
|
if (foundSection) {
|
|
if (ntHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) {
|
|
// 64位PE
|
|
auto* optHeader64 =
|
|
&reinterpret_cast<PIMAGE_NT_HEADERS64>(ntHeaders)
|
|
->OptionalHeader;
|
|
optHeader64->BaseOfCode = baseOfCode;
|
|
}
|
|
else {
|
|
// 32位PE
|
|
auto* optHeader32 =
|
|
&reinterpret_cast<PIMAGE_NT_HEADERS32>(ntHeaders)
|
|
->OptionalHeader;
|
|
optHeader32->BaseOfCode = baseOfCode;
|
|
optHeader32->SizeOfCode = sizeOfCode;
|
|
}
|
|
}
|
|
}
|