吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6808|回复: 44
收起左侧

[原创] Win11环境下使用BYOVD方法破解SandboxiePlus验证

  [复制链接]
暴龙兽 发表于 2025-9-22 10:00

前几天有评论说win11环境下之前的方法不行,试了一下确实不行。主要原因还是echo_driver.sys驱动加载失败了,返回的错误码是0x800B010C,对应的含义如下:


错误码

错误码

需要重新寻找新的具有任意地址读写漏洞的具有合法签名驱动文件。

经过一段时间的寻找,功夫不负有心人,终于找到了一个符合需求的项目BYOVD_read_write_primitive,相关项目地址如下:https://github.com/0xJs/BYOVD_read_write_primitive 。重新编写程序的过程中,发现一个有意思的问题:win11环境下,管理员执行NtQuerySystemInformation获取SbieDrv驱动模块基地址的竟然是0,而在win10环境下符合预期。

本篇文章的第一部分主要探究这个问题,第二部分给出基于BYOVD_read_write_primitive的破解思路。

NtQuerySystemInformation系统调用问题

破解程序使用该系统调用获取SbieDrv驱动模块的基地址,它的函数原型如下:

NTSTATUS NtQuerySystemInformation(
  [in]            SYSTEM_INFORMATION_CLASS SystemInformationClass,
  [in, out]       PVOID                    SystemInformation,
  [in]            ULONG                    SystemInformationLength,
  [out, optional] PULONG                   ReturnLength
);

第一个参数为SystemModuleInformation(11)时,获取当前所有驱动模块的信息,比较文件名即可获取SbieDrv驱动模块的基地址。

Win10环境

当NtQuerySystemInformation系统调用的第一个参数为SystemModuleInformation时,NtQuerySystemInformation会调用ExpQuerySystemInformation函数,该函数相关的代码如下:


函数代码

函数代码

  • ExIsRestrictedCaller的IDA F5反汇编代码如下:

_BOOL8 __fastcall ExIsRestrictedCaller(char a1)
{
  BOOLEAN v1; // bl
  _BOOL8 result; // rax
  struct _SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; // [rsp+50h] [rbp-28h] BYREF
  NTSTATUS AccessStatus; // [rsp+80h] [rbp+8h] BYREF
  ACCESS_MASK GrantedAccess; // [rsp+88h] [rbp+10h] BYREF
  AccessStatus = 0;
  GrantedAccess = 0;
  memset(&SubjectSecurityContext, 0, sizeof(SubjectSecurityContext));
  result = 0;
  if ( a1 )
  {
    SeCaptureSubjectContext(&SubjectSecurityContext);
    v1 = SeAccessCheck(
           SeMediumDaclSd,  // SecurityDescriptor
           &SubjectSecurityContext, // SubjectSecurityContext
           0,   // SubjectContextLocked
           0x20000u,    // DesiredAccess, READ_CONTROL -> 
           0,           // PreviouslyGrantedAccess
           0i64,        // Privileges
           (PGENERIC_MAPPING)&ExpRestrictedGenericMapping,  // GenericMapping
           1,   // AccessMode,KernelMode -> 0, UserMode -> 1
           &GrantedAccess,  // GrantedAccess
           &AccessStatus);  // AccessStatus
    SeReleaseSubjectContext(&SubjectSecurityContext);
    if ( !v1 || AccessStatus < 0 )
      return 1;
  }
  return result;
}

如果ExIsRestrictedCaller返回一个true,则NtQuerySystemInformatio n系统调用返回一个0xC0000022,表示STATUS_ACCESS_DENIED。管理员启动一个进程的话,ExIsRestrictedCaller返回一个False,非管理员启动则返回一个True。

  • 接下来执行ExpQueryModuleInformation函数,

IDA ExpQueryModuleInformation_win10

IDA ExpQueryModuleInformation_win10

windbg ExpQueryModuleInformation_win10

windbg ExpQueryModuleInformation_win10

