您尚未登录,立即登录享受更好的浏览体验!

您需要 登录 才可以下载或查看,没有帐号?注册(register)

x

MC基岩版官方开服器Windows版插件开发教程

2019年5月22日 作者:Player

前言:

MC基岩版官方开服器(BDS)自发布至今,已经有数月时间。其间有各种魔改的开服端以及各种功能的插件出现,但是截止目前,由于MC官方发布BDS在Linux版与Windows版之间存在一些固有的差异,导致插件开发者制作的插件无法跨平台使用,也无法跨平台编译。本文将提供一种开发出能够在Windows版开服器上使用的插件的途径。当前,BDS正处于早期测试版,本教程附带的工具能够利用测试版附带的相关信息实现插件功能。

概述:

本文中的插件是指可执行文件的动态链接库文件。开发者使用开发工具将所写的源代码编译成插件(DLL文件)。然后使用专用的启动器在开服器程序的运行时期将插件导入开服器进程之中,导入后的开服器进程在功能上因插件加载而得到扩展,得到原本没有的功能。插件的使用将允许开服器的功能有一个质的飞跃。

作为插件开发者,开发过程从零开始的流程如下:

1、下载官方BDS压缩包与插件开发工具包,并解压

2、使用工具包中“PDB导出工具”,找到解压后的BDS目录,选择bedrock_server.pdb文件,导出对应的PDB信息文件

3、用Visual Studio 2019打开工具包中的插件开发工程“MCMODDLL”。然后打开其列表中的symbol.txt,按照文件要求添加你需要修改功能的符号名称

4、再利用“PDB导出工具”,选择步骤2导出的PDB信息文件和步骤3中的symbol.txt文件,导出对应的C++头文件(默认SymHook.h)替换掉插件工程中原先的SymHook.h文件

5、打开SymHook.h文件,复制所需要的符号对应的由工具自动生成的C++变量名,再打开插件工程中的mod.cpp文件,利用这个变量名,在内部写上你要对这个符号对应的函数做出的修改部分的代码

6、确认代码无误后,编译生成DLL文件

7、在BDS目录下新建一个目录,叫MOD_DLL,然后将步骤6生成的DLL文件放入这个目录

8、启动工具包中的“MC BDS简易启动器”,勾选“加载插件”复选框(默认为勾选状态),点击“启动服务器”

至此,服务器在加载插件的情况下顺利启动,大功告成!

插件案例:爆炸箭

在Minecraft基岩版中,箭原本是不具有爆炸属性的,但是通过插件,我们可以实现这一独特的功能。

image.png (288.76 KB, 下载次数: 2)

2019-5-24 18:48 上传

之前MCMrARM写过一个关于爆炸箭的教程,目标是Linux平台,该教程由于年头久远,又缺乏维护,已经无法按步骤实现。但是可以作为看本案例之前的参考。

从这篇文章中,我们获取了一点重要的信息:

1、当箭中目标时候,会触发ProjectileComponent::onHit类方法

2、产生一次爆炸是用Level::explode类方法

另外,通过分析,我们发现其他的类方法诸如HitResult::getPos在当前版本都已经不复存在了,所以上述说MCMrARM的教程当前已经无法按步骤实现。

接下来,我们将一步步自己实现爆炸箭功能:

(一)利用IDA Pro逆向分析主程序bedrock_server.exe文件

在IDA Pro开始分析的时候会问你是否加载pdb调试信息,选择确定。

图片2.png (142.97 KB, 下载次数: 2)

2019-5-24 18:50 上传

左侧是从调试信息中分析出的各种函数名称,右侧为内容。

(一)确定需要研究的内容

上面提到了两个十分重要的类方法:

ProjectileComponent::onHit和Level::explode

前者在箭击中时候触发的,后者制造一个爆炸效果。基本思路是,让前者触发的时候调用后者制造一个爆炸。这样“爆炸箭”功能就实现了。那么让我们看一下从IDA Pro中获取的原型:

