游戏环境:
热血江湖
WIN 7专业版 x64
效果图
原理:
游戏内,角色之所以不能穿过建筑物模型,是因为在游戏代码内,存在对障碍物的检测,如角色行进到某一处,向前的坐标可能是标识为障碍物,当角色被触发前进的操作,会先执行对前方障碍物的判断的函数,当前方是障碍物时,角色不执行前行的操作,而对玩家而言,就是操作角色在障碍物前卡住不前。所以对穿墙的实现,可以将游戏内对障碍物的判断nop 掉或者让它总是返回无障碍状态。
思路:
1、角色可以移动时,会对目的地坐标进行改写和访问
2、角色可以移动时,会对当前坐标进行改写和访问
相关基址:
角色基址:Client.exe+3E80BA0
目的地X 坐标:[[Client.exe+3E80BA0]+2420]
当前X坐标:(float)[[Client.exe+80BFFC] + 30]
·注:以上地址仅作为测试使用,临时分析得出
开始分析:
1、充目的地坐标入手,对该地址进行访问查看
整理得出:
代码段1:
0049BC3B - 56 - push esi
0049BC3C - 8B 75 10 - mov esi,[ebp+10]
0049BC3F - B9 07000000 - mov ecx,00000007 <<
0049BC44 - F3 A5 - repe movsd
0049BC46 - 5E - pop esi
代码段2:
005D8C3B - 8B F3 - mov esi,ebx
005D8C3D - E9 5E010000 - jmp Client.exe+1D8DA0
005D8C42 - D9 06 - fld dword ptr [esi] <<
005D8C44 - 8B 4E 0C - mov ecx,[esi+0C]
005D8C47 - 8B 56 10 - mov edx,[esi+10]
代码段3:
00456DB4 - D9 41 F8 - fld dword ptr [ecx-08]
00456DB7 - 83 C1 1C - add ecx,1C
00456DBA - D9 18 - fstp dword ptr [eax] <<
00456DBC - 83 C0 1C - add eax,1C
00456DBF - D9 41 E0 - fld dword ptr [ecx-20]
代码段4:
0049A7BB - 56 - push esi
0049A7BC - 8B 75 10 - mov esi,[ebp+10]
0049A7BF - B9 07000000 - mov ecx,00000007 <<
0049A7C4 - F3 A5 - repe movsd
0049A7C6 - 5E - pop esi
代码段5:
0054507A - 8D 14 C5 00000000 - lea edx,[eax*8+00000000]
00545081 - 2B D0 - sub edx,eax
00545083 - D9 04 91 - fld dword ptr [ecx+edx*4] <<
00545086 - D8 A5 94FEFFFF - fsub dword ptr [ebp-0000016C]
0054508C - D9 9D A8FEFFFF - fstp dword ptr [ebp-00000158]
代码段6:
005454EF - 2B C8 - sub ecx,eax
005454F1 - 8D 04 8A - lea eax,[edx+ecx*4]
005454F4 - 8B 08 - mov ecx,[eax] <<
005454F6 - 89 8D 64FEFFFF - mov [ebp-0000019C],ecx
005454FC - 8B 50 04 - mov edx,[eax+04]
代码段7:
00530B19 - C2 0C00 - ret 000C
00530B1C - 8B 86 20240000 - mov eax,[esi+00002420]
00530B22 - 8B 08 - mov ecx,[eax] <<
00530B24 - 8B 7D 08 - mov edi,[ebp+08]
00530B27 - 89 0F - mov [edi],ecx
在角色移动这个过程中,之前也大致猜测,流程可能是先进行障碍物的判断,在对角色进行操作,这个流程,处理操作可能有:
执行对障碍物判断的CALL----> 根据结果计算路径----> 将坐标传到FPU(坐标一般为浮点型数据) ----> 将坐标结构地址传递到寄存器(或栈) ----> 操作角色移动并同步服务器数据
所以一般这个过程靠前或许距离目标比较接近,在上面的访问代码中,正好有一段代码是对FPU 传递浮点数据005D8C42 - D9 06 - fld dword ptr [esi] <<
所以,尝试在此处作为入口点
打开xdbg 32,并且附加游戏:
在这里,可能存在一段代码,是对角色前方障碍物的判断,既然有判断,那么应该会有一段判断的指令,如cmp、test 等,判断之前,可能是执行了判断前方是否有障碍物的CALL,所以可能存在如下形式代码:
call 某一处地址
cmp eax, X
jmp 某一处地址
注:这里可以使用x32 dbg 的流程图查看,比较直观的看到在哪些位置存在判断和跳转
向下查看代码,发现一处代码类似上面的结构
$+96 005D8CD8 | E8 83F3FFFF | call | 存在一个CALL 判断,可能是判断前方障碍物
$+9B 005D8CDD | 83F8 02 | cmp eax,2 | 判断eax 是否为2
$+9E 005D8CE0 | 0F84 2B020000 | je client.5D8F11 | eax == 2 跳
$+A4 005D8CE6 | 8B8D 4CFFFFFF | mov ecx,dword ptr ss:[ebp-B4] |
$+AA 005D8CEC | 2B8D 48FFFFFF | sub ecx,dword ptr ss:[ebp-B8] |
$+B0 005D8CF2 | 8BBD 78FFFFFF | mov edi,dword ptr ss:[ebp-88] |
$+B6 005D8CF8 | B8 93244992 | mov eax,92492493 |
在此处进行条件断点(eax != 1) 发现没断下来,估计这里可能只返回1,数值2应该是一个错误数值,在这里进行校正,进入到CALL 内部观察
同样,找一下有没有上面结构的代码段:
005D80DB | 8945 9C | mov dword ptr ss:[ebp-64],eax |
005D80DE | E8 3DDDFFFF | call | 在这里执行了一个CALL, 判断返回值是否为0
005D80E3 | 8BF0 | mov esi,eax |
005D80E5 | 85F6 | test esi,esi |
005D80E7 | 0F84 DD000000 | je client.5D81CA |
005D80ED | D945 08 | fld st(0),dword ptr ss:[ebp+8] |
005D80F0 | 8B7E 14 | mov edi,dword ptr ds:[esi+14] |
005D80F3 | D95D 88 | fstp dword ptr ss:[ebp-78],st(0) |
005D80F6 | D945 10 | fld st(0),dword ptr ss:[ebp+10] |
005D80F9 | D95D 8C | fstp dword ptr ss:[ebp-74],st(0) |
而此处的CALL
对其进行下段
发现当角色前方存在障碍物时,返回值eax != 0,当前方没有障碍物时,返回的值是0,角色前移
所以,找一个CALL 是对障碍物的判断的可能性比较大,进入到
或者也可以做以下修改:
这里推荐使用第一种方式修改,因为该函数在很多地方都进行了调用,修改返回值是比较高效率的改法
但修改后,并不能实现穿墙,但是可以实现坐标在障碍物上点击(之前点击是没有光标的)
修改后,出现光标:
虽然没有实现穿墙,但是找到了障碍物判断的函数,总结:
没实现穿墙的原因大概率是因为除了障碍物的判断函数以外,还有类似功能的代码,对游戏角色行进的位置进行校正。
并且也发现,当游戏角色可以移动时,当前坐标才会发生改变,当遇到障碍物时,这些代码是不会被调用的,所以从这个思路进行切入,查看改变了当前坐标的代码:
代码段1:
0043B09C - D9 50 38 - fst dword ptr [eax+38]
0043B09F - D9 50 34 - fst dword ptr [eax+34]
0043B0A2 - D9 50 30 - fst dword ptr [eax+30] <<
0043B0A5 - D9 50 2C - fst dword ptr [eax+2C]
0043B0A8 - D9 50 24 - fst dword ptr [eax+24]
代码段2:
0043B304 - 8B 45 90 - mov eax,[ebp-70]
0043B307 - B9 10000000 - mov ecx,00000010
0043B30C - 8D B5 30FFFFFF - lea esi,[ebp-000000D0] <<
0043B312 - F3 A5 - repe movsd
0043B314 - 8B BD 70FFFFFF - mov edi,[ebp-00000090]
代码段3:
005486B0 - D9 9F A41C0000 - fstp dword ptr [edi+00001CA4]
005486B6 - 8B BF 24340000 - mov edi,[edi+00003424]
005486BC - 81 C7 50020000 - add edi,00000250 <<
005486C2 - F3 A5 - repe movsd
005486C4 - D9 85 30FEFFFF - fld dword ptr [ebp-000001D0]
代码段4:
0053C0DF - 8B 83 24340000 - mov eax,[ebx+00003424]
0053C0E5 - D9 06 - fld dword ptr [esi]
0053C0E7 - D9 98 80020000 - fstp dword ptr [eax+00000280] <<
0053C0ED - 8B 8B 24340000 - mov ecx,[ebx+00003424]
0053C0F3 - D9 83 681C0000 - fld dword ptr [ebx+00001C68]
上面是对当前坐标进行访问的代码段,其中代码段1和代码段2是在角色移动开始和结束进行修改,代码段3是在角色移动过程中修改当前坐标,而代码段4是在角色移动结束后调用,所以,可以使用前面3个作为分析的切入点:
经过分析,发现代码段1和代码段2在下段点后都会一秒断下,说明在其他地方也在调用,这里我没继续分析下去,而是使用代码段3作为入口点:
同样,此处代码是在游戏角色前方没有障碍物时才会被执行到,所以可以猜测在这段代码前面的部分或者上层应该存在上述代码结构,对障碍进行判断,当没障碍时执行到该部分。使用流程图查看代码执行流程:
$-68 0054864E | E8 2DB70A00 | call |可能是判断障碍物
$-63 00548653 | 8BF0 | mov esi,eax |
$-61 00548655 | 8B47 14 | mov eax,dword ptr ds:[edi+14] |
$-5E 00548658 | 50 | push eax |
$-5D 00548659 | E8 026CECFF | call |
$-58 0054865E | 33D2 | xor edx,edx | edx = 0
$-56 00548660 | 83C4 04 | add esp,4 |
$-53 00548663 | 3BC2 | cmp eax,edx |
$-51 00548665 | 0F84 18160000 | je client.549C83 |
$-4B 0054866B | 3BF2 | cmp esi,edx | esi != 0
$-49 0054866D | 74 7A | je client.5486E9 |
$-47 0054866F | 83FE 03 | cmp esi,3 | esi != 3
$-44 00548672 | 74 75 | je client.5486E9 |
$-42 00548674 | 83FE 02 | cmp esi,2 | esi != 2
$-3F 00548677 | 75 0E | jne client.548687 |
$-3D 00548679 | 8997 E4260000 | mov dword ptr ds:[edi+26E4],edx |
$-37 0054867F | 8D42 01 | lea eax,dword ptr ds:[edx+1] |
$-34 00548682 | E9 A51B0000 | jmp client.54A22C |
$-2F 00548687 | D985 30FEFFFF | fld st(0),dword ptr ss:[ebp-1D0] |
在此处断点,发现在前进时CALL client.sub_5F3D80
返回值总是为1,猜测可能是1标识可以前行,0、2、3标识不能前行或错误数值,所以进入call 内部,修改返回值,让call 始终返回1
005F456D | 5F | pop edi |
005F456E | 5E | pop esi |
005F456F | 5B | pop ebx |
005F4570 | 8B4D F0 | mov ecx,dword ptr ss:[ebp-10] |
005F4573 | 33CD | xor ecx,ebp |
005F4575 | B8 01000000 | mov eax,1 | 修改eax = 1
005F457A | 8BE5 | mov esp,ebp |
005F457C | 5D | pop ebp |
005F457D | C2 1C00 | ret 1C |
005F4580 | 55 | push ebp |
005F4581 | 8BEC | mov ebp,esp |
005F4583 | 6A FF | push FFFFFFFF |
再次点击角色,发现实现穿墙:附上截图:卡在墙内的我
参考:郁金香老师教程
http://www.yjxsoft.com/forum.php?mod=viewthread&tid=3552&highlight=%E7%A9%BF%E5%A2%99
看雪连接:https://bbs.pediy.com/thread-260036.htm