阅读目录
游戏透视示例解析:通过D3D hook实现鬼泣4怪物透视
发布于:2016-6-28 16:07 | 223853次阅读 作者: 管理员 | 原作者: TP | 来自: 原创
一、基本原理 D3D(Direct3D )是微软为提高3D游戏在Windows中的显示性能而开发的显示程序接口,一般3D游戏中各种模型的渲染、显示等都必须通过D3D提供的API来实现。而游戏中模型之间的遮挡关系是通过其中的Z轴深度缓存实现的,这个缓冲记录每个像素的深度,在绘制每个像素之前,如果启用了深度缓冲,系统会把它的深度值和已经存储在缓冲里的这个像素的深度值进行比较。如果新像素深度值小于原先像素深度值,则新像素值会取代原先的,反之,新像素值被遮挡。深度缓冲的目的在于正确地生成通常的深度感知效果:较近的物体遮挡较远的物体。因此要实现怪物的透视只要判断当前游戏是在渲染怪物时关闭Z轴深度缓存即可。 二、基本步骤 (1)hook地址的找取 D3D绘制3D模型都需要调用DrawIndexedPrimitive()函数,因此我们的hook点就选在这个函数的函数头,这个函数的原型如下: HRSULT _stdcall IDirect3DDevice9:: DrawIndexedPrimitive(D3DPRIMITIVETYPE, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount),这个函数具体用法和参数可以参考msdn说明,这里不多加赘述。需要注意的是这个函数在d3d.dll中并不是一个导出函数,但是偏移是固定不变的,可以自己调用下这个函数下个断点在调试模式中找到这个偏移,比如下图代码所示使用DrawIndexedPrimitive绘制一个三菱锥: 将调试代码设置为反汇编模式,如下图所示:
跟进上图这个call就可以看到DrawIndexedPrimitive的实际函数地址,如下图红框所示: 使用PCHunter工具查到本例中d3d9.dll的基地址为0x5AEF0000,如下图所示: 二者相减即可得到偏移0x2B6B1,本例中函数地址就可以写为:GetModuleHandleA("d3d9.dll") + 0x2B6B1。 (2)怪物模型的过滤 最后需要在这个函数头的hook代码中加一个过滤条件:如果当前是在绘制怪物模型,就关闭Z轴深度缓存。怪物模型的过滤可以通过一些当前的参数加以判断,一般情况下通过Stride值(渲染数据流中一个顶点所占的内存的大小)、NumVertices值(绘制图形的顶点的数量)或者primCount值(图元的数量)就可以过滤,其中Stride值可以通过调用GetStreamSource函数得到,而NumVertices和primCount就是之前提到的我们要hook的函数DrawIndexedPrimitive的参数。游戏绘制怪物时这些值具体是多少就必须在游戏中逐步调试获取。具体来说可以下一个消息钩子,先用键盘不断调节Stride 的值,如果怪物有透视,说明当前Stride 值找对,如果此时能保证只有怪物透视,那就说明成功了,如果除了怪物,还有很多其他模型也透视了,那就再继续调节NumVertices 或primCount的值,直到只有怪物透视即可。比如在鬼泣4中最终过滤的关键代码如下: if (g_pDevice->GetStreamSource(0, &pStreamData, &OffsetInBytes, &Stride) == D3D_OK) pStreamData->Release(); if (Stride == 32) { if (NumVertices == 152 || //怪物身体 NumVertices == 212 || //怪物手脚 NumVertices == 298 || //怪物武器 NumVertices == 370) //怪物的头 { g_pDevice->SetRenderState(D3DRS_ZENABLE, false); //关闭深度缓冲 } } 透视效果如下图:
三、结语 用D3D hook实现游戏中的各种模型的透视是一种比较常用游戏透视方法,本例中hook的是d3d9.dll,用Stride 值和NumVertices 值过滤的怪物模型,感兴趣的同学可以尝试用DX10方式启动游戏,hook d3d10.dll,并用Stride 值和primCount值来过滤怪物模型。 |

最新评论
发表评论