如何从ID3D11PixelShader对象获取已编译的像素着色器字节码
D3D11 从ID3D11PixelShader获取着色器字节码方案
D3D11 原生公开的ID3D11PixelShader接口没有提供类似D3D9 GetFunction的直接获取字节码的方法,可通过以下两种方案实现需求:
方案1:Hook ID3D11Device::CreatePixelShader 缓存映射(兼容性最高,推荐逆向场景使用)
- D3D11所有像素着色器实例都通过
ID3D11Device::CreatePixelShader接口创建,调用时的前两个参数分别是原始着色器字节码指针、字节码长度,第四个参数是输出的ID3D11PixelShader对象指针。 - 你可以Hook这个创建接口,在每次着色器创建时将「着色器对象地址 -> 字节码副本」的映射存入自定义哈希表,后续拿到任意
ID3D11PixelShader实例直接查表即可获取对应字节码。 - 该方案兼容所有Windows版本,不依赖运行时内部实现,稳定性最高,是游戏逆向、Mod开发领域的通用实现。
方案2:通过私有GUID直接读取字节码(依赖运行时实现,兼容性一般)
微软D3D11运行时内部会将原始着色器字节码存储在着色器对象的私有数据区,可通过指定GUID调用ID3D11DeviceChild::GetPrivateData方法读取:
- 首先定义私有GUID:
GUID_D3D11_SHADER_BYTECODE = {0x3d4dd49e, 0x5ed3, 0x4E45, {0xb5, 0xa1, 0xf2, 0x55, 0xc5, 0x04, 0x04, 0x8f}} - 调用
GetPrivateData读取字节码,示例代码如下:
UINT bytecodeSize = 0; // 第一次调用查询需要的缓冲区大小 HRESULT hr = pPixelShader->GetPrivateData(GUID_D3D11_SHADER_BYTECODE, &bytecodeSize, nullptr); if (SUCCEEDED(hr) && bytecodeSize > 0) { void* pBytecode = malloc(bytecodeSize); // 第二次调用读取字节码内容 hr = pPixelShader->GetPrivateData(GUID_D3D11_SHADER_BYTECODE, &bytecodeSize, pBytecode); if (SUCCEEDED(hr)) { // 读取成功,pBytecode即为原始DXBC格式的着色器字节码 } free(pBytecode); }
- 该方案依赖D3D11运行时的内部实现,部分旧版本Windows、定制版系统可能读取失败,仅建议作为辅助方案使用。
附加说明
拿到DXBC格式的字节码后,可直接调用d3dcompiler_xx.dll导出的D3DDisassemble函数反编译为可读的HLSL汇编代码。
内容的提问来源于stack exchange,提问作者Hellacrow
相关产品推荐
相关产品推荐

