cs 透视初步尝试

受hellotong兄的Direct3D透视教程的启发,
 http://bbs.pediy.com/showthread.php?t=126933
自己也想弄弄,平常偶尔打打CS,于是拿它开刀了
先看了下网上资料,发现D3D游戏和普通windows程序结构没什么两样
包括创建窗口和消息处理循环,只不过处理WM_PAINT消息时用到d3d的渲染函数
先用OD载入cstrike.exe ,为了方便调试,设置为窗口化运行,视频模式选择为D3D
一开始查找DrawIndexedPrimitive,SetRenderState,发现并没有直接调用的地方,于是想它们要用到lpdevice参数,那就从Direct3DCreate,Direct3DCreateDvice着手吧,可是加载cstrike.exe后直接bp Direct3DCreate不行,程序一开始并没有加载D3D的DLL文件, 是在进入游戏时才加载的,于是在进入游戏前,在OD选项里--“调试设置”--“事件”--中断于新模块,呵呵,中断了两次,按F9,第三次终于发现了我们的d3dim.dll文件,bp Direct3DCreate可以用了,不过跟了一下没什么收获,查看d3dim.dll模块,结果也让人失望,
在d3dim.dll里搜索所有参考字串,结果发现了不少好东西,真是柳暗花明又一村啊
6DCA9D32   PUSH D3DIM.6DCA1B88                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\vertbuf.cpp(722):"
6DCA9D3B   PUSH D3DIM.6DCA1B5C                       ASCII "Direct3DVertexBuffer::ProcessVertices"
6DCA9EE7   PUSH D3DIM.6DCA1BF8                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\vertbuf.cpp(813):"
6DCA9EEC   PUSH D3DIM.6DCA1BCC                       ASCII "IDirect3DDevice3::DrawIndexedPrimitiveVB" 
6DCAA0B9   PUSH D3DIM.6DCA1C60                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\vertbuf.cpp(988):"
6DCAA0BE   PUSH D3DIM.6DCA1C3C                       ASCII "Direct3DDevice3::DrawPrimitiveVB"
................
6DCAD137   PUSH D3DIM.6DCA2138                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\texman.cpp(255):"
6DCAD13C   PUSH D3DIM.6DCA2114                       ASCII "TextureCacheManager::allocNode"
6DCB1741   PUSH D3DIM.6DCA23E0                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\devstate.cpp(159):"
6DCB1746   MOV EBX,D3DIM.6DCA23BC             ASCII "Direct3DDevice::SetRenderState" 
6DCB1773   PUSH D3DIM.6DCA2378                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\devstate.cpp(202):"
6DCB18F4   PUSH D3DIM.6DCA2448                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\devstate.cpp(317):"
6DCB18F9   PUSH D3DIM.6DCA2424                       ASCII "Direct3DDevice::GetRenderState"
6DCB199E   PUSH D3DIM.6DCA24B8                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\devstate.cpp(356):"
6DCB19A3   PUSH D3DIM.6DCA249C                       ASCII "Direct3DDevice::GetTexture"
6DCB1A3F   PUSH D3DIM.6DCA2528                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\devstate.cpp(398):"
6DCB1A44   PUSH D3DIM.6DCA250C                       ASCII "Direct3DDevice::SetTexture" 
6DCB1B11   PUSH D3DIM.6DCA2598                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\devstate.cpp(502):"
6DCB1B16   PUSH D3DIM.6DCA256C                       ASCII "Direct3DDevice::GetTextureStageState"
6DCB1C9B   PUSH D3DIM.6DCA2620                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\devstate.cpp(664):"
6DCB1CA0   PUSH D3DIM.6DCA25FC                       ASCII "Direct3DDevice::SetLightState"
6DCB1D03   PUSH D3DIM.6DCA2688                       ASCII "d:\xpclient\multimedia\directx\dxg\d3d\dx6\d3dim\devstate.cpp(686):"
6DCB1D08   PUSH D3DIM.6DCA2664                       ASCII "Direct3DDevice::GetLightState"
.......


经过分别在上面函数名称下断,发现在游戏里不停调用的只有如下几个函数
IDirect3DDevice3::DrawIndexedPrimitiveVB、SetRenderState、SetTexture、SetTransform、GetTransform、MultiplyTransform、CDirect3DDeviceIDP2::FlushStates
经过反复观察这几个函数中断的顺序和名称含义,个人猜测DrawIndexedPrimitiveVB是最终实施绘画的函数,而SetRenderState、SetTexture用来在绘画前设置物件的渲染状态和纹理贴图,只在SetRenderState下断(6DCB1746),通过堆栈回溯,发现返回地址为cstrike.xxxxxxxx,中断几次观察返回地址的代码均为如下结构

