Actor.hpp - cngege/Mod GitHub Wiki
-
Actor::setSize
public: virtual void __cdecl Actor::setSize(float,float) __ptr64
- 虚表函数 : 240
- 功能 : 设置实体大小
- 获取方法:
- 先找到实体的大小 活
0.6
死亡0.2
- 找改写,游泳的时候会有修改
- 反汇编
- 这条汇编语句所在的call就是。
- 先找到实体的大小 活
-
Actor::setPos
public: virtual void __cdecl Actor::setPos(class Vec3 const & __ptr64) __ptr64
- 获取方法:
- 先找到玩家Y坐标
- 然后找改写
- 丢末影珍珠
- 传送后有条语句变动,反汇编 即找到了 Actor::_refreshAABB
- 接着断点 找调用
- 即是
Actor::setPos
- 获取方法:
-
Actor::_move
public: static void __cdecl Actor::_move(struct IActorMovementProxy & __ptr64,class Vec3 const & __ptr64)
获取方法:
- 先找到玩家坐标Y
- 然后找访问 丢珍珠
- 一般共有三条记录,第一个调用很多的tick,不用
- 第二个只有一个,可能和珍珠有关
- 第三个就是要找到,有两个记录
- 反汇编,这时候的call是Actor::setAABB
- 断点找调用,正常他会马上触发
- 找到进入后发现往上找很长才到函数头的时候就是要找的
Actor::_move
-
Actor::getHealth
auto getHealth()->float
获取方法:
- 首先在Player虚表中找到 respawn(重生) 这个方法
- 因为这个方法里面有调用 本函数
- 通过对比 服务端的i64 文件 和 win10端的i64文件
- 找到 getHealth 方法的调用处,发现它并非是直接调用getHealth这个函数
- 从服务器版可以知道 getHealth 这个函数内容做了三件事调用了三个函数
__int64 __fastcall Actor::getHealth(Actor *this)
{
AttributeInstance *v1; // rax
float CurrentValue; // xmm0_4
v1 = (AttributeInstance *)(*(__int64 (__fastcall **)(Actor *, void *))(*(_QWORD *)this + 1656i64))(
this,
&SharedAttributes::HEALTH);
CurrentValue = AttributeInstance::getCurrentValue(v1);
return mce::Math::ceil(CurrentValue);
}
- 书接上回
- 第一个被优化了,看不到函数名,不过猜测是获取和血量有关的 实体能力单例
- 第二步从这个单例里面获取值
- 第三步,将这个值向上取整
- ,win10端直接将这个函数的内容插入到了 重生方法中
- 于是从这个call调用处 取特征码
1.19.22.01:
FF 90 ? ? ? ? F3 0F 10 88 ? ? ? ? F3 0F 2C C9 66 0F 6E C1 0F 5B C0 8D 41 ? 0F 2F C1
- +2 则是(ServerPlayer)虚表函数的个数,经过断点找this,发现是ServerPlayer的虚表函数
- +10 的这个int值则是上面 AttributeInstance::getCurrentValue(v1); 这个函数的实现方法
- 所以获取到了这两个值则自己实现 getHealth()方法
- 新版本看这里:
- 1.20.30.02版本发现有变了
- 在Player::respawn,函数里面的获取血量方法变成了 XXX((INT64)this + 8);
- 很明显 这里的函数就是 ActorCollision::getHealth, 因为this+8就是ActorCollision
- 所以只要用特征码定位到这个函数就可以了
- 而且,在Player::respawn里面有很多处调用这个方法,(三处)
- 这样获取三个特征码相互补充
-
Actor::isPlayer实现方法
🙌info
只有Actor 和 Player类有这个方法
Actor定义 返回false
Player重写覆盖返回true
所有从Player继承的类 调用这个方法都返回类
Mob继承Actor 所以返回false
🍳获取方法:- 分别分析出 Actor和Player的 虚表文件
- 分别搜索Actor::isPlayer 和 Player::isPlayer
- 1.19.30.04:
- Player::isPlayer 0x00085770
- Actor::isPlayer 0x00087520
- 选择一个虚表文件
- 比如Actor
- 从上往下 搜索 0x00087520,(如果选择的是Player虚表文件,则搜索0x00085770)
- 比如找到的是第19号虚表函数,然后看看另一个虚表文件的相同序号的虚表函数的地址
- 是否是另一个isPlayer的地址,比如0x00085770,那表示这个编号的虚表函数就是isPlayer
- 对应的虚表函数
- 如果不是,则接着往下找
- 正常该函数应该在69号虚函数左右
-
找Actor::isSneking 方法
🍳获取方法:
-
首先找到 GameMode::useItemOn 函数
-
GameMode 虚表的第 12 个函数
-
这个函数位置 可以用vs断点或者插件打印出来
-
1.19.30.04:Minecraft.Windows.exe+18B4170 (Actor::isSneking调用位置18B488C)
-
后面版本的 Actor::isSneaking 在 GameMode::useItemOn 中被优化掉了
-
但是实现方法很简单 调用了 Actor 的第一个虚函数 bool __cdecl Actor::getStatusFlag(enum ActorFlags)
-
传入的 actorFlags 为1
-
BDS GameMode::useItemOn() 伪代码中 目标函数大概位置
-
Win10版 IDA 伪源码
-
对比后可以找到这个函数位置
-
找到这个调用位置,从这里找特征码
-
-
Actor::getRotation
🍳获取方法:
- 直接找虚表找不到
- 首先找到BDS ida中的这个函数,内部很简单
(同时记下它的汇编代码) - 可以直接 它获取的vec2_t 变量就在Actor指针偏移 312 字节处
- 在同版本win10上,我们用本地玩家指针
- 加上上述偏移(注意进制转换 312是十进制,在CE中偏移要16进制)
- 可以得到相连的两组 vec2_t 指针
- 取第一个数,找访问
- 然后找调用最多的那个,就是目标函数(如果不确定可以对比函数的汇编代码)
- 找到这个函数后断点找调用
- 可以看到:call qword ptr [rax+00000288]
- 大胆猜测 rax就是Actor,其实看上一条就可以确定 rax就是准备调用函数的this
- 288指的是 虚表偏移,转10进制 除以8后就是 81 ,也就是说,
- Actor::getRotation 是Actor的第81个虚表函数
-
Actor::isRemoved()
53 48 83 EC ? 80 BA ? ? ? ? 0 48 8B D9 75 ? 48 8B
🍳获取方法:
- 内部 this + 偏移
- 这个函数内部过于简单 ,无法找到后用特征码定位,只能找它的调用者
- 通过它的调用者确定这个函数的位置,
- 如果调用者处被优化 也可也获取它的这个偏移,来手动实现这个函数
- 所幸 在服务端IDA中可以看到 调用者还是有很多的
- 比如:Mob::attackAnimation
- 选一个在虚表中能找到的函数,对比调用处代码,
- 就能获取目标函数 或目标函数中的偏移
-
Actor::getRotationEx
🍳获取方法:
- 这个函数本来在虚表中的,现在被去除了
- 它的返回值是一个vec2* 指针
- 该指针存储在Actor类中的偏移后的某处
- 当前的实现方法是 获取这个偏移,然后手动实现这个函数
- 在服务器IDA可以知道 它的诸多调用者,我们选取了
ServerPlayer::respawn
- 这个函数存在于虚表中,可以定位到
- 找到这个函数后 发现它调用 Actor::getRotation的地方被优化内联了
- 这个函数的其实位置开始 偏移9个字节就是 那个我们需要的关键偏移了
- 所以我们把获取这个偏移的代码放在 定位ServerPlayer虚表处
-
Actor::getRegionConst 用Actor类获取BlockSource 类
🖼️关于&实现方法:
- 这是原版函数但是不在虚表中 获取的是BlockSource*
- 我们通过ida了解 ServerPlayer::normalTick(void) 函数中调用了这个函数,当我们对比两个程序的ida的时候发现 win10版的 ServerPlayer::normalTick(void) 调用 Actor::getRegionConst 函数处被优化了,我们只能在调用处获取到了 Actor 到 BlockSource 的偏移
- Actor::getRegionConst 函数原理是 BlockSource* 在Actor类的某个偏移处
- 我们实现这个函数 我们要寻找到这个偏移
- 在 +xxx偏移处tab 查看汇编 我们在 ServerPlayer::normalTick(void) 调用处的汇编语句那里设计特征码,然后拿到偏移
- 以实现 Actor::getRegionConstEx 函数
-
Actor::getOrCreateUniqueID
🍳非虚表函数,怎么找
- 搜索:" Player: %s has the following standing: %d \n"
- 全局只有一处出现,出现这个字符串的地方上面有 Actor::getOrCreateUniqueID的调用
- 为什么要搜索这个字符串
- 用BDS的源码,搜索Actor::getOrCreateUniqueID,会发现有一处,在开头调用了Actor::getOrCreateUniqueID
- 而在下面出现了这个字符串,搜索发现全局只有一处出现了这个字符串
- 按照特殊标志搜索的原理
- 在 客户端源码中搜索这个字符串,全局也只有一处出现了这个字符串,有理由相信这两处地方在同一个函数内