修复内存泄漏。并且优化代码格式
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{e12c93d6-6150-484d-85e1-7a644e393d5a}</ProjectGuid>
|
||||
<RootNamespace>aiantimalware</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
@@ -180,11 +180,14 @@
|
||||
<ClCompile Include="sandbox_api_file.cpp" />
|
||||
<ClCompile Include="sandbox_api_process.cpp" />
|
||||
<ClCompile Include="sandbox_api_regs.cpp" />
|
||||
<ClCompile Include="sandbox_api_setmap.cpp" />
|
||||
<ClCompile Include="sandbox_api_stl.cpp" />
|
||||
<ClCompile Include="sandbox_api_wfp.cpp" />
|
||||
<ClCompile Include="sandbox_api_winhttp.cpp" />
|
||||
<ClCompile Include="sandbox_api_wlan.cpp" />
|
||||
<ClCompile Include="sandbox_callbacks.cpp" />
|
||||
<ClCompile Include="sandbox_dump_pe.cpp" />
|
||||
<ClCompile Include="sandbox_ldr.cpp" />
|
||||
<ClCompile Include="sandbox_malware_check.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -159,6 +159,15 @@
|
||||
<ClCompile Include="sandbox_api_com.cpp">
|
||||
<Filter>源文件\sandbox\apis</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sandbox_ldr.cpp">
|
||||
<Filter>源文件\sandbox</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sandbox_dump_pe.cpp">
|
||||
<Filter>源文件\sandbox</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="sandbox_api_setmap.cpp">
|
||||
<Filter>源文件\sandbox</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="head.h">
|
||||
|
||||
@@ -32,6 +32,12 @@ struct BasicPeInfo {
|
||||
PIMAGE_NT_HEADERS ntHead64;
|
||||
PIMAGE_NT_HEADERS32 ntHead32;
|
||||
bool isDll;
|
||||
~BasicPeInfo() {
|
||||
if (peBuffer != nullptr) {
|
||||
peconv::free_pe_buffer(peBuffer);
|
||||
peBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
#include "sandbox.h"
|
||||
#include "ml.h"
|
||||
@@ -5,59 +5,109 @@
|
||||
#ifdef _DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
typedef LPVOID(WINAPI* PFN_MapViewOfFile)(
|
||||
HANDLE hFileMappingObject,
|
||||
DWORD dwDesiredAccess,
|
||||
DWORD dwFileOffsetHigh,
|
||||
DWORD dwFileOffsetLow,
|
||||
SIZE_T dwNumberOfBytesToMap
|
||||
);
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
|
||||
//load file content using MapViewOfFile
|
||||
peconv::ALIGNED_BUF peconv::load_file(IN const char *filename, OUT size_t &read_size)
|
||||
{
|
||||
HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if(file == INVALID_HANDLE_VALUE) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not open file!" << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
|
||||
if (!mapping) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not create mapping!" << std::endl;
|
||||
#endif
|
||||
CloseHandle(file);
|
||||
return nullptr;
|
||||
}
|
||||
BYTE *dllRawData = (BYTE*) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!dllRawData) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not map view of file" << std::endl;
|
||||
#endif
|
||||
CloseHandle(mapping);
|
||||
CloseHandle(file);
|
||||
return nullptr;
|
||||
}
|
||||
size_t r_size = GetFileSize(file, 0);
|
||||
if (read_size != 0 && read_size <= r_size) {
|
||||
r_size = read_size;
|
||||
}
|
||||
if (IsBadReadPtr(dllRawData, r_size)) {
|
||||
std::cerr << "[-] Mapping of " << filename << " is invalid!" << std::endl;
|
||||
UnmapViewOfFile(dllRawData);
|
||||
CloseHandle(mapping);
|
||||
CloseHandle(file);
|
||||
return nullptr;
|
||||
}
|
||||
peconv::ALIGNED_BUF localCopyAddress = peconv::alloc_aligned(r_size, PAGE_READWRITE);
|
||||
if (localCopyAddress != nullptr) {
|
||||
memcpy(localCopyAddress, dllRawData, r_size);
|
||||
read_size = r_size;
|
||||
} else {
|
||||
typedef LPVOID(WINAPI* PFN_MapViewOfFile)(
|
||||
HANDLE,
|
||||
DWORD,
|
||||
DWORD,
|
||||
DWORD,
|
||||
SIZE_T
|
||||
);
|
||||
typedef BOOL(WINAPI* PFN_UnmapViewOfFile)(LPCVOID);
|
||||
typedef DWORD(WINAPI* PFN_GetFileSize)(HANDLE, LPDWORD);
|
||||
|
||||
namespace peconv {
|
||||
ALIGNED_BUF load_file(IN const char* filename, OUT size_t& read_size)
|
||||
{
|
||||
read_size = 0;
|
||||
|
||||
HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "Could not allocate memory in the current process" << std::endl;
|
||||
std::cerr << "[-] Could not open file: " << filename << std::endl;
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HANDLE hMapping = CreateFileMappingA(hFile, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
if (!hMapping) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[-] Could not create file mapping!" << std::endl;
|
||||
#endif
|
||||
CloseHandle(hFile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
|
||||
if (!hKernel32) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[-] Could not get handle to kernel32.dll" << std::endl;
|
||||
#endif
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PFN_MapViewOfFile pMapViewOfFile = (PFN_MapViewOfFile)GetProcAddress(hKernel32, "MapViewOfFile");
|
||||
PFN_UnmapViewOfFile pUnmapViewOfFile = (PFN_UnmapViewOfFile)GetProcAddress(hKernel32, "UnmapViewOfFile");
|
||||
PFN_GetFileSize pGetFileSize = (PFN_GetFileSize)GetProcAddress(hKernel32, "GetFileSize");
|
||||
|
||||
if (!pMapViewOfFile || !pUnmapViewOfFile || !pGetFileSize) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[-] Could not get required API functions from kernel32.dll" << std::endl;
|
||||
#endif
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BYTE* dllRawData = (BYTE*)pMapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
|
||||
if (!dllRawData) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[-] Failed to map view of file" << std::endl;
|
||||
#endif
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t fileSize = pGetFileSize(hFile, nullptr);
|
||||
size_t toReadSize = (read_size != 0 && read_size <= fileSize) ? read_size : fileSize;
|
||||
|
||||
if (IsBadReadPtr(dllRawData, toReadSize)) {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[-] Mapped memory is invalid: " << filename << std::endl;
|
||||
#endif
|
||||
pUnmapViewOfFile(dllRawData);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
ALIGNED_BUF localCopy = peconv::alloc_aligned(toReadSize, PAGE_READWRITE);
|
||||
if (localCopy) {
|
||||
memcpy(localCopy, dllRawData, toReadSize);
|
||||
read_size = toReadSize;
|
||||
}
|
||||
else {
|
||||
#ifdef _DEBUG
|
||||
std::cerr << "[-] Failed to allocate memory in current process" << std::endl;
|
||||
#endif
|
||||
read_size = 0;
|
||||
}
|
||||
|
||||
pUnmapViewOfFile(dllRawData);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return localCopy;
|
||||
}
|
||||
UnmapViewOfFile(dllRawData);
|
||||
CloseHandle(mapping);
|
||||
CloseHandle(file);
|
||||
return localCopyAddress;
|
||||
}
|
||||
|
||||
//load file content using ReadFile
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// 前向声明
|
||||
struct PeInfo;
|
||||
struct SectionInfo;
|
||||
class BasicPeInfo;
|
||||
struct BasicPeInfo;
|
||||
struct RichEntry {
|
||||
uint16_t productId; // 组件ID
|
||||
uint16_t buildId; // 版本号
|
||||
|
||||
@@ -1024,6 +1024,9 @@ struct struct_moudle {
|
||||
uint64_t base;
|
||||
uint64_t size;
|
||||
uint64_t real_base;
|
||||
uint64_t mapped_address;
|
||||
uint64_t mapped_size;
|
||||
|
||||
std::vector<std::shared_ptr<moudle_import>> import_function;
|
||||
std::vector<std::shared_ptr<moudle_export>> export_function;
|
||||
std::vector<std::shared_ptr<moudle_section>> sections;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "sandbox.h"
|
||||
#include "sandbox_callbacks.h"
|
||||
#include "sandbox_api_com.h"
|
||||
|
||||
// 在文件开头添加AllocateMemory函数的声明
|
||||
auto Sandbox::AllocateMemory(size_t size) -> uint64_t {
|
||||
// 使用一个简单的内存分配策略
|
||||
@@ -24,71 +23,8 @@ auto Sandbox::AllocateMemory(size_t size) -> uint64_t {
|
||||
return allocated_address;
|
||||
}
|
||||
|
||||
std::string getDllNameFromApiSetMap(const std::string& apiSet) {
|
||||
const std::wstring wApiSet(apiSet.begin(), apiSet.end());
|
||||
|
||||
// 获取系统版本信息
|
||||
using RtlGetVersionFunc = LONG(__stdcall*)(PRTL_OSVERSIONINFOW);
|
||||
const auto pRtlGetVersion = reinterpret_cast<RtlGetVersionFunc>(
|
||||
GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlGetVersion"));
|
||||
|
||||
RTL_OSVERSIONINFOEXW verInfo{};
|
||||
verInfo.dwOSVersionInfoSize = sizeof(verInfo);
|
||||
pRtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(&verInfo));
|
||||
|
||||
const ULONG verShort = (verInfo.dwMajorVersion << 8) |
|
||||
(verInfo.dwMinorVersion << 4) |
|
||||
verInfo.wServicePackMajor;
|
||||
|
||||
if (verShort >= static_cast<ULONG>(WinVer::kWin10)) {
|
||||
const auto apiSetMap = reinterpret_cast<API_SET_NAMESPACE_ARRAY_10*>(
|
||||
reinterpret_cast<X64PEB*>(__readgsqword(0x60))->ApiSetMap);
|
||||
const auto apiSetMapAsNumber = reinterpret_cast<ULONG_PTR>(apiSetMap);
|
||||
auto nsEntry = reinterpret_cast<PAPI_SET_NAMESPACE_ENTRY_10>(
|
||||
apiSetMap->Start + apiSetMapAsNumber);
|
||||
|
||||
// 遍历API集合查找匹配项
|
||||
for (ULONG i = 0; i < apiSetMap->Count; i++) {
|
||||
UNICODE_STRING nameString{}, valueString{};
|
||||
nameString.MaximumLength = static_cast<USHORT>(nsEntry->NameLength);
|
||||
nameString.Length = static_cast<USHORT>(nsEntry->NameLength);
|
||||
nameString.Buffer = reinterpret_cast<PWCHAR>(apiSetMapAsNumber +
|
||||
nsEntry->NameOffset);
|
||||
|
||||
const std::wstring name(nameString.Buffer,
|
||||
nameString.Length / sizeof(WCHAR));
|
||||
const std::wstring fullName = name + L".dll";
|
||||
|
||||
if (_wcsicmp(wApiSet.c_str(), fullName.c_str()) == 0) {
|
||||
if (nsEntry->ValueCount == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto valueEntry =
|
||||
reinterpret_cast<PAPI_SET_VALUE_ENTRY_10>(
|
||||
apiSetMapAsNumber + nsEntry->ValueOffset);
|
||||
valueString.Buffer = reinterpret_cast<PWCHAR>(
|
||||
apiSetMapAsNumber + valueEntry->ValueOffset);
|
||||
valueString.MaximumLength =
|
||||
static_cast<USHORT>(valueEntry->ValueLength);
|
||||
valueString.Length =
|
||||
static_cast<USHORT>(valueEntry->ValueLength);
|
||||
|
||||
const std::wstring value(valueString.Buffer,
|
||||
valueString.Length / sizeof(WCHAR));
|
||||
return {value.begin(), value.end()};
|
||||
}
|
||||
++nsEntry;
|
||||
}
|
||||
} else {
|
||||
// 不支持Windows 10以下版本
|
||||
throw std::runtime_error("Unsupported Windows version");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
class ImportResolver : public peconv::t_function_resolver {
|
||||
public:
|
||||
public:
|
||||
explicit ImportResolver(std::map<std::string, uint64_t> context)
|
||||
: _functionMap(std::move(context)) {}
|
||||
|
||||
@@ -96,22 +32,22 @@ class ImportResolver : public peconv::t_function_resolver {
|
||||
return reinterpret_cast<FARPROC>(_functionMap[std::string(funcName)]);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::map<std::string, uint64_t> _functionMap;
|
||||
};
|
||||
|
||||
class cListImportNames : public peconv::ImportThunksCallback {
|
||||
public:
|
||||
public:
|
||||
cListImportNames(
|
||||
BYTE* _modulePtr, size_t _moduleSize,
|
||||
std::vector<std::shared_ptr<moudle_import>>& name_to_addr,
|
||||
std::vector<std::shared_ptr<moudle_import_ordinal>>& name_to_ordinal)
|
||||
: ImportThunksCallback(_modulePtr, _moduleSize),
|
||||
nameToAddr(name_to_addr),
|
||||
ordinalImportFunc(name_to_ordinal) {}
|
||||
nameToAddr(name_to_addr),
|
||||
ordinalImportFunc(name_to_ordinal) {}
|
||||
|
||||
virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr,
|
||||
ULONG_PTR firstThunkPtr) {
|
||||
ULONG_PTR firstThunkPtr) {
|
||||
if (this->is64b) {
|
||||
IMAGE_THUNK_DATA64* desc =
|
||||
reinterpret_cast<IMAGE_THUNK_DATA64*>(origFirstThunkPtr);
|
||||
@@ -126,17 +62,17 @@ class cListImportNames : public peconv::ImportThunksCallback {
|
||||
lib_name, desc, call_via, IMAGE_ORDINAL_FLAG32);
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
|
||||
bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA* desc,
|
||||
T_FIELD* call_via, T_FIELD ordinal_flag) {
|
||||
T_FIELD* call_via, T_FIELD ordinal_flag) {
|
||||
DWORD call_via_rva = static_cast<DWORD>((ULONG_PTR)call_via -
|
||||
(ULONG_PTR)this->modulePtr);
|
||||
(ULONG_PTR)this->modulePtr);
|
||||
LPSTR func_name = NULL;
|
||||
if ((desc->u1.Ordinal & ordinal_flag) == 0) {
|
||||
PIMAGE_IMPORT_BY_NAME by_name =
|
||||
(PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr +
|
||||
desc->u1.AddressOfData);
|
||||
desc->u1.AddressOfData);
|
||||
func_name = reinterpret_cast<LPSTR>(by_name->Name);
|
||||
std::string fuck_up_api_ms = lib_name;
|
||||
if (fuck_up_api_ms.find("api-ms-") != std::string::npos) {
|
||||
@@ -146,11 +82,12 @@ class cListImportNames : public peconv::ImportThunksCallback {
|
||||
auto import_data = std::make_shared<moudle_import>();
|
||||
memcpy(import_data->name, func_name, strlen(func_name));
|
||||
memcpy(import_data->dll_name, fuck_up_api_ms.c_str(),
|
||||
fuck_up_api_ms.size());
|
||||
fuck_up_api_ms.size());
|
||||
import_data->function_address = call_via_rva;
|
||||
import_data->is_delayed_import = false;
|
||||
nameToAddr.push_back(import_data);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
auto importFunc = std::make_shared<moudle_import_ordinal>();
|
||||
T_FIELD raw_ordinal = desc->u1.Ordinal & (~ordinal_flag);
|
||||
importFunc->dll_name = lib_name;
|
||||
@@ -165,7 +102,7 @@ class cListImportNames : public peconv::ImportThunksCallback {
|
||||
std::vector<std::shared_ptr<moudle_import_ordinal>>& ordinalImportFunc;
|
||||
};
|
||||
class cFixImprot : public peconv::t_function_resolver {
|
||||
public:
|
||||
public:
|
||||
// 构造函数接收Sandbox实例的引用
|
||||
explicit cFixImprot(Sandbox* sandbox) : m_sandbox(sandbox) {}
|
||||
|
||||
@@ -200,7 +137,7 @@ class cFixImprot : public peconv::t_function_resolver {
|
||||
if (strcmp(exp->name, func_name) == 0) {
|
||||
#ifdef LOG_LEVEL > 1
|
||||
printf("fix import (fallback): %s found in %s => %llx \n",
|
||||
func_name, module->name, newBase);
|
||||
func_name, module->name, newBase);
|
||||
// 返回在模拟器中的虚拟地址
|
||||
#endif
|
||||
return newBase;
|
||||
@@ -225,12 +162,12 @@ class cFixImprot : public peconv::t_function_resolver {
|
||||
}
|
||||
|
||||
printf("Warning: Could not resolve import: %s from library: %s\n",
|
||||
func_name, lib_name);
|
||||
func_name, lib_name);
|
||||
//__debugbreak();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
Sandbox* m_sandbox; // Sandbox实例的指针
|
||||
};
|
||||
Sandbox::Sandbox() {
|
||||
@@ -272,6 +209,13 @@ Sandbox::~Sandbox() {
|
||||
delete segment;
|
||||
}
|
||||
m_heapSegments.clear();
|
||||
// 4. 清理模块
|
||||
for (auto module : m_moduleList) {
|
||||
//为0的是主程序.
|
||||
if (module->mapped_address != 0) {
|
||||
peconv::free_pe_buffer((peconv::ALIGNED_BUF)module.get()->mapped_address, module.get()->mapped_size);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 最后清理底层资源
|
||||
if (m_csHandle) {
|
||||
@@ -279,7 +223,7 @@ Sandbox::~Sandbox() {
|
||||
}
|
||||
}
|
||||
|
||||
auto Sandbox::PushModuleToVM(const char* dllName, uint64_t moduleBase) -> void {
|
||||
auto Sandbox::PushModuleToVM(const char* dllName, uint64_t moduleBase, uint64_t mappedSize) -> void {
|
||||
for (auto module : m_moduleList) {
|
||||
if (module->real_base == moduleBase) {
|
||||
printf("skip module name: %s (already loaded)\n", module->name);
|
||||
@@ -310,6 +254,8 @@ auto Sandbox::PushModuleToVM(const char* dllName, uint64_t moduleBase) -> void {
|
||||
newModule->base) == false) {
|
||||
throw std::runtime_error("Failed to relocate module");
|
||||
}
|
||||
newModule->mapped_address = moduleBase;
|
||||
newModule->mapped_size = mappedSize;
|
||||
|
||||
// 将模块添加到LDR链表中
|
||||
if (m_peInfo->isX64) {
|
||||
@@ -479,7 +425,7 @@ auto Sandbox::mapSystemModuleToVmByName(std::string systemName) -> void {
|
||||
}
|
||||
|
||||
// 添加到虚拟机
|
||||
PushModuleToVM(systemName.c_str(), moduleBase);
|
||||
PushModuleToVM(systemName.c_str(), moduleBase, mappedPeSize);
|
||||
}
|
||||
auto Sandbox::processImportModule(const moudle_import* importModule) -> void {
|
||||
|
||||
@@ -995,465 +941,3 @@ auto Sandbox::getVirtualMemorySize(BYTE* peBuffer) -> size_t {
|
||||
|
||||
return static_cast<size_t>(totalSize);
|
||||
}
|
||||
|
||||
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 (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<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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Sandbox::InitializeLdrData() -> void {
|
||||
if (m_peInfo->isX64 && m_peb64.Ldr == 0) {
|
||||
// 为LDR_DATA分配内存
|
||||
uint64_t ldrDataAddress = m_pebBase + sizeof(X64PEB);
|
||||
m_pebEnd = ldrDataAddress + sizeof(X64_PEB_LDR_DATA);
|
||||
m_peb64.Ldr = ldrDataAddress;
|
||||
|
||||
// 映射LDR数据内存
|
||||
uc_mem_map(m_ucEngine, ldrDataAddress, sizeof(X64_PEB_LDR_DATA),
|
||||
UC_PROT_ALL);
|
||||
|
||||
// 初始化LDR_DATA结构
|
||||
X64_PEB_LDR_DATA ldrData = {0};
|
||||
ldrData.Length = sizeof(X64_PEB_LDR_DATA);
|
||||
ldrData.Initialized = 1;
|
||||
|
||||
// 初始化链表头 - 使用适当的类型转换
|
||||
LIST_ENTRY inLoadOrderList = {
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InLoadOrderModuleList)),
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InLoadOrderModuleList))};
|
||||
ldrData.InLoadOrderModuleList = inLoadOrderList;
|
||||
|
||||
LIST_ENTRY inMemoryOrderList = {
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InMemoryOrderModuleList)),
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InMemoryOrderModuleList))};
|
||||
ldrData.InMemoryOrderModuleList = inMemoryOrderList;
|
||||
|
||||
LIST_ENTRY inInitOrderList = {
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InInitializationOrderModuleList)),
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InInitializationOrderModuleList))};
|
||||
ldrData.InInitializationOrderModuleList = inInitOrderList;
|
||||
|
||||
uc_mem_write(m_ucEngine, ldrDataAddress, &ldrData,
|
||||
sizeof(X64_PEB_LDR_DATA));
|
||||
|
||||
// 更新PEB中的Ldr指针
|
||||
uc_mem_write(m_ucEngine, m_pebBase, &m_peb64, sizeof(X64PEB));
|
||||
}
|
||||
}
|
||||
|
||||
auto Sandbox::CreateLdrEntry(const std::shared_ptr<struct_moudle>& module,
|
||||
uint64_t entryAddress, uint64_t fullNameAddress,
|
||||
uint64_t baseNameAddress) -> LDR_DATA_TABLE_ENTRY {
|
||||
LDR_DATA_TABLE_ENTRY entry = {0};
|
||||
entry.DllBase = reinterpret_cast<PVOID>(module->base);
|
||||
entry.EntryPoint = reinterpret_cast<PVOID>(module->base + module->entry);
|
||||
entry.SizeOfImages = static_cast<ULONG>(module->size);
|
||||
|
||||
// 准备模块名称的Unicode字符串
|
||||
wchar_t nameBuffer[MAX_PATH] = {0};
|
||||
std::mbstowcs(nameBuffer, module->name, strlen(module->name));
|
||||
|
||||
// 设置全路径
|
||||
entry.FullDllName.Length =
|
||||
static_cast<USHORT>(wcslen(nameBuffer) * sizeof(wchar_t));
|
||||
entry.FullDllName.MaximumLength = MAX_PATH * sizeof(wchar_t);
|
||||
entry.FullDllName.Buffer = reinterpret_cast<PWSTR>(fullNameAddress);
|
||||
|
||||
// 设置基本名称
|
||||
entry.BaseDllName.Length =
|
||||
static_cast<USHORT>(wcslen(nameBuffer) * sizeof(wchar_t));
|
||||
entry.BaseDllName.MaximumLength = MAX_PATH * sizeof(wchar_t);
|
||||
entry.BaseDllName.Buffer = reinterpret_cast<PWSTR>(baseNameAddress);
|
||||
|
||||
// 写入Unicode字符串
|
||||
uc_mem_write(m_ucEngine, fullNameAddress, nameBuffer,
|
||||
(wcslen(nameBuffer) + 1) * sizeof(wchar_t));
|
||||
uc_mem_write(m_ucEngine, baseNameAddress, nameBuffer,
|
||||
(wcslen(nameBuffer) + 1) * sizeof(wchar_t));
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
auto Sandbox::UpdateLdrLinks(const LDR_DATA_TABLE_ENTRY& entry,
|
||||
uint64_t entryAddress, X64_PEB_LDR_DATA& ldrData)
|
||||
-> void {
|
||||
// 更新LDR_DATA中的链表头
|
||||
ldrData.InLoadOrderModuleList.Flink = reinterpret_cast<LIST_ENTRY*>(
|
||||
entryAddress + offsetof(LDR_DATA_TABLE_ENTRY, InLoadOrderLinks));
|
||||
ldrData.InMemoryOrderModuleList.Flink = reinterpret_cast<LIST_ENTRY*>(
|
||||
entryAddress + offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
|
||||
ldrData.InInitializationOrderModuleList.Flink =
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
entryAddress +
|
||||
offsetof(LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks));
|
||||
|
||||
// 写回更新后的LDR_DATA
|
||||
uc_mem_write(m_ucEngine, m_peb64.Ldr, &ldrData, sizeof(X64_PEB_LDR_DATA));
|
||||
}
|
||||
|
||||
auto Sandbox::AddModuleToLdr(const std::shared_ptr<struct_moudle>& module)
|
||||
-> void {
|
||||
if (!m_peInfo->isX64) {
|
||||
return; // 暂时只处理64位
|
||||
}
|
||||
|
||||
if (m_peb64.Ldr == 0) {
|
||||
InitializeLdrData();
|
||||
}
|
||||
|
||||
// 为模块创建LDR_DATA_TABLE_ENTRY
|
||||
uint64_t entrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
|
||||
MAX_PATH * 2; // 额外空间用于Unicode字符串
|
||||
uint64_t entryAddress = m_pebEnd;
|
||||
m_pebEnd += entrySize;
|
||||
|
||||
// 映射内存
|
||||
uc_mem_map(m_ucEngine, entryAddress, entrySize, UC_PROT_ALL);
|
||||
|
||||
// 设置Unicode字符串地址
|
||||
uint64_t fullNameAddress = entryAddress + sizeof(LDR_DATA_TABLE_ENTRY);
|
||||
uint64_t baseNameAddress = fullNameAddress + MAX_PATH;
|
||||
|
||||
// 创建并初始化LDR_DATA_TABLE_ENTRY
|
||||
auto entry =
|
||||
CreateLdrEntry(module, entryAddress, fullNameAddress, baseNameAddress);
|
||||
|
||||
// 从PEB读取当前LDR_DATA结构
|
||||
X64_PEB_LDR_DATA ldrData;
|
||||
uc_mem_read(m_ucEngine, m_peb64.Ldr, &ldrData, sizeof(X64_PEB_LDR_DATA));
|
||||
|
||||
// 设置链表指针
|
||||
entry.InLoadOrderLinks.Flink = reinterpret_cast<LIST_ENTRY*>(
|
||||
reinterpret_cast<uintptr_t>(ldrData.InLoadOrderModuleList.Flink));
|
||||
entry.InLoadOrderLinks.Blink = reinterpret_cast<LIST_ENTRY*>(
|
||||
m_peb64.Ldr + offsetof(X64_PEB_LDR_DATA, InLoadOrderModuleList));
|
||||
|
||||
entry.InMemoryOrderLinks.Flink = reinterpret_cast<LIST_ENTRY*>(
|
||||
reinterpret_cast<uintptr_t>(ldrData.InMemoryOrderModuleList.Flink));
|
||||
entry.InMemoryOrderLinks.Blink = reinterpret_cast<LIST_ENTRY*>(
|
||||
m_peb64.Ldr + offsetof(X64_PEB_LDR_DATA, InMemoryOrderModuleList));
|
||||
|
||||
entry.InInitializationOrderLinks.Flink =
|
||||
reinterpret_cast<LIST_ENTRY*>(reinterpret_cast<uintptr_t>(
|
||||
ldrData.InInitializationOrderModuleList.Flink));
|
||||
entry.InInitializationOrderLinks.Blink = reinterpret_cast<LIST_ENTRY*>(
|
||||
m_peb64.Ldr +
|
||||
offsetof(X64_PEB_LDR_DATA, InInitializationOrderModuleList));
|
||||
|
||||
// 写入LDR_DATA_TABLE_ENTRY结构
|
||||
uc_mem_write(m_ucEngine, entryAddress, &entry,
|
||||
sizeof(LDR_DATA_TABLE_ENTRY));
|
||||
|
||||
// 更新链表
|
||||
UpdateLdrLinks(entry, entryAddress, ldrData);
|
||||
|
||||
printf("Added module '%s' to LDR data tables at 0x%llx\n", module->name,
|
||||
entryAddress);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ class Sandbox {
|
||||
|
||||
Sandbox();
|
||||
~Sandbox();
|
||||
auto PushModuleToVM(const char* dllName, uint64_t moduleBase, uint64_t mappedSize) -> void;
|
||||
std::map<uint64_t, size_t>
|
||||
process_enum_state; // 用于跟踪每个句柄的枚举状态
|
||||
// Public methods
|
||||
@@ -165,7 +166,6 @@ class Sandbox {
|
||||
DWORD CalculateChecksum(const BYTE* buffer, size_t size);
|
||||
|
||||
auto SetupVirtualMachine() -> void;
|
||||
auto PushModuleToVM(const char* dllName, uint64_t moduleBase) -> void;
|
||||
auto processImportModule(const moudle_import* importModule) -> void;
|
||||
auto GetCrossSectionExecution() -> std::vector<uint64_t> {
|
||||
return m_crossSectionExecution;
|
||||
|
||||
65
ai_anti_malware/sandbox_api_setmap.cpp
Normal file
65
ai_anti_malware/sandbox_api_setmap.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "sandbox.h"
|
||||
|
||||
std::string getDllNameFromApiSetMap(const std::string& apiSet) {
|
||||
const std::wstring wApiSet(apiSet.begin(), apiSet.end());
|
||||
|
||||
// <20><>ȡϵͳ<CFB5>汾<EFBFBD><E6B1BE>Ϣ
|
||||
using RtlGetVersionFunc = LONG(__stdcall*)(PRTL_OSVERSIONINFOW);
|
||||
const auto pRtlGetVersion = reinterpret_cast<RtlGetVersionFunc>(
|
||||
GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlGetVersion"));
|
||||
|
||||
RTL_OSVERSIONINFOEXW verInfo{};
|
||||
verInfo.dwOSVersionInfoSize = sizeof(verInfo);
|
||||
pRtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(&verInfo));
|
||||
|
||||
const ULONG verShort = (verInfo.dwMajorVersion << 8) |
|
||||
(verInfo.dwMinorVersion << 4) |
|
||||
verInfo.wServicePackMajor;
|
||||
|
||||
if (verShort >= static_cast<ULONG>(WinVer::kWin10)) {
|
||||
const auto apiSetMap = reinterpret_cast<API_SET_NAMESPACE_ARRAY_10*>(
|
||||
reinterpret_cast<X64PEB*>(__readgsqword(0x60))->ApiSetMap);
|
||||
const auto apiSetMapAsNumber = reinterpret_cast<ULONG_PTR>(apiSetMap);
|
||||
auto nsEntry = reinterpret_cast<PAPI_SET_NAMESPACE_ENTRY_10>(
|
||||
apiSetMap->Start + apiSetMapAsNumber);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>API<50><49><EFBFBD>ϲ<EFBFBD><CFB2><EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>
|
||||
for (ULONG i = 0; i < apiSetMap->Count; i++) {
|
||||
UNICODE_STRING nameString{}, valueString{};
|
||||
nameString.MaximumLength = static_cast<USHORT>(nsEntry->NameLength);
|
||||
nameString.Length = static_cast<USHORT>(nsEntry->NameLength);
|
||||
nameString.Buffer = reinterpret_cast<PWCHAR>(apiSetMapAsNumber +
|
||||
nsEntry->NameOffset);
|
||||
|
||||
const std::wstring name(nameString.Buffer,
|
||||
nameString.Length / sizeof(WCHAR));
|
||||
const std::wstring fullName = name + L".dll";
|
||||
|
||||
if (_wcsicmp(wApiSet.c_str(), fullName.c_str()) == 0) {
|
||||
if (nsEntry->ValueCount == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto valueEntry =
|
||||
reinterpret_cast<PAPI_SET_VALUE_ENTRY_10>(
|
||||
apiSetMapAsNumber + nsEntry->ValueOffset);
|
||||
valueString.Buffer = reinterpret_cast<PWCHAR>(
|
||||
apiSetMapAsNumber + valueEntry->ValueOffset);
|
||||
valueString.MaximumLength =
|
||||
static_cast<USHORT>(valueEntry->ValueLength);
|
||||
valueString.Length =
|
||||
static_cast<USHORT>(valueEntry->ValueLength);
|
||||
|
||||
const std::wstring value(valueString.Buffer,
|
||||
valueString.Length / sizeof(WCHAR));
|
||||
return { value.begin(), value.end() };
|
||||
}
|
||||
++nsEntry;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// <20><>֧<EFBFBD><D6A7>Windows 10<31><30><EFBFBD>°汾
|
||||
throw std::runtime_error("Unsupported Windows version");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
304
ai_anti_malware/sandbox_dump_pe.cpp
Normal file
304
ai_anti_malware/sandbox_dump_pe.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
#include "sandbox.h"
|
||||
|
||||
auto Sandbox::DumpPE() -> std::pair<std::unique_ptr<BYTE[]>, size_t> {
|
||||
// <20><><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF>ģ<EFBFBD><C4A3> - <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3>(ͨ<><CDA8><EFBFBD>DZ<EFBFBD><C7B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD>ִ<EFBFBD><D6B4><EFBFBD>ļ<EFBFBD>)
|
||||
std::shared_ptr<struct_moudle> 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");
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD>С
|
||||
auto virtualMemorySize = getVirtualMemorySize(m_peInfo->peBuffer);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ洢ת<E6B4A2><D7AA><EFBFBD><EFBFBD><EFBFBD>ݵĻ<DDB5><C4BB><EFBFBD><EFBFBD><EFBFBD>
|
||||
auto resultBuffer = std::make_unique<BYTE[]>(virtualMemorySize);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4>ж<EFBFBD>ȡPE<50>ļ<EFBFBD>
|
||||
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)));
|
||||
}
|
||||
|
||||
// ȷ<><C8B7>PEͷ<45><CDB7><EFBFBD><EFBFBD>ǩ<EFBFBD><C7A9><EFBFBD><EFBFBD>Ч
|
||||
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");
|
||||
}
|
||||
|
||||
// <20><>ȡ<EFBFBD><C8A1>ǰRIP/EIP<49><50>Ϊ<EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD>ڵ<EFBFBD>
|
||||
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;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>32λ<32><CEBB>64λPE<50>ļ<EFBFBD>
|
||||
if (m_peInfo->isX64) {
|
||||
auto* optHeader64 =
|
||||
&reinterpret_cast<PIMAGE_NT_HEADERS64>(ntHeaders)->OptionalHeader;
|
||||
optHeader64->ImageBase = m_peInfo->RecImageBase;
|
||||
if (currentEntryPoint != 0) {
|
||||
// <20><EFBFBD><DEB8><EFBFBD><EFBFBD>ڵ<EFBFBD>Ϊ<EFBFBD><CEAA>ǰִ<C7B0><D6B4>λ<EFBFBD><CEBB>
|
||||
optHeader64->AddressOfEntryPoint =
|
||||
static_cast<DWORD>(currentEntryPoint);
|
||||
}
|
||||
|
||||
// <20><EFBFBD>SizeOfImage
|
||||
optHeader64->SizeOfImage = static_cast<DWORD>(AlignToSectionAlignment(
|
||||
virtualMemorySize, optHeader64->SectionAlignment));
|
||||
|
||||
// <20><EFBFBD>DllCharacteristics<63><73><EFBFBD>Ƴ<EFBFBD>ASLR<4C><52><EFBFBD><EFBFBD>
|
||||
optHeader64->DllCharacteristics &=
|
||||
~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
||||
|
||||
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>Ϣ
|
||||
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) {
|
||||
// <20><EFBFBD><DEB8><EFBFBD><EFBFBD>ڵ<EFBFBD>Ϊ<EFBFBD><CEAA>ǰִ<C7B0><D6B4>λ<EFBFBD><CEBB>
|
||||
optHeader32->AddressOfEntryPoint =
|
||||
static_cast<DWORD>(currentEntryPoint);
|
||||
}
|
||||
|
||||
// <20><EFBFBD>SizeOfImage
|
||||
optHeader32->SizeOfImage = static_cast<DWORD>(AlignToSectionAlignment(
|
||||
virtualMemorySize, optHeader32->SectionAlignment));
|
||||
|
||||
// <20><EFBFBD>DllCharacteristics<63><73><EFBFBD>Ƴ<EFBFBD>ASLR<4C><52><EFBFBD><EFBFBD>
|
||||
optHeader32->DllCharacteristics &=
|
||||
~IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
|
||||
|
||||
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>Ϣ
|
||||
sectionHeaders = reinterpret_cast<PIMAGE_SECTION_HEADER>(
|
||||
reinterpret_cast<ULONG_PTR>(ntHeaders) +
|
||||
sizeof(ntHeaders->Signature) + sizeof(ntHeaders->FileHeader) +
|
||||
ntHeaders->FileHeader.SizeOfOptionalHeader);
|
||||
numberOfSections = ntHeaders->FileHeader.NumberOfSections;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD>´<EFBFBD><C2B4><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>ʹ<EFBFBD>С
|
||||
UpdateBaseOfCode(sectionHeaders, ntHeaders, numberOfSections,
|
||||
static_cast<DWORD>(currentEntryPoint));
|
||||
|
||||
// <20><EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD>
|
||||
FixSections(sectionHeaders, numberOfSections, virtualMemorySize);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>ExportsMapper<65><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
peconv::ExportsMapper exportsMap;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѽ<EFBFBD><D1BC><EFBFBD>ģ<EFBFBD>鵽<EFBFBD><E9B5BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3><EFBFBD><EFBFBD>
|
||||
for (const auto& module : m_moduleList) {
|
||||
if (module->base == 0 || module->size == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ洢ģ<E6B4A2><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
std::unique_ptr<BYTE[]> moduleBuffer =
|
||||
std::make_unique<BYTE[]>(module->size);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD>ȡģ<C8A1><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
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;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>ģ<EFBFBD>鵽<EFBFBD><E9B5BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3>
|
||||
exportsMap.add_to_lookup(module->name,
|
||||
reinterpret_cast<HMODULE>(moduleBuffer.get()),
|
||||
module->base);
|
||||
}
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><C3B4><EFBFBD><EFBFBD><EFBFBD>:
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>³<EFBFBD><C2B3><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϳǵĵ<C7B5><C4B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC>һ<EFBFBD><D2BB>.
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><DEB5>ǿǵ<C7BF> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD>Ե<EFBFBD><D4B5><EFBFBD><EFBFBD><EFBFBD> <20><> <20><> ȫ
|
||||
// <20>и<EFBFBD><D0B8>ܼİ취,<2C><>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>IAT<41>ṹ,Ȼ<><C8BB><EFBFBD><EFBFBD><DEB8>ѿǺ<D1BF><C7BA><EFBFBD>IAT<41><54><EFBFBD>ֶε<D6B6><CEB5>ǵ<EFBFBD><C7B5>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD>,Ȼ<><C8BB><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>һ<EFBFBD><D2BB>fix_imports
|
||||
// <20><><EFBFBD><EFBFBD>д<EFBFBD><D0B4>,<2C><>ͥ<EFBFBD><CDA5>ҵ.<2E>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD>
|
||||
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;
|
||||
|
||||
// <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD>
|
||||
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 };
|
||||
}
|
||||
|
||||
// <20><EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
|
||||
void Sandbox::FixSections(PIMAGE_SECTION_HEADER sectionHeaders,
|
||||
WORD numberOfSections, size_t virtualMemorySize) {
|
||||
if (numberOfSections == 0 || sectionHeaders == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// <20><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD><CEB5><EFBFBD>Ϣ
|
||||
for (WORD i = 0; i < numberOfSections - 1; i++) {
|
||||
auto& currentSection = sectionHeaders[i];
|
||||
auto& nextSection = sectionHeaders[i + 1];
|
||||
|
||||
// <20><EFBFBD><DEB8><EFBFBD>С<EFBFBD><D0A1>ʹ֮<CAB9><D6AE><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD><CEB5><EFBFBD>ʼ<EFBFBD><CABC>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>
|
||||
currentSection.SizeOfRawData =
|
||||
nextSection.VirtualAddress - currentSection.VirtualAddress;
|
||||
currentSection.PointerToRawData = currentSection.VirtualAddress;
|
||||
currentSection.Misc.VirtualSize = currentSection.SizeOfRawData;
|
||||
}
|
||||
|
||||
// <20><EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
auto& lastSection = sectionHeaders[numberOfSections - 1];
|
||||
lastSection.SizeOfRawData =
|
||||
static_cast<DWORD>(virtualMemorySize) - lastSection.VirtualAddress;
|
||||
lastSection.PointerToRawData = lastSection.VirtualAddress;
|
||||
lastSection.Misc.VirtualSize = lastSection.SizeOfRawData;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD>
|
||||
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));
|
||||
|
||||
// <20><>ȡУ<C8A1><D0A3><EFBFBD><EFBFBD><EFBFBD>ֶε<D6B6>ƫ<EFBFBD><C6AB>
|
||||
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);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ܺͣ<DCBA><CDA3><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD>ֶα<D6B6><CEB1><EFBFBD>
|
||||
for (DWORD i = 0; i < count; i++) {
|
||||
// <20><><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD>
|
||||
if ((i * sizeof(DWORD)) == checksumOffset ||
|
||||
(i * sizeof(DWORD)) == checksumOffset + sizeof(DWORD) - 1) {
|
||||
continue;
|
||||
}
|
||||
sum += ptr[i];
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
if (sum < ptr[i]) {
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
|
||||
// <20><><EFBFBD>ɼ<EFBFBD><C9BC><EFBFBD>
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
sum = sum + static_cast<DWORD>(size);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ζ<EFBFBD><CEB6><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1><EFBFBD>ж<EFBFBD><D0B6><EFBFBD>
|
||||
DWORD Sandbox::AlignToSectionAlignment(size_t size, DWORD alignment) {
|
||||
return static_cast<DWORD>(((size + alignment - 1) / alignment) * alignment);
|
||||
}
|
||||
|
||||
// <20><><EFBFBD>´<EFBFBD><C2B4><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>ʹ<EFBFBD><CDB4><EFBFBD><EFBFBD><EFBFBD>С
|
||||
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;
|
||||
|
||||
// Ѱ<>Ұ<EFBFBD><D2B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Σ<EFBFBD>ʹ<EFBFBD>õ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>NTͷ<54><CDB7><EFBFBD><EFBFBD>Ϣ
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
164
ai_anti_malware/sandbox_ldr.cpp
Normal file
164
ai_anti_malware/sandbox_ldr.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "sandbox.h"
|
||||
|
||||
|
||||
auto Sandbox::InitializeLdrData() -> void {
|
||||
if (m_peInfo->isX64 && m_peb64.Ldr == 0) {
|
||||
// ΪLDR_DATA<54><41><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>
|
||||
uint64_t ldrDataAddress = m_pebBase + sizeof(X64PEB);
|
||||
m_pebEnd = ldrDataAddress + sizeof(X64_PEB_LDR_DATA);
|
||||
m_peb64.Ldr = ldrDataAddress;
|
||||
|
||||
// ӳ<><D3B3>LDR<44><52><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>
|
||||
uc_mem_map(m_ucEngine, ldrDataAddress, sizeof(X64_PEB_LDR_DATA),
|
||||
UC_PROT_ALL);
|
||||
|
||||
// <20><>ʼ<EFBFBD><CABC>LDR_DATA<54>ṹ
|
||||
X64_PEB_LDR_DATA ldrData = { 0 };
|
||||
ldrData.Length = sizeof(X64_PEB_LDR_DATA);
|
||||
ldrData.Initialized = 1;
|
||||
|
||||
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ - ʹ<><CAB9><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>
|
||||
LIST_ENTRY inLoadOrderList = {
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InLoadOrderModuleList)),
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InLoadOrderModuleList)) };
|
||||
ldrData.InLoadOrderModuleList = inLoadOrderList;
|
||||
|
||||
LIST_ENTRY inMemoryOrderList = {
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InMemoryOrderModuleList)),
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InMemoryOrderModuleList)) };
|
||||
ldrData.InMemoryOrderModuleList = inMemoryOrderList;
|
||||
|
||||
LIST_ENTRY inInitOrderList = {
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InInitializationOrderModuleList)),
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
ldrDataAddress +
|
||||
offsetof(X64_PEB_LDR_DATA, InInitializationOrderModuleList)) };
|
||||
ldrData.InInitializationOrderModuleList = inInitOrderList;
|
||||
|
||||
uc_mem_write(m_ucEngine, ldrDataAddress, &ldrData,
|
||||
sizeof(X64_PEB_LDR_DATA));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>PEB<45>е<EFBFBD>Ldrָ<72><D6B8>
|
||||
uc_mem_write(m_ucEngine, m_pebBase, &m_peb64, sizeof(X64PEB));
|
||||
}
|
||||
}
|
||||
|
||||
auto Sandbox::CreateLdrEntry(const std::shared_ptr<struct_moudle>& module,
|
||||
uint64_t entryAddress, uint64_t fullNameAddress,
|
||||
uint64_t baseNameAddress) -> LDR_DATA_TABLE_ENTRY {
|
||||
LDR_DATA_TABLE_ENTRY entry = { 0 };
|
||||
entry.DllBase = reinterpret_cast<PVOID>(module->base);
|
||||
entry.EntryPoint = reinterpret_cast<PVOID>(module->base + module->entry);
|
||||
entry.SizeOfImages = static_cast<ULONG>(module->size);
|
||||
|
||||
// <><D7BC>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD>Unicode<64>ַ<EFBFBD><D6B7><EFBFBD>
|
||||
wchar_t nameBuffer[MAX_PATH] = { 0 };
|
||||
std::mbstowcs(nameBuffer, module->name, strlen(module->name));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>ȫ·<C8AB><C2B7>
|
||||
entry.FullDllName.Length =
|
||||
static_cast<USHORT>(wcslen(nameBuffer) * sizeof(wchar_t));
|
||||
entry.FullDllName.MaximumLength = MAX_PATH * sizeof(wchar_t);
|
||||
entry.FullDllName.Buffer = reinterpret_cast<PWSTR>(fullNameAddress);
|
||||
|
||||
// <20><><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
entry.BaseDllName.Length =
|
||||
static_cast<USHORT>(wcslen(nameBuffer) * sizeof(wchar_t));
|
||||
entry.BaseDllName.MaximumLength = MAX_PATH * sizeof(wchar_t);
|
||||
entry.BaseDllName.Buffer = reinterpret_cast<PWSTR>(baseNameAddress);
|
||||
|
||||
// д<><D0B4>Unicode<64>ַ<EFBFBD><D6B7><EFBFBD>
|
||||
uc_mem_write(m_ucEngine, fullNameAddress, nameBuffer,
|
||||
(wcslen(nameBuffer) + 1) * sizeof(wchar_t));
|
||||
uc_mem_write(m_ucEngine, baseNameAddress, nameBuffer,
|
||||
(wcslen(nameBuffer) + 1) * sizeof(wchar_t));
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
auto Sandbox::UpdateLdrLinks(const LDR_DATA_TABLE_ENTRY& entry,
|
||||
uint64_t entryAddress, X64_PEB_LDR_DATA& ldrData)
|
||||
-> void {
|
||||
// <20><><EFBFBD><EFBFBD>LDR_DATA<54>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD>ͷ
|
||||
ldrData.InLoadOrderModuleList.Flink = reinterpret_cast<LIST_ENTRY*>(
|
||||
entryAddress + offsetof(LDR_DATA_TABLE_ENTRY, InLoadOrderLinks));
|
||||
ldrData.InMemoryOrderModuleList.Flink = reinterpret_cast<LIST_ENTRY*>(
|
||||
entryAddress + offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
|
||||
ldrData.InInitializationOrderModuleList.Flink =
|
||||
reinterpret_cast<LIST_ENTRY*>(
|
||||
entryAddress +
|
||||
offsetof(LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks));
|
||||
|
||||
// д<>ظ<EFBFBD><D8B8>º<EFBFBD><C2BA><EFBFBD>LDR_DATA
|
||||
uc_mem_write(m_ucEngine, m_peb64.Ldr, &ldrData, sizeof(X64_PEB_LDR_DATA));
|
||||
}
|
||||
|
||||
auto Sandbox::AddModuleToLdr(const std::shared_ptr<struct_moudle>& module)
|
||||
-> void {
|
||||
if (!m_peInfo->isX64) {
|
||||
return; // <20><>ʱֻ<CAB1><D6BB><EFBFBD><EFBFBD>64λ
|
||||
}
|
||||
|
||||
if (m_peb64.Ldr == 0) {
|
||||
InitializeLdrData();
|
||||
}
|
||||
|
||||
// Ϊģ<CEAA>鴴<EFBFBD><E9B4B4>LDR_DATA_TABLE_ENTRY
|
||||
uint64_t entrySize = sizeof(LDR_DATA_TABLE_ENTRY) +
|
||||
MAX_PATH * 2; // <20><><EFBFBD><EFBFBD><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD><EFBFBD><EFBFBD>Unicode<64>ַ<EFBFBD><D6B7><EFBFBD>
|
||||
uint64_t entryAddress = m_pebEnd;
|
||||
m_pebEnd += entrySize;
|
||||
|
||||
// ӳ<><D3B3><EFBFBD>ڴ<EFBFBD>
|
||||
uc_mem_map(m_ucEngine, entryAddress, entrySize, UC_PROT_ALL);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>Unicode<64>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD>ַ
|
||||
uint64_t fullNameAddress = entryAddress + sizeof(LDR_DATA_TABLE_ENTRY);
|
||||
uint64_t baseNameAddress = fullNameAddress + MAX_PATH;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>LDR_DATA_TABLE_ENTRY
|
||||
auto entry =
|
||||
CreateLdrEntry(module, entryAddress, fullNameAddress, baseNameAddress);
|
||||
|
||||
// <20><>PEB<45><42>ȡ<EFBFBD><C8A1>ǰLDR_DATA<54>ṹ
|
||||
X64_PEB_LDR_DATA ldrData;
|
||||
uc_mem_read(m_ucEngine, m_peb64.Ldr, &ldrData, sizeof(X64_PEB_LDR_DATA));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>
|
||||
entry.InLoadOrderLinks.Flink = reinterpret_cast<LIST_ENTRY*>(
|
||||
reinterpret_cast<uintptr_t>(ldrData.InLoadOrderModuleList.Flink));
|
||||
entry.InLoadOrderLinks.Blink = reinterpret_cast<LIST_ENTRY*>(
|
||||
m_peb64.Ldr + offsetof(X64_PEB_LDR_DATA, InLoadOrderModuleList));
|
||||
|
||||
entry.InMemoryOrderLinks.Flink = reinterpret_cast<LIST_ENTRY*>(
|
||||
reinterpret_cast<uintptr_t>(ldrData.InMemoryOrderModuleList.Flink));
|
||||
entry.InMemoryOrderLinks.Blink = reinterpret_cast<LIST_ENTRY*>(
|
||||
m_peb64.Ldr + offsetof(X64_PEB_LDR_DATA, InMemoryOrderModuleList));
|
||||
|
||||
entry.InInitializationOrderLinks.Flink =
|
||||
reinterpret_cast<LIST_ENTRY*>(reinterpret_cast<uintptr_t>(
|
||||
ldrData.InInitializationOrderModuleList.Flink));
|
||||
entry.InInitializationOrderLinks.Blink = reinterpret_cast<LIST_ENTRY*>(
|
||||
m_peb64.Ldr +
|
||||
offsetof(X64_PEB_LDR_DATA, InInitializationOrderModuleList));
|
||||
|
||||
// д<><D0B4>LDR_DATA_TABLE_ENTRY<52>ṹ
|
||||
uc_mem_write(m_ucEngine, entryAddress, &entry,
|
||||
sizeof(LDR_DATA_TABLE_ENTRY));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
UpdateLdrLinks(entry, entryAddress, ldrData);
|
||||
|
||||
printf("Added module '%s' to LDR data tables at 0x%llx\n", module->name,
|
||||
entryAddress);
|
||||
}
|
||||
Reference in New Issue
Block a user