吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1418|回复: 19
上一主题 下一主题
收起左侧

[原创] 基于BYOVD方法无限使用SandboxiePlus的高级功能

[复制链接]
跳转到指定楼层
楼主
暴龙兽 发表于 2025-6-10 16:13 回帖奖励
本帖最后由 暴龙兽 于 2025-6-10 16:16 编辑

前言

随着SandboxiePlus版本的迭代,从1.15.10版本开始,原有无限试用其高级功能的方法已经不再适用。



上图中,proces.c中的Process_Create函数在目标进程启动的时候校验了证书的active字段.如果active是0,则在目标进程启动五分钟后,kill掉目标进程。否则,进程正常执行,不进行kill。

原来的破解方法是基于证书有效期的字段全在用户态进行校验,修改用户态校验的结果,进而达到无限试用高级功能的目的。但从1.15.10版本开始出现了驱动侧(r0)验证证书的有效性,自然而然原来的破解方法就失效了。本文使用BYOVD的方法修改驱动侧的全局变量Verify_CertInfo,实现在没有证书的情况下也可以免费试用其高级功能。

原理介绍

BYOVD(Bring Your Own Vulnerable Driver),即攻击者向目标环境植入一个带有漏洞的合法驱动程序,再通过漏洞利用获得内核权限以杀死/致盲终端安全软件等。这项技术最初主要被如Turla和方程式这样的顶级APT组织所使用,而随着攻击成本的降低,其它攻击组织也逐渐开始使用这项技术。

SandboxiePlus 高级功能无限试用文章中,我介绍了SandboxiePlus的验证过程。它通过验证证书的内容和签名,来判断当前证书的类型和有效期,最后将这些信息写入到Verify_CertInfo这个全局变量中。每次使用带有高级功能的沙盒时,会获取该变量的信息,来判断是否可以使用高级功能,不能使用高级功能则出现如下提示:



如果能够直接修改驱动侧Verify_CertInfo变量的值为一个有效期证书验证之后的结果,那么即便没有证书,我们也可以实现无限使用高级功能的效果。而是实现驱动侧修改Verify_CertInfo变量的方法就是使用一个带有写任意地址漏洞的签名驱动。

过程分析

为了保证使用者系统的安全性,在需要破解的时候创建漏洞驱动服务,马上启动该服务。在修改变量结束之后,马上停止该漏洞服务,并删除。这里使用的漏洞驱动是echo_driver,漏洞利用的Github地址是https://github.com/kite03/echoac-poc/tree/main/PoC。

获取Verify_CertInfo变量地址

SandboxiePlus的安装目录中存在SbieDrv.sys和SbieDrv.pdb文件,可以解析这个PDB文件获取Verify_CertInfo变量的偏移offset。然后获取SbieDrv驱动的基地址,然后两者之和就是Verify_CertInfo地址。在Windows系统中,所有进程共享内核地址空间,因此当前进程修改Verify_CertInfo地址就可以实现预期的效果。

  • 借助DbgHelp库中的函数获取Verify_CertInfo变量的偏移。

    // 参数是sbiedrv驱动路径和sbiedrv pdb路径
    uint64_t getVerifyCertInfoOffset(const wchar_t* sysPath, const wchar_t* pdbPath)
    {
        uint64_t res = 0;
    
        SymInitialize(GetCurrentProcess(), NULL, FALSE);
        // load sys file
        uint64_t baseAddress = SymLoadModuleExW(GetCurrentProcess(), NULL, sysPath, NULL, 0x10000000, 0, NULL, 0);
        if (baseAddress == 0)
        {
                printf("[!] Error load sys file\n");
                return 0;
        }
    
        // load pdb file
        if (!SymSetSearchPathW(GetCurrentProcess(), pdbPath))
        {
                printf("[!] Error load pdb file\n");
                SymUnloadModule(GetCurrentProcess(), baseAddress);
                SymCleanup(GetCurrentProcess());
                return 0;
        }
    
        char symbolBuffer[sizeof(SYMBOL_INFOW) + 0x100 * sizeof(wchar_t)] = { 0 };
        PSYMBOL_INFOW pSymbol = (PSYMBOL_INFOW)symbolBuffer;
        pSymbol->SizeOfStruct = sizeof(SYMBOL_INFOW);
        pSymbol->MaxNameLen = 0xff;
    
        if (SymFromNameW(GetCurrentProcess(), L"Verify_CertInfo", pSymbol))
        {
                res = pSymbol->Address - baseAddress;
        }
    
        SymUnloadModule(GetCurrentProcess(), baseAddress);
        SymCleanup(GetCurrentProcess());
        return res;
    }
  • 遍历当前系统中的驱动模块,获取SbieDrv模块的基地址。
