修复内存泄漏。并且优化代码格式
This commit is contained in:
@@ -23,7 +23,7 @@
|
|||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<ProjectGuid>{e12c93d6-6150-484d-85e1-7a644e393d5a}</ProjectGuid>
|
<ProjectGuid>{e12c93d6-6150-484d-85e1-7a644e393d5a}</ProjectGuid>
|
||||||
<RootNamespace>aiantimalware</RootNamespace>
|
<RootNamespace>aiantimalware</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
@@ -180,11 +180,14 @@
|
|||||||
<ClCompile Include="sandbox_api_file.cpp" />
|
<ClCompile Include="sandbox_api_file.cpp" />
|
||||||
<ClCompile Include="sandbox_api_process.cpp" />
|
<ClCompile Include="sandbox_api_process.cpp" />
|
||||||
<ClCompile Include="sandbox_api_regs.cpp" />
|
<ClCompile Include="sandbox_api_regs.cpp" />
|
||||||
|
<ClCompile Include="sandbox_api_setmap.cpp" />
|
||||||
<ClCompile Include="sandbox_api_stl.cpp" />
|
<ClCompile Include="sandbox_api_stl.cpp" />
|
||||||
<ClCompile Include="sandbox_api_wfp.cpp" />
|
<ClCompile Include="sandbox_api_wfp.cpp" />
|
||||||
<ClCompile Include="sandbox_api_winhttp.cpp" />
|
<ClCompile Include="sandbox_api_winhttp.cpp" />
|
||||||
<ClCompile Include="sandbox_api_wlan.cpp" />
|
<ClCompile Include="sandbox_api_wlan.cpp" />
|
||||||
<ClCompile Include="sandbox_callbacks.cpp" />
|
<ClCompile Include="sandbox_callbacks.cpp" />
|
||||||
|
<ClCompile Include="sandbox_dump_pe.cpp" />
|
||||||
|
<ClCompile Include="sandbox_ldr.cpp" />
|
||||||
<ClCompile Include="sandbox_malware_check.cpp" />
|
<ClCompile Include="sandbox_malware_check.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -159,6 +159,15 @@
|
|||||||
<ClCompile Include="sandbox_api_com.cpp">
|
<ClCompile Include="sandbox_api_com.cpp">
|
||||||
<Filter>源文件\sandbox\apis</Filter>
|
<Filter>源文件\sandbox\apis</Filter>
|
||||||
</ClCompile>
|
</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>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="head.h">
|
<ClInclude Include="head.h">
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ struct BasicPeInfo {
|
|||||||
PIMAGE_NT_HEADERS ntHead64;
|
PIMAGE_NT_HEADERS ntHead64;
|
||||||
PIMAGE_NT_HEADERS32 ntHead32;
|
PIMAGE_NT_HEADERS32 ntHead32;
|
||||||
bool isDll;
|
bool isDll;
|
||||||
|
~BasicPeInfo() {
|
||||||
|
if (peBuffer != nullptr) {
|
||||||
|
peconv::free_pe_buffer(peBuffer);
|
||||||
|
peBuffer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#include "sandbox.h"
|
#include "sandbox.h"
|
||||||
#include "ml.h"
|
#include "ml.h"
|
||||||
@@ -5,59 +5,109 @@
|
|||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#endif
|
#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
|
typedef LPVOID(WINAPI* PFN_MapViewOfFile)(
|
||||||
peconv::ALIGNED_BUF peconv::load_file(IN const char *filename, OUT size_t &read_size)
|
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)
|
||||||
{
|
{
|
||||||
HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
read_size = 0;
|
||||||
if(file == INVALID_HANDLE_VALUE) {
|
|
||||||
|
HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
std::cerr << "Could not open file!" << std::endl;
|
std::cerr << "[-] Could not open file: " << filename << std::endl;
|
||||||
#endif
|
#endif
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
|
|
||||||
if (!mapping) {
|
HANDLE hMapping = CreateFileMappingA(hFile, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||||
|
if (!hMapping) {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
std::cerr << "Could not create mapping!" << std::endl;
|
std::cerr << "[-] Could not create file mapping!" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
CloseHandle(file);
|
CloseHandle(hFile);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
BYTE *dllRawData = (BYTE*) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
|
|
||||||
|
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) {
|
if (!dllRawData) {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
std::cerr << "Could not map view of file" << std::endl;
|
std::cerr << "[-] Failed to map view of file" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
CloseHandle(mapping);
|
CloseHandle(hMapping);
|
||||||
CloseHandle(file);
|
CloseHandle(hFile);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
size_t r_size = GetFileSize(file, 0);
|
|
||||||
if (read_size != 0 && read_size <= r_size) {
|
size_t fileSize = pGetFileSize(hFile, nullptr);
|
||||||
r_size = read_size;
|
size_t toReadSize = (read_size != 0 && read_size <= fileSize) ? read_size : fileSize;
|
||||||
}
|
|
||||||
if (IsBadReadPtr(dllRawData, r_size)) {
|
if (IsBadReadPtr(dllRawData, toReadSize)) {
|
||||||
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 {
|
|
||||||
read_size = 0;
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
std::cerr << "Could not allocate memory in the current process" << std::endl;
|
std::cerr << "[-] Mapped memory is invalid: " << filename << std::endl;
|
||||||
#endif
|
#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
|
//load file content using ReadFile
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// 前向声明
|
// 前向声明
|
||||||
struct PeInfo;
|
struct PeInfo;
|
||||||
struct SectionInfo;
|
struct SectionInfo;
|
||||||
class BasicPeInfo;
|
struct BasicPeInfo;
|
||||||
struct RichEntry {
|
struct RichEntry {
|
||||||
uint16_t productId; // 组件ID
|
uint16_t productId; // 组件ID
|
||||||
uint16_t buildId; // 版本号
|
uint16_t buildId; // 版本号
|
||||||
|
|||||||
@@ -1024,6 +1024,9 @@ struct struct_moudle {
|
|||||||
uint64_t base;
|
uint64_t base;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint64_t real_base;
|
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_import>> import_function;
|
||||||
std::vector<std::shared_ptr<moudle_export>> export_function;
|
std::vector<std::shared_ptr<moudle_export>> export_function;
|
||||||
std::vector<std::shared_ptr<moudle_section>> sections;
|
std::vector<std::shared_ptr<moudle_section>> sections;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "sandbox.h"
|
#include "sandbox.h"
|
||||||
#include "sandbox_callbacks.h"
|
#include "sandbox_callbacks.h"
|
||||||
#include "sandbox_api_com.h"
|
#include "sandbox_api_com.h"
|
||||||
|
|
||||||
// 在文件开头添加AllocateMemory函数的声明
|
// 在文件开头添加AllocateMemory函数的声明
|
||||||
auto Sandbox::AllocateMemory(size_t size) -> uint64_t {
|
auto Sandbox::AllocateMemory(size_t size) -> uint64_t {
|
||||||
// 使用一个简单的内存分配策略
|
// 使用一个简单的内存分配策略
|
||||||
@@ -24,69 +23,6 @@ auto Sandbox::AllocateMemory(size_t size) -> uint64_t {
|
|||||||
return allocated_address;
|
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 {
|
class ImportResolver : public peconv::t_function_resolver {
|
||||||
public:
|
public:
|
||||||
explicit ImportResolver(std::map<std::string, uint64_t> context)
|
explicit ImportResolver(std::map<std::string, uint64_t> context)
|
||||||
@@ -150,7 +86,8 @@ class cListImportNames : public peconv::ImportThunksCallback {
|
|||||||
import_data->function_address = call_via_rva;
|
import_data->function_address = call_via_rva;
|
||||||
import_data->is_delayed_import = false;
|
import_data->is_delayed_import = false;
|
||||||
nameToAddr.push_back(import_data);
|
nameToAddr.push_back(import_data);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
auto importFunc = std::make_shared<moudle_import_ordinal>();
|
auto importFunc = std::make_shared<moudle_import_ordinal>();
|
||||||
T_FIELD raw_ordinal = desc->u1.Ordinal & (~ordinal_flag);
|
T_FIELD raw_ordinal = desc->u1.Ordinal & (~ordinal_flag);
|
||||||
importFunc->dll_name = lib_name;
|
importFunc->dll_name = lib_name;
|
||||||
@@ -272,6 +209,13 @@ Sandbox::~Sandbox() {
|
|||||||
delete segment;
|
delete segment;
|
||||||
}
|
}
|
||||||
m_heapSegments.clear();
|
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. 最后清理底层资源
|
// 5. 最后清理底层资源
|
||||||
if (m_csHandle) {
|
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) {
|
for (auto module : m_moduleList) {
|
||||||
if (module->real_base == moduleBase) {
|
if (module->real_base == moduleBase) {
|
||||||
printf("skip module name: %s (already loaded)\n", module->name);
|
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) {
|
newModule->base) == false) {
|
||||||
throw std::runtime_error("Failed to relocate module");
|
throw std::runtime_error("Failed to relocate module");
|
||||||
}
|
}
|
||||||
|
newModule->mapped_address = moduleBase;
|
||||||
|
newModule->mapped_size = mappedSize;
|
||||||
|
|
||||||
// 将模块添加到LDR链表中
|
// 将模块添加到LDR链表中
|
||||||
if (m_peInfo->isX64) {
|
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 {
|
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);
|
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();
|
||||||
~Sandbox();
|
~Sandbox();
|
||||||
|
auto PushModuleToVM(const char* dllName, uint64_t moduleBase, uint64_t mappedSize) -> void;
|
||||||
std::map<uint64_t, size_t>
|
std::map<uint64_t, size_t>
|
||||||
process_enum_state; // 用于跟踪每个句柄的枚举状态
|
process_enum_state; // 用于跟踪每个句柄的枚举状态
|
||||||
// Public methods
|
// Public methods
|
||||||
@@ -165,7 +166,6 @@ class Sandbox {
|
|||||||
DWORD CalculateChecksum(const BYTE* buffer, size_t size);
|
DWORD CalculateChecksum(const BYTE* buffer, size_t size);
|
||||||
|
|
||||||
auto SetupVirtualMachine() -> void;
|
auto SetupVirtualMachine() -> void;
|
||||||
auto PushModuleToVM(const char* dllName, uint64_t moduleBase) -> void;
|
|
||||||
auto processImportModule(const moudle_import* importModule) -> void;
|
auto processImportModule(const moudle_import* importModule) -> void;
|
||||||
auto GetCrossSectionExecution() -> std::vector<uint64_t> {
|
auto GetCrossSectionExecution() -> std::vector<uint64_t> {
|
||||||
return m_crossSectionExecution;
|
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