关于D3D透视的文章其实早就有位大牛发过了这里我就以我的视角详细讲讲,制作一个D3D辅助的详细过程吧,下面我还会把源码给大家,也算是个万能模板吧,只要是使用D3D9的游戏都可以吧。
工具 VS2010 ,游戏就是360的终极火力,debugview ,VC 6.0里面的工具(spy ,depends),dxsdk_jun10(开发环境),kerneldective。
下面我就说说原理,3d游戏有使用两种渲染的方法,一种是Direct3D,一种是opengl,所以说开opengl就不能用d3d透视了
,那么我今天说得是使用d3d9这个动态链接库的游戏。
既然是透视那么,必然要hook某个函数对其做做过滤,所以我们可以用depends打开c盘下system32文件夹里面的d3d9.ll
,发现并没有我们想要的DrawIndexedPrimitive这个函数,查阅msdn才发现,都被封装在com组件里,以类的方式调用,所
以当我们查看msdn的时候,总是看到IDirect3DDevice9::DrawIndexedPrimitive ,DrawIndexedPrimitive是在
IDirect3DDevice9这个类里面,所以说要找DrawIndexedPrimitive的地址就变得很棘手了,但是我们可以另辟蹊径自己写一
个D3D9的程序然后自己调用DrawIndexedPrimitive,这时候我们调试它就在DrawIndexedPrimitive下个断点,跟踪就找到
DrawIndexedPrimitive的地址了,因为每一次开机
dll都要重定位,但是每个进程加载相同dll时候dll的基地址不变,只有重启才会变化,我们找到DrawIndexedPrimitive的地址
然后减去我们用kerneldective查看到的d3d9.dll的基地址,这样就得到偏移了,我们编程的时候就可以算出
DrawIndexedPrimitive的地址了。
至于HRESULT DrawIndexedPrimitive(
[in] ,D3DPRIMITIVETYPE Type
[in] INT pDevice,
[in] UINT MinIndex,
[in] UINT NumVertices,
[in] UINT StartIndex,
[in] UINT PrimitiveCount
);
有五个参数其中对我们有用的就是NumVertices(渲染的顶点索引的跨度 ,这个和Strides(数据流中每个顶点所占内存的大
小),都是我们区分人物模型的重要来源,Strides可以这样得到 pDevice->GetStreamSource(0, &Stream_Data, &Stride);
一个简单的调用,获得两个参数后接下来再在游戏中通过char temp【512】 sprint(temp,"d
",Stride);OutputDebugStrinA(temp);
来打印,然后打开debugview勾上capture32来接收信息,接下来就可以进行过滤工作了。一般Stirde的值都在100之内而且
也就几个而已,对于这个游戏用Stride判断就可以了,一个个过滤,
我们写个判断语句if(Stride==1){ pDevice->SetRenderState( D3DRS_ZENABLE,FALSE);
else{ pDevice->SetRenderState( D3DRS_ZENABLE,TRUE},SetRenderState的第三个参数为假意思是禁用z轴缓冲。不知道
大家听懂了没,我都是把自己觉得容易的都说出来了。
原理说完了,接下来就是编程解决问题了,这个对于我来说也是个很大的挑战,因为编程我也是不太的菜鸟,其中有些细节
也是困扰了我很久,我会在下面提示需要注意的地方。
首先安装好VS2010 感觉挺不错的加了代码错误提示极大方便了我们,和dxsdk_jun10(开发环境),然后我们在D盘目录
下创建个D3DHook文件夹 打开VS2010 新建
MFC的应用程序类型选择基于对话框,,接着在解决方案中添加win32项目,在应用程序设置中选择dll(名字就叫Hookdll),
勾上导出符号(这是我们注入用的动态链接库),完成,接下去在Hookdll开始写函数了,既然是hook就需要改写进程方法就
是注入,我用的是 HHOOK WINAPI SetWindowsHookEx(
__in int idHook, \钩子类型
__in HOOKPROC lpfn, \回调函数地址
__in HINSTANCE hMod, \实例句柄
__in DWORD dwThreadId); \线程ID
通过钩子注入,其中 第一个参数就是钩子的类型,其中类型好多详情参考msdn,那就是选择WH_CBT ,这是一个notice类型
的钩子,然后第二个参数回调函数,
LRESULT CALLBACK HookProc
(
int nCode,
WPARAM wParam,
LPARAM lParam
);
就是触发钩子后操作系统会调用这个函数,
简单的dll写好后我们试着编译,编译好了就编译另一个注入用的程序,他需要调用动态链接库所以编译前得配置一下包含
文件等等,右键这个对话框程序的项目点属性-》配置属性-》vc 目录,其中添加包含目录D:D3DHookD3DHook
Hookdll,链接器-》输入-》附加依赖项是Hookdll.lib,链接器-》输入-》常规-》附加库目录是D:D3DHookD3DHook
Debug,然后编译。
配置ide环境,为后面使用d3d绘图函数提供所需文件,也是在项目属性里面VC 目录中的包含文件那一项,添加,
E:d3dinclude,库文件中的那项添加,E:d3dlibx86(我的dx sdk 安装在d:d3d目录)。这样ide环境就配置好了。
其他,编程的我都在源码里面注释很清楚了。
代码中 jmp 地址换算问题 ,这里有个公式 ,
JMP的地址(88881234) – 代码地址(010073bb) – 5(字节) = 机器码跳转地址(E9 87879e74)
下面讲一下,调试中的问题和工具的使用:
附件,示例代码拿来编译,在Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,0,5,0,1);插入int3断点,运行,
就会断下来了,这还没显示出汇编,按下调试选项-》窗口-》反汇编
,接着F11跟进call eax,就到了,如何用spy 获取窗口类,search下面那个望远镜,点一下,然后鼠标点击新窗口的那个靶子,按住不放,再移到游戏窗口中就会显示出它的类了,class就是类
,