初步增加32位支持(没加全)
This commit is contained in:
@@ -313,26 +313,24 @@ auto doMalwareScan(int argc, char* argv[]) -> void {
|
||||
}
|
||||
|
||||
int doSandbox(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
std::cout << "用法: " << argv[0] << " <文件路径> <地址>" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string filePath = argv[1];
|
||||
std::string filePath = "C:\\opengl32.dll";
|
||||
auto peInfo = getPeInfo(filePath);
|
||||
if (peInfo == nullptr) {
|
||||
return 0;
|
||||
std::cout << "无法加载PE文件: " << filePath << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Sandbox se;
|
||||
se.InitEnv(peInfo);
|
||||
// se.Run(0x180003980);
|
||||
se.Run(0x10002F20);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir)ai_anti_malware\libpeconv\libpeconv\;$(SolutionDir)ai_anti_malware\libpeconv\libpeconv\include;$(SolutionDir)ai_anti_malware\libpeconv\;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -131,8 +132,9 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
||||
@@ -120,6 +120,12 @@ typedef struct _UNICODE_STRING {
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING;
|
||||
typedef struct _UNICODE_STRING32 {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
DWORD Buffer;
|
||||
} UNICODE_STRING32;
|
||||
|
||||
typedef UNICODE_STRING* PUNICODE_STRING;
|
||||
typedef const UNICODE_STRING* PCUNICODE_STRING;
|
||||
typedef PVOID(NTAPI* RtlImageDirectoryEntryToDataFn)(PVOID, BOOLEAN, USHORT,
|
||||
@@ -905,6 +911,54 @@ union SegmentSelector {
|
||||
};
|
||||
static_assert(sizeof(SegmentSelector) == 2, "Size check");
|
||||
#include <poppack.h>
|
||||
typedef struct _STARTUPINFOW32 {
|
||||
DWORD cb;
|
||||
DWORD lpReserved;
|
||||
DWORD lpDesktop;
|
||||
DWORD lpTitle;
|
||||
DWORD dwX;
|
||||
DWORD dwY;
|
||||
DWORD dwXSize;
|
||||
DWORD dwYSize;
|
||||
DWORD dwXCountChars;
|
||||
DWORD dwYCountChars;
|
||||
DWORD dwFillAttribute;
|
||||
DWORD dwFlags;
|
||||
WORD wShowWindow;
|
||||
WORD cbReserved2;
|
||||
DWORD lpReserved2;
|
||||
DWORD hStdInput;
|
||||
DWORD hStdOutput;
|
||||
DWORD hStdError;
|
||||
} STARTUPINFOW32, * LPSTARTUPINFOW32;
|
||||
static_assert(sizeof(STARTUPINFOW32) == 68, "Size check");
|
||||
typedef struct tagPROCESSENTRY32W_32
|
||||
{
|
||||
DWORD dwSize;
|
||||
DWORD cntUsage;
|
||||
DWORD th32ProcessID; // this process
|
||||
DWORD th32DefaultHeapID;
|
||||
DWORD th32ModuleID; // associated exe
|
||||
DWORD cntThreads;
|
||||
DWORD th32ParentProcessID; // this process's parent process
|
||||
LONG pcPriClassBase; // Base priority of process's threads
|
||||
DWORD dwFlags;
|
||||
WCHAR szExeFile[MAX_PATH]; // Path
|
||||
} PROCESSENTRY32W_32;
|
||||
static_assert(sizeof(PROCESSENTRY32W_32) == 556, "Size check");
|
||||
#pragma pack(push, 8)
|
||||
|
||||
typedef struct _RTL_CRITICAL_SECTION32 {
|
||||
DWORD DebugInfo;
|
||||
LONG LockCount;
|
||||
LONG RecursionCount;
|
||||
DWORD OwningThread; // from the thread's ClientId->UniqueThread
|
||||
DWORD LockSemaphore;
|
||||
DWORD SpinCount; // force size on 64-bit systems when packed
|
||||
} RTL_CRITICAL_SECTION32, * PRTL_CRITICAL_SECTION32;
|
||||
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(RTL_CRITICAL_SECTION32) == 24, "Size check");
|
||||
|
||||
union FlagRegister {
|
||||
ULONG_PTR all;
|
||||
|
||||
@@ -651,7 +651,7 @@ auto Sandbox::InitEnv(std::shared_ptr<BasicPeInfo> peInfo) -> void {
|
||||
if (!peconv::load_imports(m_peInfo->peBuffer, &importFixer)) {
|
||||
throw std::runtime_error("Failed to fix imports");
|
||||
}
|
||||
//给所有导入表加c3
|
||||
// 给所有导入表加c3
|
||||
for (const auto& module : this->GetModuleList()) {
|
||||
// 遍历导出函数查找对应名称
|
||||
for (const auto& exp : module->export_function) {
|
||||
@@ -751,8 +751,8 @@ auto Sandbox::Run(uint64_t address) -> void {
|
||||
}
|
||||
// 系统调用钩子
|
||||
err = uc_hook_add(m_ucEngine, &hook_syscall, UC_HOOK_INTR | UC_HOOK_INSN,
|
||||
reinterpret_cast<void*>(sandboxCallbacks::handleSyscall),
|
||||
this, 1, 0, UC_X86_INS_SYSCALL);
|
||||
reinterpret_cast<void*>(sandboxCallbacks::handleSyscall),
|
||||
this, 1, 0, UC_X86_INS_SYSCALL);
|
||||
if (err != UC_ERR_OK) {
|
||||
throw std::runtime_error("Failed to add syscall hook");
|
||||
}
|
||||
@@ -773,9 +773,38 @@ auto Sandbox::Run(uint64_t address) -> void {
|
||||
// 1.入口点是必须跑的
|
||||
if (m_peInfo->isDll) {
|
||||
// 给rcx和rdx设置dll应该设置的
|
||||
auto dll_fdwReason = 1;
|
||||
uc_reg_write(m_ucEngine, UC_X86_REG_RCX, &m_peInfo->RecImageBase);
|
||||
uc_reg_write(m_ucEngine, UC_X86_REG_RDX, &dll_fdwReason);
|
||||
auto dll_fdwReason = 1; // DLL_PROCESS_ATTACH
|
||||
if (m_peInfo->isX64) {
|
||||
uc_reg_write(m_ucEngine, UC_X86_REG_RCX, &m_peInfo->RecImageBase);
|
||||
uc_reg_write(m_ucEngine, UC_X86_REG_RDX, &dll_fdwReason);
|
||||
} else {
|
||||
// 32位使用栈传参而不是寄存器传参
|
||||
uint32_t rsp;
|
||||
uc_reg_read(m_ucEngine, UC_X86_REG_ESP, &rsp);
|
||||
|
||||
// 为参数腾出空间
|
||||
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
|
||||
uint32_t imageBase = static_cast<uint32_t>(m_peInfo->RecImageBase);
|
||||
|
||||
// 按照从右到左的调用约定写入参数到栈上
|
||||
uc_mem_write(m_ucEngine, rsp, &lpvReserved,
|
||||
sizeof(uint32_t)); // lpvReserved (最右侧参数最先入栈)
|
||||
uc_mem_write(m_ucEngine, rsp + 4, &reason,
|
||||
sizeof(uint32_t)); // fdwReason (中间参数次之入栈)
|
||||
uc_mem_write(m_ucEngine, rsp + 8, &imageBase,
|
||||
sizeof(uint32_t)); // hinstDLL (最左侧参数最后入栈)
|
||||
|
||||
// 在Windows下,DLL的返回地址也需要压栈
|
||||
uint32_t returnAddress = 0xABABABAB; // 虚拟的返回地址
|
||||
rsp -= 4; // 为返回地址腾出空间
|
||||
uc_reg_write(m_ucEngine, UC_X86_REG_ESP, &rsp);
|
||||
uc_mem_write(m_ucEngine, rsp, &returnAddress, sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
err = uc_emu_start(m_ucEngine, entryPoint, m_peInfo->imageEnd, timeout, 0);
|
||||
// 2. 有自定义地址 再跑自定义地址
|
||||
|
||||
@@ -425,4 +425,7 @@ auto Api_FwpmProviderAdd0(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void;
|
||||
auto Api_FwpmFilterAdd0(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
auto Api_FwpmEngineClose0(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void;
|
||||
-> void;
|
||||
auto Api_TlsFree(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
auto Api_FlsAlloc(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
auto Api_FlsGetValue(void* sandbox, uc_engine* uc, uint64_t address) -> void;
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "sandbox_callbacks.h"
|
||||
#include "sandbox_api_winhttp.h"
|
||||
#include <tlhelp32.h>
|
||||
|
||||
auto Api_QueryPerformanceCounter(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
@@ -602,7 +603,16 @@ auto Api_VirtualProtect(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
|
||||
// 检查地址范围是否已映射
|
||||
uint32_t unicornProtect = WindowsToUnicornProtect(flNewProtect);
|
||||
uc_err err = uc_mem_protect(uc, lpAddress, dwSize, unicornProtect);
|
||||
// 对齐地址和大小到页面边界
|
||||
uint64_t aligned_address =
|
||||
lpAddress & ~(PAGE_SIZE - 1); // 向下对齐到页面边界
|
||||
uint64_t end_address = (lpAddress + dwSize + PAGE_SIZE - 1) &
|
||||
~(PAGE_SIZE - 1); // 向上对齐到页面边界
|
||||
uint64_t aligned_size = end_address - aligned_address;
|
||||
|
||||
uc_err err =
|
||||
uc_mem_protect(uc, aligned_address, aligned_size, unicornProtect);
|
||||
|
||||
if (err != UC_ERR_OK) {
|
||||
uint64_t result = 0; // FALSE
|
||||
uc_reg_write(
|
||||
@@ -909,6 +919,285 @@ auto Api_CreateDirectoryW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
}
|
||||
}
|
||||
}
|
||||
auto Api_GetStringTypeW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint32_t dwInfoType = 0;
|
||||
uint64_t lpSrcStr = 0;
|
||||
int32_t cchSrc = 0;
|
||||
uint64_t lpCharType = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = dwInfoType, rdx = lpSrcStr, r8 = cchSrc, r9 = lpCharType
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &dwInfoType);
|
||||
uc_reg_read(uc, UC_X86_REG_RDX, &lpSrcStr);
|
||||
uint64_t temp_size;
|
||||
uc_reg_read(uc, UC_X86_REG_R8, &temp_size);
|
||||
cchSrc = static_cast<int32_t>(temp_size);
|
||||
uc_reg_read(uc, UC_X86_REG_R9, &lpCharType);
|
||||
} else {
|
||||
// x86: 从栈上读取参数
|
||||
uint32_t esp_address = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4; // 跳过返回地址
|
||||
|
||||
uc_mem_read(uc, esp_address, &dwInfoType, sizeof(uint32_t));
|
||||
esp_address += 0x4;
|
||||
|
||||
uint32_t temp_src_str;
|
||||
uc_mem_read(uc, esp_address, &temp_src_str, sizeof(uint32_t));
|
||||
lpSrcStr = temp_src_str;
|
||||
esp_address += 0x4;
|
||||
|
||||
uc_mem_read(uc, esp_address, &cchSrc, sizeof(int32_t));
|
||||
esp_address += 0x4;
|
||||
|
||||
uint32_t temp_char_type;
|
||||
uc_mem_read(uc, esp_address, &temp_char_type, sizeof(uint32_t));
|
||||
lpCharType = temp_char_type;
|
||||
}
|
||||
|
||||
// 验证参数
|
||||
if (lpSrcStr == 0 || lpCharType == 0) {
|
||||
uint64_t result = 0; // FALSE
|
||||
uc_reg_write(
|
||||
uc, context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
DWORD error = ERROR_INVALID_PARAMETER;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
} else {
|
||||
context->GetTeb32()->LastErrorValue = error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果cchSrc为负数,计算字符串长度
|
||||
if (cchSrc < 0) {
|
||||
cchSrc = 0;
|
||||
wchar_t temp_char;
|
||||
do {
|
||||
uc_mem_read(uc, lpSrcStr + (cchSrc * 2), &temp_char,
|
||||
sizeof(wchar_t));
|
||||
cchSrc++;
|
||||
} while (temp_char != 0 && cchSrc < 1024); // 设置一个合理的上限
|
||||
cchSrc--; // 不包括null终止符
|
||||
}
|
||||
|
||||
// 读取源字符串
|
||||
std::vector<wchar_t> srcStr(cchSrc);
|
||||
uc_mem_read(uc, lpSrcStr, srcStr.data(), cchSrc * sizeof(wchar_t));
|
||||
|
||||
// 处理每个字符
|
||||
std::vector<WORD> charTypes(cchSrc);
|
||||
for (int i = 0; i < cchSrc; i++) {
|
||||
WORD type = 0;
|
||||
wchar_t ch = srcStr[i];
|
||||
|
||||
switch (dwInfoType) {
|
||||
case CT_CTYPE1: {
|
||||
// 基本字符类型检查
|
||||
if (iswupper(ch)) type |= C1_UPPER;
|
||||
if (iswlower(ch)) type |= C1_LOWER;
|
||||
if (iswdigit(ch)) type |= C1_DIGIT;
|
||||
if (iswspace(ch)) type |= C1_SPACE;
|
||||
if (iswpunct(ch)) type |= C1_PUNCT;
|
||||
if (iswcntrl(ch)) type |= C1_CNTRL;
|
||||
if (ch == L' ' || ch == L'\t') type |= C1_BLANK;
|
||||
if ((ch >= L'0' && ch <= L'9') || (ch >= L'A' && ch <= L'F') ||
|
||||
(ch >= L'a' && ch <= L'f'))
|
||||
type |= C1_XDIGIT;
|
||||
if (iswalpha(ch)) type |= C1_ALPHA;
|
||||
if (type == 0) type |= C1_DEFINED;
|
||||
break;
|
||||
}
|
||||
case CT_CTYPE2: {
|
||||
// 简单的双向文本支持
|
||||
if ((ch >= L'A' && ch <= L'Z') || (ch >= L'a' && ch <= L'z') ||
|
||||
(ch >= L'0' && ch <= L'9')) {
|
||||
type = C2_LEFTTORIGHT;
|
||||
} else if (iswspace(ch)) {
|
||||
type = C2_WHITESPACE;
|
||||
} else {
|
||||
type = C2_NOTAPPLICABLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CT_CTYPE3: {
|
||||
// 基本文本处理信息
|
||||
if (iswalpha(ch)) type |= C3_ALPHA;
|
||||
// 这里可以添加更多的C3类型检查
|
||||
break;
|
||||
}
|
||||
}
|
||||
charTypes[i] = type;
|
||||
}
|
||||
|
||||
// 写入结果
|
||||
uc_mem_write(uc, lpCharType, charTypes.data(), cchSrc * sizeof(WORD));
|
||||
|
||||
printf("[*] GetStringTypeW: InfoType=0x%x, StrLen=%d\n", dwInfoType,
|
||||
cchSrc);
|
||||
|
||||
// 返回成功
|
||||
uint64_t result = 1; // TRUE
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
}
|
||||
|
||||
auto Api_LCMapStringW(void* sandbox, uc_engine* uc, uint64_t address) -> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint32_t Locale = 0;
|
||||
uint32_t dwMapFlags = 0;
|
||||
uint64_t lpSrcStr = 0;
|
||||
int32_t cchSrc = 0;
|
||||
uint64_t lpDestStr = 0;
|
||||
int32_t cchDest = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = Locale, rdx = dwMapFlags, r8 = lpSrcStr, r9 = cchSrc
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &Locale);
|
||||
uc_reg_read(uc, UC_X86_REG_RDX, &dwMapFlags);
|
||||
uc_reg_read(uc, UC_X86_REG_R8, &lpSrcStr);
|
||||
uint64_t temp_src_size;
|
||||
uc_reg_read(uc, UC_X86_REG_R9, &temp_src_size);
|
||||
cchSrc = static_cast<int32_t>(temp_src_size);
|
||||
|
||||
// 从栈上读取剩余参数
|
||||
uint64_t rsp;
|
||||
uc_reg_read(uc, UC_X86_REG_RSP, &rsp);
|
||||
uc_mem_read(uc, rsp + 0x28, &lpDestStr, sizeof(uint64_t));
|
||||
uc_mem_read(uc, rsp + 0x30, &cchDest, sizeof(int32_t));
|
||||
} else {
|
||||
// x86: 从栈上读取参数
|
||||
uint32_t esp_address = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4; // 跳过返回地址
|
||||
|
||||
uc_mem_read(uc, esp_address, &Locale, sizeof(uint32_t));
|
||||
esp_address += 0x4;
|
||||
|
||||
uc_mem_read(uc, esp_address, &dwMapFlags, sizeof(uint32_t));
|
||||
esp_address += 0x4;
|
||||
|
||||
uint32_t temp_src_str;
|
||||
uc_mem_read(uc, esp_address, &temp_src_str, sizeof(uint32_t));
|
||||
lpSrcStr = temp_src_str;
|
||||
esp_address += 0x4;
|
||||
|
||||
uc_mem_read(uc, esp_address, &cchSrc, sizeof(int32_t));
|
||||
esp_address += 0x4;
|
||||
|
||||
uint32_t temp_dest_str;
|
||||
uc_mem_read(uc, esp_address, &temp_dest_str, sizeof(uint32_t));
|
||||
lpDestStr = temp_dest_str;
|
||||
esp_address += 0x4;
|
||||
|
||||
uc_mem_read(uc, esp_address, &cchDest, sizeof(int32_t));
|
||||
}
|
||||
|
||||
// 验证参数
|
||||
if (lpSrcStr == 0) {
|
||||
uint32_t result = 0;
|
||||
uc_reg_write(
|
||||
uc, context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
DWORD error = ERROR_INVALID_PARAMETER;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
} else {
|
||||
context->GetTeb32()->LastErrorValue = error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果cchSrc为负数,计算源字符串长度
|
||||
if (cchSrc < 0) {
|
||||
cchSrc = 0;
|
||||
wchar_t temp_char;
|
||||
do {
|
||||
uc_mem_read(uc, lpSrcStr + (cchSrc * 2), &temp_char,
|
||||
sizeof(wchar_t));
|
||||
cchSrc++;
|
||||
} while (temp_char != 0 && cchSrc < 1024); // 设置一个合理的上限
|
||||
cchSrc--; // 不包括null终止符
|
||||
}
|
||||
|
||||
// 读取源字符串
|
||||
std::vector<wchar_t> srcStr(cchSrc);
|
||||
uc_mem_read(uc, lpSrcStr, srcStr.data(), cchSrc * sizeof(wchar_t));
|
||||
|
||||
// 如果cchDest为0,返回所需缓冲区大小
|
||||
if (cchDest == 0) {
|
||||
uint32_t required_size = cchSrc;
|
||||
if (dwMapFlags & LCMAP_SORTKEY) {
|
||||
required_size = cchSrc * 2 + 1; // 排序键通常需要更多空间
|
||||
}
|
||||
uc_reg_write(
|
||||
uc, context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&required_size);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查目标缓冲区大小是否足够
|
||||
if (cchDest < cchSrc) {
|
||||
uint32_t result = 0;
|
||||
uc_reg_write(
|
||||
uc, context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
DWORD error = ERROR_INSUFFICIENT_BUFFER;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
} else {
|
||||
context->GetTeb32()->LastErrorValue = error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理字符串映射
|
||||
std::vector<wchar_t> destStr(cchSrc);
|
||||
for (int i = 0; i < cchSrc; i++) {
|
||||
wchar_t ch = srcStr[i];
|
||||
if (dwMapFlags & LCMAP_UPPERCASE) {
|
||||
destStr[i] = towupper(ch);
|
||||
} else if (dwMapFlags & LCMAP_LOWERCASE) {
|
||||
destStr[i] = towlower(ch);
|
||||
} else {
|
||||
destStr[i] = ch; // 默认保持不变
|
||||
}
|
||||
}
|
||||
|
||||
// 写入结果
|
||||
if (dwMapFlags & LCMAP_SORTKEY) {
|
||||
// 生成简单的排序键(这里只是一个基本实现)
|
||||
std::vector<BYTE> sortKey(cchSrc * 2 + 1);
|
||||
for (int i = 0; i < cchSrc; i++) {
|
||||
sortKey[i * 2] = static_cast<BYTE>(destStr[i] & 0xFF);
|
||||
sortKey[i * 2 + 1] = static_cast<BYTE>((destStr[i] >> 8) & 0xFF);
|
||||
}
|
||||
sortKey[cchSrc * 2] = 0; // 终止符
|
||||
uc_mem_write(uc, lpDestStr, sortKey.data(), sortKey.size());
|
||||
uint32_t result = static_cast<uint32_t>(sortKey.size());
|
||||
uc_reg_write(
|
||||
uc, context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
} else {
|
||||
// 写入映射后的字符串
|
||||
uc_mem_write(uc, lpDestStr, destStr.data(), cchSrc * sizeof(wchar_t));
|
||||
uint32_t result = cchSrc;
|
||||
uc_reg_write(
|
||||
uc, context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&result);
|
||||
}
|
||||
|
||||
printf(
|
||||
"[*] LCMapStringW: Locale=0x%x, MapFlags=0x%x, SrcLen=%d, DestLen=%d\n",
|
||||
Locale, dwMapFlags, cchSrc, cchDest);
|
||||
}
|
||||
|
||||
auto Sandbox::InitApiHooks() -> void {
|
||||
auto FakeApi_GetSystemTimeAsFileTime =
|
||||
_fakeApi{.func = Api_GetSystemTimeAsFileTime, .paramCount = 1};
|
||||
@@ -1062,6 +1351,15 @@ auto Sandbox::InitApiHooks() -> void {
|
||||
_fakeApi{.func = Api_CreateDirectoryW, .paramCount = 2};
|
||||
auto FakeApi_URLDownloadToFileW =
|
||||
_fakeApi{.func = Api_URLDownloadToFileW, .paramCount = 5};
|
||||
auto FakeApi_TlsFree = _fakeApi{.func = Api_TlsFree, .paramCount = 1};
|
||||
auto FakeApi_FlsAlloc = _fakeApi{.func = Api_FlsAlloc, .paramCount = 1};
|
||||
auto FakeApi_FlsGetValue =
|
||||
_fakeApi{.func = Api_FlsGetValue, .paramCount = 1};
|
||||
auto FakeApi_GetStringTypeW =
|
||||
_fakeApi{.func = Api_GetStringTypeW, .paramCount = 4};
|
||||
auto FakeApi_LCMapStringW =
|
||||
_fakeApi{.func = Api_LCMapStringW, .paramCount = 6};
|
||||
|
||||
api_map = {
|
||||
{"GetSystemTimeAsFileTime",
|
||||
std::make_shared<_fakeApi>(FakeApi_GetSystemTimeAsFileTime)},
|
||||
@@ -1187,14 +1485,15 @@ auto Sandbox::InitApiHooks() -> void {
|
||||
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)},
|
||||
{"TlsFree", std::make_shared<_fakeApi>(FakeApi_TlsFree)},
|
||||
{"FlsAlloc", std::make_shared<_fakeApi>(FakeApi_FlsAlloc)},
|
||||
{"FlsGetValue", std::make_shared<_fakeApi>(FakeApi_FlsGetValue)},
|
||||
{"GetStringTypeW", std::make_shared<_fakeApi>(FakeApi_GetStringTypeW)},
|
||||
{"LCMapStringW", std::make_shared<_fakeApi>(FakeApi_LCMapStringW)},
|
||||
};
|
||||
}
|
||||
auto Sandbox::EmulateApi(uc_engine* uc, uint64_t address, uint64_t rip,
|
||||
@@ -1202,8 +1501,8 @@ auto Sandbox::EmulateApi(uc_engine* uc, uint64_t address, uint64_t rip,
|
||||
auto it = api_map.find(ApiName);
|
||||
if (it != api_map.end()) {
|
||||
it->second->func(this, uc, address);
|
||||
this->ApiCallList.push_back(ApiName);
|
||||
|
||||
this->ApiCallList.push_back(ApiName);
|
||||
// 获取参数数量
|
||||
int paramCount = it->second->paramCount;
|
||||
uint32_t esp;
|
||||
@@ -1236,7 +1535,8 @@ auto Sandbox::EmulateApi(uc_engine* uc, uint64_t address, uint64_t rip,
|
||||
// x86下,所有参数都通过栈传递
|
||||
// 调整栈指针:每个参数4字节 + 返回地址4字节
|
||||
esp += (paramCount * 4) + 4;
|
||||
// 设置EIP为返回地址
|
||||
// esp += 4;
|
||||
// 设置EIP为返回地址
|
||||
uc_reg_write(uc, UC_X86_REG_EIP, &return_address_32);
|
||||
}
|
||||
if (this->GetPeInfo()->isX64) {
|
||||
|
||||
@@ -270,23 +270,46 @@ auto Api_Process32FirstW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
// 读取结构体大小
|
||||
DWORD structSize = 0;
|
||||
if (uc_mem_read(uc, lppe, &structSize, sizeof(DWORD)) == UC_ERR_OK) {
|
||||
if (structSize == sizeof(PROCESSENTRY32W)) {
|
||||
// 获取第一个进程信息(在我们的实现中是DingTalk.exe)
|
||||
PROCESSENTRY32W pe32 = {0};
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32W);
|
||||
pe32.th32ProcessID = 1001; // DingTalk的PID
|
||||
pe32.cntThreads = 1;
|
||||
pe32.th32ParentProcessID = 4; // 父进程是System
|
||||
pe32.pcPriClassBase = 8; // 正常优先级
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
if (structSize == sizeof(PROCESSENTRY32W)) {
|
||||
// 获取第一个进程信息(在我们的实现中是DingTalk.exe)
|
||||
PROCESSENTRY32W pe32 = { 0 };
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32W);
|
||||
pe32.th32ProcessID = 1001; // DingTalk的PID
|
||||
pe32.cntThreads = 1;
|
||||
pe32.th32ParentProcessID = 4; // 父进程是System
|
||||
pe32.pcPriClassBase = 8; // 正常优先级
|
||||
|
||||
// 设置进程名
|
||||
std::wstring procName = L"DingTalk.exe";
|
||||
wcscpy_s(pe32.szExeFile, procName.c_str());
|
||||
// 设置进程名
|
||||
std::wstring procName = L"DingTalk.exe";
|
||||
wcscpy_s(pe32.szExeFile, procName.c_str());
|
||||
|
||||
// 写入进程信息到用户提供的缓冲区
|
||||
if (uc_mem_write(uc, lppe, &pe32, sizeof(PROCESSENTRY32W)) ==
|
||||
UC_ERR_OK) {
|
||||
success = true;
|
||||
// 写入进程信息到用户提供的缓冲区
|
||||
if (uc_mem_write(uc, lppe, &pe32, sizeof(PROCESSENTRY32W)) ==
|
||||
UC_ERR_OK) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (structSize == sizeof(PROCESSENTRY32W_32)) {
|
||||
// 获取第一个进程信息(在我们的实现中是DingTalk.exe)
|
||||
PROCESSENTRY32W_32 pe32 = { 0 };
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32W_32);
|
||||
pe32.th32ProcessID = 1001; // DingTalk的PID
|
||||
pe32.cntThreads = 1;
|
||||
pe32.th32ParentProcessID = 4; // 父进程是System
|
||||
pe32.pcPriClassBase = 8; // 正常优先级
|
||||
|
||||
// 设置进程名
|
||||
std::wstring procName = L"DingTalk.exe";
|
||||
wcscpy_s(pe32.szExeFile, procName.c_str());
|
||||
|
||||
// 写入进程信息到用户提供的缓冲区
|
||||
if (uc_mem_write(uc, lppe, &pe32, sizeof(PROCESSENTRY32W_32)) ==
|
||||
UC_ERR_OK) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,6 +411,36 @@ auto Api_Process32NextW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
hSnapshot = temp_handle;
|
||||
lppe = temp_lppe;
|
||||
}
|
||||
// 获取当前进程索引
|
||||
size_t currentIndex = 0;
|
||||
auto it = context->process_enum_state.find(hSnapshot);
|
||||
if (it != context->process_enum_state.end()) {
|
||||
currentIndex = it->second;
|
||||
currentIndex++; // 移动到下一个进程
|
||||
}
|
||||
|
||||
// 定义进程列表
|
||||
struct ProcessInfo {
|
||||
const wchar_t* name;
|
||||
uint32_t pid;
|
||||
uint32_t parentPid;
|
||||
};
|
||||
|
||||
ProcessInfo processes[] = {
|
||||
{L"DingTalk.exe", 1001, 4}, // 钉钉
|
||||
{L"Lanxin.exe", 1002, 4}, // 蓝信
|
||||
{L"QQ.exe", 1003, 4}, // QQ
|
||||
{L"Feishu.exe", 1004, 4}, // 飞书
|
||||
{L"explorer.exe", 1005, 4}, // Windows 资源管理器
|
||||
{L"svchost.exe", 1006, 4}, // 系统服务宿主进程
|
||||
{L"System", 4, 0}, // 系统进程
|
||||
{L"smss.exe", 376, 4}, // 会话管理器
|
||||
{L"csrss.exe", 648, 376}, // 客户端服务器运行时子系统
|
||||
{L"winlogon.exe", 672, 376}, // Windows 登录进程
|
||||
};
|
||||
|
||||
const size_t processCount =
|
||||
sizeof(processes) / sizeof(processes[0]);
|
||||
|
||||
// 验证句柄
|
||||
bool success = false;
|
||||
@@ -395,43 +448,37 @@ auto Api_Process32NextW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
// 读取结构体大小
|
||||
DWORD structSize = 0;
|
||||
if (uc_mem_read(uc, lppe, &structSize, sizeof(DWORD)) == UC_ERR_OK) {
|
||||
if (structSize == sizeof(PROCESSENTRY32W)) {
|
||||
// 获取当前进程索引
|
||||
size_t currentIndex = 0;
|
||||
auto it = context->process_enum_state.find(hSnapshot);
|
||||
if (it != context->process_enum_state.end()) {
|
||||
currentIndex = it->second;
|
||||
currentIndex++; // 移动到下一个进程
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
if (structSize == sizeof(PROCESSENTRY32W)) {
|
||||
// 检查是否还有更多进程
|
||||
if (currentIndex < processCount) {
|
||||
// 填充进程信息
|
||||
PROCESSENTRY32W pe32 = { 0 };
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32W);
|
||||
pe32.th32ProcessID = processes[currentIndex].pid;
|
||||
pe32.th32ParentProcessID =
|
||||
processes[currentIndex].parentPid;
|
||||
pe32.cntThreads = 1;
|
||||
pe32.pcPriClassBase = 8; // 正常优先级
|
||||
|
||||
// 设置进程名
|
||||
wcscpy_s(pe32.szExeFile, processes[currentIndex].name);
|
||||
|
||||
// 写入进程信息到用户提供的缓冲区
|
||||
if (uc_mem_write(uc, lppe, &pe32,
|
||||
sizeof(PROCESSENTRY32W)) == UC_ERR_OK) {
|
||||
success = true;
|
||||
// 更新进程索引
|
||||
context->process_enum_state[hSnapshot] = currentIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 定义进程列表
|
||||
struct ProcessInfo {
|
||||
const wchar_t* name;
|
||||
uint32_t pid;
|
||||
uint32_t parentPid;
|
||||
};
|
||||
|
||||
ProcessInfo processes[] = {
|
||||
{L"DingTalk.exe", 1001, 4}, // 钉钉
|
||||
{L"Lanxin.exe", 1002, 4}, // 蓝信
|
||||
{L"QQ.exe", 1003, 4}, // QQ
|
||||
{L"Feishu.exe", 1004, 4}, // 飞书
|
||||
{L"explorer.exe", 1005, 4}, // Windows 资源管理器
|
||||
{L"svchost.exe", 1006, 4}, // 系统服务宿主进程
|
||||
{L"System", 4, 0}, // 系统进程
|
||||
{L"smss.exe", 376, 4}, // 会话管理器
|
||||
{L"csrss.exe", 648, 376}, // 客户端服务器运行时子系统
|
||||
{L"winlogon.exe", 672, 376}, // Windows 登录进程
|
||||
};
|
||||
|
||||
const size_t processCount =
|
||||
sizeof(processes) / sizeof(processes[0]);
|
||||
|
||||
// 检查是否还有更多进程
|
||||
}
|
||||
else {
|
||||
if (currentIndex < processCount) {
|
||||
// 填充进程信息
|
||||
PROCESSENTRY32W pe32 = {0};
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32W);
|
||||
PROCESSENTRY32W_32 pe32 = { 0 };
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32W_32);
|
||||
pe32.th32ProcessID = processes[currentIndex].pid;
|
||||
pe32.th32ParentProcessID =
|
||||
processes[currentIndex].parentPid;
|
||||
@@ -443,7 +490,7 @@ auto Api_Process32NextW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
|
||||
// 写入进程信息到用户提供的缓冲区
|
||||
if (uc_mem_write(uc, lppe, &pe32,
|
||||
sizeof(PROCESSENTRY32W)) == UC_ERR_OK) {
|
||||
sizeof(PROCESSENTRY32W_32)) == UC_ERR_OK) {
|
||||
success = true;
|
||||
// 更新进程索引
|
||||
context->process_enum_state[hSnapshot] = currentIndex;
|
||||
|
||||
@@ -1333,39 +1333,72 @@ auto Api_EnterCriticalSection(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
lpCriticalSection = temp_cs;
|
||||
}
|
||||
|
||||
// 获取当前线程ID
|
||||
HANDLE currentThreadHandle = nullptr;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
currentThreadHandle =
|
||||
(HANDLE)(ULONG_PTR)context->GetTeb64()->ClientId.UniqueThread;
|
||||
}
|
||||
else {
|
||||
currentThreadHandle =
|
||||
(HANDLE)(ULONG_PTR)context->GetTeb32()->ClientId.UniqueThread;
|
||||
}
|
||||
|
||||
if (lpCriticalSection != 0) {
|
||||
RTL_CRITICAL_SECTION cs;
|
||||
uc_mem_read(uc, lpCriticalSection, &cs, sizeof(RTL_CRITICAL_SECTION));
|
||||
|
||||
// 获取当前线程ID
|
||||
HANDLE currentThreadHandle = nullptr;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
currentThreadHandle =
|
||||
(HANDLE)(ULONG_PTR)context->GetTeb64()->ClientId.UniqueThread;
|
||||
} else {
|
||||
currentThreadHandle =
|
||||
(HANDLE)(ULONG_PTR)context->GetTeb32()->ClientId.UniqueThread;
|
||||
}
|
||||
RTL_CRITICAL_SECTION cs;
|
||||
uc_mem_read(uc, lpCriticalSection, &cs, sizeof(RTL_CRITICAL_SECTION));
|
||||
|
||||
// 如果当前线程已经拥有锁,增加递归计数
|
||||
if (cs.OwningThread == currentThreadHandle) {
|
||||
cs.RecursionCount++;
|
||||
} else {
|
||||
// 如果没有线程拥有锁,获取它
|
||||
if (cs.LockCount == -1) {
|
||||
cs.OwningThread = currentThreadHandle;
|
||||
cs.RecursionCount = 1;
|
||||
cs.LockCount = 0;
|
||||
} else {
|
||||
// 在实际情况下这里应该自旋等待,但在模拟环境中我们直接获取锁
|
||||
cs.OwningThread = currentThreadHandle;
|
||||
cs.RecursionCount = 1;
|
||||
cs.LockCount++;
|
||||
|
||||
// 如果当前线程已经拥有锁,增加递归计数
|
||||
if (cs.OwningThread == currentThreadHandle) {
|
||||
cs.RecursionCount++;
|
||||
}
|
||||
else {
|
||||
// 如果没有线程拥有锁,获取它
|
||||
if (cs.LockCount == -1) {
|
||||
cs.OwningThread = currentThreadHandle;
|
||||
cs.RecursionCount = 1;
|
||||
cs.LockCount = 0;
|
||||
}
|
||||
else {
|
||||
// 在实际情况下这里应该自旋等待,但在模拟环境中我们直接获取锁
|
||||
cs.OwningThread = currentThreadHandle;
|
||||
cs.RecursionCount = 1;
|
||||
cs.LockCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 写回更新后的关键段结构
|
||||
uc_mem_write(uc, lpCriticalSection, &cs, sizeof(RTL_CRITICAL_SECTION));
|
||||
// 写回更新后的关键段结构
|
||||
uc_mem_write(uc, lpCriticalSection, &cs, sizeof(RTL_CRITICAL_SECTION));
|
||||
}
|
||||
else {
|
||||
RTL_CRITICAL_SECTION32 cs;
|
||||
uc_mem_read(uc, lpCriticalSection, &cs, sizeof(RTL_CRITICAL_SECTION32));
|
||||
|
||||
|
||||
// 如果当前线程已经拥有锁,增加递归计数
|
||||
if (cs.OwningThread == (DWORD)currentThreadHandle) {
|
||||
cs.RecursionCount++;
|
||||
}
|
||||
else {
|
||||
// 如果没有线程拥有锁,获取它
|
||||
if (cs.LockCount == -1) {
|
||||
cs.OwningThread = (DWORD)currentThreadHandle;
|
||||
cs.RecursionCount = 1;
|
||||
cs.LockCount = 0;
|
||||
}
|
||||
else {
|
||||
// 在实际情况下这里应该自旋等待,但在模拟环境中我们直接获取锁
|
||||
cs.OwningThread = (DWORD)currentThreadHandle;
|
||||
cs.RecursionCount = 1;
|
||||
cs.LockCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// 写回更新后的关键段结构
|
||||
uc_mem_write(uc, lpCriticalSection, &cs, sizeof(RTL_CRITICAL_SECTION32));
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] EnterCriticalSection: CS=0x%llx\n", lpCriticalSection);
|
||||
@@ -1426,7 +1459,7 @@ auto Api_GetStartupInfoW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
-> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint64_t lpStartupInfo = 0;
|
||||
|
||||
printf("[*] GetStartupInfoW start dump vmenv\n");
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = lpStartupInfo
|
||||
@@ -1442,28 +1475,49 @@ auto Api_GetStartupInfoW(void* sandbox, uc_engine* uc, uint64_t address)
|
||||
}
|
||||
|
||||
if (lpStartupInfo != 0) {
|
||||
// 创建一个默认的 STARTUPINFOW 结构
|
||||
STARTUPINFOW si = {0};
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_SHOWNORMAL;
|
||||
si.lpDesktop = nullptr;
|
||||
si.lpTitle = nullptr;
|
||||
si.dwX = 0;
|
||||
si.dwY = 0;
|
||||
si.dwXSize = 0;
|
||||
si.dwYSize = 0;
|
||||
si.dwXCountChars = 0;
|
||||
si.dwYCountChars = 0;
|
||||
si.dwFillAttribute = 0;
|
||||
si.cbReserved2 = 0;
|
||||
si.lpReserved2 = nullptr;
|
||||
si.hStdInput = nullptr;
|
||||
si.hStdOutput = nullptr;
|
||||
si.hStdError = nullptr;
|
||||
|
||||
// 写入结构到目标内存
|
||||
uc_mem_write(uc, lpStartupInfo, &si, sizeof(STARTUPINFOW));
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
STARTUPINFOW si = { 0 };
|
||||
si.cb = sizeof(STARTUPINFOW);
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_SHOWNORMAL;
|
||||
si.lpDesktop = nullptr;
|
||||
si.lpTitle = nullptr;
|
||||
si.dwX = 0;
|
||||
si.dwY = 0;
|
||||
si.dwXSize = 0;
|
||||
si.dwYSize = 0;
|
||||
si.dwXCountChars = 0;
|
||||
si.dwYCountChars = 0;
|
||||
si.dwFillAttribute = 0;
|
||||
si.cbReserved2 = 0;
|
||||
si.lpReserved2 = nullptr;
|
||||
si.hStdInput = nullptr;
|
||||
si.hStdOutput = nullptr;
|
||||
si.hStdError = nullptr;
|
||||
uc_mem_write(uc, lpStartupInfo, &si, sizeof(STARTUPINFOW));
|
||||
}
|
||||
else {
|
||||
STARTUPINFOW32 si = { 0 };
|
||||
si.cb = sizeof(STARTUPINFOW32);
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_SHOWNORMAL;
|
||||
si.lpDesktop = 0;
|
||||
si.lpTitle = 0;
|
||||
si.dwX = 0;
|
||||
si.dwY = 0;
|
||||
si.dwXSize = 0;
|
||||
si.dwYSize = 0;
|
||||
si.dwXCountChars = 0;
|
||||
si.dwYCountChars = 0;
|
||||
si.dwFillAttribute = 0;
|
||||
si.cbReserved2 = 0;
|
||||
si.lpReserved2 = 0;
|
||||
si.hStdInput = 0;
|
||||
si.hStdOutput = 0;
|
||||
si.hStdError = 0;
|
||||
uc_mem_write(uc, lpStartupInfo, &si, sizeof(STARTUPINFOW32));
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] GetStartupInfoW: lpStartupInfo=0x%llx\n", lpStartupInfo);
|
||||
@@ -2058,15 +2112,25 @@ auto Api_RtlFormatCurrentUserKeyPath(void* sandbox, uc_engine* uc,
|
||||
if (stringBuffer != 0 && keyPathBuffer != 0) {
|
||||
// 将路径字符串写入到分配的缓冲区
|
||||
uc_mem_write(uc, stringBuffer, userKeyPath, bufferSize);
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// 创建UNICODE_STRING结构
|
||||
UNICODE_STRING unicodeString;
|
||||
unicodeString.Length = static_cast<USHORT>(pathLen * sizeof(wchar_t));
|
||||
unicodeString.MaximumLength = static_cast<USHORT>(bufferSize);
|
||||
unicodeString.Buffer = reinterpret_cast<PWSTR>(stringBuffer);
|
||||
|
||||
// 创建UNICODE_STRING结构
|
||||
UNICODE_STRING unicodeString;
|
||||
unicodeString.Length = static_cast<USHORT>(pathLen * sizeof(wchar_t));
|
||||
unicodeString.MaximumLength = static_cast<USHORT>(bufferSize);
|
||||
unicodeString.Buffer = reinterpret_cast<PWSTR>(stringBuffer);
|
||||
// 将UNICODE_STRING结构写入到提供的缓冲区
|
||||
uc_mem_write(uc, keyPathBuffer, &unicodeString, sizeof(UNICODE_STRING));
|
||||
}
|
||||
else {
|
||||
UNICODE_STRING32 unicodeString;
|
||||
unicodeString.Length = static_cast<USHORT>(pathLen * sizeof(wchar_t));
|
||||
unicodeString.MaximumLength = static_cast<USHORT>(bufferSize);
|
||||
unicodeString.Buffer = (DWORD)(stringBuffer);
|
||||
|
||||
// 将UNICODE_STRING结构写入到提供的缓冲区
|
||||
uc_mem_write(uc, keyPathBuffer, &unicodeString, sizeof(UNICODE_STRING));
|
||||
// 将UNICODE_STRING结构写入到提供的缓冲区
|
||||
uc_mem_write(uc, keyPathBuffer, &unicodeString, sizeof(UNICODE_STRING32));
|
||||
}
|
||||
}
|
||||
|
||||
// 返回NTSTATUS成功代码 (0x00000000 = STATUS_SUCCESS)
|
||||
@@ -2143,3 +2207,189 @@ auto Api_FlsSetValue(void* sandbox, uc_engine* uc, uint64_t address) -> void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实现TlsFree API
|
||||
auto Api_TlsFree(void* sandbox, uc_engine* uc, uint64_t address) -> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint32_t dwTlsIndex = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = dwTlsIndex
|
||||
uint64_t temp_index;
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &temp_index);
|
||||
dwTlsIndex = static_cast<uint32_t>(temp_index);
|
||||
} else {
|
||||
// x86: 从栈上读取参数
|
||||
uint32_t esp_address = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4; // 跳过返回地址
|
||||
uc_mem_read(uc, esp_address, &dwTlsIndex, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// 检查索引是否有效(小于64)并释放对应的TLS槽
|
||||
BOOL success = FALSE;
|
||||
if (dwTlsIndex < 64) {
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
auto teb = context->GetTeb64();
|
||||
// 检查槽是否已分配(不为0x1337ffffff)
|
||||
if (teb->TlsSlots[dwTlsIndex] != (void*)0x1337ffffff) {
|
||||
// 将槽位标记为可用
|
||||
teb->TlsSlots[dwTlsIndex] = (void*)0x1337ffffff;
|
||||
success = TRUE;
|
||||
}
|
||||
} else {
|
||||
auto teb = context->GetTeb32();
|
||||
// 检查槽是否已分配(不为0x1337)
|
||||
if (teb->TlsSlots[dwTlsIndex] != 0x1337) {
|
||||
// 将槽位标记为可用
|
||||
teb->TlsSlots[dwTlsIndex] = 0x1337;
|
||||
success = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
// 设置错误码
|
||||
DWORD error = ERROR_INVALID_PARAMETER;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
} else {
|
||||
context->GetTeb32()->LastErrorValue = error;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] TlsFree: Index=0x%x, Success=%d\n", dwTlsIndex, success);
|
||||
|
||||
// 返回操作是否成功
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&success);
|
||||
}
|
||||
|
||||
// 实现FlsAlloc API
|
||||
auto Api_FlsAlloc(void* sandbox, uc_engine* uc, uint64_t address) -> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint64_t lpCallback = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = lpCallback
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &lpCallback);
|
||||
} else {
|
||||
// x86: 从栈上读取参数
|
||||
uint32_t esp_address = 0;
|
||||
uint32_t temp_callback = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4; // 跳过返回地址
|
||||
uc_mem_read(uc, esp_address, &temp_callback, sizeof(uint32_t));
|
||||
lpCallback = temp_callback;
|
||||
}
|
||||
|
||||
// 初始化返回值为失败状态
|
||||
DWORD fls_index = FLS_OUT_OF_INDEXES;
|
||||
|
||||
// 获取TEB结构
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
auto teb = context->GetTeb64();
|
||||
// 在TLS槽中查找第一个可用的位置
|
||||
for (DWORD i = 0; i < 64; i++) { // TEB中TlsSlots数组大小为64
|
||||
if (teb->TlsSlots[i] == (void*)0x1337ffffff) {
|
||||
teb->TlsSlots[i] = (void*)0; // 标记为已使用
|
||||
fls_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto teb = context->GetTeb32();
|
||||
// 在TLS槽中查找第一个可用的位置
|
||||
for (DWORD i = 0; i < 64; i++) { // TEB中TlsSlots数组大小为64
|
||||
if (teb->TlsSlots[i] == 0x1337) {
|
||||
teb->TlsSlots[i] = 0; // 标记为已使用
|
||||
fls_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fls_index == FLS_OUT_OF_INDEXES) {
|
||||
// 设置LastError为没有可用的FLS索引
|
||||
DWORD error = ERROR_NO_MORE_ITEMS;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
} else {
|
||||
context->GetTeb32()->LastErrorValue = error;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] FlsAlloc: Callback=0x%llx, Allocated FLS Index=0x%x\n",
|
||||
lpCallback, fls_index);
|
||||
|
||||
// 返回分配的FLS索引
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&fls_index);
|
||||
}
|
||||
|
||||
// 实现FlsGetValue API
|
||||
auto Api_FlsGetValue(void* sandbox, uc_engine* uc, uint64_t address) -> void {
|
||||
auto context = static_cast<Sandbox*>(sandbox);
|
||||
uint32_t dwFlsIndex = 0;
|
||||
uint64_t return_value = 0;
|
||||
|
||||
// 获取参数
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
// x64: rcx = dwFlsIndex
|
||||
uint64_t temp_index;
|
||||
uc_reg_read(uc, UC_X86_REG_RCX, &temp_index);
|
||||
dwFlsIndex = static_cast<uint32_t>(temp_index);
|
||||
} else {
|
||||
// x86: 从栈上读取参数
|
||||
uint32_t esp_address = 0;
|
||||
uc_reg_read(uc, UC_X86_REG_ESP, &esp_address);
|
||||
esp_address += 0x4; // 跳过返回地址
|
||||
uc_mem_read(uc, esp_address, &dwFlsIndex, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
// 检查索引是否有效(小于64)
|
||||
if (dwFlsIndex < 64) {
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
auto teb = context->GetTeb64();
|
||||
// 检查槽是否已分配(不为nullptr)
|
||||
if (teb->TlsSlots[dwFlsIndex] != (void*)0x1337ffffff) {
|
||||
return_value =
|
||||
reinterpret_cast<uint64_t>(teb->TlsSlots[dwFlsIndex]);
|
||||
} else {
|
||||
// 槽未分配,设置LastError
|
||||
DWORD error = ERROR_INVALID_PARAMETER;
|
||||
teb->LastErrorValue = error;
|
||||
}
|
||||
} else {
|
||||
auto teb = context->GetTeb32();
|
||||
// 检查槽是否已分配(不为0)
|
||||
if (teb->TlsSlots[dwFlsIndex] != 0x1337) {
|
||||
return_value = teb->TlsSlots[dwFlsIndex];
|
||||
} else {
|
||||
// 槽未分配,设置LastError
|
||||
DWORD error = ERROR_INVALID_PARAMETER;
|
||||
teb->LastErrorValue = error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 索引无效,设置LastError
|
||||
DWORD error = ERROR_INVALID_PARAMETER;
|
||||
if (context->GetPeInfo()->isX64) {
|
||||
context->GetTeb64()->LastErrorValue = error;
|
||||
} else {
|
||||
context->GetTeb32()->LastErrorValue = error;
|
||||
}
|
||||
}
|
||||
|
||||
printf("[*] FlsGetValue: Index=0x%x, Value=0x%llx\n", dwFlsIndex,
|
||||
return_value);
|
||||
|
||||
// 返回FLS槽中的值
|
||||
uc_reg_write(uc,
|
||||
context->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
|
||||
&return_value);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ void handleCodeRun(uc_engine* uc, uint64_t address, uint32_t size,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到区段,并且与上次执行的区段不同,记录跨区段行为
|
||||
if (currentSectionIndex >= 0 &&
|
||||
sandbox->GetLastExecuteSectionIndex() != currentSectionIndex &&
|
||||
@@ -84,7 +83,7 @@ void handleCodeRun(uc_engine* uc, uint64_t address, uint32_t size,
|
||||
}
|
||||
cs_free(instruction, instructionCount);
|
||||
|
||||
// dumpVmenv(uc, userData);
|
||||
//dumpVmenv(uc, userData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,9 +176,9 @@ void dumpVmenv(uc_engine* uc, void* userData) {
|
||||
"%08x Ecx: %08x\n",
|
||||
Rip, Rax, Rsp, Rbp, Rcx, Rdx, Eax, Ecx);
|
||||
|
||||
// 打印16层栈内存
|
||||
printf("\n[Stack Memory Dump (16 levels)]\n");
|
||||
const int STACK_LEVELS = 16;
|
||||
// 打印32层栈内存
|
||||
printf("\n[Stack Memory Dump (32 levels)]\n");
|
||||
const int STACK_LEVELS = 32;
|
||||
const int POINTER_SIZE = sandbox->GetPeInfo()->isX64 ? 8 : 4;
|
||||
|
||||
for (int i = 0; i < STACK_LEVELS; i++) {
|
||||
@@ -219,7 +218,7 @@ void dumpVmenv(uc_engine* uc, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n[Frame Pointer Stack (16 levels)]\n");
|
||||
printf("\n[Frame Pointer Stack (32 levels)]\n");
|
||||
uint64_t currentBp = Rbp;
|
||||
for (int i = 0; i < STACK_LEVELS && currentBp != 0; i++) {
|
||||
uint64_t nextBp = 0;
|
||||
|
||||
Reference in New Issue
Block a user