从PsLoadModuleList链表中遍历已经加载的内核模块,提取信息赋值给NtQuerySystemInformation的第二个参数SystemInformation,它是一个PRTL_PROCESS_MODULES结构体。该结构体的内容如下:

typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
    HANDLE Section;
    PVOID MappedBase;
    PVOID ImageBase;
    ULONG ImageSize;
    ULONG Flags;
    USHORT LoadOrderIndex;
    USHORT InitOrderIndex;
    USHORT LoadCount;
    USHORT OffsetToFileName;
    UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
    ULONG NumberOfModules;
    RTL_PROCESS_MODULE_INFORMATION Modules[1];
}
//

总结:在win10环境下,只要使用管理员启动进程来调用NtQuerySyst emInformation系统调用即可获取所有内核模块的的信息,包括基地址。

Win11环境

Win11下NtQuerySystemInformation系统调用的执行和win10相似,主要在ExIsRestrictedCaller和ExpQueryModuleInformation函数中有些不同。

  • ExIsRestrictedCaller函数的不同,增加了是否拥有SeDebugPrivilege权限的验证。

__int64 __fastcall ExIsRestrictedCaller(KPROCESSOR_MODE a1, _DWORD *a2)
{
  unsigned int v2; // edi
  BOOLEAN v5; // bl
  struct _SECURITY_SUBJECT_CONTEXT SubjectContext; // [rsp+50h] [rbp-28h] BYREF
  NTSTATUS AccessStatus; // [rsp+80h] [rbp+8h] BYREF
  ACCESS_MASK GrantedAccess; // [rsp+88h] [rbp+10h] BYREF
  v2 = 0;
  AccessStatus = 0;
  GrantedAccess = 0;
  memset(&SubjectContext, 0, sizeof(SubjectContext));
  if ( a2 )
    *a2 = 0;
  if ( !a1 )
    return 0i64;
  // 不同之处,新增
  if ( a2 && (unsigned int)Feature_RestrictKernelAddressLeaks__private_IsEnabledDeviceUsageNoInline() )
    *a2 = SeSinglePrivilegeCheck(SeDebugPrivilege, a1) == 0;    
  SeCaptureSubjectContext(&SubjectContext);
  v5 = SeAccessCheck(
         SeMediumDaclSd,
         &SubjectContext,
         0,
         0x20000u,
         0,
         0i64,
         (PGENERIC_MAPPING)&ExpRestrictedGenericMapping,
         1,
         &GrantedAccess,
         &AccessStatus);
  SeReleaseSubjectContext(&SubjectContext);
  if ( !v5 )
    return 1i64;
  LOBYTE(v2) = AccessStatus < 0;
  return v2;
}

如果拥有SeDebugPrivilege权限,将a2指针处设置为False,否则为True。从Feature_RestrictKernelAddressLeaks__private_IsEnabled DeviceUsageNoInline这个符号名也可以看出,此处是为了限制非SeDebugPrivilege权限的进程获取内核模块的基地址的。

  • ExpQueryModuleInformation函数的不同,ExIsRestrictedCaller函数验证通过之后,会将a2指针处的值传递给ExpQueryModuleInforma tion函数的第一个参数。

__int64 __fastcall ExpQueryModuleInformation(int a1, _DWORD *a2, unsigned int a3, _DWORD *a4)
{
  __int64 result; // rax
  unsigned int v8; // ecx
  _QWORD v9[2]; // [rsp+30h] [rbp-38h] BYREF
  unsigned int v10; // [rsp+40h] [rbp-28h]
  int v11; // [rsp+44h] [rbp-24h]
  _DWORD *v12; // [rsp+48h] [rbp-20h]
  int v13; // [rsp+50h] [rbp-18h]
  int v14; // [rsp+54h] [rbp-14h]
  v9[0] = 0i64;
  v13 = a1;
  v14 = 0;
  v12 = a4;
  v11 = 8;
  v9[1] = a2 + 2;
  v10 = a3;
  // v9是一个结构体,
  result = MmEnumerateSystemImagesShared(ExpQueryModuleInformationImage, v9);   
  v8 = 0xC0000004;
  if ( (int)(result + 0x80000000) < 0 || (_DWORD)result == 0xC0000004 )
  {
    *a4 = v11;
    if ( a3 >= 8 )
    {
      *a2 = v14;
      return LODWORD(v9[0]);
    }
    return v8;
  }
  return result;
}
__int64 __fastcall MmEnumerateSystemImagesShared(__int64 a1, __int64 a2)
{
  return MiEnumerateSystemImages(a1, a2, 2i64);
}
  • MiEnumerateSystemImages函数的反汇编代码如下:

// a1 -> ExpQueryModuleInformationImage函数
// a2 -> ExpQueryModuleInformation的v9
__int64 __fastcall MiEnumerateSystemImages(__int64 a1, __int64 a2, __int64 a3)
{
  struct _KTHREAD *CurrentThread; // r9
  int v4; // edi
  unsigned int v5; // r12d
  __int64 Lock; // rax
  PVOID *v8; // rbx
  __int64 v9; // rbp
  __int64 v10; // r8
  __int64 v11; // r9
  PVOID *i; // rbx
  CurrentThread = KeGetCurrentThread();
  v4 = 0;
  v5 = a3;
  if ( (struct _KTHREAD *)qword_140E2D610 == CurrentThread )
  {
    for ( i = (PVOID *)PsLoadedModuleList; i != &PsLoadedModuleList; i = (PVOID *)*i )
    {
      v4 = guard_dispatch_icall_no_overrides(i, a2, a3, CurrentThread); // 
      if ( v4 < 0 )
        break;
    }
  }
  else
  {
    Lock = MiAcquireLoadLock(0i64);
    v8 = (PVOID *)PsLoadedModuleList;
    v9 = Lock;
    while ( v8 != &PsLoadedModuleList )
    {
      MiLockLoaderEntry(v8, v5);
      v4 = guard_dispatch_icall_no_overrides(v8, a2, v10, v11);
      MiUnlockLoaderEntry(v8, v5);
      if ( v4 < 0 )
        break;
      v8 = (PVOID *)*v8;
    }
    MmReleaseLoadLockShared(v9);
  }
  return (unsigned int)v4;
}

这个函数就是遍历PsLoadedModuleList链表中的内核模块,每一个模块都调用一次ExpQueryModuleInformationImage函数。ExpQueryModuleInformationImage函数伪代码如下:


IDA ExpQueryModuleInformationImage_win11

IDA ExpQueryModuleInformationImage_win11


其实a2就是v9,那a2+0x20其实就是ExpQueryModuleInformation函数的 _QWORD v9[2]; // [rsp+30h] [rbp-38h] BYREF加0x20,就是 int v13; // [rsp+50h] [rbp-18h]。这就是说,如果拥有SeDebugPrivilege就将内核模块的地址透出,否则置为空。

总结:win11环境下除了需要管理员权限启动进程之外,还需要额外获取SeDebugPrivilege权限才能破解成功。设想一下,补丁程序在win11上面运行,管理员权限启动,发现破解失败;这时你需要使用调试器去定位问题,发现又可以破解成功,这就很让人迷糊。当你使用管理员权限启动一个调试器创建管理员进程,进行分析,其实被调试的进程已经具备了SeDebugPrivilege权限,但如果你附加调试,目标进程的权限位并未发生变化。


SeDebugPrivilege

SeDebugPrivilege

而问题的真正原因呢,还是在内核,如果不逆向分析内核,无法得出定位出。

破解程序代码

  • 第一步:获取Debug权限
