关于Hook函数或偏移的查找以及杂项 - cngege/Mod GitHub Wiki

  • Hook函数 是否显示坐标

    特征码: 48 83 EC ? 48 8B 49 ? 48 8B 01 FF 90 ? ? ? ? 48 85 C0 74 ? 48 8B 88

    函数结构 bool(void*, void*, void*)
    使用方法: Hook函数,强制返回 true 即可强制显示坐标
    特征码查找方法:

    1. 先找到能够控制坐标显示的指针
    2. 搜索字节 0/1
    3. 然后找"谁访问了这个地址",取在非暂停页面持续调用的一项

    ^更新

    特征码: 01 01 FF FF ? EC 7F 92 73 68 6F 77 63 6F 6F 72 64 69 6E 61 74 65 73 00 0F

    • 这个特征码和上面的特征码不一样 (必须执行一次/gamerule showcoordinates false这个特征码才会出现)
    • 上面说找到能够控制坐标显示的指针 指针就在定位特征码之后的偏移4字节处,也就是? 的位置
    • 该位置为 00 时不显示坐标,但查询showcoordinates规则依旧显示true
    • 能够控制坐标显示的指针在重新进入存档的时候会失效,所以这个特征码旨在帮助开发者定位这个指针
  • 饥饿值(暂时作废)

    特征码: 4C 8B D1 44 0F B6 CA 49 BB ? ? ? ? ? ? ? ? 48 B8 ? ? ? ? ? ? ? ? 4C 33 C8 8B C2 4D 0F AF CB C1 E8 08 44 0F B6 C0 8B C2 4D 33 C8 C1 E8 10 4D 8B 42 08 4D 0F AF CB 0F B6 C8 4C 33 C9 8B C2 49 8B 4A 30 4D 0F AF CB 48 C1 E8 18 4C 33 C8 4D 0F AF CB 49 23 C9 48 C1 E1 04 49 03 4A 18 48 8B 41 08 49 3B C0 74 27 48 8B 09 3B 50 10 74 0E 48 3B C1 74 1A 48 8B 40 08 3B 50 10 75 F2 48 85 C0 49 0F 44 C0 49 3B C0 74 05 ? ? ? ? C3 48 8D 05 ? ? ? ? C3

    函数结构: void*(void*, void*)
    使用方法: 返回值 void* +84 为饥饿值

  • 非Hook 非创造模式攻击长度修改

    特征码: 84 C0 74 ? C7 45 ? ? ? ? ? 48 8D 85 ? ? ? ? 48 8D 4D ? 44 0F 2F 25 ? ? ? ? 48 0F 43 C1

    使用方法:

    • 定位后往后找到第二个44 0F 2F 25 [指针位置] (第一个是创造模式的攻击长度修改)
    • 指针位置为指向攻击长度值得指针偏移,从这个指针位置后得那个字节算起
    • 如:44 0F 2F 25 XX XX XX XX 76 则从76所在的这个字节算偏移
      特征码查找方法:
    1. 搜索单浮点 3.00000 ,直至10个以内 挨个修改为7 看看修改哪个攻击长度能加长则定位到关键点
    2. 然后改创造模式,右键找出谁访问了这个指针,再改生存模式,看看新增的访问改指针处就是该特征码位置
    3. 访问记录有很多,那么哪个才是我们需要的。
    4. 很简单, 这么多记录进入反汇编后肯定有一条,在3.0上面有7.0,那么这就是我们需要的
  • 函数 破坏方块时调用的TICK

    特征码: 48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 83 EC 30 48 8B D9 0F 29 74 24 ? 48 8B 49 08

    函数结构: float(void*, void*, int, float)
    使用方法: 第一个参数 + 偏移0x24 设置破坏进度
    特征码查找方法:

    1. 1.19.11 :Minecraft.Windows.exe+17C032A
    2. 先计算出能够瞬间破坏的单浮点地址
    3. 找出谁改写了这个地址
    4. 一般只有两个 找到破坏方块时一直触发的那个
  • 下落无伤害1 (这个函数只能在不高的地方(7格不跳)下落免伤)

    特征码:40 53 56 57 48 83 EC 50 48 8B 05 ? ? ? ? 48 33 C4 48 89 44 24 ? F2 41 0F 10 01
    参数1 void*
    参数2 void*
    参数3 float* 当前需要的指针 在Hook里将他强制设置为0
    参数4 void*
    返回值 void*
    __int64 __fastcall sub_14175BEB0(__int64 a1, float *a2, float *a3, __int64 *a4)
    先搜索空气跳的地址(四字节) :16777473 / 0
    出来后有两个地址
    一个真一个假
    将假的那个地址偏移减去4 (单浮点)锁定0就能下落无伤的地址了
    找出谁写入了这个地址 一般是第一个 movss [rbp
    反汇编后下面两层有个call 这个值刚好在这个call的参数区域

  • 下落无伤害2

    特征码:48 89 5C 24 ? 57 48 83 EC 40 48 8B D9 48 8B FA 48 8B 89 ? ? ? ? 48 8B 01
    __int64 __fastcall sub_141932540(__int64 a1, float *a2)
    先定位下落无伤的地址
    先搜索空气跳的地址(四字节) :16777473 / 0
    出来后有两个地址
    一个真一个假
    将假的那个地址偏移减去4 (单浮点)锁定0就能下落无伤的地址了
    找出谁写入了这个地址 这次搜索的是第三个
    第一个里面找到能用的call Hook后只能在不高的高度(7格不跳)下落免伤
    第二个悬空时 不调用
    第四个只在落地的一瞬间调用一次 可能是将这个值归零的
    第三个反汇编后 可以看到 rbx+1D4 是关键指针
    往下找 第一个call字节太少,不能用特征码定位
    第二个call可以 他第一个参数刚好就是rbx的指针
    将他加上1D4就能转为float指针 写入0,以打到目的

  • HitBox

    特征码:48 8B C4 48 89 58 ? 48 89 68 ? 56 57 41 56 48 83 EC 70 48 8B EA
    __int64 __fastcall sub_1419763A0(__int64 a1, __int64 a2, __int64 a3)
    第二个参数+4D0 就是关键指针
    调用原函数前修改
    搜索关键指针:
    搜索单浮点 0.6,kill后搜索0.2
    将搜到的指针值改为4 ,看看玩家影子有没有变大
    找谁访问了这个指针,一般只有在玩家疾跑的时候才有个
    进去往上找call
    大概是第三个call 这个call的第二个参数刚好含有 rbx(可以加上偏移变成关键指针)
    且经过CE注入测试,在调用原函数前后都可以使用这个rbx加偏移得到关键指针
    Rbx +4D0

  • TICK函数 (无用)

    Minecraft.Windows.exe+F97BA0
    第二行 48 8B 02 mov rax [rdx] Rdx 即为玩家地址, 不过貌似函数参数没有和玩家相关的地址 无法定位特征码

  • 本地玩家Tick函数

    函数 特征码:48 83 EC 28 48 8B 91 ? ? ? ? 45 33 C0 48 8B 81 ? ? ? ? 48 2B C2 48 C1 F8 03 66 44 3B C0 73 ? 48 8B 02
    Minecraft.Windows.exe+1937C10 1.19.11
    double __fastcall sub_141937C10(_QWORD *a1)
    第一个参数即为玩家 还可能只是本地玩家
    找特征码
    先找到本地玩家指针
    然后找谁访问了这个指针
    一般是第二个 较多的那个mov rdx,[rax]
    反汇编后
    可以看到 这里rax就是玩家指针
    往下两个就是call
    而这个call的第一个参数就是 rax,即玩家指针
    疑似:

  • 玩家位置修改

玩家+偏移4B8 1.19.11
一次改 24字节 24字节共两个xyz坐标,分别是玩家在地图上的两个顶点

  • Player can jump

如何找到这个函数指针
首先找到本地玩家指针 和 正确的 16777473这个能使玩家空气跳的指针
找到玩家到这个指针的偏移 1.19.11 的偏移是 +1D8
函数内容大概是

猜测函数的结构是 void(__fastcall)(Player*,int)
1.19.11 Minecraft.Windows.exe+8236B0 7FF6221F36B0

  • 获取玩家位置(可修改的 342 两个坐标点)偏移

48 89 5C 24 ? 57 48 83 EC ? F3 0F 10 02 48 8B D9 F3 0F 58 81
获取玩家位置(可修改的 342 两个坐标点)偏移
public: void __cdecl Actor::moveBBs(class Vec3 const & __ptr64) __ptr64
定位这个函数,
+21 -> int Xoffset X
+X Xpos1 玩家X1位置指针
+X+4 Ypos1 玩家Y1位置指针
+X+8 Zpos1 玩家Z1位置指针

+X+12 Xpos2 玩家X2位置指针
+X+16 Ypos2 玩家Y2位置指针
+X+20 Zpos2 玩家Z2位置指针

两个坐标,第一个坐标的xyz值要小于第二个坐标
x相差:0.5999756
y相差: 1.80000305
z相差: 0.60002518

可以顺便把 HitBox偏移也设置了
就在上面第二个坐标的后面
+X+24 XHitbox 玩家横向碰撞体积的指针
+X+28 YHitBox 玩家纵向碰撞体积的指针

怎么找到这个特征码:
先找到(修改有效的)玩家X坐标地址
找谁修改了这个地址,只有一个
反汇编后就能看到偏移,这个偏移正好正确
这个偏移所在的函数即为这个特征码的地址

void __cdecl Actor::moveBBs(class Vec3 const & __ptr64) __ptr64
特征码:48 89 5C 24 ? 57 48 83 EC ? F3 0F 10 02 48 8B D9 F3 0F 58 81
实体移动消息
获取方法:
找到玩家的坐标,找到谁改写,只有一个,反汇编
按同样的方法进入 BDS反汇编可以知道这条汇编命令所在的call的名称是Actor::moveBBs

  • 找玩家视角偏移

0F B6 D0 48 8B CE E8 ? ? ? ? F2 0F 10 86 ? ? ? ? F2 0F 11 86
找特征码:
首先从玩家地址结构中找到玩家视角
一般是这样两对一起 +15

选择第一个找谁访问了这个地址(这个地址只能读,写入无效)
一般第一个
(计数最多的:Actor::getRotation 很短的call 可惜不能特征码定位 )
可以看到上面有个call 下面有几个movsd, 将第一对中的第一第二个视角
传值给到第二对中的第一第二个视角
我们从上面这个call的传入参数部分开始算特征码
(下面是非最多的那些的第一个)

更新至 1.19.50版本以后 玩家的视角存储在一个结构里,这个结构在Player类中以指针的形式存在
也就是说 玩家视角由两个vec2组成,本该占用 4*2 *2 16字节的内存
由于这里以指针的形式存在于玩家类中 所以只占8字节的内存,这8字节是指向玩家视角结构的指针
比如从玩家指针到指向该视角指针的偏移为X
先找到本地玩家地址
然后看地址结构 展开其中的指针,观察指针指向的地址 其前四个float为玩家视角
找到后 将第一个拉入列表
找访问
访问次数高到低排列
选第二个 反汇编,往上可以看到 偏移X的值 从这一行开始计算特征码,拿到这个X的值

  • 所有玩家Tick

1.19.11 特征码:48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 30 48 8B 01 48 8B F2 0F 29 74 24 ? 48 8B D9 0F 28 F2 (更新后函数变量,参数包含了所有实体)

float *__fastcall sub_14198A400(__int64 a1, float *a2, float a3)
1.19.20.02:Minecraft.Windows.exe+1A13950 7FF6FCC73950
第一个参数A1可能是玩家地址
(找到的另外一个函数 : Minecraft.Windows.exe+8FA180 )函数的第四行(无法定位特征码)
(找到的另外一个函数 : Minecraft.Windows.exe+FE5260 )函数的第二行(无法定位特征码)

怎么找:
用本地玩家地址找谁访问了
有很多 从上往下找
(让房间有两个玩家
反汇编,看 找出指令访问的地址,确保只出两个玩家地址,且进入别人房间这条指令也可以用
那这条指令所在的函数就是要找的call
1.19.11:Minecraft.Windows.exe+198A400


所有中计数最多?约每秒一千条
public: void __cdecl Dimension::forEachPlayer(class std::function<bool __cdecl(class Player & __ptr64)>)const __ptr64

  • AttributeInstance::_calculateValue

[原型] private: float __cdecl AttributeInstance::_calculateValue(void) __ptr64
属性单例 计算值
由饥饿值 找改写,跳跃自然消耗,选只有一个的第一个
(还有其他属性调用这个函数)

  • Player / Mob / Actor 虚表

以及还有 ServerPlayer 虚表
首先按照上面的方法找到 Player::setPlayerGameType 函数位置
然后退出地图到主界面
硬件断点(这里设置5000 可以视情况再少一点)找调用

调用者既是(可以比对BDS的伪源码得知)Player::Player
大概在伪源码 206 行左右找到 Player 虚表赋值
由此找到 Player虚表


在Player虚表赋值的上一行既是 Mob::Mob 构造函数 进入
在函数的开头即可看到虚表赋值 既是Mob的虚表找到


在Mob虚表赋值的上一行 既是Actor::Actor 构造函数
进入 往下 91行左右 大概能找到 Actor的虚表赋值
由此 Actor的虚表找到


ServerPlayer 虚表
进本地存档
找到Player构造函数结尾
断点找调用
找另外一个玩家进这个房间,触发断点
比对BDS伪源码,可以大致确定
调用者就是 ServerPlayer::ServerPlayer 构造函数
在大概 在源码 94 行左右 有ServerPlayer的虚函数地址赋值

  • isKeyDown

非Hook 特征码:4C 8D 05 ? ? ? ? 89 54 24 ? 88 4C 24
获取方法,进行游戏背包页面,仅在Minecraft.Windows.exe 中搜索
字节搜索 长按F搜索1 放开搜索0
最后得到一个值
找修改 则看到一个函数

这里 [r8+rax*4],edx 是关键信息,可以知道rax是是按键键值
R8 则是怎么键值表的开始,关键找到r8的地址
上面lea这条函数,可根据这条函数计算 从下一条也就是 1B6B0E 往后偏移 42F7422 即键值表

  • KeyUpdate

特征码:48 83 EC ? 0F B6 C1 4C 8D 05 ? ? ? ? 89 54 24
获取方法:
和上面 isKeyDown 一样,这个即是上面特征码所在的函数
__int64 __fastcall sub_1401B6B00(__int64 a1, int a2)
A1 is key
A2 is 是否按下 int 1 按下 int 0 松开

由KeyUpdate 找到MouseUpdate 首先定位到KeyUpdate 断点找调用 100个就行,找到调用处,注意它调用处的位置
找到其调用者开头,断点跟踪,看看它的运行轨迹,(这时没有按下按键他也触发了)
看看它是哪里跳过了call keyUpdate的代码,比如在300调用KeyUpdate,但它运行到 250 就jmp到了400,那就看看250处的代码,在后面一行再断点跟踪,这次发现只要鼠标悬浮在游戏窗口就触发了,然后看它是哪里触发了call,这个call就是调用MouseUpdate

  • 发送消息

调用 14059052C
Minecraft.Windows.exe+59052C (1.19.22.01)

函数:
Minecraft.Windows.exe+6D6EF0
原型:__int64 __fastcall sub_1406D6EF0(__int64 a1, __int64 a2)
返回值:u int8 (if ( (unsigned __int8)sub_1406D6EF0(v11, v16) != 1 ))
A2: 聊天输入框内容地址

特征码寻找
E8 ? ? ? ? 3C ? 75 ? 48 8B 8F ? ? ? ? 48 8B 01 4C 89 75
调用处
首先在聊天框输入内容,然后CE搜索字符串,大概只有4、5个值,
找改写 然后改动聊天输入框的值,然后发送, 如果有个值中,只有在发送时调用一次的,则反汇编此处代码
将代码开头ret,会发现,消息发送不出去,用断点找函数运行路径
然后nop函数中调用的函数,看看能不能阻止发送消息

直到nop掉一个call,发送后 输入框清空但没有发送出去
这个call就是目标call,nop的这个位置就是调用处

  • 获取鼠标位置:

首先找到CI单例指针
然后查结构
鼠标在游戏窗口内移动
大概在0x400位置,就能找到存储鼠标xy的指针
找访问或者改写
只有一条
代码很短很简单,但可能由于靠前,所以能用特征码定位
特征码:(1.19.30.04)F3 0F 11 89 ? ? ? ? F3 0F 11 91 ? ? ? ? F3 0F 11 99 ? ? ? ? C3
Minecraft.Windows.exe+21D570

前面458 和 45C 分别是相对CI的偏移,特征码定位后 获取这个偏移

(得获得CI的虚表指针后)
还有一种方法,这个函数定是CI的虚表地址,找到这个目标函数后,断点找调用,调用处为:
call qword ptr [rdx+00000818]
这里的818就是虚表偏移 就是将CI的虚表地址加上818就是目标函数的地址,所以可以从调用处这里获取特征码,来获取这个818,利用虚表和偏移找到目标函数地址

  • 获取窗口大小

首先模糊搜索float大致大小,搜索几次后找结果中的大概在1000左右的数,然后精确搜索一次这个数。
在剩余的结果中找和CI最近的一个指针
选择它
找改写 反汇编
则这个函数就是我们要找的函数:
1.19.30.04:Minecraft.Windows.exe+217220

这里的+218 21C,就是我们的窗口大小指针相对CI的偏移
这点我们可以在CI的结构里确认

同样可以用上面的方法找虚表函数的偏移(找调用)
这个无法特征码定位,只有找到CI的虚表 用虚表定位了
调用处位置:Minecraft.Windows.exe+545490

  • 鼠标调用CALL

原型: void(__thiscall* Mouse)(__int64 a1, char mouseButton, char isDown, __int16 mouseX, __int16 mouseY, __int16 relativeMovementX, __int16 relativeMovementY, char a8);

函数获取 搜索字节 游戏窗口 鼠标按下为1 松开为0,扫描最后大概剩10条,有一条是7FF开头的 选中这条,找查找,按下和松开鼠标均有访问,进入汇编,找这条函数开头,分析特征码,该函数就是我们的目标函数 1.19.30.04:Minecraft.Windows.exe+307E450
特征码: 48 8B C4 48 89 58 ? 48 89 68 ? 48 89 70 ? 57 41 54 41 55 41 56 41 57 48 83 EC ? 44 0F B7 BC 24 (来自:https://github.com/NRGJobro/Minecraft-DX12-Hook/blob/master/Hooks/Hooks.h) 48 8B C4 48 89 58 ? 48 89 68 ? 48 89 70 ? 57 41 54 41 55 41 56 41 57 48 83 EC ? 44 0F