代码:
01D57B62  56                PUSH ESI   (或push edi)
01D57B63  6A 1B             PUSH 1B                                    ;这里是D3DRENDERSTATETYPE,
01D57B65  50                PUSH EAX
01D57B66  8B10              MOV EDX,DWORD PTR DS:[EAX]
01D57B68  8935 BCA42F02     MOV DWORD PTR DS:[22FA4BC],ESI
01D57B6E  FF52 58           CALL DWORD PTR DS:[EDX+58]            ;这里就是SetRenderState函数
01D57B71  5F                POP EDI
01D57B72  5E                POP ESI
01D57B73  83C4 2C           ADD ESP,2C
01D57B76  C2 0400           RETN 4
其中D3DRENDERSTATETYPE有很多,查找MSDN如下
typedef enum _D3DRENDERSTATETYPE {
    D3DRS_ZENABLE                   =   7,
    D3DRS_FILLMODE                  =   8,
    D3DRS_SHADEMODE                 =   9,
  。。。。。。。。。。
    D3DRS_TWEENFACTOR               = 170,
    D3DRS_BLENDOP                   = 171,
    D3DRS_FORCE_DWORD               = 0x7fffffff
} D3DRENDERSTATETYPE;

显然我们感兴趣的只有7,ctrl+s搜索命令序列 push 7 push eax,最后符合的代码有两处如下
代码:
01D57A10  56                PUSH ESI
01D57A11  6A 07             PUSH 7
01D57A13  50                PUSH EAX
01D57A14  8B10              MOV EDX,DWORD PTR DS:[EAX]
01D57A16  8935 6CA42F02     MOV DWORD PTR DS:[22FA46C],ESI
01D57A1C  FF52 58           CALL DWORD PTR DS:[EDX+58]
01D57A1F  5F                POP EDI
01D57A20  5E                POP ESI
01D57A21  83C4 2C           ADD ESP,2C
01D57A24  C2 0400           RETN 4
代码:
01D57EAA  57                PUSH EDI
01D57EAB  6A 07             PUSH 7
01D57EAD  50                PUSH EAX
01D57EAE  8B08              MOV ECX,DWORD PTR DS:[EAX]
01D57EB0  893D 6CA42F02     MOV DWORD PTR DS:[22FA46C],EDI
01D57EB6  FF51 58           CALL DWORD PTR DS:[ECX+58]
01D57EB9  5F                POP EDI
01D57EBA  5E                POP ESI
01D57EBB  83C4 2C           ADD ESP,2C
01D57EBE  C2 0400           RETN 4
 
将上面代码更改为
代码:
01D57A10  E9 AB252C02       JMP cstrike.04019FC0
01D57A15  90                NOP
01D57A16  8935 6CA42F02     MOV DWORD PTR DS:[22FA46C],ESI
01D57A1C  FF52 58           CALL DWORD PTR DS:[EDX+58]
。。。。。
01D57EAA  E9 1D212C02       JMP cstrike.04019FCC
01D57EAF  90                NOP
01D57EB0  893D 6CA42F02     MOV DWORD PTR DS:[22FA46C],EDI
01D57EB6  FF51 58           CALL DWORD PTR DS:[ECX+58]
。。。。。。
04019FC0  6A 00             PUSH 0
04019FC2  6A 07             PUSH 7
04019FC4  50                PUSH EAX
04019FC5  8B10              MOV EDX,DWORD PTR DS:[EAX]
04019FC7  E9 4ADAD3FD       JMP cstrike.01D57A16
04019FCC  6A 00             PUSH 0
04019FCE  6A 07             PUSH 7
04019FD0  50                PUSH EAX
04019FD1  8B08              MOV ECX,DWORD PTR DS:[EAX]
04019FD3  E9 D8DED3FD       JMP cstrike.01D57EB0
哈哈,现在看看效果吧,是不是都看见了,另外在更改尝试后,发现第一个地方更改没用,第二个地方才有用,可调用时明明都调用了,而且两者是交替调用,不明白。。。。
good luck!

刚刚调试才发现 第一个是用来禁用Z轴缓冲(ESI=0),第二个是恢复(EDI=1),难怪改第一个没用

晚上又看了下,发现弄得太复杂了,在第二段代码往上翻一翻,就能发现如下代码
代码:
01D57E27  A1 6CA42F02       MOV EAX,DWORD PTR DS:[22FA46C]
01D57E2C  BF 01000000       MOV EDI,1             ;EDI=1就是在这里赋值的
01D57E31  3BC7              CMP EAX,EDI
01D57E33  0F84 EF020000     JE cstrike.01D58128
EDI就是在上面被赋值的,并且将是否启用Z缓冲的状态保存在[22FA46C],这样就好办了,不用另外添加跳转代码,直接将上面的MOV EDI,1 改为mov edi,0即可

现在只完成了第一步,所有的东西都显现出来了,看起来有些眼花,怎么样才能只显示人物模型呢?

2011-1-25
 先尝试不用OD改,写了个小程序实现,代码很简单
.data
   ClassName db "Half-Life",0
   AppName  db "Counter-Strike",0
   address  dword 01d57e2dh     ;更改的地址
   buffer db 0          ;开透视为0,关透视为1
.data?
     pid    dword ?
     hwin dword ?
     hinst  dword ?
  .code
start:  invoke FindWindow,addr ClassName,addr AppName
        mov hwin,eax
        invoke GetWindowThreadProcessId,eax,addr pid
        invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,pid
        mov hinst,eax
        invoke WriteProcessMemory,eax,address,addr buffer,1,0
        invoke CloseHandle,hwin
        invoke CloseHandle,hinst
        invoke ExitProcess,0
end start

需要进入游戏后再执行
上传的附件 toushi.rar