引言
因为一些签名被禁用,导致无法使用高级功能,这里使用了内存修改方式规避检测,附上C++代码提供一种绕过黑名单签名的方法。
此文章仅用于学习交流,不提供二进制程序,切勿由于非法用途,否则后果自负。
提示 sandboxie >=1.15.11版本已失效
逻辑和思考过程
- 通过grep -rl 发现禁用的签名存在于
SbieSvc.exe
中,因为它被签名,所以需要其他方式进行修改 - 内存注入方式,始终注入不进去,功力不够,(lll¬ω¬)
- 通过
openark
或cheat engine
修改SbieSvc.exe
关键字符串,成功实现规避。 - 因为一旦提示过
您尝试使用的许可证已被封禁,这意味着它已因故失效。任何使用该许可证的企图都构成对其使用条款的违反!
,逻辑将会先走注册表中的计算机\HKEY_LOCAL_MACHINE\SECURITY\SBIE\
里面的CertBlockList
,所以需要删掉它(需提权)
- 先结束
SbieSvc.exe
- 删除注册表中的记录
- 启动
SbieSvc.exe
服务 - 内存替换
- 启动sandman.exe
代码
#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;
}
结语
程序编译后需要提权:
如:
PsExec.exe -s -i 1 D:\software\Sandboxie-Plus\sandboxie_launcher.exe
最终简化批处理
D:\software\Sandboxie-Plus\PsExec.exe -s -i 1 D:\software\Sandboxie-Plus\sandboxie_launcher.exe start D:\software\Sandboxie-Plus\SandMan.exe
此方案并不是最优解,也可以考虑通过镜像劫持进行注入,这样就不用这个启动器了。其实方法有很多。
方案二
wtsapi32 劫持也可以实现相同效果,并且更方便,其中可以省略提权等步骤。
7 条评论
新版1.15.11是除了EXE额外加入了sys驱动里面的黑名单验证,能劫持替换吗?
这个实测是不行了,可以找找其他方法,我在52pj上看到有无限试用的方案,可以试试。
方案2 有成品吗?
已经邮件您了,注意查收,如果没找到,可以尝试检查垃圾邮件。注意,这仅用于逆向学习,一切非法用途自负。
谢谢,有修改好的工程文件发一份吗?我编译一下
对了,最新版好像失效了。
不客气,这里可以通过Baymax Patch Tools x64生成劫持代码,打开后点击菜单中的工具,劫持代码生成器,文件找到系统文件wtsapi32,不加载PYG64.dll,右侧版本选择你的vs版本,创建工程,随后打开vs2022,打开工程,其中建议附到DLL_PROCESS_ATTACH节中,劫持部分和上面代码类似,但是需要稍加改造(其实也就是main内容放到了ATTACH节里面)。删除注册表的那里可以优化,自己动手尝试一下吧。