Skip to content
12 changes: 11 additions & 1 deletion .vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,18 @@ export default defineConfig({
text: 'Rendering',
collapsed: true,
items: [
{ text: 'Overview', link: '/rendering/overview' }
{ text: 'Overview', link: '/rendering/overview' },
{ text: 'Getting Started with DirectX', link: '/rendering/getting-started-with-directx' }
]
},
{
text: 'Reverse Engineering',
collapsed: true,
items: [
{text: 'Introduction', link:'/reverse-engineering/introduction'},
{text: 'Using IDA', link: '/reverse-engineering/using-ida'}
]

}
],
socialLinks: [
Expand Down
209 changes: 209 additions & 0 deletions wiki/rendering/getting-started-with-directx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# Getting Started with DirectX
In this guide, you will create hooks for various DirectX functions and create a suitable environment for rendering.

## Background
Unlike most games, Minecraft attempts to use the latest version of DirectX supported by your system, instead of sticking
to one version. This **must** be taken into account when hooking DirectX functions to provide the widest level of
support for your mod. Specifics on each backend and their in-game render capabilities are covered
[here](/rendering/overview#backends).

## Requirements
To facilitate hooking DirectX functions, we will be using an updated fork of [kiero](https://github.com/BasedInc/kiero).
kiero handles the boilerplate that is required to get the runtime implementations of DirectX's interfaces, and provides
a type-safe API for looking up functions and creating hooks.

If you have a CMake project using CPM ([setup](/beginners-guide/your-first-hook#cpm)), adding kiero is as follows:

```cmake
CPMAddPackage(
URI "gh:BasedInc/kiero#269860311ac04b0ee89e68f68bca55abd02a3390" # Dec 2, 2025
OPTIONS
"KIERO_INCLUDE_D3D11 ON"
"KIERO_INCLUDE_D3D12 ON"
)
```

::: info
While the [BasedInc](https://github.com/BasedInc) fork of kiero supports many new quality-of-life features that this
article leverages, it is still under active-development. The commit hash in the previous snippet reflects the version
this article is based on, and usage in future versions may be subject to change.
:::

In addition to kiero, you will need a hooking library. kiero offers an opt-in hooking API that can be integrated with
either `MinHook` or `SafetyHook`, but it must be configured with additional options for your specific setup.
Currently, 3 targets are provided:

| Hook Library | CMake Target | `kiero::getMethod` | `kiero::bind` |
|--------------|---------------------------|--------------------|---------------|
| N/A | `kiero::kiero` | ✔️ | ✖️ |
| MinHook | `kiero::kiero-minhook` | ✔️ | ✔️ |
| SafetyHook | `kiero::kiero-safetyhook` | ✔️ | ✔️ |

For example, using kiero if `MinHook` is already included in an existing project:

```cmake
CPMAddPackage(
URI # <...>
OPTIONS
# <...>
"KIERO_BUILD_MINHOOK ON" // [!code ++]
"KIERO_MINHOOK_EXTERNAL ON" # If you already have MinHook included // [!code ++]
)
```

```cmake
# Using Kiero with kiero::bind supported by MinHook
target_link_libraries(<project_name_here> PRIVATE
kiero::kiero-minhook)
```


## `IDXGISwapChain::Present`
As of Direct3D 10, [`IDXGISwapChain::Present`](https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-present) is called by a program to display the resulting frame to the user,
after all draw calls are submitted. Since Minecraft on Windows only supports Direct3D 11 and Direct3D 12 as
rendering backends, this is the only function needed to submit draw calls before a frame is displayed.

### Creating the hook
This is the full function prototype for `IDXGISwapChain::Present`:

```cpp
HRESULT IDXGISwapChain::Present(UINT SyncInterval, UINT Flags);
```

We **must** match the ABI of this member-function prototype when creating a callback for this function hook. This
requirement is enforced at compile time by `kiero::bind`:

```cpp
#include <dxgi.h>

using presentFunc = HRESULT(*)(IDXGISwapChain*, UINT, UINT);
static presentFunc oPresent{};
```

Next, create your function callback, making sure to match the function prototype above:

```cpp
static HRESULT hk_Present(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags) {
// You can interface with DirectX here.

// When you're done, call the original function to return
// control to the game and display the resulting frame.
return oPresent(_this, SyncInterval, Flags);
}
```

Finally, we can initialize kiero and create the hook:

```cpp
#include <kiero.hpp>

void createHooks() {
if (kiero::init(kiero::RenderType::Auto) != kiero::Status::Success) {
// Kiero failed to initialize, handle failure case.
return;
}

// Kiero provides IDXGISwapChain for both D3D11 and D3D12.
// We can use it to hook Present, regardless of the renderer:
auto status = kiero::bind<&IDXGISwapChain::Present>(&oPresent, &hk_Present);
assert(status == kiero::Status::Success);

// If you are using kiero without kiero::bind support, the function's
// addressed can be fetched and passed to your own hook function.
auto pPresent = kiero::getMethod<&IDXGISwapChain::Present>();
my_hook_function(pPresent, &oPresent, &hk_Present);
}
```

::: info
Specifics on how to draw content using DirectX is out of scope for this wiki. You can refer to other sources and
tutorials on how to use DirectX. For a renderer-independent approach, it's worth considering a third-party library to do
the heavy lifting. A commonly used one is [Dear ImGui](https://github.com/ocornut/imgui), which provides an interface
for drawing text and geometry across many rendering backends.
:::

Although `kiero::init` has resolved a renderer, it may not actually match the active renderer in use by Minecraft. This
can happen if a fallback to Direct3D 11 occurs, even when the system supports Direct3D 12. We can query for which type
of D3D device is in use via `IDXGISwapChain::GetDevice` in our `Present` hook:

```cpp
#include <d3d11.h>
#include <d3d12.h>
#include <dxgi.h>
#include <Windows.h>

// Required for winrt::com_ptr, which is effectively a smart-pointer type
// for COM (and subsequently DirectX) objects. winrt::com_ptr uses RAII
// to manage the reference count of the underlying object, so we can avoid
// manual calls to AddRef() and Release().
#include <winrt/base.h>

static winrt::com_ptr<ID3D11Device> d3d11Device;
static winrt::com_ptr<ID3D12Device> d3d12Device;

static HRESULT hk_Present(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags) {
if (SUCCEEDED(_this->GetDevice(IID_PPV_ARGS(d3d12device.put())))) {
// If this call succeeds, DirectX 12 is being used.
// Do your DirectX 12-specific initialization work here.
} else if (SUCCEEDED(_this->GetDevice(IID_PPV_ARGS(d3d11device.put())))) {
// If this call succeeds, DirectX 11 is being used.
// Do your DirectX 11-specific initialization work here.
} else {
// No device could be retrieved.
}

return oPresent(_this, SyncInterval, Flags);
}
```

::: info
You can read more about `winrt::com_ptr` on [Microsoft Learn](https://learn.microsoft.com/en-us/uwp/cpp-ref-for-winrt/com-ptr).
:::

## `IDXGISwapChain::ResizeBuffers`
If you've held any references to the game's back buffer(s) in your `Present` callback, your game will crash when attempting
to resize the window. This is because the game is calling [`IDXGISwapChain::ResizeBuffers`](https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-resizebuffers), which requires
all references to the swap chain's back buffers to be released before it is called (see [Remarks](https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-resizebuffers#remarks)).

```cpp
HRESULT IDXGISwapChain::ResizeBuffers(
UINT BufferCount,
UINT Width,
UINT Height,
DXGI_FORMAT NewFormat,
UINT SwapChainFlags
);
```

This issue can be resolved with another function hook:
```cpp
using resizeBuffersFunc = HRESULT(*)(IDXGISwapChain*,
UINT, UINT, UINT, DXGI_FORMAT, UINT);
static resizeBuffersFunc oResizeBuffers{};

// Possible outstanding reference
static winrt::com_ptr<ID3D11RenderTargetView> backBufferRTV;

static HRESULT hk_ResizeBuffers(
IDXGISwapChain* _this, UINT BufferCount, UINT Width,
UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags
) {
// Release reference(s)
backBufferRTV = nullptr;

// Finish resizing
return oResizeBuffers(_this, BufferCount, Width,
Height, NewFormat, SwapChainFlags);
}

void createHooks() {
// ...
kiero::bind<&IDXGISwapChain::ResizeBuffers>(
&oResizeBuffers, &hk_ResizeBuffers);
}
```

::: info
As of Minecraft 1.21.120 (the initial GDK release), the [`IDXGISwapChain3::ResizeBuffers1`](https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_4/nf-dxgi1_4-idxgiswapchain3-resizebuffers1)
extension is called instead of `ResizeBuffers`. The prototype and bind target must be updated accordingly.
:::
5 changes: 4 additions & 1 deletion wiki/rendering/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ On the Windows build of the game, Mojang includes 3 different rendering backends
|------------------|--------|-------|-----------------|-------------|
| DirectX 11 | ✔️ | ✔️ | ✖️ | ✖️ |
| DirectX 12 | ✔️ | ✔️ | ✔️ | ✖️ |
| DirectX 12 (RTX) | ✔️ | ✔️ | ✔️ | ✔️ |
| DirectX 12 (RTX) | ✔️ | ✔️ | ✔️ | ✔️ |

## Other Rendering Abstractions
On top of the base RenderDragon rendering system, Minecraft: Bedrock Edition also implements other rendering abstractions. These can include specialized entity renderers, UI rendering contexts, and tesselators. Depending on your use case, these can be more beneficial than submitting raw DirectX calls to the game. We will attempt to document as many of these as possible in the wiki.
53 changes: 53 additions & 0 deletions wiki/reverse-engineering/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Introduction
Reverse engineering, in the context of software engineering, is the process of deconstructing a program to understand
its architecture, functionality, and original design.

Reverse engineering is a very broad topic that is predominantly made up of logical thinking,
however, there are many techniques and shortcuts that can be used when reversing Minecraft, with two core methods
that summarize the topic:
- Static Analysis
- Dynamic Analysis

Both of these methods will be covered and used within this section to define data structures and classes
or find functions and analyze their behavior.

It is subjective which method you prefer to use, and neither is better than the other, though they both have their use
cases. This topic will aim to describe both static and dynamic analysis as thoroughly as possible, including
scenarios where one method is more suitable.

> [!NOTE]
> Reverse engineering is sometimes shortened to *reversing*, or just *R.E.*

## Static Analysis
Static analysis is the process of reverse engineering a program's code **without** executing it.

We can statically analyze Minecraft: Bedrock Edition by using a *disassembler* to convert its compiled machine code back
into human-readable assembly, and inspecting the code.

> [!NOTE]
> As MCBE is compiled from C++ directly into machine code that runs natively on the system, it is impossible to
> decompile its code back to source code.

There are many disassemblers that provide an environment for static analysis. We recommend
[IDA Pro](https://hex-rays.com/ida-pro) for its robust feature set, wide use in the Bedrock native modding
community, and use within this wiki.

> [!NOTE]
> It is not guaranteed that the [IDA Freeware](https://hex-rays.com/ida-free) distribution will provide every feature used in this wiki.
> We strongly suggest that you use IDA Pro.

Keep in mind, static analysis is **not** just analyzing a disassembly. There are many other resources and tools that can be
used to reverse engineer Minecraft: Bedrock Edition statically, some of which will be covered.

## Dynamic Analysis
Dynamic analysis is the process of examining a program's behavior **while it is executing**.

There are many tools that can be used to perform dynamic analysis, for example:
- [ReClass.NET](https://github.com/ReClassNET/ReClass.NET): A tool mainly used to map data structures in memory
- [Cheat Engine](https://www.cheatengine.org/): A program featuring a robust set of dynamic analysis tools,
namely, a memory scanner and debugger

Again, it is subjective what tools you use. Every tool has its own use case; feel free to use one tool or a variety of
programs you see fit.


71 changes: 71 additions & 0 deletions wiki/reverse-engineering/using-ida.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Using IDA

> [!TIP]
> For a more in depth write-up of the basic usage of IDA, we recommend you read the official Hex-Rays article on this
> topic, this can be found [here](https://docs.hex-rays.com/getting-started/basic-usage).

[Hex-Rays IDA](https://hex-rays.com/ida-pro) is a powerful disassembler and reverse engineering environment, used by many in the Bedrock Native
Modding community for static analysis. This article will cover how to set up your IDA environment for
MCBE.

> [!NOTE]
> This wiki assumes you are on [IDA Pro 9.2](https://docs.hex-rays.com/release-notes/9_2), the latest as of writing.
> It is not guaranteed that certain features or plugins used in this wiki support other versions of IDA.
> [IDA Free](https://hex-rays.com/ida-free) is a viable alternative that supports disassembly and decompilation of
> x86/x64 binaries.

## Running IDA
When you run IDA, an **IDA Quickstart** window will open.

In this dialog, there are four areas of interest:
- **New** - This will ask you to select a file for loading.
- **Go** - This will bring you to the main IDA view, in a dormant state.
- **Previous** - This will load the previously loaded file.
- **Recent files box** - This will display your recently opened files for quick access.

Here, you can just press **Go**.

## Loading Minecraft into IDA

[FloppyDolphin57](https://github.com/FloppyDolphin57) kindly provides pre-analyzed Minecraft binaries for most Minecraft Bedrock versions in the form of
packed IDA databases (i64 or idb files). These databases can be downloaded
[here](https://www.mediafire.com/folder/ammda8wfvbw9x/The_Flopper_Databases).

Most versions include a Windows Client, Windows Server, and Linux Server database. Server versions prior to 1.21.2
shipped with debug symbols, and are useful for cross-referencing code against even the latest client versions.

Once you have downloaded and extracted the client version of your choice, you can simply **drag and drop the i64 file
into your IDA window** to load it.

If you are using a newer version of IDA than the database was created with, IDA will prompt you to upgrade to the latest
supported format. This is a mandatory step and may take a while, but it only has to be done once. Once the upgrade is
complete, it's recommended to immediately save the database to avoid having to do so again, should the database be
improperly saved.

Alternatively, you can manually analyze Minecraft by dragging and dropping the `Minecraft.Windows.exe` file from your
Minecraft install into IDA. If you are analyzing a GDK version, the executable must be
[extracted](/topics/gdk#extracting-the-executable-file) first. This process **will** take multiple hours.

> [!NOTE]
> IDA may seem to freeze when loading a database or during general use. Don't worry, as IDA is likely working in the background.

At this point, Minecraft should be loaded into IDA. You can now start reversing.

> [!TIP]
> The database file will be available within the quickstart menu after opening it, along with other recently opened files.
> You can now double-click its entry to load the database.


## Plugins
IDA supports [plugins](https://docs.hex-rays.com/user-guide/plugins) to extend its capability. In the context of reverse engineering, this can be used to
automate many tasks which are otherwise tedious and/or monotonous.

A plugin can either come as an IDAPython script or a native binary, and may be installed by copying their respective
file (`.py` or `.dll`) into the `plugins` subdirectory in IDA's installation directory.

> [!WARNING]
> IDA plugins can contain malware. Only install plugins from sources you trust.

For efficiently creating [signatures](/beginners-guide/introduction#what-s-a-signature), it's recommended to use a
plugin such as [A200K's SigMaker plugin](https://github.com/A200K/IDA-Pro-SigMaker) (Usage provided in the repository's
README).
Loading