首页
社区
课程
招聘
[原创]函数简单逆向并录制隐私窗口 -part1 直接帧捕获
发表于: 9小时前 231

[原创]函数简单逆向并录制隐私窗口 -part1 直接帧捕获

9小时前
231

虚拟机环境WIN11 24H2。
我们先通过注入的方式调用函数SetWindowDisplayAffinity,因为该视频加密播放器为了不判断系统版本提高兼容性,均设置参数2为0x1,这里为保持一致性也设置1,至此将我们的CE设置为了隐私窗口,截图和录屏效果为:

我们转到win32kfull.sys中定位函数:NtUserGetWindowDisplayAffinity:

函数将我们的窗口句柄通过函数ValidateHwnd转为了tagWND,通过IsTopLevelWindow判断是否是顶级窗口,这个函数体内也可以帮助我们修复部分tagWND结构的成员。我们可以通过调用ValidateHwnd函数的方式获取到CE窗口的tagWND,也可以通过24H2最顶级二叉树节点窗口句柄0x10002,遍历所有tagWND。GetDisplayAffinity函数的参数1依旧是我们获取到的tagWND。

W32GetUserSessionState函数可以通过win32k.sys函数查找到,当然用windbg也可以看到函数所在的模块,就是将全局变量gSessionGlobalSlots解引用两次即可。

这里我们也拿到了GetProp函数参数2的值,也就是0xC032。我们继续进入函数GetProp查看:

通过调用函数RealGetProp最终得到对应窗口的DisplayAffinity的值。函数RealGetProp在模块win32kbase.sys中,我们在windbg中通过模拟执行来走一遍流程:


那么我们就走完了函数GetWindowDisplayAffinity进入内核获取DisplayAffinity的流程,这里并不是实际控制窗口保护的位置,你修改这里为0x0,依旧是隐私窗口。即使你注入到播放器进程,调用SetWindowDisplayAffinity,播放器应用层肯定会创建线程循环获取DisplayAffinity,发现被修改可以直接封禁账号。
我们转到函数NtUserSetWindowDisplayAffinity,依次通过SetDisplayAffinity->InternalSetProp->RealInternalSetProp来写入DisplayAffinity到我们刚刚查询到的位置。流程也非常简单就不再次废话了。
在SetDisplayAffinity中进入ChangeWindowTreeProtection再进入ProtectWindowBitmap再进入GreProtectSpriteContent就可以找到实际控制窗口隐私的位置:

当然直接调用GreProtectSpriteContent将加密视频播放器的顶级窗口修改DisplayAffinity为0x0后,自行编写录制工具也是可以单独获取画面的。因为该加密视频播放器纯三环应用程序没有使用驱动。
进入DWMSPRITEREF::DWMSPRITEREF函数后,再进入DWMSPRITEREF::hspLookupWindow函数:

可以看到数据结构依旧使用的二叉树,RtlLookupElementGenericTable中通又使用了HwndLookupCompareTableData函数进行查找,聪明的你肯定想要使用RtlDeleteElementGenericTable尝试删除二叉树节点,这样调用hspLookupWindow就无法找到我们播放器顶级窗口的相关节点信息。不过,还需要注意删除节点后的窗体不能被激活刷新,否则会出现一些异常。当然删除节点后也并非就完全找不到了,因为删除节点后PRTL_SPLAY_LINKS Links->Parent依旧存在,TableRoot->LeftChild清零,TableRoot = TableRoot->RightChild清零,我们可以内存搜索hWnd,根据Links->Parent所在内存区段,并且左右子树清零的内存特征进行搜索。
接下来模拟获取hspLookupWindow函数返回值,调用HmgLock,根据偏移修改控制DisplayAffinity的位置。到windbg中来演示,首先还是按照IDA中的流程模拟执行hspLookupWindow,来查找CE窗口的entry:


因为IDA中Buffer[0] = a1;a1是窗口句柄,那么我们定位到的entry的位置也是窗口句柄所在的位置。然后我们到ntoskrnl.exe中查看函数RtlLookupElementGenericTable:

我们在windbg中查看我们的hWnd在二叉树中的哪一个位置:

可以看到在0x28的偏移处,我们对定位到的entry-0x28就是我们当前hWnd所在的子树:

然后在hWnd地址+8的位置拿到HmgLog函数的参数1:

回到这一行:


当我们的DisplayAffinity设置为1时:

所以写入这个地址的值末位为9,将9清零即可实现去掉窗口隐私保护的目的。我们通过简单的右移左移指令即可实现。
当我们的DisplayAffinity设置为0x11时:

同样清除这里的0x49即可。



对于音频录制该加密播放器并没有太多处理,直接采集电脑输出声音即可,然后视频与音频融合完成录制。当然蓝牙耳机加密播放的除外。

NVIDIA Corporation\ShadowPlay\CaptureCore.log保存了英伟达显卡运行时的所有调试输出语句,可以定位到错误信息,也可以分析截图流程与录制流程。通过Hook GetWindowDisplayAffinity调用链上不管是3环还是内核中的位置都可以。因为该加密播放器极其容易封号,一封就是24小时,还得找卖课的解除,这种方式就未测试了。NVIDA显卡的截屏与录制也是两套方案,NvApi调用失败通过注入DWM进程捕获,对于要开发加密播放器的话,即使GetWindowDisplayAffinity调用链被Hook也有多种多样的方式检测到。

遍历获取到加密播放器的顶级窗口后,使用:

对新创建的窗口进行帧捕获也可以拿到画面。因为github上或者某E语言论坛开源例子很丰富,各位自行尝试三种方法的优缺点。当我们自行开发加密播放器时也能应对这些盗版翻录的小人。

__int64 SessionGoables = PDB.Gre_Base_Globals();
if (!SessionGoables){
    KLog("faild to get Gre_Base_Globals result", Error);
    return false;
}
KLog("SessionGoables = %llX", SessionGoables);
 
PRTL_GENERIC_TABLE SessionTable = ((WIN1124H2_SESSION_GLOBALS*)SessionGoables)->SessionTable;
 
PERESOURCE SessionTableLock = (PERESOURCE)((ULONG64)SessionTable + sizeof(RTL_GENERIC_TABLE));
 
if ((ULONG64)SessionTable != 0xFFFFFFFFFFFFFFB8uLL){
    bool bLock = PDB.DirectComposition_CCriticalSection_TryAcquireExclusive(SessionTableLock);
    if (!bLock){
        KLog("faild to DirectComposition_CCriticalSection_TryAcquireExclusive", Error);
        return false;
    }
}
 
WIN1124H2_SESSION_entry session_entry{};
session_entry.hWnd = (HWND)hWnd;
 
PVOID cache_entry = PDB.RtlLookupElementGenericTable(SessionTable, &session_entry);
if (cache_entry){
    KLog("cache_entry = %llX", false, cache_entry);
    if (!PDB.RtlDeleteElementGenericTable(SessionTable, cache_entry))
    {
        KLog("faild to RtlDeleteElementGenericTable", Error);
    }
 
    __int64 v1 = *((__int64*)cache_entry + 1);
    KLog("v1 = %llX", v1);
}
 
if (SessionTableLock){
    PDB.ExReleaseResourceLite((PERESOURCE)SessionTableLock);
    PDB.KeLeaveCriticalRegion();
}
__int64 SessionGoables = PDB.Gre_Base_Globals();
if (!SessionGoables){
    KLog("faild to get Gre_Base_Globals result", Error);
    return false;
}
KLog("SessionGoables = %llX", SessionGoables);
 
PRTL_GENERIC_TABLE SessionTable = ((WIN1124H2_SESSION_GLOBALS*)SessionGoables)->SessionTable;
 
PERESOURCE SessionTableLock = (PERESOURCE)((ULONG64)SessionTable + sizeof(RTL_GENERIC_TABLE));
 
if ((ULONG64)SessionTable != 0xFFFFFFFFFFFFFFB8uLL){
    bool bLock = PDB.DirectComposition_CCriticalSection_TryAcquireExclusive(SessionTableLock);
    if (!bLock){
        KLog("faild to DirectComposition_CCriticalSection_TryAcquireExclusive", Error);
        return false;
    }
}
 
WIN1124H2_SESSION_entry session_entry{};

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
感谢分享
4小时前
0
游客
登录 | 注册 方可回帖
返回