void __fastcall ProjectileComponent::onHit

(ProjectileComponent *__hidden this, const struct HitResult *)

void __fastcall Level::explode

(Level *this, struct BlockSource *, struct Actor *, const struct Vec3 *, float, bool, bool, float, bool)

乍一看,似乎前者给的参数不够调用后者,这该如何是好呢?

现在我们来收集整理一下我们手上现有的信息:

这个onHit 方法提供了两个指针,ProjectileComponent(抛射物)指针和HitResult(击中结果)指针。而explode需要四个结构体指针:

1、Level* 存档指针,MC基岩版使用Level表示存档,用于存档的kv数据库叫LevelDB;

2、BlockSource* 不知道是什么结构的指针,不过看上去十分重要;

3、Actor* 似乎是玩家/生物结构的指针;

4、Vec3* 嗯,就是坐标结构的指针,没跑了。

至于后续的float和bool,因为我们可以直接提供,所以先不管。

(二)分析Level::explode和ProjectileComponent::onHit参数指向的结构体

上面我们看到,仅仅使用onHit提供的参数不做任何处理是不能够完成对explode直接调用的。那么我们不妨先找一下其他的函数对Level::explode调用让我们学习参考一下。

首先找到 Level::explode:

图片3.png (6.5 KB, 下载次数: 3)

2019-5-24 18:55 上传

然后打开,在右侧的反汇编内容里选择函数符号,右键,点击Jump to xref to operand(跳转到该函数的调用位置列表):

图片4.png (45.32 KB, 下载次数: 4)

2019-5-24 18:56 上传

图片5.png (29.95 KB, 下载次数: 5)

2019-5-24 18:56 上传

可能你也发现了,中间的那个BedBlock::use显得格格不入,而且十分亮眼!没错,这就是玩家在地狱放置床的时候发生的爆炸。那么我们现在就进去看看这葫芦里卖的是啥药呢。为了方便查看,这里我们使用F5插件进行反编译:

图片6.png (49.84 KB, 下载次数: 3)

2019-5-24 18:57 上传

哦?这里Actor*居然是不必要的,这算是潜在可能会减少一点我们分析的工作量。接着我们继续追查其他三个指针的来源:

首先分析Level*:

图片7.png (2.99 KB, 下载次数: 5)

2019-5-24 18:59 上传

图片8.png (2.06 KB, 下载次数: 2)

2019-5-24 18:59 上传

图片9.png (1.12 KB, 下载次数: 4)

2019-5-24 18:59 上传

是从Player结构体里出来的,我们继续追查,打开Player::Player类构造函数,发现:

图片10.png (2.43 KB, 下载次数: 1)

2019-5-24 19:00 上传

再进入Mob::Mob:

图片11.png (3.69 KB, 下载次数: 1)

2019-5-24 19:00 上传

再进入Actor::Actor:

图片12.png (1.71 KB, 下载次数: 1)

2019-5-24 19:02 上传

图片13.png (4.93 KB, 下载次数: 3)

2019-5-24 19:02 上传

于是,我们发现Player类是由Mod类派生而来,而Mod类又是由Actor类派生出来,而且Level*指针最终归在了Actor结构体内416*sizeof(QWORD*)的位置。

然后分析BlockSource*:

图片14.png (4.88 KB, 下载次数: 0)

2019-5-24 19:04 上传

图片15.png (3 KB, 下载次数: 7)

2019-5-24 19:05 上传

从上文分析得知,这个a2是Player*的,v5是取Player内部414*sizeof(QWORD*)的位置,那么这个位置也同样是Actor类的内部。

接下来就是分析Vec3了:

图片16.png (6.64 KB, 下载次数: 5)

2019-5-24 19:07 上传

图片17.png (3.74 KB, 下载次数: 3)

2019-5-24 19:07 上传

