优化rip的速度

This commit is contained in:
Huoji's
2025-04-23 04:47:01 +08:00
parent 785f0da7fe
commit db31cd90b5
7 changed files with 276 additions and 116 deletions

View File

@@ -1007,6 +1007,8 @@ struct moudle_export {
uint64_t function_address;
void* function_callback;
uint64_t ordinal;
uc_hook sys_ook;
};
struct moudle_import {
char name[MAX_PATH];

View File

@@ -548,7 +548,10 @@ auto Sandbox::InitEnv(std::shared_ptr<BasicPeInfo> peInfo) -> void {
}
mapSystemModuleToVmByName("kernelbase.dll");
}
// 闭合ldr
FinalizeLdrLinks();
// 给所有导入表加c3
/*
for (const auto& module : this->GetModuleList()) {
// 遍历导出函数查找对应名称
for (const auto& exp : module->export_function) {
@@ -556,6 +559,15 @@ auto Sandbox::InitEnv(std::shared_ptr<BasicPeInfo> peInfo) -> void {
uc_mem_write(m_ucEngine, inMemAddr, "\xCC", sizeof(char));
}
}
*/
// 挂导入表钩子
for (const auto& module : this->GetModuleList()) {
// 遍历导出函数查找对应名称
for (const auto& exp : module->export_function) {
auto inMemAddr = module->base + exp->function_address;
uc_hook_add(m_ucEngine, &exp->sys_ook, UC_HOOK_CODE, sandboxCallbacks::handleApiCall,(void*)this, inMemAddr, inMemAddr + 5, 0);
}
}
uc_err ucErr = uc_mem_map(m_ucEngine, m_peInfo->RecImageBase,
m_peInfo->peSize, UC_PROT_ALL);
if (ucErr != UC_ERR_OK) {
@@ -682,7 +694,6 @@ auto Sandbox::Run(uint64_t address) -> void {
// 为参数腾出空间
rsp -= 3 * 4; // 三个参数hinstDLL, fdwReason, lpvReserved
uc_reg_write(m_ucEngine, UC_X86_REG_ESP, &rsp);
// 按照从右到左的顺序压栈
uint32_t lpvReserved = 0; // 第三个参数为NULL
uint32_t reason = dll_fdwReason; // DLL_PROCESS_ATTACH
@@ -704,6 +715,7 @@ auto Sandbox::Run(uint64_t address) -> void {
}
}
err = uc_emu_start(m_ucEngine, entryPoint, m_peInfo->imageEnd, timeout, 0);
// 2. 有自定义地址 再跑自定义地址
std::cerr << "Entry Point Emulation error: " << uc_strerror(err)
<< std::endl;

View File

@@ -247,6 +247,8 @@ class Sandbox {
}
auto TestLdrListTraversal() -> bool;
auto FinalizeLdrLinks() -> void;
// 注册COM相关API
void RegisterComApis();
@@ -338,6 +340,8 @@ class Sandbox {
auto AddModuleToLdr(const std::shared_ptr<struct_moudle>& module) -> void;
auto CloseLdrList(uint64_t listHeadAddr, size_t entryLinkOffset) -> void;
auto DumpLdrList(const char* listName, uint64_t ldrDataBase, size_t listOffset, size_t entryLinkOffset) -> void;
// 创建LDR_DATA_TABLE_ENTRY结构

View File

@@ -66,140 +66,142 @@ auto Api_GetCurrentThread(void* sandbox, uc_engine* uc, uint64_t address)
printf("[*] GetCurrentThread called, returning pseudo-handle 0x%llx\n",
pseudo_handle);
}
auto Api_LoadLibraryA(void* sandbox, uc_engine* uc, uint64_t address) -> void {
auto context = static_cast<Sandbox*>(sandbox);
uint64_t params_address = 0;
// 获取参数地址
if (context->GetPeInfo()->isX64) {
uc_reg_read(uc, UC_X86_REG_RCX, &params_address);
} else {
uint64_t ebp_address = 0;
uc_reg_read(uc, UC_X86_REG_ESP, &ebp_address);
ebp_address += 0x4;
uc_mem_read(uc, ebp_address, &params_address, 0x4);
}
uint64_t return_address = 0;
std::string module_name;
char buffer[MAX_PATH];
size_t i = 0;
// 读取模块名称
if (params_address != 0) {
do {
uint8_t byte;
uc_mem_read(uc, params_address + i, &byte, 1);
buffer[i] = byte;
i++;
} while (buffer[i - 1] != 0 && i < MAX_PATH);
if (i > 0 && i < MAX_PATH) {
module_name = std::string(buffer);
// 确保模块名以.dll结尾不区分大小写
if (module_name.length() > 4) {
std::string ext = module_name.substr(module_name.length() - 4);
if (_stricmp(ext.c_str(), ".dll") != 0) {
module_name += ".dll";
}
} else {
module_name += ".dll";
}
std::string fuck_up_api_ms = module_name;
if (fuck_up_api_ms.find("api-ms-") != std::string::npos) {
module_name = getDllNameFromApiSetMap(fuck_up_api_ms);
if (module_name.size() <= 1) __debugbreak();
}
// 从模块列表中查找对应模块
for (const auto& module : context->GetModuleList()) {
if ((*module).name == module_name.c_str()) {
return_address = (*module).base;
break;
}
}
}
}
printf("[*] LoadLibraryA: Module=%s, Base=0x%llx\n", module_name.c_str(),
return_address);
uc_reg_write(uc,
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
&return_address);
}
auto Api_LoadLibraryExW(void* sandbox, uc_engine* uc, uint64_t address)
-> void {
// 统一的LoadLibrary辅助函数
auto LoadLibraryHelper(void* sandbox, uc_engine* uc, uint64_t address,
bool isWideChar, bool isEx = false) -> void {
auto context = static_cast<Sandbox*>(sandbox);
uint64_t module_name_address = 0;
uint64_t flags = 0;
// 获取参数
if (context->GetPeInfo()->isX64) {
// x64: rcx = lpLibFileName, r8 = dwFlags
uc_reg_read(uc, UC_X86_REG_RCX, &module_name_address);
uc_reg_read(uc, UC_X86_REG_R8, &flags);
} else {
// x86: 从栈上读取参数
if (isEx) {
uc_reg_read(uc, UC_X86_REG_R8, &flags);
}
}
else {
uint64_t esp_address = 0;
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
esp_address += 0x4; // 跳过返回地址
uc_mem_read(uc, esp_address, &module_name_address, 0x4);
esp_address += 0x8; // 跳过hFile参数
uc_mem_read(uc, esp_address, &flags, 0x4);
if (isEx) {
esp_address += 0x8; // 跳过hFile参数
uc_mem_read(uc, esp_address, &flags, 0x4);
}
}
uint64_t return_address = 0;
std::wstring module_name;
wchar_t buffer[MAX_PATH];
size_t i = 0;
std::string ansi_name;
bool isApiSetMapMeme = false;
// 读取宽字符模块名称
// 读取模块名称
if (module_name_address != 0) {
do {
uint16_t wchar;
uc_mem_read(uc, module_name_address + (i * 2), &wchar, 2);
buffer[i] = wchar;
i++;
} while (buffer[i - 1] != 0 && i < MAX_PATH);
if (isWideChar) {
// 读取宽字符串
std::wstring module_name;
wchar_t buffer[MAX_PATH];
size_t i = 0;
if (i > 0 && i < MAX_PATH) {
module_name = std::wstring(buffer);
std::string ansi_name(module_name.begin(), module_name.end());
do {
uint16_t wchar;
uc_mem_read(uc, module_name_address + (i * 2), &wchar, 2);
buffer[i] = wchar;
i++;
} while (buffer[i - 1] != 0 && i < MAX_PATH);
std::string fuck_up_api_ms = ansi_name;
if (ansi_name.length() > 4) {
std::string ext = ansi_name.substr(ansi_name.length() - 4);
if (_stricmp(ext.c_str(), ".dll") != 0) {
ansi_name += ".dll";
}
} else {
if (i > 0 && i < MAX_PATH) {
module_name = std::wstring(buffer);
ansi_name = std::string(module_name.begin(), module_name.end());
}
}
else {
// 读取ASCII字符串
char buffer[MAX_PATH];
size_t i = 0;
do {
uint8_t byte;
uc_mem_read(uc, module_name_address + i, &byte, 1);
buffer[i] = byte;
i++;
} while (buffer[i - 1] != 0 && i < MAX_PATH);
if (i > 0 && i < MAX_PATH) {
ansi_name = std::string(buffer);
}
}
// 确保模块名以.dll结尾
if (ansi_name.length() > 4) {
std::string ext = ansi_name.substr(ansi_name.length() - 4);
if (_stricmp(ext.c_str(), ".dll") != 0) {
ansi_name += ".dll";
}
if (ansi_name.find("api-ms-") != std::string::npos) {
ansi_name = getDllNameFromApiSetMap(ansi_name);
isApiSetMapMeme = true;
// if (ansi_name.size() <= 1) __debugbreak();
}
}
else {
ansi_name += ".dll";
}
// 从模块列表中查找对应模块
for (const auto& module : context->GetModuleList()) {
if ((*module).name == ansi_name.c_str()) {
return_address = (*module).base;
break;
}
// 处理api-ms-前缀
if (ansi_name.find("api-ms-") != std::string::npos) {
ansi_name = getDllNameFromApiSetMap(ansi_name);
isApiSetMapMeme = true;
if (!isEx && ansi_name.size() <= 1) __debugbreak();
}
// 从模块列表中查找对应模块
for (const auto& module : context->GetModuleList()) {
if ((*module).name == ansi_name.c_str()) {
return_address = (*module).base;
break;
}
}
}
printf("[*] LoadLibraryExW: Module=%ls, Flags=0x%llx, Base=0x%llx\n",
module_name.c_str(), flags, return_address);
if (return_address == 0 && isApiSetMapMeme) {
// 根据调用的函数输出日志
if (isEx) {
printf("[*] LoadLibraryExW: Module=%s, Flags=0x%llx, Base=0x%llx\n",
ansi_name.c_str(), flags, return_address);
}
else {
if (isWideChar) {
printf("[*] LoadLibraryW: Module=%s, Base=0x%llx\n",
ansi_name.c_str(), return_address);
}
else {
printf("[*] LoadLibraryA: Module=%s, Base=0x%llx\n",
ansi_name.c_str(), return_address);
}
}
// 处理API set映射失败的特殊情况
if (return_address == 0 && isApiSetMapMeme && isEx) {
// 找不到就不管他了,操
return_address = 0x1337;
}
// 设置返回值
uc_reg_write(uc,
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
&return_address);
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
&return_address);
}
// LoadLibraryA函数包装器
auto Api_LoadLibraryA(void* sandbox, uc_engine* uc, uint64_t address) -> void {
LoadLibraryHelper(sandbox, uc, address, false);
}
// 新增的LoadLibraryW函数包装器
auto Api_LoadLibraryW(void* sandbox, uc_engine* uc, uint64_t address) -> void {
LoadLibraryHelper(sandbox, uc, address, true);
}
// LoadLibraryExW函数包装器
auto Api_LoadLibraryExW(void* sandbox, uc_engine* uc, uint64_t address) -> void {
LoadLibraryHelper(sandbox, uc, address, true, true);
}
auto Api_GetProcAddress(void* sandbox, uc_engine* uc, uint64_t address)
-> void {
@@ -1376,7 +1378,9 @@ auto Sandbox::InitApiHooks() -> void {
_fakeApi{.func = Api_VariantClear, .paramCount = 1};
auto FakeApi_SysAllocString =
_fakeApi{.func = Api_SysAllocString, .paramCount = 1};
auto FakeApi_LoadLibraryW =
_fakeApi{ .func = Api_LoadLibraryW, .paramCount = 1 };
api_map = {
{"GetSystemTimeAsFileTime",
std::make_shared<_fakeApi>(FakeApi_GetSystemTimeAsFileTime)},
@@ -1519,6 +1523,7 @@ auto Sandbox::InitApiHooks() -> void {
{"VariantInit", std::make_shared<_fakeApi>(FakeApi_VariantInit)},
{"VariantClear", std::make_shared<_fakeApi>(FakeApi_VariantClear)},
{"SysAllocString", std::make_shared<_fakeApi>(FakeApi_SysAllocString)},
{"LoadLibraryW", std::make_shared<_fakeApi>(FakeApi_LoadLibraryW)},
};
}
auto Sandbox::EmulateApi(uc_engine* uc, uint64_t address, uint64_t rip,

View File

@@ -1,11 +1,30 @@
#include "sandbox_callbacks.h"
// 通用模板函数实现绝对值
template <typename T>
inline T duck_abs(T value) {
// 针对有符号类型
if constexpr (std::is_signed<T>::value) {
return value < 0 ? -value : value;
}
// 无符号类型直接返回
else {
return value;
}
}
// 或者使用这个更简单的实现
inline uint64_t duck_abs(int64_t a, int64_t b) {
uint64_t diff = (a > b) ? (uint64_t)(a - b) : (uint64_t)(b - a);
return diff;
}
namespace sandboxCallbacks {
static uint64_t lastRip = 0;
void handleCodeRun(uc_engine* uc, uint64_t address, uint32_t size,
void* userData) {
uint64_t currentRip = 0;
uint64_t currentRsp = 0;
uint64_t currentRax = 0;
static uint64_t lastRip = 0;
auto* sandbox = static_cast<Sandbox*>(userData);
if (!sandbox) return;
@@ -66,7 +85,9 @@ void handleCodeRun(uc_engine* uc, uint64_t address, uint32_t size,
if (currentSectionIndex >= 0) {
sandbox->SetLastExecuteSectionIndex(currentSectionIndex);
}
/*
auto [lastReadImpAddr, lastImp] = sandbox->GetLastImpRead();
if (lastImp != nullptr && currentRip == lastReadImpAddr) {
printf(
"direct call function [%s]%s at file address: %llx lastRip: "
@@ -76,19 +97,24 @@ void handleCodeRun(uc_engine* uc, uint64_t address, uint32_t size,
sandbox->EmulateApi(uc, lastReadImpAddr, currentRip, lastImp->name);
sandbox->SetLastImpRead(0, nullptr);
} else {
for (auto module : sandbox->GetModuleList()) {
for (auto item : module->export_function) {
const auto vmAddress = module->base + item->function_address;
if (vmAddress == currentRip) {
printf("[!!!]detect no correct call, currentRip: 0x%llx\n",
currentRip);
sandbox->SetLastImpRead(0, nullptr);
if (duck_abs(currentRip - address) > PAGE_SIZE) {
for (auto module : sandbox->GetModuleList()) {
for (auto item : module->export_function) {
const auto vmAddress = module->base + item->function_address;
if (vmAddress == currentRip) {
printf("[!!!]detect no correct call, currentRip: 0x%llx\n",
currentRip);
sandbox->SetLastImpRead(0, nullptr);
sandbox->EmulateApi(uc, vmAddress, currentRip, item->name);
sandbox->EmulateApi(uc, vmAddress, currentRip, item->name);
}
}
}
}
}
*/
lastRip = currentRip;
if (LOG_LEVEL > 2) {
// 使用Capstone反汇编
@@ -107,6 +133,43 @@ void handleCodeRun(uc_engine* uc, uint64_t address, uint32_t size,
}
}
void handleApiCall(uc_engine* uc, uint64_t address, uint32_t size, void* userData)
{
uint64_t currentRip = 0;
auto* sandbox = static_cast<Sandbox*>(userData);
if (!sandbox) return;
uc_reg_read(uc,
sandbox->GetPeInfo()->isX64 ? UC_X86_REG_RIP : UC_X86_REG_EIP,
&currentRip);
auto [lastReadImpAddr, lastImp] = sandbox->GetLastImpRead();
if (lastImp != nullptr && currentRip == lastReadImpAddr) {
printf(
"direct call function [%s]%s at file address: %llx lastRip: "
"%llx\n",
lastImp->dll_name,
lastImp->name, address, lastRip);
sandbox->EmulateApi(uc, lastReadImpAddr, currentRip, lastImp->name);
sandbox->SetLastImpRead(0, nullptr);
}
else {
for (auto module : sandbox->GetModuleList()) {
for (auto item : module->export_function) {
const auto vmAddress = module->base + item->function_address;
if (vmAddress == currentRip) {
printf("[!!!]detect no correct call, currentRip: 0x%llx\n",
currentRip);
sandbox->SetLastImpRead(0, nullptr);
sandbox->EmulateApi(uc, vmAddress, currentRip, item->name);
}
}
}
}
}
void handleMemoryRead(uc_engine* uc, uc_mem_type type, uint64_t address,
int size, int64_t value, void* userData) {
auto* sandbox = static_cast<Sandbox*>(userData);

View File

@@ -3,6 +3,7 @@
namespace sandboxCallbacks {
void handleCodeRun(uc_engine* uc, uint64_t address, uint32_t size,
void* userData);
void handleApiCall(uc_engine* uc, uint64_t address, uint32_t size, void* userData);
void handleMemoryRead(uc_engine* uc, uc_mem_type type, uint64_t address,
int size, int64_t value, void* userData);
void handleMemoryUnmapRead(uc_engine* uc, uc_mem_type type, uint64_t address,

View File

@@ -283,7 +283,80 @@ auto Sandbox::TestLdrListTraversal() -> bool {
}
return true;
}
auto Sandbox::FinalizeLdrLinks() -> void {
if (!m_peInfo->isX64) {
return;
}
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>ַ
uint64_t inLoadOrderListHead = m_peb64.Ldr + offsetof(X64_PEB_LDR_DATA, InLoadOrderModuleList);
uint64_t inMemoryOrderListHead = m_peb64.Ldr + offsetof(X64_PEB_LDR_DATA, InMemoryOrderModuleList);
uint64_t inInitOrderListHead = m_peb64.Ldr + offsetof(X64_PEB_LDR_DATA, InInitializationOrderModuleList);
// <20>պ<EFBFBD>InLoadOrderModuleList<73><74><EFBFBD><EFBFBD>
CloseLdrList(inLoadOrderListHead, offsetof(LDR_DATA_TABLE_ENTRY, InLoadOrderLinks));
// <20>պ<EFBFBD>InMemoryOrderModuleList<73><74><EFBFBD><EFBFBD>
CloseLdrList(inMemoryOrderListHead, offsetof(LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks));
// <20>պ<EFBFBD>InInitializationOrderModuleList<73><74><EFBFBD><EFBFBD>
CloseLdrList(inInitOrderListHead, offsetof(LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks));
}
auto Sandbox::CloseLdrList(uint64_t listHeadAddr, size_t entryLinkOffset) -> void {
LIST_ENTRY listHead;
uc_mem_read(m_ucEngine, listHeadAddr, &listHead, sizeof(LIST_ENTRY));
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>գ<EFBFBD><D5A3><EFBFBD><EFBFBD><EFBFBD><E8B4A6>
if (listHead.Flink == (LIST_ENTRY*)listHeadAddr) {
return;
}
// <20>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>Ԫ<EFBFBD><D4AA>
uint64_t currentLink = (uint64_t)listHead.Flink;
uint64_t lastLink = 0;
while (currentLink != listHeadAddr && currentLink != 0) {
LIST_ENTRY currentEntry;
uc_mem_read(m_ucEngine, currentLink, &currentEntry, sizeof(LIST_ENTRY));
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>ջ<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD>Լ<EFBFBD><D4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>Ч<EFBFBD>ڵ<EFBFBD>
if (currentEntry.Flink == nullptr ||
(uint64_t)currentEntry.Flink == currentLink ||
(uint64_t)currentEntry.Flink == 0) {
lastLink = currentLink;
break;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>˵<EFBFBD><CBB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD>պ<EFBFBD>
if ((uint64_t)currentEntry.Flink == listHeadAddr) {
return; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD>պϣ<D5BA><CFA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD>
}
lastLink = currentLink;
currentLink = (uint64_t)currentEntry.Flink;
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>Ԫ<EFBFBD>أ<EFBFBD><D8A3><EFBFBD><EFBFBD>޸<EFBFBD><DEB8><EFBFBD><EFBFBD><EFBFBD>
if (lastLink != 0) {
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>Ԫ<EFBFBD><D4AA>
LIST_ENTRY lastEntry;
uc_mem_read(m_ucEngine, lastLink, &lastEntry, sizeof(LIST_ENTRY));
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>Ԫ<EFBFBD>ص<EFBFBD>Flinkָ<6B><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ
lastEntry.Flink = (LIST_ENTRY*)listHeadAddr;
uc_mem_write(m_ucEngine, lastLink, &lastEntry, sizeof(LIST_ENTRY));
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>Blinkָ<6B><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>Ԫ<EFBFBD><D4AA>
listHead.Blink = (LIST_ENTRY*)lastLink;
uc_mem_write(m_ucEngine, listHeadAddr, &listHead, sizeof(LIST_ENTRY));
if (LOG_LEVEL > 4) {
printf("<EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ=0x%llx, <20><><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA>=0x%llx\n",
listHeadAddr, lastLink);
}
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡָ<D3A1><D6B8><EFBFBD><EFBFBD>LDR<44><52><EFBFBD><EFBFBD>
auto Sandbox::DumpLdrList(const char* listName, uint64_t ldrDataBase, size_t listOffset, size_t entryLinkOffset) -> void {
if (LOG_LEVEL > 4) {