欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

d3d透视逆向篇:第5课:D3D9游戏黑屏优化2 DrawIndexedPrimitive

程序员文章站 2022-07-02 11:37:51
...

本逆向安全章节是我业余之间编写的,也借鉴了前辈的经验来给大家做一个简单的文字逆向安全教程,欢迎大家讨论和指正,共同学习。禁止非法用途。教程我从最简单的开始给大家做一个简单的讲解d3d 类的3d游戏和fps游戏黑屏、透视等功能。后面有更多的经验分享给大家。

这节课还是用老掉牙的方法,对上节课完善。这节课目的是:
1.你想你实现的一些功能不想给别人看到
2.优化cpu和GPU
3.这个知识后期做透视做准备
技术讨论QQ:2273545181 Q群:550839408

DrawPrimitive渲染  虚函数,不能根据函数名称获取函数地址 HOOK?
DrawIndexedPrimitive渲染
SetRenderState() 渲染状态
BeginScene开始渲染
EndScene结束渲染
Present显示后置缓冲的动画

HRESULT DrawIndexedPrimitive (
D3DPRIMITIVETYPE Type,
INT BaseVertexIndex, UINT MinIndex,
UINT NumVertices, UINT StartIndex,
UINT PrimitiveCounts);

偏移计算=5F097740-5f040000   =  57740     Loadlibrary 
公式: DrawIndexPrimitive函数地址=模块D3D9基地址+偏移

	//HMODULE hm = LoadLibrary("d3d9.dll");  //575F0
	DWORD addr_real_drawPrimitive = (DWORD)hm + 0x575F0;  //挂钩 addr_real_drawPrimitive变量的值就是函数地址
	HookDetours(&(PVOID&)addr_real_drawPrimitive, (PVOID)NewDrawPrimitive, GetCurrentThread()); //挂钩  & 引用意思  & 取地址

	DWORD addr_real_drawIndexedPrimitive = (DWORD)hm + 0x57740;  //挂钩 addr_real_drawIndexedPrimitive变量的值就是函数地址
	HookDetours(&(PVOID&)addr_real_drawIndexedPrimitive, (PVOID)NewDrawIndexedPrimitive, GetCurrentThread());
	MessageBox(NULL, "暂停", NULL);
	UnHookDetours(&(PVOID&)addr_real_drawIndexedPrimitive, (PVOID)NewDrawIndexedPrimitive, GetCurrentThread());//卸载挂钩
	UnHookDetours(&(PVOID&)addr_real_drawPrimitive, (PVOID)NewDrawPrimitive, GetCurrentThread()); //卸载挂钩
汇编分析
5F097740  mov         edi,edi  
5F097742  push        ebp  
5F097743  mov         ebp,esp  
5F097745  push        0FFFFFFFFh  
5F097747  push        5F0B8BB8h  
5F09774C  mov         eax,dword ptr fs:[00000000h]  
5F097752  push        eax  
5F097753  sub         esp,24h  
5F097756  mov         eax,dword ptr ds:[5F191264h]  
5F09775B  xor         eax,ebp  
5F09775D  mov         dword ptr [ebp-14h],eax

DrawIndexedPrimitive参考函数说明资料:

参数1:D3DPRIMITIVETYPE type-图元类型
   使用的图元类型,这个比较好理解,D3D只能绘制三种图元-点、线和三角形,其中线和三角形又细分为线列表(LINELIST)、线条带(LINESTRIP)、三角列表(TRIANGLELIST)、三角条带(TRIANGLESTRIP),根据实际需要选择使用某一种图元,这不会影响最终的绘制效果,但理论上讲,同样多边形数目的物体,使用三角形要比使用线绘制效率高(一个三角形=3条线),而条带比列表要节省顶点数量,同样n个顶点,线列表能绘制n/2条线,线条带能绘制n-1条线,同样,三角列表能绘制n/3个三角形,而三角条带能绘制n-2个三角形,不过经过D3D最优化处理后,绘制条带或列表的性能差别并不大。

 

   参数2:INT BaseVertexIndex-起始顶点索引
   MSDN中的原话是这样:Offset from the start of the vertex buffer to the first vertex. 
   “从顶点缓冲的起始位置到第一个顶点的偏移量”,第一个顶点不就是起始位置么?不一定是,DrawIndexedPrimitive这个函数接受从顶点缓冲的任何一个位置开始读入顶点数据,你可以从index0的位置开始读取顶点数据,那这时BaseVertexIndex就是0,也可以从index2的位置开始读取数据,那这时BaseVertexIndex就是2,如此类推。

 

   参数3:UINT MinVertexIndex-最小顶点索引(这里MSDN应该是个笔误,写成MinIndex了,应该是MinVertexIndex)
   MSDN:Minimum vertex index for vertices used during this call. This is a zero based index relative to BaseVertexIndex. 
   本次函数调用中,顶点缓冲中最小的顶点索引。MSDN解释中我认为最关键的一句是“relative to BaseVertexIndex”-“相对与起始顶点”,即MinVertexIndex实际上也是个相对偏移量,例如,起始顶点是index2,MinVertexIndex是0,那么实际是从index2读入数据,起始顶点是index1,MinVertexIndex是1,那么实际也是从index2读入数据,即实际上的第一个顶点位置在BaseVertexIndex+MinVertexIndex处,最终偏移量=BaseVertexIndex+MinVertexIndex,这里很容易产生误解,就是认为MinVertexIndex是指顶点索引的最小值,即总是0,如果这样那MinVertexIndex这个参数就没有意义了。当初MS如果把这形参声明为OffsetRelativeToBaseVertexIndex应该是更明确一点,不会让人产生误解。
   另一个问题就是,理论上这个偏移量如果是负值也可能是有意义的,例如BaseVertexIndex是1,而MinVertexIndex是-1就是指的顶点缓冲中的第一个顶点,这是有意义的,但实际中如果给MinVertexIndex赋负值我没有试验过。一般情况下MinVertexIndex都是0。
   
   参数4:UINT NumVertices-顶点数量
   MSDN:Number of vertices used during this call. The first vertex is located at index: BaseVertexIndex + MinIndex.
   本次调用所使用的顶点数量。MSDN的解释依然(依旧)模糊,第一个顶点位于BaseVertexIndex + MinIndex这个我已经知道啦,还写这个干什么?这里的顶点数量不是指的顶点缓冲中的顶点总数量,如vb有6个顶点,“The first vertex is located at index: BaseVertexIndex + MinIndex”这句话是要告诉我们,计算顶点数量是要从BaseVertexIndex + MinIndex开始的,例如,我要画一条从顶点index4到顶点index5的线段,那么参数应该是这样的:
   BaseVertexIndex=4

   MinVertexIndex=0
   NumVertices=2
   NumVertices是2而不是6,即NumVertices不是顶点总数,而总是你绘制图元实际需要的顶点数,注意这个“实际需要”,指的是你用到了几个顶点,这取决于索引缓冲的绘制这个图形所使用的不同的顶点个数(可能不太好理解,看下面的例子就明白了)。1条线段需要2个顶点,所以就是2,也许这形参声明为NumVerticesUsedForDrawing更明确一些。

 

   参数5:UINT StartIndex-起始索引
   又是一个Index,如果把这个形参声明为StartIndexOfIndexBuffer,我想就不会头晕了,这个起始索引指的是索引缓冲中的起始索引,也就是指索引缓冲数组的下标(顶点缓冲和索引缓冲都是用数组表示)-ib[StartIndex]。

 

   参数6:UINT PrimitiveCount-图元数量
   这个没什么难度,有一点要注意,对于绘制的几何图形而言,n-2和n/3指的都是索引的数量而不是顶点的数量,也就是说n是索引缓冲中索引的数量。
   

下面就是黑屏优化效果。左边是黑屏,右边是某f测试。(仅仅测试)
d3d透视逆向篇:第5课:D3D9游戏黑屏优化2 DrawIndexedPrimitive
技术测试,禁止非法用途。