图片18.png (5.36 KB, 下载次数: 3)

2019-5-24 19:07 上传

图片19.png (4.21 KB, 下载次数: 3)

2019-5-24 19:07 上传

图片20.png (4.28 KB, 下载次数: 5)

2019-5-24 19:07 上传

在一系列复杂的操作之前,v56和v57最终来自于BlockPos结构,这是BedBlock::use的第三个参数:

图片21.png (2.41 KB, 下载次数: 5)

2019-5-24 19:09 上传

图片22.png (1.32 KB, 下载次数: 4)

2019-5-24 19:09 上传

显然这里BlockPos储存的是放置的床的坐标,而放置床的操作显然不会跟打击动作扯上关系,更不应该跟HitResult有关系。这里我们选择放弃继续追查这里的坐标来源。

根据MCMrARM的教程,HitResult储存了坐标信息,我们转而去分析HitResult内部的结构。试试看有没有可能取得突破。

由于HitResult没有任何类成员函数,除了一个operator=,给我们的分析带来了麻烦,此时只能选择动态分析内部结构。找到ProjectileComponent::onHit,在它的第一条指令上下断点:

图片23.png (9.28 KB, 下载次数: 4)

2019-5-24 19:10 上传

然后我们利用IDA Pro附加windbg(x64)调试器启动开服器进行调试分析。打开MC基岩版客户端(我用的win10版)进入游戏,这里为了构建一个足够识别Vec3的环境,我们进入创造模式,在控制台输入:

图片24.png (41.17 KB, 下载次数: 3)

2019-5-24 19:11 上传

然后朝这个基岩射箭:

file_1558696312000.jpg (161.61 KB, 下载次数: 3)

2019-5-24 19:11 上传

回到IDA Pro调试界面,我们发现IDA Pro已经截获到了这个断点,HitResult是onHit方法的第二个参数,根据微软的x64程序调用约定(fastcall),第二个参数保存位置是RDX寄存器,然后我们跟踪RDX指向的内存区域:

图片26.png (12.83 KB, 下载次数: 4)

2019-5-24 19:13 上传

并选择float类型查看该区域:

图片27.png (22.61 KB, 下载次数: 2)

2019-5-24 19:14 上传

怎么样?跟刚才输入的/setblock后的坐标是不是大致相同?那么,现在我们确定HitResult内部在一开始的位置就包含Vec3坐标,而且顺序是X,Y,Z。那么这四个结构的来源我们都搞定了,explode中剩下的5个参数就照搬床爆炸的参数吧:“5.0, true, true, 3.4, false”。

最后,我们需要找到ProjectileComponent*与Actor*的关系,找到ProjectileComponent::ProjectileComponent,发现其中正好有一个函数附带Actor*的参数:

图片28.png (43.04 KB, 下载次数: 1)

2019-5-24 19:15 上传

Actor*被保存在结构体内2*sizeof(QWORD*)的位置。

至此,爆炸箭功能研究分析部分就完成了,下面我们将要开始着手实现这一切。

(一)下载BDS开服器和工具包,并解压:

本案例中使用的是1.11.2.1版本BDS。

图片29.png (37.83 KB, 下载次数: 3)

2019-5-24 19:17 上传

图片30.png (33.29 KB, 下载次数: 4)

2019-5-24 19:17 上传

(二)解压缩MOD插件工程包,用VS2019打开,复制我们需要的符号到Symbol.txt中,并使用“PDB导出工具”将必要符号导出到工程SymHook.h文件:

图片31.png (61.93 KB, 下载次数: 4)

2019-5-24 19:19 上传

图中的符号分别是ProjectileComponent::onHit与Level::explode方法的,点击保存,先使用PDB工具生成PDB信息文件,再使用PDB工具生成SymHook.h覆盖掉原文件:

图片32.png (26.71 KB, 下载次数: 4)

2019-5-24 19:20 上传

打开SymHook.h,发现符号对应的变量已成功生成:

