RenderDoc 启动原理

RenderDoc 会通过注入的方式,在所有Graphics API调用之前,在目标进程挂载 renderdoc.dll。这个dll挂载的时候会 wrap 所有的 Graphics API接口(与 壳 FAKER 的做法类似),然后在进程调用 Graphics API 的时候,进行需要的操作,例如:记录所有 API 调用时候的参数,从而完成对每帧数据的记录。 不同的 Graphics API 采用不同的 FAKER,例如:Vulkan 采取加载 RenderDoc 自定义的验证层的方式。

一些特殊的项目会对RenderDoc这样的工具进行检测,从而防止截帧。我们可以采取一些逆向的方案绕过检测,从而达到截帧的目的。

项目工程:VestLee/MagicRDC

Windows 平台 Android 模拟器环境启动过程

Windows 平台上的 Android 模拟器在运行时,会首先加载 d3d11.dll。

可以通过制造一个 Fake d3d11.dll 的方式,在加载系统的 d3d11.dll 之后,接着加载 renderdoc.dll 即可。

LoadLibrary 加载 dll 的搜索路径是:
1.应用程序所在的目录

2.系统目录

3.当前工作目录

4.path变量中的目录

需要保证模拟器先加载 FAKER 。

以 Mumu 模拟器为例,进行说明。

Ps:模拟器注意需要下载 64 bit 版本,很多游戏已经不再支持32位了。

FAKER d3d11.dll

Fake dll制作,参考开源库:SeanPesce/d3d11-wrapper

可以使用这个轮子进行修改,使得模拟器可以在加载 FAKER 之后加载 renderdoc.dll

去掉“sp/environment.h”等未找到的头文件,和相关的函数使用,变量声明(对编译没影响)。

在 dllmain.h &cpp 中,dll 入口函数中,DLL_PROCESS_ATTACH 创建线程事件中会触发函数:d3d11::hook_exports(),

BOOL APIENTRY DllMain(HMODULE h_module, DWORD ul_reason_for_call, LPVOID lp_reserved){    switch (ul_reason_for_call)    {    case DLL_PROCESS_ATTACH:        return dll::on_process_attach(h_module, lp_reserved);        break;........................................................    inline BOOL on_process_attach(HMODULE h_module, LPVOID lp_reserved){    d3d11::hook_exports();    WRAPPER_ON_PROCESS_ATTACH_GLOBAL_NS(h_module, lp_reserved);    return TRUE;}

修改 d3d11::hook_exports() 函数,首先判断当前环境是否是64 bit,从而决定加载对应的d3d11.dll(true)。

BOOL IsWow64(){typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);LPFN_ISWOW64PROCESS fnIsWow64Process = nullptr;BOOL bIsWow64 = FALSE;//IsWow64Process is not available on all supported versions of Windows.//Use GetModuleHandle to get a handle to the DLL that contains the function//and GetProcAddress to get a pointer to the function if available.fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");if (NULL != fnIsWow64Process){if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)){//handle error}}return bIsWow64;}void hook_exports(){if (IsWow64()){chain = LoadLibrary("C:\\Windows\\SysWOW64\\d3d11.dll");}else{chain = LoadLibrary("C:\\Windows\\System32\\d3d11.dll");}........................................................................

加载d3d.dll之后,接着加载 renderdoc.dll ,具体的地址根据各自的项目而定(这里使用了绝对路径)。

void hook_exports(){.................................................................................std::string rdcpath = "D:\\RenderDoc\\RenderDoc1.14\\renderdoc.dll";HMODULE renderdoc = LoadLibrary(rdcpath.c_str());if (!renderdoc) {MessageBox(NULL, "Unable to locate renderdoc (or compatible library to chain)", "ERROR: Failed to load original d3d11.dll", NULL);exit(0);}}

编译得到d3d11.dll(fake) ,把生成的d3d11.dll(fake)放到 \emulator\nemu\device 文件夹下,(如果写的是相对路径,则renderdoc.dll拷贝到 \emulator\nemu\device 文件夹的相对路径下)

启动RDC

运行mumu模拟器,左上角应该会renderdoc 的信息

打开renderdoc,attach到进程上,点击:File->Attach to Running Instance 之后可以在界面中Capture了 。