// 这里需要使用未公开的系统调用参数SystemModuleInformation,对应的系统调用是NtQuerySystemInformation
uint64_t getSbieDrvBaseAddress()
{
        NTSTATUS status = STATUS_SUCCESS;
        uint64_t sbiedrvBaseAddress = 0;
        PRTL_PROCESS_MODULES moduleInfo = (PRTL_PROCESS_MODULES)VirtualAlloc(NULL, 0x400 * 0x400, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
        if (moduleInfo == NULL)
        {
                printf("[!] Error allocating module memory! Error Code: %lu\n", GetLastError());
                return 0;
        }

        if(!NT_SUCCESS(status = NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)11,
                moduleInfo, 0x400 * 0x400, NULL)))
        {
                printf("[!] Error: Unable to query module list (%#x)\n", status);
                VirtualFree(moduleInfo, 0, MEM_RELEASE);
                return 0;
        }

        for (ULONG i = 0; i < moduleInfo->NumberOfModules; i++)
        {
                if (!_stricmp((const char*)moduleInfo->Modules[i].FullPathName +
                        moduleInfo->Modules[i].OffsetToFileName, "sbiedrv.sys"))
                {
                        sbiedrvBaseAddress = (uint64_t)moduleInfo->Modules[i].ImageBase;
                        break;
                }
        }
        return sbiedrvBaseAddress;
}

修改Verify_CertInfo变量的值

  • 前文echoac-poc项目首先需要将代签名的漏洞驱动echo_driver.sys运行起来,然后获取驱动创建的设备的句柄,并设置当前进程。

    DriverInterface::DriverInterface()
    {
    // 获取对应的设备句柄
    hDevice = CreateFileA(
        "\\\\.\\EchoDrv",
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        NULL,
        NULL
    );
    
    //If driver handle failed to open print message and return
    if (hDevice == INVALID_HANDLE_VALUE) {
        std::cout << "Invalid handle on CreateFileA!" << std::endl;
        //Get the last error from windows for CreateFile
        std::cout << "Error code: " << GetLastError() << std::endl;
    }
    
    // Yes, this buffer seems useless - but without it the driver BSOD's the PC.
    //Create a buffer to have data returned to.
    void* buf = (void*)malloc(4096);
    
    //Call IOCTL that sets the PID variable and gets past the DWORD check
    //0x9e6a0594 - IOCTL Code,设置当前的进程。如果不设置当前进程,无法调用驱动对应的功能,具体原因请逆向分析echo_driver.sys文件
    BOOL success = DeviceIoControl(hDevice, 0x9e6a0594, NULL, NULL, buf, 4096, NULL, NULL);
    if (!success) {
        std::cout << "DeviceIOControl 0x9e6a0594 failed!" << std::endl;
        std::cout << "Error code: " << GetLastError() << std::endl;
    
        CloseHandle(hDevice);
        return;
    }
    
    //We don't need that buffer anymore
    free(buf);
    }
  • 调用read_memory_raw函数将合适的值写入到Verify_CertInfo变量中
HANDLE processHandle = Driver.get_handle_for_pid(GetCurrentProcessId());
uint64_t newValue = 0xfffffffff000fcc1;
// 0x000c3550 f000fcc1 -> 0xffffffff f000fcc1,其中0x000c3550表示证书的有效期,修改为0xffffffff表示可以无限长时间使用
Driver.read_memory_raw((void *)&newValue, (void *)(SbieDrvBaseAddress + verifyCertInfoOffset), 8, processHandle);

// read_memory_raw 函数如下
BOOL read_memory_raw(void* address, void* buf, size_t len, HANDLE targetProcess) 
{
    k_param_readmem req{};
    req.fromAddress = (void*)address;
    req.length = len;
    req.targetProcess = targetProcess;
    req.toAddress = (void*)buf;

    BOOL success = DeviceIoControl(hDevice, 0x60a26124, &req, sizeof(k_param_readmem), &req, sizeof(k_param_readmem), NULL, NULL);
    return success;
}

read_memory_raw函数参数的意思是将targetProcess进程的address地址的len字节内容写入到当前进程buf地址中。这里processHandle我们设置成当前进程,表示从当前进程中读取newValue对应的值写入到Verify_CertInfo变量中,而newValue变量的值是一个合法试用期证书的值,但将时间调至了无限。

什么时候修改

前面两个小结介绍了修改变量Verify_CertInfo的方法,即怎么修改。还有一个关键问题:什么时候修改?通过阅读SandboxiePlus的代码,发现了什么时候会触发Verify_CertInfo变量的修改:

  • SbieDrv.sys驱动加载时,会校验证书的有效性。
_FX NTSTATUS DriverEntry(
    IN  DRIVER_OBJECT  *DriverObject,
    IN  UNICODE_STRING *RegistryPath)
{
    ......
    if (ok)
        MyValidateCertificate();
    ......
}

_FX NTSTATUS MyValidateCertificate(void)
{
    if(!*g_uuid_str)
        InitFwUuid();

    NTSTATUS status = KphValidateCertificate();

    if (status == STATUS_ACCOUNT_EXPIRED)
        status = STATUS_SUCCESS;

    return status;
}
  • 用户态的校验。SbieDrv模块的源码中有一个Conf_Api_Reload,当用户态调用该函数且带有SBIE_CONF_FLAG_RELOAD_CERT参数时,会重置Verify_CertInfo变量的值。而且调用这个参数的地方有多出。