图片33.png (33.4 KB, 下载次数: 1)

2019-5-24 19:20 上传

(三)打开mod.cpp,编写插件代码,注意,这里的Hook宏的使用方式与MCMrARM那篇教程大致相同,有不同点但在mod.cpp内说明了。

图片34.png (45.35 KB, 下载次数: 0)

2019-5-24 19:22 上传

(四)编译出插件DLL,将它放在开服器目录MOD_DLL目录下,使用工具包中的“BDS简易启动器”启动服务器:

图片35.png (6.98 KB, 下载次数: 1)

2019-5-24 19:23 上传

图片36.png (4.33 KB, 下载次数: 3)

2019-5-24 19:23 上传

(五)测试爆炸箭

file_1558697076000.jpg (202.56 KB, 下载次数: 3)

2019-5-24 19:24 上传

最后,实验成功!

注意事项:

1、当你在使用IDA Pro附加windbg(x64)调试的时候一定要先设置好windbg(x64)所在的位置,windbg可以通过Windows SDK安装包来安装,通过设置PATH变量或者更改IDA Pro目录下的/cfg/ida.cfg文件来让IDA Pro找到windbg(x64)。另外,当你发现设置没有问题但是无法启动调试的时候,请注意被调试的程序所在的文件路径,为稳妥考虑,路径中最好不要出现特殊字符或者中文,这些内容可能导致无法调试。我没有去测试到底是不是中文字符的问题。

2、MOD工程中的“T”开头的宏的使用方法参考MCMrARM的教程,如果你写过Linux上的BDS插件,那么你可能对它十分熟悉。另外,SYM_CALL宏是我自己写的,上面已经用注释说明了使用方法。

3、针对不同版本的开服器,插件互相是无法通用的,开服器使用不合适版本的插件将会导致严重错误,这也是为什么我将插件目录设置在开服器目录下而不是启动器目录下的原因。让插件适应当前版本的办法是用“PDB导出工具”将新版的符号重新生成出SymHook.h文件,然后再次编译插件。

4、如果你发现工具中存在的Bug,请反馈给我!在工具中的“关于”按钮内有我的网上联系方式。

