Player.hpp (ServerPlayer LocalPlayer ALL) - cngege/Mod GitHub Wiki

  • LocalPlayer虚表

RemotePlayer::RemotePlayer
首先按上面的方法找到Player::Player
如果玩家虚表定位的特征码可用的话,可直接特征码定位,然后往上找到函数开头

找到Player::Player 函数执行结尾ret
到游戏主界面
断点,(不是断点后跟踪,断点后跟踪会跑到ServerPlayer 构造函数里面去)
进入本地存档
断点触发后 点击运行
第二次触发后 步过 即可找到调用处 即LocalPlayer::LocalPlayer
往上找到这个函数开头
Hook验证后即可发现第一个参数就是本地玩家指针
这个函数即是 LocalPlayer构造函数
可能的特征码:40 55 53 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 4C 89 4D ? 4C 89 45 ? 48 8B DA
第二种方法
找到Player::Player后 断点找调用
然后进入一个没有人的服务器,
断点只会触发一次,那就是LocalPlayer::LocalPlayer触发

按照第二种方法,断点后 进入已经有一个玩家的服务器
第一次触发的是LocalPlayer
点击运行
第二次断点触发后
直接点击调式工具栏的 “走出”
即可进入到调用者函数
即RemotePlayer::RemotePlayer

对照idapro 即可找到虚表赋值
可能的特征码:48 8D 05 ? ? ? ? 48 89 06 48 8D 8E ? ? ? ? 48 8B 86 ? ? ? ? 4C 8B 80 ? ? ? ? 48 8B D6

  • 找本地玩家指针

以前是找16777473,但是1.20新版本好像不好使了,依旧好使的是 坐标

  • 找Y坐标,一直找到锁定后能影响玩家的
  • 看内存,由于附近结构是AABB,所以往前四个字节,加入列表,字节数组 2*(4*3) = 24
  • 找访问
  • 其中有个反汇编函数开头有偏移的,就是- mov rax,[rcx+000002A8] , 断点后找rcx的值就是本地玩家地址
  • Player::teleportTo

null

首先找到玩家坐标Y
然后找访问
然后tp玩家
一般会有两条记录
第一条是Tick不用管
第二个一般很少,只在TP时计数才增加
进入第二条
断点找调用,记录数量设置1000
tp玩家
发现断点成功
最里面一层call是 Actor::_refreshAABB
第二层call是Actor::setPos
第三次call是 Actor::teleportTo
第四层最外面一层call是 Player::teleportTo

  • ServerPlayer::checkFallDamage

public: virtual void __cdecl ServerPlayer::checkFallDamage(float,bool) __ptr64

先获取抗摔落伤害的指针
找改写 一般有三个tick
第一个计数较少,另外两个较多
进第一个反汇编
可以看到触发位置离改函数结尾较近,往上面找这个函数的开头

如果找改写时,尝试跳跃过
可以看到在落地时也会有一条语句触发,进入反汇编
这条语句所在的函数就是
[原型] public: virtual void __cdecl ServerPlayer::normalTick(void) __ptr64


或者找访问,跳一下
可以看到非Tick中有四条记录
但其中一二两条的地址非常接近,三四的地址也非常接近
说明这四条记录其实是两个函数发出来的
这两条函数分别是
ServerPlayer::checkFallDamage
ServerPlayer::normalTick
BDS中地址较小的是前者

  • 设置玩家人称视角 Perspective (第n人称视角)

(其实并不是设置, 此函数的第二个参数的传入值直接影响客户端玩家显示)
void __fastcall sub_141211260(__int64 a1, int a2)

A1 未知
A2 int 0-2
(1.19.30.04:Minecraft.Windows.exe+1211260 )
寻找:
先游戏中的玩家人称视角顺序,依次搜0 、1 、2
只有一个有效结果
找改写
修改视角后 只有一条
反汇编,则该函数即是目标函数,
找改写无法将功能放到程序里面
要找调用

Hook这个调用的TICK函数
我手动的根据需要,去给他返回0-2,以修改玩家视角

  • 空气跳 模块

首先搜索空气跳地址 16777473
AIRJump
然后找查找 大概是第二个Tick记录
特征码:80 BF ? ? ? ? 00 74 ? 80 7B ? ? 74 ? 83 7B

第一个定位不了特征码
从 80 BF开始设计特征码,然后从第三个字节处取出int类型的整数,这就是本地玩家空气跳的偏移
不知道这个偏移是否对Mob有效,当然了对ServerPlayer应该没效,所以设计成函数放在localplayer里面

  • 抗击退函数(NoKB)

KB改为 setVelocity setVelocity是Actor的46号虚表函数,所以不用特征码定位
从中提取Speed vec3 的偏移
1.19.41版本开始 官方将原本的速度信息存在Actor类中改为 将 速度信息放在一个数据块中
然后将这个数据块的指针放在Actor类中
HitBox Pos 亦是同理
从setVelocity中可以得到偏移值X,Actor偏移X后得到一个指针,该指针的值指向的是无法写入的坐标 Px1 ,Py1,Pz1,Px2,Py2,Pz2,Speedx,Speedy,Speedz
所以指针指向的值要往后加24字节才是速度 Vec3

  • (控制健锁定)锁定疾跑 和 行走