_FX NTSTATUS Conf_Api_Reload(PROCESS *proc, ULONG64 *parms)
{
    NTSTATUS status;
    ULONG flags;

    if (proc)
        return STATUS_NOT_IMPLEMENTED;

    flags = (ULONG)parms[2];

    if (flags & SBIE_CONF_FLAG_RELOAD_CERT) {
        status = MyValidateCertificate();
        goto finish;
    }
    ......
}

解决方法:

  • 第一种触发情况,其实不必处理,因为SandboxiePlus必须依赖SbieDrv驱动。可以将第一种情况归类于第二种情况。
  • 第二种触发情况,可以选择在用户态调用Conf_Api_Reload之后,执行一下我们的修改程序。幸运的是,调用Conf_Api_Reload的地方都在dll中,可以修改dll中的代码,然后编译替换对应的模块即可。这里修改的代码为SbieAPI.cpp文件中的ReloadConf函数,修改的函数如下:
SB_STATUS CSbieAPI::ReloadConf(quint32 flags, quint32 SessionId)
{
        __declspec(align(8)) ULONG64 parms[API_NUM_ARGS];

        memset(parms, 0, sizeof(parms));
        parms[0] = API_RELOAD_CONF;
        parms[1] = SessionId;
        parms[2] = flags;

        NTSTATUS status = m->IoControl(parms);
    // 新增的代码
        /**********************开始*************************/
    if(flags & SBIE_CONF_FLAG_RELOAD_CERT)
        {
                WCHAR exePatchPath[MAX_PATH] = { L'\x00' };
                if (GetModuleFileNameW(NULL, exePatchPath, MAX_PATH))
                {
                        PathRemoveFileSpecW(exePatchPath);
            // SandBoxiePlusPatch是我们编译出的补丁文件,用于加载驱动和修改Verify_CertInfo变量
                        wcscat(exePatchPath, L"\\SandBoxiePlusPatch.exe");
                        ShellExecuteW(NULL, L"open", exePatchPath, NULL, NULL, SW_SHOW);
                        OutputDebugStringW(exePatchPath);
                }
        }
    /**********************结尾*************************/
        if (!NT_SUCCESS(status))
                return SB_ERR(status);

        emit ConfigReloaded();

        m_bBoxesDirty = true;

        return SB_OK;
}

总结

本文利用BYOVD方法直接修改驱动SbieDrv的变量Verify_CertInfo为一个有效的值,实现了无证书的情况下使用其高级功能的效果。

免费评分

参与人数 5吾爱币 +5 热心值 +5 收起 理由
pojie20230721 + 1 + 1 用心讨论,共获提升!
m_h + 1 + 1 热心回复!
5omggx + 1 + 1 用心讨论,共获提升!
onskk + 1 + 1 我很赞同!
qqycra + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
netspirit 发表于 2025-6-12 13:49
暴龙兽 发表于 2025-6-12 13:28
差不多是这个意思

我去看了以下官方1.15.9版本的github更新
Please note that SbieShellExt.dll is missing in 1.15.9, which will be fixed in 1.15.10. SbieShellExt.dll is used for the shell integration, so don't worry if you can't start applications sandboxed from the explorer by right-clicking on it.
请注意,1.15.9 中缺少 SbieShellExt.dll,这将在 1.15.10 中修复。SbieShellExt.dll 用于 shell 集成,因此如果您无法通过右键单击资源管理器来启动沙盒化应用程序,请不要担心。


意思是官方故意把1.15.9里面的文件删掉了,然后阻止用户使用无限试用?
沙发
qqycra 发表于 2025-6-10 17:12
3#
zhouxinyi 发表于 2025-6-10 17:13
已经准备购买授权了,不过还是感谢技术分析
4#
 楼主| 暴龙兽 发表于 2025-6-10 17:21 |楼主
zhouxinyi 发表于 2025-6-10 17:13
已经准备购买授权了,不过还是感谢技术分析

买订阅制的?
5#
m_h 发表于 2025-6-10 22:44
看上去好复杂 没学会。
6#
zhouxinyi 发表于 2025-6-11 03:35

买断使用,但是更新只包1年
7#
SN1t2lO 发表于 2025-6-11 08:05
刚从公众号看到,楼主就是公众号作者吗?
8#
 楼主| 暴龙兽 发表于 2025-6-11 08:21 |楼主
SN1t2lO 发表于 2025-6-11 08:05
刚从公众号看到,楼主就是公众号作者吗?

是的,你应该看到补丁文件的下载提示了吧
9#
SN1t2lO 发表于 2025-6-11 10:01
暴龙兽 发表于 2025-6-11 08:21
是的,你应该看到补丁文件的下载提示了吧

是的,下载了,还没试
10#
m_h 发表于 2025-6-11 11:28
SN1t2lO 发表于 2025-6-11 10:01
是的,下载了,还没试

是同名文章吗?某某某x开发日常  公众号??
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-6-15 15:09

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表