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
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
现在只完成了第一步,所有的东西都显现出来了,看起来有些眼花,怎么样才能只显示人物模型呢?
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
需要进入游戏后再执行