Loading... # 引言 因为一些签名被禁用,导致无法使用高级功能,这里使用了内存修改方式规避检测,附上C++代码提供一种绕过黑名单签名的方法。 `此文章仅用于学习交流,不提供二进制程序,切勿由于非法用途,否则后果自负。` 提示 sandboxie >=1.15.11版本已失效 # 逻辑和思考过程 1. 通过grep -rl 发现禁用的签名存在于`SbieSvc.exe`中,因为它被签名,所以需要其他方式进行修改 2. 内存注入方式,始终注入不进去,功力不够,(lll¬ω¬) 3. 通过`openark`或`cheat engine`修改`SbieSvc.exe`关键字符串,成功实现规避。 4. 因为一旦提示过`您尝试使用的许可证已被封禁,这意味着它已因故失效。任何使用该许可证的企图都构成对其使用条款的违反!`,逻辑将会先走注册表中的`计算机\HKEY_LOCAL_MACHINE\SECURITY\SBIE\`里面的`CertBlockList`,所以需要删掉它(需提权) --- 1. 先结束`SbieSvc.exe` 2. 删除注册表中的记录 3. 启动`SbieSvc.exe`服务 4. 内存替换 5. 启动sandman.exe # 代码 ```cpp #include <windows.h> #include <tlhelp32.h> #include <vector> #include <iostream> #include <string> #include <io.h> #include <fcntl.h> // 获取指定进程的所有线程ID std::vector<DWORD> GetProcessThreads(DWORD processId) { std::vector<DWORD> threadIds; THREADENTRY32 te; te.dwSize = sizeof(THREADENTRY32); HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { std::wcout << L"创建快照失败!" << std::endl; return threadIds; } // 枚举线程 if (Thread32First(hSnapshot, &te)) { do { if (te.th32OwnerProcessID == processId) { threadIds.push_back(te.th32ThreadID); } } while (Thread32Next(hSnapshot, &te)); } CloseHandle(hSnapshot); return threadIds; } // 挂起进程的所有线程 bool SuspendProcess(DWORD processId) { std::vector<DWORD> threadIds = GetProcessThreads(processId); for (DWORD threadId : threadIds) { HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadId); if (hThread != NULL) { DWORD suspendCount = SuspendThread(hThread); if (suspendCount == (DWORD)-1) { std::wcout << L"[i] 进程挂起,线程ID: " << threadId << std::endl; } CloseHandle(hThread); } else { std::wcout << L"[i] 无法打开线程,线程ID: " << threadId << std::endl; } } return true; } // 恢复进程的所有线程 bool ResumeProcess(DWORD processId) { std::vector<DWORD> threadIds = GetProcessThreads(processId); for (DWORD threadId : threadIds) { HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadId); if (hThread != NULL) { DWORD resumeCount = ResumeThread(hThread); if (resumeCount == (DWORD)-1) { std::wcout << L"[i] 恢复进程挂起状态,线程ID: " << threadId << std::endl; } CloseHandle(hThread); } else { std::wcout << L"[x] 恢复进程挂起失败: " << threadId << std::endl; } } return true; } // 获取指定进程的句柄 HANDLE GetProcessHandle(const std::wstring& processName) { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) return NULL; PROCESSENTRY32 pe; pe.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hSnapshot, &pe)) { do { if (!processName.compare(pe.szExeFile)) { CloseHandle(hSnapshot); return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID); } } while (Process32Next(hSnapshot, &pe)); } CloseHandle(hSnapshot); return NULL; } // 在进程内存中搜索字节模式 std::vector<uintptr_t> SearchMemory(HANDLE hProcess, const std::vector<uint8_t>& pattern) { std::vector<uintptr_t> results; MEMORY_BASIC_INFORMATION mbi; uintptr_t address = 0; while (VirtualQueryEx(hProcess, (LPCVOID)address, &mbi, sizeof(mbi))) { if (mbi.State == MEM_COMMIT && (mbi.Protect & (PAGE_READWRITE | PAGE_READONLY | PAGE_EXECUTE_READ))) { std::vector<uint8_t> buffer(mbi.RegionSize); SIZE_T bytesRead; if (ReadProcessMemory(hProcess, (LPCVOID)address, buffer.data(), mbi.RegionSize, &bytesRead)) { for (size_t i = 0; i < bytesRead - pattern.size(); ++i) { if (memcmp(buffer.data() + i, pattern.data(), pattern.size()) == 0) { results.push_back(address + i); } } } } address += mbi.RegionSize; } return results; } bool WriteMemory(HANDLE hProcess, uintptr_t address, const std::vector<uint8_t>& newData) { DWORD oldProtect; // 改变内存区域的保护为可写 if (!VirtualProtectEx(hProcess, (LPVOID)address, newData.size(), PAGE_READWRITE, &oldProtect)) { return false; } SIZE_T bytesWritten; if (WriteProcessMemory(hProcess, (LPVOID)address, newData.data(), newData.size(), &bytesWritten)) { // 恢复原来的内存保护 VirtualProtectEx(hProcess, (LPVOID)address, newData.size(), oldProtect, &oldProtect); return bytesWritten == newData.size(); } // 恢复原来的内存保护 VirtualProtectEx(hProcess, (LPVOID)address, newData.size(), oldProtect, &oldProtect); return false; } bool EnablePrivilege(LPCWSTR priv) { HANDLE hToken; TOKEN_PRIVILEGES tp; LUID luid; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { return false; } if (!LookupPrivilegeValueW(NULL, priv, &luid)) { CloseHandle(hToken); return false; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) { CloseHandle(hToken); return false; } CloseHandle(hToken); return true; } bool TerminateProcessByName(const std::wstring& processName) { // 获取进程快照 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { std::wcout << L"[x] 无法获取进程快照" << std::endl; return false; } PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); // 遍历进程列表 if (Process32First(hSnapshot, &pe32)) { do { // 如果进程名称匹配 if (processName == pe32.szExeFile) { // 打开进程 HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe32.th32ProcessID); if (hProcess != NULL) { // 终止进程 BOOL result = TerminateProcess(hProcess, 0); CloseHandle(hProcess); if (result) { std::wcout << L"[v] " << processName << L"已经被结束" << std::endl; CloseHandle(hSnapshot); return true; } else { std::wcout << L"[x] 无法结束进程" << std::endl; CloseHandle(hSnapshot); return false; } } } } while (Process32Next(hSnapshot, &pe32)); } std::wcout << L"[x] 未找到进程" << std::endl; CloseHandle(hSnapshot); return false; } bool StartProcessWithArgs(const std::wstring& exePath, const std::wstring& args) { // 创建 STARTUPINFO 结构体,初始化为零 STARTUPINFO si = { 0 }; si.cb = sizeof(STARTUPINFO); // 创建 PROCESS_INFORMATION 结构体,初始化为零 PROCESS_INFORMATION pi = { 0 }; // 构造命令行 std::wstring commandLine = exePath + L" " + args; // 使用 CreateProcess 启动进程 if (CreateProcess( nullptr, // 应用程序名称,如果命令行中包含程序路径,此参数可以为 nullptr &commandLine[0], // 命令行字符串 nullptr, // 进程安全属性 nullptr, // 线程安全属性 FALSE, // 是否继承句柄 0, // 创建标志 nullptr, // 环境变量 nullptr, // 当前目录 &si, // STARTUPINFO &pi // PROCESS_INFORMATION )) { std::wcout << L"[i] 进程创建成功" << std::endl; // 等待进程结束 // WaitForSingleObject(pi.hProcess, INFINITE); // 关闭进程和线程句柄 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return true; } else { std::wcout << L"[x] 无法创建进程 错误代码: " << GetLastError() << std::endl; return false; } } int setRegister() { std::wstring command = L"reg delete \"HKEY_LOCAL_MACHINE\\SECURITY\\SBIE\" /f"; int result = _wsystem(command.c_str()); return (result == 0); } int search() { std::wstring processName = L"SbieSvc.exe"; HANDLE hProcess = GetProcessHandle(processName); std::wcout << L"[i] 正在打开进程" << std::endl; if (!hProcess) { std::wcout << L"[x] 无法打开进程: " << processName << std::endl; return -1; } DWORD pid = GetProcessId(hProcess); SuspendProcess(pid); std::wcout << L"[i] 正在查找特征字符串" << std::endl; // 查找 UTF-8 编码的字符串 "63F49D96BDBA28F8428B4A5008D1A587" std::string searchString = "63F49D96BDBA28F8428B4A5008D1A587"; std::vector<uint8_t> pattern(searchString.begin(), searchString.end()); std::vector<uintptr_t> addresses = SearchMemory(hProcess, pattern); if (addresses.size() == 0) { std::wcout << L"[x] 找不到匹配项" << std::endl; std::string searchString2 = "ZunMXZunMXZunMXZunMXZunMXZunMX55"; std::vector<uint8_t> newData(searchString2.begin(), searchString2.end()); std::vector<uintptr_t> addresses2 = SearchMemory(hProcess, newData); if (addresses2.size() > 0) { std::wcout << L"[i] 已经替换过了" << std::endl; return 0; } return -1; } std::string newString = "ZunMXZunMXZunMXZunMXZunMXZunMX55"; std::vector<uint8_t> newData(newString.begin(), newString.end()); for (auto addr : addresses) { std::wcout << L"[i] 找到匹配项: 0x" << std::hex << addr << std::endl; if (WriteMemory(hProcess, addr, newData)) { std::wcout << L"[v] 成功写入: 0x" << std::hex << addr << std::endl; } else { std::wcout << L"[x] 写入失败: 0x" << std::hex << addr << std::endl; } } CloseHandle(hProcess); ResumeProcess(pid); return 0; } int main() { _setmode(_fileno(stdout), _O_U16TEXT); // 启用 wcout Unicode 输出 // 启用 SeBackupPrivilege 来获取高级权限 if (!EnablePrivilege(SE_TAKE_OWNERSHIP_NAME)) { std::wcout << L"[x] 提权失败" << std::endl; return 1; } if (TerminateProcessByName(L"SbieSvc.exe")) { std::wcout << L"[i] 结束进程成功,准备重新启动" << std::endl; } StartProcessWithArgs(L"KmdUtil.exe", L"start SbieSvc"); setRegister(); while (search() == -1) { Sleep(1000); } std::wcout << L"[i] 程序已结束" << std::endl; Sleep(3000); return 0; } ```  # 结语 程序编译后需要提权: 如: ```bash PsExec.exe -s -i 1 D:\software\Sandboxie-Plus\sandboxie_launcher.exe ``` 最终简化批处理 ```bash D:\software\Sandboxie-Plus\PsExec.exe -s -i 1 D:\software\Sandboxie-Plus\sandboxie_launcher.exe start D:\software\Sandboxie-Plus\SandMan.exe ``` 此方案并不是最优解,也可以考虑通过镜像劫持进行注入,这样就不用这个启动器了。其实方法有很多。 # 方案二 wtsapi32 劫持也可以实现相同效果,并且更方便,其中可以省略提权等步骤。 推荐使用Baymax Patch Tools 生成vs模板,代码和上面类似。  © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏
7 条评论
新版1.15.11是除了EXE额外加入了sys驱动里面的黑名单验证,能劫持替换吗?
这个实测是不行了,可以找找其他方法,我在52pj上看到有无限试用的方案,可以试试。
方案2 有成品吗?
已经邮件您了,注意查收,如果没找到,可以尝试检查垃圾邮件。注意,这仅用于逆向学习,一切非法用途自负。
谢谢,有修改好的工程文件发一份吗?我编译一下
对了,最新版好像失效了。
不客气,这里可以通过Baymax Patch Tools x64生成劫持代码,打开后点击菜单中的工具,劫持代码生成器,文件找到系统文件wtsapi32,不加载PYG64.dll,右侧版本选择你的vs版本,创建工程,随后打开vs2022,打开工程,其中建议附到DLL_PROCESS_ATTACH节中,劫持部分和上面代码类似,但是需要稍加改造(其实也就是main内容放到了ATTACH节里面)。删除注册表的那里可以优化,自己动手尝试一下吧。