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
    • 而在下面出现了这个字符串,搜索发现全局只有一处出现了这个字符串
    • 按照特殊标志搜索的原理
    • 在 客户端源码中搜索这个字符串,全局也只有一处出现了这个字符串,有理由相信这两处地方在同一个函数内