n卡截图是通过dwm实现的
其中nvwgf2umx.dll为n卡用户层模块,nvspcap64.dll为n卡截图模块
nvspcap64.dll模块导出了三个函数,其中QueryShadowPlayDdiShimInterface可以查询到接口
可以发现导出一堆代理函数,n卡驱动会调用,其中两很重要
1.CreateSession_V2创建实例
2.DdiPrePresent_V2 present的前回调函数(截图部分)
先看CreateSession_V2Instance = CShadowPlayProxyShim__CreateInstance();
__int64 __fastcall sub_18003B480(__int64 a1)
__int64 v2; // rax
__int64 v3; // rax
CHAR MultiByteStr[272]; // [rsp+70h] [rbp-548h] BYREF
WCHAR Filename[264]; // [rsp+180h] [rbp-438h] BYREF
WCHAR WideCharStr[264]; // [rsp+390h] [rbp-228h] BYREF
*(_QWORD *)a1 = &ShadowPlayDdiShim_vtable;一直追可以找到 vtable instance 这个后面会经常用到
下面可以研究DdiPrePresent_V2 中是怎么截图的了return (*(__int64 (__fastcall **)(__int64, __int64 *))(*(_QWORD *)a1 + 0x40LL))(a1, v14);分析其中调用了一个虚函数,根据刚才的虚函数表找到函数if ( *(_QWORD *)(v46 + 8) )
if ( (unsigned __int8)CSPCaptureScreenShot__Initialise(*(_QWORD *)(a1 + 80), (__int64)PerformanceCount) )
CurrentProcessId = GetCurrentProcessId();
if ( *(_BYTE *)(v46 + 56) )
v45 = sub_18000BDAC(v46, CurrentProcessId, v47);
goto LABEL_116;
else
sub_180001C21(v48);
sub_180008F6C(7LL, "CSPCaptureScreenShot::CaptureScreenShotWrapper: ScreenShot Initialize failed");
}其中截图部分,通过文字可以知道,sub_18000BDAC是真正的截图部分。
进入,截图函数v13 = sub_180003E22(v12, 0LL, 0LL);
LABEL_16:
v14 = v13;
if ( !v13 )
goto LABEL_38;
v15 = *(_QWORD *)(a1 + 8);
v25[7] = v13 + 160;
v16 = (*(__int64 (__fastcall **)(__int64, _QWORD *))(*(_QWORD *)v15 + 8LL))(v15, v25);
if ( v16 )
dword_1802BFF70 = 7;
if ( dword_1802C00AC <= 7 )
sub_18000A1D7(
&off_1802BFF60,
"CSPCaptureScreenShot::CaptureScreenShot: Screenshot Capture Frame Failed(0x%X)",
v16);
if ( *(_QWORD *)a1 )
sub_180009CC3(a1);
return 0;
return 0;
}其中v13是共享buffer,v25[7] = v13 + 160是buffer中的截图部分,下面需要追v16 = (*(__int64 (__fastcall **)(__int64, _QWORD *))(*(_QWORD *)v15 + 8LL))(v15, v25)这个函数是哪里来的。v15 = (_QWORD )(a1 + 8);
可知v15是a1的一个成员。
回到DdiPrePresent_V2v45 = sub_18000BDAC(v46, CurrentProcessId, v47);
v46 = *(_QWORD *)(instance + 80);发现截图函数的a1是instance的偏移80部分,其实a1是CSPCaptureScreenShot的对象。
往上找有这么一行*(_QWORD *)(*(_QWORD *)(instance + 80) + 8LL) = *(_QWORD *)(*(_QWORD *)(instance + 64) + 24LL);继续向上v43 = CSPRendererManager__GetRenderer(*(_QWORD *)(instance + 56), *(_QWORD *)(a2 + 8), 0, 0, 0LL, 0);
*(_QWORD *)(instance + 64) = v43;可是偏移64是CSPRendererManager,分析CSPRendererManager__GetRenderer
sub_18002DC50*(_BYTE *)(v15 + 16) = 0;
*(_BYTE *)(v15 + 37) = 0;
*(_QWORD *)(v15 + 8) = a3;
*(_QWORD *)v15 = a2;
*(_DWORD *)(v15 + 20) = a4;
*(_QWORD *)(v15 + 24) = a5;
*(_DWORD *)(v15 + 32) = a6;
*(_BYTE *)(v15 + 46) = 0;
*(_QWORD *)(v15 + 48) = 0LL;
*(_BYTE *)(v15 + 36) = 0;
*(_QWORD *)(v15 + 38) = 0LL;可知v15 + 24也就是截图调用的对象为
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288266.htm
[转帖]nvidia截图分析
131 浏览
5 回复
牛逼
牛掰的~
>_< 感谢分享
Oxygen1a1
牛逼
你牛逼什么,你们不是分析的明明白白的吗。
牛逼
你牛逼什么,你们不是分析的明明白白的吗。
牛