bool GetDebugPrivilege()
{
    HANDLE hToken;
    LUID luid;
    TOKEN_PRIVILEGES tokenPrivileges;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    {
        std::cerr << "Error : get current process token, error code : " << GetLastError() << std::endl;
        return false;
    }
    if (!LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &luid))
    {
        std::cerr << "Error : get debug privilege luid, error code : " << GetLastError() << std::endl;
        return false;
    }
    tokenPrivileges.PrivilegeCount = 1;
    tokenPrivileges.Privileges[0].Luid = luid;
    tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(tokenPrivileges), NULL, NULL))
    {
        std::cerr << "Error : adjust debug privilege, error code : " << GetLastError() << std::endl;
        CloseHandle(hToken);
        return false;
    }
    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        std::cerr << "Error : no enough privilege to adjust debug privilege" << std::endl;
        CloseHandle(hToken);
        return false;
    }
    CloseHandle(hToken);
    return true;
}
  • 第二步:获取Verify_CertInfo的地址。getVerifyCertInfoOffset获取Verify_CertInfo关键验证变量的偏移
    // sysPath -> 驱动文件的位置
    // pdbPath -> 驱动文件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;
    }

getSbieDrvBaseAddress获取SbieDrv内核模块的基地址

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变量的内核地址


第三步:修改变量的内容

DriverInterface Driver(rotcoreSysPath);
uint64_t newValue = 0xfffffffff000fcc1;
res =  Driver.write_arbitary_address_memory((SbieDrvBaseAddress + verifyCertInfoOffset), (newValue & 0xffffffff));        // // 0x000c3550 f000fcc1 -> 0xffffffff f000fcc1
if (res == false)
{
        printf("Failure\n");
        return 0;
}
res = Driver.write_arbitary_address_memory((SbieDrvBaseAddress + verifyCertInfoOffset + 4), (newValue & 0xffffffff00000000) >> 32);        // // 0x000c3550 f000fcc1 -> 0xffffffff f000fcc1
if (res == false)
{
        printf("Failure\n");
        return 0;
}

总结

Win11系统中采用更加严格的驱动策略导致驱动加载失败,无法破解SandboxiePlus。使用新版漏洞驱动之后,内核的一些策略导致了获取驱动地址失败。以后,为了兼容各种windows系统版本,可以check一遍操作所需的权限,不管有没有已经获得。

免费评分

参与人数 16吾爱币 +16 热心值 +13 收起 理由
52pjadmi + 1 谢谢@Thanks!
qianmiao + 1 我很赞同!
a51318261 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
fengbolee + 2 + 1 用心讨论,共获提升!
gaokun996 + 1 + 1 热心回复!
IE1 + 1 谢谢@Thanks!
i07070707 + 1 我很赞同!
fiscivaj + 1 我很赞同!
pojie20230721 + 1 + 1 我很赞同!
UFOfeifei + 1 + 1 我很赞同!
江南小虫虫 + 1 + 1 用心讨论,共获提升!
allspark + 1 + 1 用心讨论,共获提升!
smile1110 + 3 + 1 6666
daxz + 1 + 1 谢谢@Thanks!
5omggx + 1 + 1 用心讨论,共获提升!
PoJieDaWang123 + 1 热心回复!

查看全部评分

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

VMxxxz 发表于 2025-9-22 10:44
厉害了,我滴神。学习学习
w1066602520 发表于 2025-9-22 10:45
HuaGdao1 发表于 2025-9-22 10:52
SN1t2lO 发表于 2025-9-22 11:16
只要不升级,第一代方案好用
 楼主| 暴龙兽 发表于 2025-9-22 11:57
SN1t2lO 发表于 2025-9-22 11:16
只要不升级,第一代方案好用

新版本会修复一些bug和cve漏洞
seanwang 发表于 2025-9-22 20:52
新版本修复了cve漏洞,这个挺好的。
yuhu1123 发表于 2025-9-23 20:35
好东西啊   不过我用的还是WIN10
jlt 发表于 2025-9-23 21:13
厉害了,我滴神
weiguopei 发表于 2025-9-23 22:51
虽然看不懂,但还是觉得很厉害!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-2-1 19:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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