diff --git a/.vitepress/config.mts b/.vitepress/config.mts index 16c939c..cbe09b4 100644 --- a/.vitepress/config.mts +++ b/.vitepress/config.mts @@ -42,18 +42,8 @@ export default defineConfig({ text: 'Rendering', collapsed: true, items: [ - { text: 'Overview', link: '/rendering/overview' }, - { text: 'Getting Started with DirectX', link: '/rendering/getting-started-with-directx' } + { text: 'Overview', link: '/rendering/overview' } ] - }, - { - text: 'Reverse Engineering', - collapsed: true, - items: [ - {text: 'Introduction', link:'/reverse-engineering/introduction'}, - {text: 'Using IDA', link: '/reverse-engineering/using-ida'} - ] - } ], socialLinks: [ diff --git a/wiki/rendering/getting-started-with-directx.md b/wiki/rendering/getting-started-with-directx.md deleted file mode 100644 index 7af534e..0000000 --- a/wiki/rendering/getting-started-with-directx.md +++ /dev/null @@ -1,209 +0,0 @@ -# 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( 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 - -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 - -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 -#include -#include -#include - -// 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 - -static winrt::com_ptr d3d11Device; -static winrt::com_ptr 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 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. -::: diff --git a/wiki/rendering/overview.md b/wiki/rendering/overview.md index baaf696..89f1bb1 100644 --- a/wiki/rendering/overview.md +++ b/wiki/rendering/overview.md @@ -8,7 +8,4 @@ On the Windows build of the game, Mojang includes 3 different rendering backends |------------------|--------|-------|-----------------|-------------| | DirectX 11 | ✔️ | ✔️ | ✖️ | ✖️ | | DirectX 12 | ✔️ | ✔️ | ✔️ | ✖️ | -| 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. \ No newline at end of file +| DirectX 12 (RTX) | ✔️ | ✔️ | ✔️ | ✔️ | \ No newline at end of file diff --git a/wiki/reverse-engineering/introduction.md b/wiki/reverse-engineering/introduction.md deleted file mode 100644 index da08e53..0000000 --- a/wiki/reverse-engineering/introduction.md +++ /dev/null @@ -1,53 +0,0 @@ -# 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. - - diff --git a/wiki/reverse-engineering/using-ida.md b/wiki/reverse-engineering/using-ida.md deleted file mode 100644 index 8506803..0000000 --- a/wiki/reverse-engineering/using-ida.md +++ /dev/null @@ -1,71 +0,0 @@ -# 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). diff --git a/wiki/tools/ld-for-embedding-resources.md b/wiki/tools/ld-for-embedding-resources.md index 9e52dd1..fc4e843 100644 --- a/wiki/tools/ld-for-embedding-resources.md +++ b/wiki/tools/ld-for-embedding-resources.md @@ -69,7 +69,7 @@ When you have a lot of files to embed, this process of adding files manually can ```cmake # Recursively search for files in the 'resources' directory -# and add them as resources: +# and add them as resources file(GLOB_RECURSE RESOURCES RELATIVE ${CMAKE_CURRENT_LIST_DIR} CONFIGURE_DEPENDS "resources/*") add_resources(EMBEDDED_RESOURCES ${RESOURCES}) ``` @@ -77,11 +77,11 @@ add_resources(EMBEDDED_RESOURCES ${RESOURCES}) The `add_resources` function will build your resources as object files, and place them inside of the output variable you provide in the first argument. These object files must be added as sources to your project: ```cmake -# Use 'target_sources' to add these object files to your project: +# Use 'target_sources' to add these object files to your project target_sources(project_name_here PRIVATE ${EMBEDDED_RESOURCES}) # Alternatively, they can be placed within 'add_library' -# alongside your project source files: +# alongside your project source files add_library(project_name_here SHARED ... ${EMBEDDED_RESOURCES}) ``` @@ -102,8 +102,6 @@ We can use this info to write some abstractions to reference and use the data fr ```cpp #include -#include -#include #define LOAD_RESOURCE(x) extern "C" char _binary_resources_##x##_start, _binary_resources_##x##_end; #define GET_RESOURCE(x) Resource{&_binary_resources_##x##_start, &_binary_resources_##x##_end} @@ -134,16 +132,16 @@ The `LOAD_RESOURCE` and `GET_RESOURCE` macros assume your resources are in a fol Example usage in your project is as follows: ```cpp -// Define the external definitions for your resources. +// Define the external definitions for your resources LOAD_RESOURCE(image_png) LOAD_RESOURCE(Roboto_ttf) void loadResources() { - // We can now create instances of Resource from these definitions. + // We can now create instances of Resource from these definitions const Resource image = GET_RESOURCE(image_png) const Resource roboto = GET_RESOURCE(Roboto_png) - // Pseudocode to load each resource: + // Pseudocode to load each resource Images::load(image.data(), image.size()); Fonts::load(roboto.data(), roboto.size()); } diff --git a/wiki/topics/gdk.md b/wiki/topics/gdk.md index 49cb688..7170d0a 100644 --- a/wiki/topics/gdk.md +++ b/wiki/topics/gdk.md @@ -10,8 +10,8 @@ Because Minecraft is no longer a UWP app, that means a few things: For unknown reasons, GDK apps have their main executable files encrypted at-rest. You also can't copy the file. This makes it more difficult to extract the executable for static analysis, but fortunately the protection is pretty easy to get around. -To extract the decrypted executable, use this PowerShell command to drop the executable onto your desktop: +To extract the decrypted executable, use this PowerShell command (replace `User` with your username): ```ps -Invoke-CommandInDesktopPackage -PackageFamilyName "Microsoft.MinecraftUWP_8wekyb3d8bbwe" -AppId "Game" -Command "cmd.exe" -Args "/C copy `"$((Get-AppxPackage "Microsoft.MinecraftUWP").InstallLocation)\Minecraft.Windows.exe`" `"$ENV:USERPROFILE\Desktop\Minecraft.Windows.exe`"" -``` +Invoke-CommandInDesktopPackage -PackageFamilyName "MICROSOFT.MINECRAFTUWP_8wekyb3d8bbwe" -AppId "Game" -Command "cmd.exe" -Args "/C copy `"C:\XboxGames\Minecraft for Windows\Content\Minecraft.Windows.exe`" `"C:\Users\User\Desktop\Minecraft.Windows.exe`"" +``` \ No newline at end of file