NVDIA PerfHUD是NVDIA公司开发的免费产品,已经被世界上无数的游戏开发人员用来分析DX程序的性能。它的原理是在系统中安装上一块虚拟的显卡设备,一个DX程序在调用CreateDevice时,只要使用这块指定的显卡,就可以使用这款工具进行性能分析。相对于DXSDK中提供的PIX,PerfHUD有很明显的优势,它工作在驱动层,速度快,而且可以实时进行调试,显示正使用的shader程序,纹理,模型等数据。
尽管用PerfHUD分析自己的程序非常方便,但PerfHUD并不被允许用来分析其他商业程序,显而易见,这是由于版权的限制,因为大部分商业程序的许可协议都不允许用户对其进行反汇编分析。
这个限制其实很容易被“破解”掉,主要思路如下:
1. 利用Detours库的withdll功能启动PerfHUD进程,将一个动态库注入到该进程中,该动态库首先使用apihook功能勾住CreateProcess函数,这样当PerfHUD创建子进程时,可以同样将这个动态库注入子进程中
detours库是微软研究院开发的进程工具库,其中的apihook,PE导入表修改等功能使用起来都非常方便,但在Hook CreateProcess这个函数时需要注意一点,因为DetourCreateProcessWithDll需要调用CreateProcess函数,需要避免调用关系进入死循环。
2. 进入DX程序后,勾住d3d9.dll中的“Direct3DCreate9”函数,当用户程序调用该函数返回时,获得返回值,也就是IDirect3D9指针
由于PerfHUD同样先使用了Detours库修改了Direct3DCreate9的入口函数,就无法在使用同样的方法了进行APIHOOK了,我使用的方法是,修改该函数入口处的jmp指令指向的地址,指向我的函数onDirect3DCreate9,在该函数中修改栈内存的顶端数据,这是由于__stdcall函数被调用时,栈内存的顶端是函数执行完的返回地址,这样当Direct3DCreate9执行完毕后,会首先进入我的函数onDirect3DCreate9Ret
3. 在onDirect3DCreate9Ret函数中,eax指向IDirect3D9指针,我们知道,COM对象中的第一个DWORD指向的就是虚函数表,而CreateDevice函数是其中的第17个函数(这个可以通过查询d3d9.h得到),修改函数表,将第17个函数指向的我的onCreateDevice函数
在onDirect3DCreate9Ret这个函数中,比较难处理的是,执行完毕后如何跳回原程序的返回地址,即上一步骤中,栈内存顶端指向的地址。由于只能通过jmp返回,而又不能破坏寄存器中的内容,所以我使用了直接32字节长jmp指令返回原程序,即0xE9指令,而jmp指令中的地址是在onDirect3DCreate9函数中通过WriteProcessMemory函数写入的
4.在onCreateDevice函数中,修改栈内存中的参数,将将Adapter和DeviceType修改成指向PerfHUD虚拟显卡即可。
程序源代码下载: PerfHUDAny.rar(114KB)
下面是利用该工具分析WOW时的画面:
![](http://www.thecodeway.com/blog/wp-content/uploads/2009/05/wow_perf.jpg)
PS:
在分析一些程序的时候发现一些兼容性问题
1. 使用DXUT框架的程序,在创建正式设备前,会反复调用很多次CreateDevice函数然后释放,而在PerfHUD环境中,释放device的时间很长(具体什么原因不清楚),所以这类程序运行后会有很长时间没有相应。
2. 如果程序调用了Direct3DCreate9前曾经还调用Direct3DCreate9并且没有释放,那么PerfHUD会失败
Update:2009-05-20
1. 大部分游戏的主程序都无法直接启动,必须通过各自的“patch”程序启动,针对这个问题我更新了一下,只要在主界面选择patch程序,并且选中“Hook Child Process”选项,就可以切进游戏主进程中
2. 有些游戏和PerfHUD的兼容性并不好,虽然能切进去,但不稳定,很容易就失去响应
3. 有一些游戏为了反外挂,会使用一些底层技术保护游戏进程不被注入陌生动态库,这时PerfHUDAny会失效,一些杀毒软件也会这么做,比如瑞星的账号保险箱,需要注意
附上使用方法:
1. 运行PerfHUDAny.exe
![](http://www.thecodeway.com/blog/wp-content/uploads/2009/05/perfhudany.gif)
2.选择需要调试的程序或者快捷方式,如果该程序无法直接运行,比如某些游戏必须通过Patcher才能运行,可以选择这些patcher程序并且把”Hook Child Process”选中
3.选择NvdiaPerfHUD的主程序,一般情况下,这是自动完成的
4.点击运行按钮,开始调试进程。如果选中了”Hook Child Process”选项,在子进程创建时,PerfHUDAny会弹出对话框询问是否开始调试这些进程,如果你确认这就是需要调试的主进程,点击”Yes”按钮即可
程序源代码下载(2009-05-20): PerfHUDAny.rar(88.3KB)