#include "sandbox.h" auto Sandbox::DumpPE() -> std::pair, size_t> { // 查找目标模块 - 这里我们使用主模块(通常是被分析的可执行文件) std::shared_ptr targetModule = nullptr; for (const auto& module : m_moduleList) { if (strcmp(module->name, "huoji.exe") == 0) { 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(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(resultBuffer.get()); if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { throw std::runtime_error("Invalid DOS signature in dumped PE"); } auto* ntHeaders = reinterpret_cast(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(ntHeaders)->OptionalHeader; optHeader64->ImageBase = m_peInfo->RecImageBase; if (currentEntryPoint != 0) { // 修改入口点为当前执行位置 optHeader64->AddressOfEntryPoint = static_cast(currentEntryPoint); } // 修改SizeOfImage optHeader64->SizeOfImage = static_cast(AlignToSectionAlignment( virtualMemorySize, optHeader64->SectionAlignment)); // 修改DllCharacteristics以移除ASLR标记 optHeader64->DllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; // 获取区段头信息 sectionHeaders = reinterpret_cast( reinterpret_cast(ntHeaders) + sizeof(ntHeaders->Signature) + sizeof(ntHeaders->FileHeader) + ntHeaders->FileHeader.SizeOfOptionalHeader); numberOfSections = ntHeaders->FileHeader.NumberOfSections; } else { auto* optHeader32 = &reinterpret_cast(ntHeaders)->OptionalHeader; optHeader32->ImageBase = static_cast(m_peInfo->RecImageBase); if (currentEntryPoint != 0) { // 修改入口点为当前执行位置 optHeader32->AddressOfEntryPoint = static_cast(currentEntryPoint); } // 修改SizeOfImage optHeader32->SizeOfImage = static_cast(AlignToSectionAlignment( virtualMemorySize, optHeader32->SectionAlignment)); // 修改DllCharacteristics以移除ASLR标记 optHeader32->DllCharacteristics &= ~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; // 获取区段头信息 sectionHeaders = reinterpret_cast( reinterpret_cast(ntHeaders) + sizeof(ntHeaders->Signature) + sizeof(ntHeaders->FileHeader) + ntHeaders->FileHeader.SizeOfOptionalHeader); numberOfSections = ntHeaders->FileHeader.NumberOfSections; } // 更新代码基址和大小 UpdateBaseOfCode(sectionHeaders, ntHeaders, numberOfSections, static_cast(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 moduleBuffer = std::make_unique(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(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(ntHeaders)->OptionalHeader; optHeader64->CheckSum = CalculateChecksum(resultBuffer.get(), virtualMemorySize); } else { auto* optHeader32 = &reinterpret_cast(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(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(peBuffer); const DWORD count = static_cast(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(size); return sum; } // 按区段对齐大小进行对齐 DWORD Sandbox::AlignToSectionAlignment(size_t size, DWORD alignment) { return static_cast(((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(ntHeaders) ->OptionalHeader; optHeader64->BaseOfCode = baseOfCode; } else { // 32位PE auto* optHeader32 = &reinterpret_cast(ntHeaders) ->OptionalHeader; optHeader32->BaseOfCode = baseOfCode; optHeader32->SizeOfCode = sizeOfCode; } } }