在内存中某个指针A处,第一个字节存储着疾跑键是否按下的状态
没有按下:0 按下1 (没有打开背包或暂停页时)
这个指针后间隔两个 00 00 字节处 也就是A+2偏移处
这个字节存储着是否正在前进,锁定为1 则是前进(没有打开背包和暂停页)
如果
没有走路 但按下疾跑键 : 01 00 00 00 : int 1
疾跑前进中并按着疾跑键: 01 00 00 01 int : 16777217
前进但没有疾跑、疾跑中但没有按下疾跑键: 00 00 00 01 : int 16777216
因此 我们要找到这个指针,
那么 在不同的状态搜索 四字节 int类型对应的值即可。 (一定要把“快速扫描”取消勾选才能找到)
Minecraft.Windows.exe+1351490
特征码 1.19.51.01:48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 0F B6 41
Hook这个特征码函数 且获取这个特征码0F B6 41之后的一个字节 (5C)
在Hook中 执行原函数前 将 rcx+5C 的字节值改为1则能锁定疾跑
如何找到这个特征码函数:
首先按照上面的方法找到该关键指针(将类型从4字节改为字节)
找访问,找到关闭背包时持续,打开背包时停止的那个的tick。定位汇编码,
则这个汇编所在的函数就是我们要找的函数
Updata: 更新后 找读取没有那种 关闭背包调用,打开背包不调用的 只能退而求其次 找打不打开背包均调用的

  • 找到 疾跑控制的地址后,往前大概八个字节,就是控制下蹲的 使用字节添加到列表
  • 找访问
  • 取打不打开背包均访问的汇编语句
  • 进入汇编 可以看到 如movups xmm0,[r15+20]
  • 这里的r15 就是函数的第四个参数, +20就是16进制的偏移
  • 我们Hook这个函数,对了 函数的原型是:
  • __int64 __fastcall sub_141C45E20(__int64** a1,_DWORD* a2,__int64* a3,__int64 a4,__int64 a5,__int64 a6,__int64 a7,__int64 a8,__int64 a9,__int64 a10,__int64 a11)
  • hook后在调用原函数前 将a4 + 0x20 的指针传入 模块

在 1.20.71+版本 符合 “取打不打开背包均访问的汇编语句” 只有一个函数
该函数代码原型为:

Minecraft.Windows.exe+803A20 - movzx eax,byte ptr [rdx]
Minecraft.Windows.exe+803A23 - mov [rcx],al
Minecraft.Windows.exe+803A25 - movzx eax,byte ptr [rdx+01]
Minecraft.Windows.exe+803A29 - mov [rcx+01],al
Minecraft.Windows.exe+803A2C - movzx eax,byte ptr [rdx+02]
Minecraft.Windows.exe+803A30 - mov [rcx+02],al
Minecraft.Windows.exe+803A33 - movzx eax,byte ptr [rdx+03]
Minecraft.Windows.exe+803A37 - mov [rcx+03],al
Minecraft.Windows.exe+803A3A - movzx eax,byte ptr [rdx+04]
Minecraft.Windows.exe+803A3E - mov [rcx+04],al
Minecraft.Windows.exe+803A41 - movzx eax,byte ptr [rdx+05]
Minecraft.Windows.exe+803A45 - mov [rcx+05],al
Minecraft.Windows.exe+803A48 - movzx eax,byte ptr [rdx+06]
Minecraft.Windows.exe+803A4C - mov [rcx+06],al
Minecraft.Windows.exe+803A4F - movzx eax,byte ptr [rdx+07]
Minecraft.Windows.exe+803A53 - mov [rcx+07],al
Minecraft.Windows.exe+803A56 - movzx eax,byte ptr [rdx+08]
Minecraft.Windows.exe+803A5A - mov [rcx+08],al
Minecraft.Windows.exe+803A5D - movzx eax,byte ptr [rdx+09]
Minecraft.Windows.exe+803A61 - mov [rcx+09],al
Minecraft.Windows.exe+803A64 - movzx eax,byte ptr [rdx+0A]
...

反汇编函数结构:__int64 __fastcall sub_140803A20(__int64 a1, __int64 a2) return a1
特征码:(1.20.71)0F B6 ? 88 ? 0F B6 42 01 88 41 01 0F 第二个参数即是关键结构

  • Player::getSupplies((Player *)this);

用Player类获取 PlayerInventory 类
同样调用处在 ServerPlayer::normalTick(void) 函数中
调用 Actor::getRegionConst 的下面一点 大概139行代码处

对比后发现 又被优化了
v26 = *(_QWORD *)(a1 + 3512); 就等于 Supplies = Player::getSupplies((Player *)this);
我们就是要获取这个 3512
找到的特征码 :48 8B 96 ? ? ? ? 44 38 B2 该特征码可以找到我们目标偏移 但不是ServerPlayer::normalTick函数中

  • END