我的世界手机有PHP的开服器下载,【BDS】MC基岩版官方开服器Windows版插件开发包...相关推荐

  1. 救砖用三星i9300官方4.1.2固件刷机包下载港版和国行版 手机天堂-软件世界 | 手机天堂-软件世界...

    说明:这些固件包是官方的4.1.2版本的固件线刷包,都是五件套系列,如果有需要五件套系列的可以下载下来备用了,包内有详细的刷机教程和root教程,下载下来解压出来,然后采用odin工具刷入即可. 一: ...

  2. 微信windows版_微信多开教程:Win、Mac、iOS、Android

    微信双开一般来说问题不大,但仍需节制 覆盖全平台:Windows.Mac.iOS.Android 微信,这个App,已经成为了不可或缺的存在:而越来越多的朋友拥有不止一个微信号.为了适应这个趋势,越来 ...

  3. w我的世界pe开服器php7,我的世界手机自主开启PE服务器教程

    我的世界手机自主开启PE服务器教程.这次为大家带来的是教大家使用游戏狗联机盒子,手机自主开启PE服务器教程.不过这种方法比较麻烦,需要下 载对应版本的整合包还要添加对应开服核心.并且有时就算版本对应, ...

  4. 我的世界手机有php的开服器下载地址,我的世界手机版怎么联机 PE手机版开服教程...

    很多在玩我的世界的手机版的朋友们还在苦苦寻找关于手机版开服的问题,我的世界PE手机版怎么联机和小伙伴们一起玩耍呢.别急,下面游戏园小编就来给大家介绍下我的世界手机版中联机教程,希望能对大家有所帮助. ...

  5. 我的世界电脑正版怎么开服务器,我的世界手机版开服器怎么用 开服务器方法...

    我的世界手机版游戏中,开服是能够让我们和小伙伴们一起玩游戏的好方法,那么开夫妻怎么用呢?下面就请看小编为大家带来的攻略吧! 大家都知道,因为8.0目前的pocketmine处在测试版的状态中.同时由於 ...

  6. 迷你世界怎么显示服务器未连接,迷你世界手机版怎么开服务器 | 手游网游页游攻略大全...

    发布时间:2016-08-25 我的世界手机版服务器怎么创建,Minecraft PE服务器怎么开,这些都是大家比较关注的话题,很多玩家在寻求大型的服务器,但是没有服务器的ip也是枉然,还不如自己创建 ...

  7. 我的世界手机有PHP的开服器下载,《我的世界手机版》怎么用电脑开服,pocketminePC版使用教程...

    原标题:<我的世界手机版>怎么用电脑开服,pocketminePC版使用教程 我的世界手机版玩家使用电脑应该如何开服呢?这个时候只需要安装一个电脑版的pocketmine软件就可以了,下面 ...

  8. 我的世界手机版开服务器领地系统,我的世界手机版领地指令大全 领地指令怎么用...

    我的世界手机版这款游戏中,领地是一个非常棒的设定,可以在游戏中设定自己的规则,那么领地有些什么指令呢?下面就请看小编为大家带来的攻略吧! 我的世界手机版领地指令大全 领地指令怎么用 领地其实就是一个立 ...

  9. 网易我的世界手游服务器怎么发全体信息,网易我的世界手机怎么私聊 | 手游网游页游攻略大全...

    发布时间:2015-09-27 我的世界手机版那些你不知道的小知识.的世界是一个简单而又复杂的沙盒游戏,里面的一些知识技巧都可以进一步延伸,今天99单机网小编就给大家带来我的世界手机版那些你不知道的小 ...

最新文章

  1. 我,AI专家,模型检测COVID-19准确率高达97.5%,约吗
  2. NoneBot2插件——进群欢迎
  3. 【ASP.NET 进阶】验证码的实现
  4. 零售商的“基因改造”浪潮
  5. 基于ARM9的视频采集传输系统
  6. python的浮点数_python – range()用于浮点数
  7. Linux电源管理(1)_整体架构
  8. linux 儒略日时间计算,C/C++ 儒略日计算以及恒星时计算
  9. npm install --legacy-peer-deps
  10. unity 实验演示 教程_Unity的演示团队– Unity最出色的视觉效果背后的创造者
  11. 阿里云安全恶意程序检测冠军经验分享(万字长文)
  12. 程序架构之redis扩容 (增加端口)
  13. python打招呼的代码_GitHub - worry45678/LearnPython: 以撸代码的形式学习Python
  14. PAT 乙级 1020  月饼
  15. 青柠开车Spring Cloud(三) —— Spring cloud Eureka
  16. Mac升级go版本(指定或最新)
  17. vue使用vue-video-player播放视频及遇到的问题
  18. 【信息学奥赛一本通】2075:【21CSPJ普及组】插入排序(sort)
  19. c语言中的where用法,c#查询关键字where 子句的运用
  20. 通俗理解极大似然估计

热门文章

  1. 到底多少够用 11款USB设备供电大揭秘
  2. 《计算机科学》投稿心得
  3. 第九届“图灵杯”NEUQ-ACM程序设计竞赛个人赛 nn与游戏
  4. scanf函数中输入格式及输入基本原理讲解
  5. android实时视频方案,Android中实时视频监控方案设计思路
  6. 企业家故事|香港最后一位少爷,走了(下)
  7. 获取微信用户信息java开发_Java微信公众平台开发(十二)--微信用户信息的获取
  8. android 图片缩放,github开源库,PhotoView 使用
  9. matlab经典实例,BP神经网络matlab实例(简单而经典)
  10. 记一次赛题--保护全开