修复沙箱功能和API实现
- 在沙箱中添加了对CreateProcessW的支持,整合了CreateProcessA和CreateProcessW的共同逻辑 - 实现了URLDownloadToFileW函数,增加了对可疑URL的检测 - 更新了API钩子以支持新的API功能 - 改进了错误处理和日志记录,确保更好的调试信息输出 - 调整了主函数中的恶意软件扫描和沙箱功能调用顺序,确保恶意软件扫描优先执行
This commit is contained in:
@@ -313,29 +313,26 @@ auto doMalwareScan(int argc, char* argv[]) -> void {
|
||||
}
|
||||
|
||||
int doSandbox(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
std::cout << "用法: " << argv[0] << " <文件路径> <地址>" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//if (argc < 3) {
|
||||
// std::cout << "用法: " << argv[0] << " <文件路径> <地址>" << std::endl;
|
||||
// return;
|
||||
//}
|
||||
//std::string filePath = argv[1];
|
||||
|
||||
std::string filePath = "Z:\\mso.dll";
|
||||
|
||||
std::string filePath = argv[1];
|
||||
auto peInfo = getPeInfo(filePath);
|
||||
if (peInfo == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
Sandbox se;
|
||||
se.InitEnv(peInfo);
|
||||
se.Run(0x180003980);
|
||||
// se.Run(0x180003980);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// doMl(argc, argv);
|
||||
// doPredict(argc, argv);
|
||||
//doMalwareScan(argc, argv);
|
||||
doSandbox(argc, argv);
|
||||
doMalwareScan(argc, argv);
|
||||
// doSandbox(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -408,6 +408,7 @@ auto Api_FlsSetValue(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
auto Api_CreateFileW(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
auto Api_WriteFile(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
auto Api_CreateProcessA(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
auto Api_CreateProcessW(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
auto Api_GetCurrentProcess(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void;
|
||||
auto Api_GetCurrentThread(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
|
||||
@@ -659,6 +659,256 @@ auto Api_Sleep(void* sandbox, uc_engine* uc, uint64_t address) -> void {
|
||||
printf("Sleep API called with %u milliseconds\n", milliseconds);
|
||||
}
|
||||
|
||||
auto Api_OpenThreadToken(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint64_t ThreadHandle = 0;
|
||||
uint64_t DesiredAccess = 0;
|
||||
uint64_t OpenAsSelf = 0;
|
||||
uint64_t TokenHandle = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = ThreadHandle, rdx = DesiredAccess, r8 = OpenAsSelf, r9 =
|
||||
// TokenHandle
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &ThreadHandle);
|
||||
uc_reg_read(uc, UC_X86_REG_RDX, &DesiredAccess);
|
||||
uint64_t temp_open_as_self;
|
||||
uc_reg_read(uc, UC_X86_REG_R8, &temp_open_as_self);
|
||||
OpenAsSelf = static_cast<uint32_t>(temp_open_as_self);
|
||||
uc_reg_read(uc, UC_X86_REG_R9, &TokenHandle);
|
||||
} else {
|
||||
// x86: 从栈上读取参数
|
||||
uint32_t esp_address = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4; // 跳过返回地址
|
||||
|
||||
uint32_t temp_handle;
|
||||
uc_mem_read(uc, esp_address, &temp_handle, sizeof(uint32_t));
|
||||
ThreadHandle = temp_handle;
|
||||
esp_address += 0x4;
|
||||
|
||||
uc_mem_read(uc, esp_address, &DesiredAccess, sizeof(uint32_t));
|
||||
esp_address += 0x4;
|
||||
|
||||
uc_mem_read(uc, esp_address, &OpenAsSelf, sizeof(uint32_t));
|
||||
esp_address += 0x4;
|
||||
|
||||
uint32_t temp_token_handle;
|
||||
uc_mem_read(uc, esp_address, &temp_token_handle, sizeof(uint32_t));
|
||||
TokenHandle = temp_token_handle;
|
||||
}
|
||||
|
||||
// 创建一个模拟的令牌句柄
|
||||
uint64_t fake_token_handle = 0x1234; // 使用一个假的令牌句柄
|
||||
|
||||
// 将令牌句柄写入输出参数
|
||||
if (TokenHandle != 0) {
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
uc_mem_write(uc, TokenHandle, &fake_token_handle, sizeof(uint64_t));
|
||||
} else {
|
||||
uint32_t token_handle_32 = static_cast<uint32_t>(fake_token_handle);
|
||||
uc_mem_write(uc, TokenHandle, &token_handle_32, sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
printf(
|
||||
"[*] OpenThreadToken: ThreadHandle=0x%llx, DesiredAccess=0x%x, "
|
||||
"OpenAsSelf=%d, TokenHandle=0x%llx\n",
|
||||
ThreadHandle, DesiredAccess, OpenAsSelf, fake_token_handle);
|
||||
|
||||
// 设置返回值为TRUE
|
||||
uint64_t result = 1;
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
}
|
||||
auto Api_LookupPrivilegeValueA(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint64_t lpSystemName = 0;
|
||||
uint64_t lpName = 0;
|
||||
uint64_t lpLuid = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &lpSystemName);
|
||||
uc_reg_read(uc, UC_X86_REG_RDX, &lpName);
|
||||
uc_reg_read(uc, UC_X86_REG_R8, &lpLuid);
|
||||
} else {
|
||||
uint32_t esp_address = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4;
|
||||
|
||||
uint32_t temp_system_name, temp_name, temp_luid;
|
||||
uc_mem_read(uc, esp_address, &temp_system_name, sizeof(uint32_t));
|
||||
uc_mem_read(uc, esp_address + 0x4, &temp_name, sizeof(uint32_t));
|
||||
uc_mem_read(uc, esp_address + 0x8, &temp_luid, sizeof(uint32_t));
|
||||
|
||||
lpSystemName = temp_system_name;
|
||||
lpName = temp_name;
|
||||
lpLuid = temp_luid;
|
||||
}
|
||||
|
||||
// 读取权限名称
|
||||
char privName[256] = {0};
|
||||
if (lpName != 0) {
|
||||
size_t i = 0;
|
||||
do {
|
||||
uint8_t byte;
|
||||
uc_mem_read(uc, lpName + i, &byte, 1);
|
||||
privName[i] = byte;
|
||||
i++;
|
||||
} while (privName[i - 1] != 0 && i < sizeof(privName));
|
||||
}
|
||||
|
||||
// 模拟LUID结构
|
||||
LUID luid = {0};
|
||||
if (strcmp(privName, "SeDebugPrivilege") == 0) {
|
||||
luid.LowPart = 20; // SeDebugPrivilege的典型LUID值
|
||||
luid.HighPart = 0;
|
||||
}
|
||||
|
||||
// 写入LUID到输出参数
|
||||
if (lpLuid != 0) {
|
||||
uc_mem_write(uc, lpLuid, &luid, sizeof(LUID));
|
||||
}
|
||||
|
||||
printf("[*] LookupPrivilegeValueA: SystemName=%s, Name=%s\n",
|
||||
lpSystemName ? "Local" : "NULL", privName);
|
||||
|
||||
// 返回TRUE
|
||||
uint64_t result = 1;
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
}
|
||||
|
||||
auto Api_AdjustTokenPrivileges(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint64_t TokenHandle = 0;
|
||||
uint64_t DisableAllPrivileges = 0;
|
||||
uint64_t NewState = 0;
|
||||
uint32_t BufferLength = 0;
|
||||
uint64_t PreviousState = 0;
|
||||
uint64_t ReturnLength = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &TokenHandle);
|
||||
uc_reg_read(uc, UC_X86_REG_RDX, &DisableAllPrivileges);
|
||||
uc_reg_read(uc, UC_X86_REG_R8, &NewState);
|
||||
uint64_t temp_length;
|
||||
uc_reg_read(uc, UC_X86_REG_R9, &temp_length);
|
||||
BufferLength = static_cast<uint32_t>(temp_length);
|
||||
// 从栈上获取剩余参数
|
||||
uint64_t rsp;
|
||||
uc_reg_read(uc, UC_X86_REG_RSP, &rsp);
|
||||
uc_mem_read(uc, rsp + 0x28, &PreviousState, sizeof(uint64_t));
|
||||
uc_mem_read(uc, rsp + 0x30, &ReturnLength, sizeof(uint64_t));
|
||||
} else {
|
||||
uint32_t esp_address = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4;
|
||||
|
||||
uint32_t temp_values[6];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
uc_mem_read(uc, esp_address + (i * 4), &temp_values[i],
|
||||
sizeof(uint32_t));
|
||||
}
|
||||
|
||||
TokenHandle = temp_values[0];
|
||||
DisableAllPrivileges = temp_values[1];
|
||||
NewState = temp_values[2];
|
||||
BufferLength = temp_values[3];
|
||||
PreviousState = temp_values[4];
|
||||
ReturnLength = temp_values[5];
|
||||
}
|
||||
|
||||
printf("[*] AdjustTokenPrivileges: TokenHandle=0x%llx, DisableAll=%d\n",
|
||||
TokenHandle, (int)DisableAllPrivileges);
|
||||
|
||||
// 返回TRUE
|
||||
uint64_t result = 1;
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
|
||||
// 设置ERROR_NOT_ALL_ASSIGNED
|
||||
DWORD error = ERROR_NOT_ALL_ASSIGNED; // 1300
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
} else {
|
||||
context->GetTeb32()->LastErrorValue = error;
|
||||
}
|
||||
}
|
||||
auto Api_CreateDirectoryW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint64_t lpPathName = 0;
|
||||
uint64_t lpSecurityAttributes = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = lpPathName, rdx = lpSecurityAttributes
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &lpPathName);
|
||||
uc_reg_read(uc, UC_X86_REG_RDX, &lpSecurityAttributes);
|
||||
} else {
|
||||
// x86: 从栈上读取参数
|
||||
uint32_t esp_address = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4; // 跳过返回地址
|
||||
|
||||
uint32_t temp_path_name, temp_security_attr;
|
||||
uc_mem_read(uc, esp_address, &temp_path_name, sizeof(uint32_t));
|
||||
uc_mem_read(uc, esp_address + 0x4, &temp_security_attr,
|
||||
sizeof(uint32_t));
|
||||
|
||||
lpPathName = temp_path_name;
|
||||
lpSecurityAttributes = temp_security_attr;
|
||||
}
|
||||
|
||||
// 读取目录路径
|
||||
wchar_t pathBuffer[MAX_PATH] = {0};
|
||||
if (lpPathName != 0) {
|
||||
size_t i = 0;
|
||||
do {
|
||||
uint16_t wchar;
|
||||
uc_mem_read(uc, lpPathName + (i * 2), &wchar, 2);
|
||||
pathBuffer[i] = wchar;
|
||||
i++;
|
||||
} while (pathBuffer[i - 1] != 0 && i < MAX_PATH);
|
||||
}
|
||||
|
||||
// 将宽字符转换为常规字符串用于日志输出
|
||||
std::wstring widePath(pathBuffer);
|
||||
std::string path(widePath.begin(), widePath.end());
|
||||
|
||||
// 在实际的实现中,可能需要检查目录是否已存在
|
||||
// 这里简单地返回成功,不实际创建目录
|
||||
bool success = true;
|
||||
|
||||
// 输出日志
|
||||
printf("[*] CreateDirectoryW: Path=%s, Result=%s\n", path.c_str(),
|
||||
success ? "TRUE" : "FALSE");
|
||||
|
||||
// 设置返回值
|
||||
uint64_t result = success ? 1 : 0;
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
|
||||
// 如果失败,可以设置LastError
|
||||
if (!success) {
|
||||
DWORD error = ERROR_PATH_NOT_FOUND; // 或其他适当的错误代码
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
} else {
|
||||
context->GetTeb32()->LastErrorValue = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto Sandbox::InitApiHooks() -> void {
|
||||
auto FakeApi_GetSystemTimeAsFileTime =
|
||||
_fakeApi{.func = Api_GetSystemTimeAsFileTime, .paramCount = 1};
|
||||
@@ -774,6 +1024,8 @@ auto Sandbox::InitApiHooks() -> void {
|
||||
auto FakeApi_CreatePipe = _fakeApi{.func = Api_CreatePipe, .paramCount = 4};
|
||||
auto FakeApi_CreateProcessA =
|
||||
_fakeApi{.func = Api_CreateProcessA, .paramCount = 10};
|
||||
auto FakeApi_CreateProcessW =
|
||||
_fakeApi{.func = Api_CreateProcessW, .paramCount = 10};
|
||||
auto FakeApi_ReadFile = _fakeApi{.func = Api_ReadFile, .paramCount = 5};
|
||||
auto FakeApi_WlanOpenHandle =
|
||||
_fakeApi{.func = Api_WlanOpenHandle, .paramCount = 4};
|
||||
@@ -800,7 +1052,16 @@ auto Sandbox::InitApiHooks() -> void {
|
||||
_fakeApi{.func = Api_FwpmFilterAdd0, .paramCount = 4};
|
||||
auto FakeApi_FwpmEngineClose0 =
|
||||
_fakeApi{.func = Api_FwpmEngineClose0, .paramCount = 1};
|
||||
|
||||
auto FakeApi_OpenThreadToken =
|
||||
_fakeApi{.func = Api_OpenThreadToken, .paramCount = 4};
|
||||
auto FakeApi_LookupPrivilegeValueA =
|
||||
_fakeApi{.func = Api_LookupPrivilegeValueA, .paramCount = 3};
|
||||
auto FakeApi_AdjustTokenPrivileges =
|
||||
_fakeApi{.func = Api_AdjustTokenPrivileges, .paramCount = 6};
|
||||
auto FakeApi_CreateDirectoryW =
|
||||
_fakeApi{.func = Api_CreateDirectoryW, .paramCount = 2};
|
||||
auto FakeApi_URLDownloadToFileW =
|
||||
_fakeApi{.func = Api_URLDownloadToFileW, .paramCount = 5};
|
||||
api_map = {
|
||||
{"GetSystemTimeAsFileTime",
|
||||
std::make_shared<_fakeApi>(FakeApi_GetSystemTimeAsFileTime)},
|
||||
@@ -896,6 +1157,7 @@ auto Sandbox::InitApiHooks() -> void {
|
||||
{"FlsSetValue", std::make_shared<_fakeApi>(FakeApi_FlsSetValue)},
|
||||
{"CreatePipe", std::make_shared<_fakeApi>(FakeApi_CreatePipe)},
|
||||
{"CreateProcessA", std::make_shared<_fakeApi>(FakeApi_CreateProcessA)},
|
||||
{"CreateProcessW", std::make_shared<_fakeApi>(FakeApi_CreateProcessW)},
|
||||
{"ReadFile", std::make_shared<_fakeApi>(FakeApi_ReadFile)},
|
||||
{"WlanOpenHandle", std::make_shared<_fakeApi>(FakeApi_WlanOpenHandle)},
|
||||
{"WlanEnumInterfaces",
|
||||
@@ -911,6 +1173,8 @@ auto Sandbox::InitApiHooks() -> void {
|
||||
std::make_shared<_fakeApi>(FakeApi_OpenProcessToken)},
|
||||
{"GetTokenInformation",
|
||||
std::make_shared<_fakeApi>(FakeApi_GetTokenInformation)},
|
||||
{"OpenThreadToken",
|
||||
std::make_shared<_fakeApi>(FakeApi_OpenThreadToken)},
|
||||
// 添加WFP相关API映射
|
||||
{"FwpmEngineOpen0",
|
||||
std::make_shared<_fakeApi>(FakeApi_FwpmEngineOpen0)},
|
||||
@@ -919,6 +1183,18 @@ auto Sandbox::InitApiHooks() -> void {
|
||||
{"FwpmFilterAdd0", std::make_shared<_fakeApi>(FakeApi_FwpmFilterAdd0)},
|
||||
{"FwpmEngineClose0",
|
||||
std::make_shared<_fakeApi>(FakeApi_FwpmEngineClose0)},
|
||||
{"LookupPrivilegeValueA",
|
||||
std::make_shared<_fakeApi>(FakeApi_LookupPrivilegeValueA)},
|
||||
{"AdjustTokenPrivileges",
|
||||
std::make_shared<_fakeApi>(FakeApi_AdjustTokenPrivileges)},
|
||||
{"LookupPrivilegeValueA",
|
||||
std::make_shared<_fakeApi>(FakeApi_LookupPrivilegeValueA)},
|
||||
{"AdjustTokenPrivileges",
|
||||
std::make_shared<_fakeApi>(FakeApi_AdjustTokenPrivileges)},
|
||||
{"CreateDirectoryW",
|
||||
std::make_shared<_fakeApi>(FakeApi_CreateDirectoryW)},
|
||||
{"URLDownloadToFileW",
|
||||
std::make_shared<_fakeApi>(FakeApi_URLDownloadToFileW)},
|
||||
};
|
||||
}
|
||||
auto Sandbox::EmulateApi(uc_engine* uc, uint64_t address, uint64_t rip,
|
||||
@@ -974,4 +1250,4 @@ auto Sandbox::EmulateApi(uc_engine* uc, uint64_t address, uint64_t rip,
|
||||
printf("ApiName: %s not found\n", ApiName.c_str());
|
||||
uc_emu_stop(uc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -474,6 +474,211 @@ auto Api_Process32NextW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
}
|
||||
}
|
||||
|
||||
// 内部函数,用于处理CreateProcessA和CreateProcessW的共同逻辑
|
||||
auto CreateProcessInternal(void* sandbox, uc_engine* uc,
|
||||
uint64_t lpApplicationName, uint64_t lpCommandLine,
|
||||
uint64_t lpProcessInformation,
|
||||
uint64_t lpStartupInfo, bool isWideChar) -> bool {
|
||||
auto* context = static_cast<Sandbox*>(sandbox);
|
||||
std::string applicationName;
|
||||
std::wstring wApplicationName;
|
||||
std::string commandLine;
|
||||
std::wstring wCommandLine;
|
||||
|
||||
// 读取应用程序名称
|
||||
if (lpApplicationName != 0) {
|
||||
if (isWideChar) {
|
||||
// 读取宽字符应用程序名称
|
||||
wchar_t buffer[MAX_PATH] = {0};
|
||||
size_t i = 0;
|
||||
bool success = true;
|
||||
|
||||
do {
|
||||
wchar_t ch;
|
||||
uc_err err =
|
||||
uc_mem_read(uc, lpApplicationName + (i * 2), &ch, 2);
|
||||
if (err != UC_ERR_OK) {
|
||||
printf(
|
||||
"[!] Error reading wide application name at address "
|
||||
"0x%llx: %u\n",
|
||||
lpApplicationName + (i * 2), err);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if (ch == 0) break;
|
||||
buffer[i] = ch;
|
||||
i++;
|
||||
} while (i < MAX_PATH - 1);
|
||||
|
||||
// 确保字符串以 NULL 结尾
|
||||
buffer[i] = 0;
|
||||
|
||||
if (success) {
|
||||
wApplicationName = std::wstring(buffer);
|
||||
// 转换为ANSI以便于日志记录
|
||||
std::string ansiAppName(wApplicationName.begin(),
|
||||
wApplicationName.end());
|
||||
printf("[*] Read Wide ApplicationName: %s (Length: %zu)\n",
|
||||
ansiAppName.c_str(), wApplicationName.length());
|
||||
}
|
||||
} else {
|
||||
// 读取ANSI应用程序名称
|
||||
char buffer[MAX_PATH] = {0};
|
||||
size_t i = 0;
|
||||
bool success = true;
|
||||
|
||||
do {
|
||||
uint8_t byte;
|
||||
uc_err err = uc_mem_read(uc, lpApplicationName + i, &byte, 1);
|
||||
if (err != UC_ERR_OK) {
|
||||
printf(
|
||||
"[!] Error reading application name at address 0x%llx: "
|
||||
"%u\n",
|
||||
lpApplicationName + i, err);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if (byte == 0) break;
|
||||
buffer[i] = byte;
|
||||
i++;
|
||||
} while (i < MAX_PATH - 1);
|
||||
|
||||
// 确保字符串以 NULL 结尾
|
||||
buffer[i] = 0;
|
||||
|
||||
if (success) {
|
||||
applicationName = std::string(buffer);
|
||||
printf("[*] Read ANSI ApplicationName: %s (Length: %zu)\n",
|
||||
buffer, applicationName.length());
|
||||
// 转换为宽字符
|
||||
wApplicationName = std::wstring(applicationName.begin(),
|
||||
applicationName.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 读取命令行
|
||||
if (lpCommandLine != 0) {
|
||||
if (isWideChar) {
|
||||
// 读取宽字符命令行
|
||||
wchar_t buffer[MAX_PATH] = {0};
|
||||
size_t i = 0;
|
||||
bool success = true;
|
||||
|
||||
do {
|
||||
wchar_t ch;
|
||||
uc_err err = uc_mem_read(uc, lpCommandLine + (i * 2), &ch, 2);
|
||||
if (err != UC_ERR_OK) {
|
||||
printf(
|
||||
"[!] Error reading wide command line at address "
|
||||
"0x%llx: %u\n",
|
||||
lpCommandLine + (i * 2), err);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if (ch == 0) break;
|
||||
buffer[i] = ch;
|
||||
i++;
|
||||
} while (i < MAX_PATH - 1);
|
||||
|
||||
// 确保字符串以 NULL 结尾
|
||||
buffer[i] = 0;
|
||||
|
||||
if (success) {
|
||||
wCommandLine = std::wstring(buffer);
|
||||
// 转换为ANSI以便于日志记录
|
||||
std::string ansiCmdLine(wCommandLine.begin(),
|
||||
wCommandLine.end());
|
||||
printf("[*] Read Wide CommandLine: %s (Length: %zu)\n",
|
||||
ansiCmdLine.c_str(), wCommandLine.length());
|
||||
}
|
||||
} else {
|
||||
// 读取ANSI命令行
|
||||
char buffer[MAX_PATH] = {0};
|
||||
size_t i = 0;
|
||||
bool success = true;
|
||||
|
||||
do {
|
||||
uint8_t byte;
|
||||
uc_err err = uc_mem_read(uc, lpCommandLine + i, &byte, 1);
|
||||
if (err != UC_ERR_OK) {
|
||||
printf(
|
||||
"[!] Error reading command line at address 0x%llx: "
|
||||
"%u\n",
|
||||
lpCommandLine + i, err);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if (byte == 0) break;
|
||||
buffer[i] = byte;
|
||||
i++;
|
||||
} while (i < MAX_PATH - 1);
|
||||
|
||||
// 确保字符串以 NULL 结尾
|
||||
buffer[i] = 0;
|
||||
|
||||
if (success) {
|
||||
commandLine = std::string(buffer);
|
||||
printf("[*] Read ANSI CommandLine: %s (Length: %zu)\n", buffer,
|
||||
commandLine.length());
|
||||
// 转换为宽字符
|
||||
wCommandLine =
|
||||
std::wstring(commandLine.begin(), commandLine.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录调用信息
|
||||
if (isWideChar) {
|
||||
std::string ansiAppName(wApplicationName.begin(),
|
||||
wApplicationName.end());
|
||||
std::string ansiCmdLine(wCommandLine.begin(), wCommandLine.end());
|
||||
printf("[*] CreateProcessW: ApplicationName=%s, CommandLine=%s\n",
|
||||
ansiAppName.empty() ? "(null)" : ansiAppName.c_str(),
|
||||
ansiCmdLine.empty() ? "(null)" : ansiCmdLine.c_str());
|
||||
} else {
|
||||
printf("[*] CreateProcessA: ApplicationName=%s, CommandLine=%s\n",
|
||||
applicationName.empty() ? "(null)" : applicationName.c_str(),
|
||||
commandLine.empty() ? "(null)" : commandLine.c_str());
|
||||
}
|
||||
|
||||
// 模拟创建进程,设置进程和线程ID
|
||||
DWORD processId = 0x1234;
|
||||
DWORD threadId = 0x5678;
|
||||
HANDLE hProcess = (HANDLE)0x1340;
|
||||
HANDLE hThread = (HANDLE)0x1341;
|
||||
|
||||
// 写入进程信息
|
||||
if (lpProcessInformation != 0) {
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
struct PROCESS_INFORMATION64 {
|
||||
HANDLE hProcess;
|
||||
HANDLE hThread;
|
||||
DWORD dwProcessId;
|
||||
DWORD dwThreadId;
|
||||
} pi;
|
||||
pi.hProcess = (HANDLE)hProcess;
|
||||
pi.hThread = (HANDLE)hThread;
|
||||
pi.dwProcessId = processId;
|
||||
pi.dwThreadId = threadId;
|
||||
uc_mem_write(uc, lpProcessInformation, &pi, sizeof(pi));
|
||||
printf("[*] Wrote process info (x64) to 0x%llx\n",
|
||||
lpProcessInformation);
|
||||
} else {
|
||||
PROCESS_INFORMATION pi;
|
||||
pi.hProcess = hProcess;
|
||||
pi.hThread = hThread;
|
||||
pi.dwProcessId = processId;
|
||||
pi.dwThreadId = threadId;
|
||||
uc_mem_write(uc, lpProcessInformation, &pi, sizeof(pi));
|
||||
printf("[*] Wrote process info (x86) to 0x%llx\n",
|
||||
lpProcessInformation);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Api_CreateProcessA(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
@@ -521,109 +726,73 @@ auto Api_CreateProcessA(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
esp, temp_app_name, temp_cmd_line);
|
||||
}
|
||||
|
||||
// 读取应用程序名称
|
||||
std::string applicationName;
|
||||
if (lpApplicationName != 0) {
|
||||
// 增加大小检测以避免内存溢出
|
||||
char buffer[MAX_PATH] = {0};
|
||||
size_t i = 0;
|
||||
bool success = true;
|
||||
// 调用内部函数处理共同逻辑
|
||||
bool success =
|
||||
CreateProcessInternal(sandbox, uc, lpApplicationName, lpCommandLine,
|
||||
lpProcessInformation, lpStartupInfo, false);
|
||||
|
||||
do {
|
||||
uint8_t byte;
|
||||
uc_err err = uc_mem_read(uc, lpApplicationName + i, &byte, 1);
|
||||
if (err != UC_ERR_OK) {
|
||||
printf(
|
||||
"[!] Error reading application name at address 0x%llx: "
|
||||
"%u\n",
|
||||
lpApplicationName + i, err);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
buffer[i] = byte;
|
||||
i++;
|
||||
} while (buffer[i - 1] != 0 && i < MAX_PATH - 1);
|
||||
// 返回结果
|
||||
uint64_t result = success ? 1 : 0;
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
}
|
||||
|
||||
// 确保字符串以 NULL 结尾
|
||||
buffer[i] = 0;
|
||||
// CreateProcessW的实现
|
||||
auto Api_CreateProcessW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint64_t lpApplicationName = 0;
|
||||
uint64_t lpCommandLine = 0;
|
||||
uint64_t lpProcessInformation = 0;
|
||||
uint64_t lpStartupInfo = 0;
|
||||
|
||||
if (success) {
|
||||
applicationName = std::string(buffer);
|
||||
printf("[*] Read ApplicationName: %s (Length: %zu)\n", buffer,
|
||||
applicationName.length());
|
||||
}
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = lpApplicationName, rdx = lpCommandLine
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &lpApplicationName);
|
||||
uc_reg_read(uc, UC_X86_REG_RDX, &lpCommandLine);
|
||||
// 从栈上获取 PROCESS_INFORMATION 和 STARTUPINFO
|
||||
uint64_t rsp;
|
||||
uc_reg_read(uc, UC_X86_REG_RSP, &rsp);
|
||||
rsp += 0x28; // 跳过前4个参数的影子空间
|
||||
uc_mem_read(uc, rsp + 0x20, &lpProcessInformation, sizeof(uint64_t));
|
||||
uc_mem_read(uc, rsp + 0x18, &lpStartupInfo, sizeof(uint64_t));
|
||||
|
||||
printf(
|
||||
"[*] CreateProcessW Debug (x64): AppNameAddr=0x%llx, "
|
||||
"CmdLineAddr=0x%llx\n",
|
||||
lpApplicationName, lpCommandLine);
|
||||
} else {
|
||||
// x86: 从栈上读取参数
|
||||
uint32_t esp;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp);
|
||||
esp += 0x4; // 跳过返回地址
|
||||
uint32_t temp_app_name, temp_cmd_line, temp_proc_info,
|
||||
temp_startup_info;
|
||||
uc_mem_read(uc, esp, &temp_app_name, sizeof(uint32_t));
|
||||
uc_mem_read(uc, esp + 0x4, &temp_cmd_line, sizeof(uint32_t));
|
||||
// 修正x86下的参数读取偏移,使用实际结构的偏移量
|
||||
uc_mem_read(uc, esp + 0x24, &temp_proc_info, sizeof(uint32_t));
|
||||
uc_mem_read(uc, esp + 0x1C, &temp_startup_info, sizeof(uint32_t));
|
||||
lpApplicationName = temp_app_name;
|
||||
lpCommandLine = temp_cmd_line;
|
||||
lpProcessInformation = temp_proc_info;
|
||||
lpStartupInfo = temp_startup_info;
|
||||
|
||||
printf(
|
||||
"[*] CreateProcessW Debug (x86): ESP=0x%x, AppNameAddr=0x%x, "
|
||||
"CmdLineAddr=0x%x\n",
|
||||
esp, temp_app_name, temp_cmd_line);
|
||||
}
|
||||
|
||||
// 读取命令行
|
||||
std::string commandLine;
|
||||
if (lpCommandLine != 0) {
|
||||
char buffer[MAX_PATH] = {0};
|
||||
size_t i = 0;
|
||||
bool success = true;
|
||||
// 调用内部函数处理共同逻辑
|
||||
bool success =
|
||||
CreateProcessInternal(sandbox, uc, lpApplicationName, lpCommandLine,
|
||||
lpProcessInformation, lpStartupInfo, true);
|
||||
|
||||
do {
|
||||
uint8_t byte;
|
||||
uc_err err = uc_mem_read(uc, lpCommandLine + i, &byte, 1);
|
||||
if (err != UC_ERR_OK) {
|
||||
printf("[!] Error reading command line at address 0x%llx: %u\n",
|
||||
lpCommandLine + i, err);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
buffer[i] = byte;
|
||||
i++;
|
||||
} while (buffer[i - 1] != 0 && i < MAX_PATH - 1);
|
||||
|
||||
// 确保字符串以 NULL 结尾
|
||||
buffer[i] = 0;
|
||||
|
||||
if (success) {
|
||||
commandLine = std::string(buffer);
|
||||
printf("[*] Read CommandLine: %s (Length: %zu)\n", buffer,
|
||||
commandLine.length());
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] CreateProcessA: ApplicationName=%s, CommandLine=%s\n",
|
||||
applicationName.empty() ? "(null)" : applicationName.c_str(),
|
||||
commandLine.empty() ? "(null)" : commandLine.c_str());
|
||||
|
||||
// 模拟创建进程,设置进程和线程ID
|
||||
DWORD processId = 0x1234;
|
||||
DWORD threadId = 0x5678;
|
||||
HANDLE hProcess = (HANDLE)0x1340;
|
||||
HANDLE hThread = (HANDLE)0x1341;
|
||||
|
||||
// 写入进程信息
|
||||
if (lpProcessInformation != 0) {
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
struct PROCESS_INFORMATION64 {
|
||||
HANDLE hProcess;
|
||||
HANDLE hThread;
|
||||
DWORD dwProcessId;
|
||||
DWORD dwThreadId;
|
||||
} pi;
|
||||
pi.hProcess = (HANDLE)hProcess;
|
||||
pi.hThread = (HANDLE)hThread;
|
||||
pi.dwProcessId = processId;
|
||||
pi.dwThreadId = threadId;
|
||||
uc_mem_write(uc, lpProcessInformation, &pi, sizeof(pi));
|
||||
printf("[*] Wrote process info (x64) to 0x%llx\n",
|
||||
lpProcessInformation);
|
||||
} else {
|
||||
PROCESS_INFORMATION pi;
|
||||
pi.hProcess = hProcess;
|
||||
pi.hThread = hThread;
|
||||
pi.dwProcessId = processId;
|
||||
pi.dwThreadId = threadId;
|
||||
uc_mem_write(uc, lpProcessInformation, &pi, sizeof(pi));
|
||||
printf("[*] Wrote process info (x86) to 0x%llx\n",
|
||||
lpProcessInformation);
|
||||
}
|
||||
}
|
||||
|
||||
// 返回成功
|
||||
uint64_t result = 1;
|
||||
// 返回结果
|
||||
uint64_t result = success ? 1 : 0;
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
|
||||
@@ -1726,16 +1726,6 @@ auto Api_MultiByteToWideChar(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
uint64_t rsp = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_RSP, &rsp);
|
||||
|
||||
// 为了确保安全访问,先验证栈地址的有效性
|
||||
if (rsp < 0x8000000000000000 || rsp + 0x40 > 0x8000000000010000) {
|
||||
// 无效的栈地址
|
||||
DWORD error = ERROR_INVALID_PARAMETER;
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
int result = 0;
|
||||
uc_reg_write(uc, UC_X86_REG_RAX, &result);
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取栈上的参数
|
||||
uint64_t shadow_space = 0x20; // x64调用约定中的shadow space
|
||||
uc_mem_read(uc, rsp + shadow_space + 0x8, &lpWideCharStr,
|
||||
@@ -1783,9 +1773,9 @@ auto Api_MultiByteToWideChar(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
}
|
||||
srcBuffer.push_back(ch);
|
||||
len++;
|
||||
} while (ch != 0 && len < MAX_PATH); // 添加长度限制防止无限循环
|
||||
} while (ch != 0 && len < 2 * 1024); // 添加长度限制防止无限循环
|
||||
|
||||
if (len >= MAX_PATH) {
|
||||
if (len >= 2 * 1024) {
|
||||
// 设置错误码
|
||||
DWORD error = ERROR_INSUFFICIENT_BUFFER;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
@@ -1922,7 +1912,7 @@ auto Api_MultiByteToWideChar(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
"InputLen=%d, Output=%p, OutputLen=%d, Result=%d\n",
|
||||
CodePage, dwFlags, (void*)lpMultiByteStr, cbMultiByte,
|
||||
(void*)lpWideCharStr, cchWideChar, result);
|
||||
|
||||
printf("MultiByteToWideChar pre cover string: %s\n", srcBuffer.data());
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
|
||||
@@ -347,4 +347,100 @@ auto Api_InternetReadFile(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&returnValue);
|
||||
}
|
||||
|
||||
auto Api_URLDownloadToFileW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
|
||||
// 获取参数
|
||||
uint64_t pCaller = 0; // LPUNKNOWN pCaller
|
||||
uint64_t szURL = 0; // LPCWSTR szURL
|
||||
uint64_t szFileName = 0; // LPCWSTR szFileName
|
||||
uint64_t dwReserved = 0; // DWORD dwReserved
|
||||
uint64_t lpfnCB = 0; // LPBINDSTATUSCALLBACK lpfnCB
|
||||
|
||||
// 根据x86或x64架构读取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &pCaller);
|
||||
uc_reg_read(uc, UC_X86_REG_RDX, &szURL);
|
||||
uc_reg_read(uc, UC_X86_REG_R8, &szFileName);
|
||||
uc_reg_read(uc, UC_X86_REG_R9, &dwReserved);
|
||||
|
||||
uint64_t rsp = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_RSP, &rsp);
|
||||
uc_mem_read(uc, rsp + 0x28, &lpfnCB, sizeof(lpfnCB));
|
||||
} else {
|
||||
uint32_t esp = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp);
|
||||
|
||||
uint32_t param_addr = esp + 4;
|
||||
uc_mem_read(uc, param_addr, &pCaller, sizeof(uint32_t));
|
||||
|
||||
param_addr += 4;
|
||||
uc_mem_read(uc, param_addr, &szURL, sizeof(uint32_t));
|
||||
|
||||
param_addr += 4;
|
||||
uc_mem_read(uc, param_addr, &szFileName, sizeof(uint32_t));
|
||||
|
||||
param_addr += 4;
|
||||
uc_mem_read(uc, param_addr, &dwReserved, sizeof(uint32_t));
|
||||
|
||||
param_addr += 4;
|
||||
uc_mem_read(uc, param_addr, &lpfnCB, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// 将此行为标记为可能的恶意行为
|
||||
context->SetMalwareAnalysisType(MalwareAnalysisType::kMalware);
|
||||
|
||||
// 读取URL (宽字符)
|
||||
std::wstring wUrlString;
|
||||
if (szURL != 0) {
|
||||
wchar_t buffer[1024] = {0};
|
||||
uc_mem_read(uc, szURL, buffer, sizeof(buffer) - sizeof(wchar_t));
|
||||
wUrlString = buffer;
|
||||
|
||||
// 转换为UTF-8字符串用于日志记录
|
||||
std::string urlString(wUrlString.begin(), wUrlString.end());
|
||||
printf("[URLDownloadToFileW] URL: %s\n", urlString.c_str());
|
||||
|
||||
// 记录到API调用列表
|
||||
context->ApiCallList.push_back("URLDownloadToFileW: " + urlString);
|
||||
}
|
||||
|
||||
// 读取文件名 (宽字符)
|
||||
std::wstring wFileNameString;
|
||||
if (szFileName != 0) {
|
||||
wchar_t buffer[1024] = {0};
|
||||
uc_mem_read(uc, szFileName, buffer, sizeof(buffer) - sizeof(wchar_t));
|
||||
wFileNameString = buffer;
|
||||
|
||||
// 转换为UTF-8字符串用于日志记录
|
||||
std::string fileNameString(wFileNameString.begin(),
|
||||
wFileNameString.end());
|
||||
printf("[URLDownloadToFileW] File name: %s\n", fileNameString.c_str());
|
||||
}
|
||||
|
||||
// 检查URL是否包含可疑内容
|
||||
const std::vector<std::wstring> suspiciousUrlPatterns = {
|
||||
L"http://", L"https://", L"ftp://", L".exe", L".dll", L".bat",
|
||||
L".ps1", L".vbs", L".js", L".cmd", L".msi", L".hta"};
|
||||
|
||||
for (const auto& pattern : suspiciousUrlPatterns) {
|
||||
if (wUrlString.find(pattern) != std::wstring::npos) {
|
||||
context->SetMalwareAnalysisType(MalwareAnalysisType::kMalware);
|
||||
#if LOG_LEVEL >= 1
|
||||
std::string patternString(pattern.begin(), pattern.end());
|
||||
printf("[!!!] Malicious URL pattern detected: %s\n",
|
||||
patternString.c_str());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟下载成功
|
||||
uint32_t returnValue = S_OK; // 0 表示成功
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&returnValue);
|
||||
}
|
||||
@@ -8,4 +8,6 @@ auto Api_InternetOpenUrlA(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
auto Api_InternetCloseHandle(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void;
|
||||
auto Api_InternetReadFile(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void;
|
||||
auto Api_URLDownloadToFileW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void;
|
||||
Reference in New Issue
Block a user