Skip to content

Commit

Permalink
Updated the guide
Browse files Browse the repository at this point in the history
  • Loading branch information
UE4SS committed Dec 14, 2024
1 parent a5810b0 commit 06da171
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 109 deletions.
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@

- [Guides]()
- [Fixing missing AOBs](./guides/fixing-compatibility-problems.md)
- [Fixing missing AOBs (Advanced)](./guides/fixing-compatibility-problems-advanced.md)
- [Generating UHT headers](./guides/generating-uht-compatible-headers.md)
- [Creating a C++ Mod](./guides/creating-a-c++-mod.md)
- [Installing a C++ Mod](./guides/installing-a-c++-mod.md)
Expand Down
88 changes: 30 additions & 58 deletions docs/guides/fixing-compatibility-problems-advanced.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,53 @@
# Fixing Missing AOBs (Advanced & In-Depth)

When UE4SS fails to properly launch due to missing AOBs (Array of Bytes signatures), you can provide custom AOBs and callback functions using Lua. Doing so, however, requires a level of reverse engineering knowledge and tooling setup that may feel complex at first. This guide expands upon the original instructions, providing even more detail, context, and recommended best practices.
When UE4SS fails to properly launch due to missing AOBs (Array of Bytes signatures), you can provide custom AOBs and callback functions using Lua.
Doing so, however, requires a level of reverse engineering knowledge and tooling setup that may feel complex at first.
This guide expands upon the original instructions, providing more detail, some context and tips.

## Prerequisites

- **Knowledge of Basic Reverse Engineering Concepts:**
You should have a general idea of what a signature (AOB) is, how to use a debugger, and how to navigate memory in x64dbg.

- **Understanding ‘root directory’ and ‘working directory’:**
- **Root directory:** The directory containing `ue4ss.dll`.
- **Working directory:** This can be either the root directory **or** a game-specific directory such as `<root directory>/SatisfactoryEarlyAccess`.

- **Familiarity with UE4SS Setup & Directories:**
Make sure you know where `UE4SS_Signatures` folder should be created (it should be next to `ue4ss.dll` or in a game-specific working directory as described above).
Make sure you know where the `UE4SS_Signatures` folder should be created (it should be next to `ue4ss.dll` or in a game-specific working directory).

- **Preparation and Tools Installed:**
- **Epic Games Launcher & Unreal Engine:** For creating a “blank shipped game” environment with the correct engine version.
- **x64dbg:** A debugger tool for Windows (https://x64dbg.com/).
- **(Optional) Baymax Tools:** A plugin to help generate signatures easily.
- **(Optional) Swiss Army Knife (by Nukem9):** For extracting signatures.
- **(Optional) Swiss Army Knife (by Nukem9):** For more easily extracting signatures with correct wildcards.

## Why Create Your Own AOBs?
## When is this needed, and why ?

When UE4SS updates or when you attempt to mod a game with a newer or unusual engine build, official AOB signatures inside UE4SS may fail. In these cases, providing your own AOBs and callbacks allows UE4SS to locate critical engine functions and global variables in memory and resume normal operation.
Some games don't use Unreal Engine with its default configuration, and we only support the default configuration out of the box.
Anything that affects the code generated by the compiler, including the devs using Clang instead of MSVC, can make our built-in AOBs no longer be valid.
These AOBs are used to find functions and variables that are critical for UE4SS to work.

## High-Level Overview

1. **Identify Which Signatures Are Missing:** Determine which functions or variables UE4SS cannot find (e.g., GUObjectArray, GMalloc, FName or FText constructors).
2. **Set Up a Reference Environment:** Create a blank Unreal Engine shipped game with debug files (PDBs) that matches your game’s Unreal Engine version. This environment helps you identify function signatures cleanly.
3. **Reverse Engineer and Extract AOBs:** Using x64dbg (and optional plugins), open the shipped game and locate the desired function in memory. Copy out the unique bytes that form a reliable signature.
2. **Set Up a Reference Environment:** Create a blank Unreal Engine game (using the Shipping target) with debug files (PDBs) that uses the same Unreal Engine version as your game. This environment helps you identify function signatures cleanly.
3. **Reverse Engineer and Extract AOBs:** Using x64dbg (and optional plugins), open the blank game and locate the desired function in memory. Copy out the unique bytes that form a reliable signature. This signature should be properly wildcarded, if it's not, it won't be found in your game.
4. **Apply Your Signatures to the Actual Game:** Attach x64dbg to the target game, find the matching bytes, and confirm that the signature you extracted matches code in the game you want to mod.
5. **Create a Lua Script:** Write a Lua file in `UE4SS_Signatures` to tell UE4SS what AOB pattern to search for (through `Register`) and what final address to return (through `OnMatchFound`).

## Finding AOBs: A More Detailed Explanation

> [!CAUTION]
> Reverse engineering these signatures isn’t trivial. You may need to step outside the scope of this guide, read reverse-engineering tutorials, or ask for community support. The steps below are a starting point, not a complete primer on reverse engineering.
> Reverse engineering these signatures isn’t trivial. You may need to step outside the scope of this guide, read reverse-engineering tutorials, or ask for community support. The steps below are a starting point, not a complete guide on reverse engineering.
### Step 1: Determine Your Game’s Unreal Engine Version

UE4SS tries to detect the engine version automatically. If you need to verify:
UE4SS tries to detect the engine version automatically. If you need to verify, the following steps usually work:

- Right-click on the game’s `.exe` file (often in `Binaries` folder).
- Select **Properties** -> **Details** tab.
- Look for the “File Version” or “Product Version” field, which often correlates to the Unreal Engine version.

For example: If it says `5.3.2.0`, it likely corresponds to UE 5.3.2.
For example: If it says `5.3.2.0`, it likely corresponds to UE 5.3.2.
In rare cases, the version will either be empty, or it will refer to the game version instead of the engine version.
Note that the last number doesn't usually matter, so if your game is using UE 5.3.2, your blank game can generally use any 5.3 version.

### Step 2: Installing the Matching Unreal Engine Version

Expand All @@ -56,7 +58,7 @@ For example: If it says `5.3.2.0`, it likely corresponds to UE 5.3.2.

1. Launch the installed Unreal Engine version.
2. In the New Project window, select the **Games** tab -> **Blank** template.
- Uncheck “Starter Content” if you prefer a minimal project.
- Uncheck “Starter Content” because it's not needed, and unchecking this will save time and space.
- Name your project and specify a directory.
3. Once created, open **Platforms** -> **Packaging Settings**, and enable “Include Debug Files in Shipping Builds”.
4. From **Platforms** -> **Windows**, select “Shipping” configuration (or whichever build matches your target game’s build type).
Expand Down Expand Up @@ -84,6 +86,10 @@ You need to know which function or variable you’re trying to match in your tar

### Step 6: Locating the Function in x64dbg

Note that there's a bug in x64dbg where navigating to code or memory from the symbols tab sometimes doesn't work properly.
If you're navigating and not seeing what you expect, it's worth restarting x64dbg and trying again.
You can also try copy the address from the symbols tab and manually navigate to it in the correct panel in the CPU tab.

1. In x64dbg, switch to the **Symbols** tab.
2. In the left pane, select the `.exe`.
3. In the right pane, search for the function name (e.g., `FMemory::Free`).
Expand All @@ -93,7 +99,7 @@ You need to know which function or variable you’re trying to match in your tar

Once you’ve identified the start of the function, you need to copy a unique sequence of bytes:

1. Consider installing [Baymax Tools](https://github.com/sicaril/BaymaxTools) for x64dbg to ease signature extraction.
1. Consider installing [Baymax Tools](https://github.com/sicaril/BaymaxTools) or Swiss Army Knife for x64dbg to ease signature extraction.
2. Highlight a set of instructions at the start of the function.
- Right-click -> **Copy** -> **Selection (Bytes only)** to get a raw byte sequence.
- With Baymax Tools: Right-click -> **Baymax Tools** -> **Copy Signature** for a ready-made signature pattern.
Expand All @@ -116,7 +122,8 @@ Now that you have a reference signature, you need to find it in your target game
- Try patterns generated by Baymax Tools.
- Compare and contrast instructions between the blank project and the actual game to locate a similar code region.

If you find a match, you’ve identified the address that corresponds to the target function or variable in the actual game. If you can’t find it, you may need to refine your signature, pick a different part of the function, or ask for community help (UE4SS Discord or GitHub Issues).
If you find a match, you’ve identified the address that corresponds to the target function or variable in the actual game.
If you can’t find it, you may need to refine your signature, pick a different part of the function, or ask for community help (UE4SS Discord or GitHub Issues).

### Step 9: Applying the Signature in UE4SS

Expand Down Expand Up @@ -154,48 +161,12 @@ end
- That your AOB is correct and unique.
- That `OnMatchFound` returns the correct final address.

If still stuck, consider posting detailed steps, logs, and code snippets to the UE4SS community channels. The more detail you provide, the more likely someone can guide you to a solution.

## What ‘OnMatchFound’ Should Return

Recap of the required returns for each known signature type:

- **GUObjectArray:** Return the exact address of the `GUObjectArray` global variable.
- **FName_ToString:** Return the start address of the `FName::ToString` function.
- **FName_Constructor:** Return the start address of `FName::FName`. Multiple versions might exist (e.g., for `char*` and `wchar_t*`), but UE4SS validates the correct one internally.
- **FText_Constructor:** Return the start address of `FText::FText`.
- **StaticConstructObject:** Return the start address of the `StaticConstructObject_Internal` global function.
- **GMalloc:** Return the address of the global `GMalloc` variable. Typically found by scanning around `FMemory::Free` and resolving a MOV instruction.

## Example Scripts

### Direct Scan Example

```lua
function Register()
return "48 8B C4 57 48 83 EC 70 80 3D ?? ?? ?? ?? ?? 48 89"
end
If still stuck, consider posting detailed steps, logs, and code snippets to the UE4SS community channels.
The more detail you provide, the more likely someone can guide you to a solution.

function OnMatchFound(MatchAddress)
return MatchAddress
end
```
## What ‘OnMatchFound’ Should Return, and Example Scripts

### Indirect Scan Example

```lua
function Register()
return "41 B8 01 00 00 00 48 8D 15 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? E9"
end

function OnMatchFound(MatchAddress)
local InstrSize = 0x05
local JmpInstr = MatchAddress + 0x14
local Offset = DerefToInt32(JmpInstr + 0x1)
local Destination = JmpInstr + Offset + InstrSize
return Destination
end
```
[See the regular guide](./fixing-compatibility-problems.md#how-to-setup-your-own-aob-and-callback).

## Tips, Tricks, and Troubleshooting

Expand All @@ -205,4 +176,5 @@ end
- **Check Offsets Carefully:** Off-by-one or incorrect indexing is a common issue. Double-check your calculations.
- **Manual Verification:** Sometimes running the blank project again in x64dbg and comparing with the target game’s memory can highlight discrepancies.

By following these expanded steps and leveraging the provided tools, you’ll have a more comprehensive understanding of how to fix missing AOBs with UE4SS. Although still complex, this extended guide should help clarify the process and offer practical insights for both beginners and experienced modders venturing into reverse engineering territory.
By following these expanded steps and leveraging the provided tools, you’ll have a more comprehensive understanding of how to fix missing AOBs with UE4SS.
Although still complex, this extended guide should help clarify the process and offer practical insights into the reverse engineering territory.
52 changes: 1 addition & 51 deletions docs/guides/fixing-compatibility-problems.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,57 +20,7 @@ Since the process is quite complicated, here will just cover the general steps y
5. Open your game's memory in x64dbg and search it for the same block of bytes
6. If you find it, you can use the [swiss army knife](https://github.com/Nukem9/SwissArmyKnife) tool to extract the AOB for it which you can use in a simple script such as example [here](#example-script-simple-direct-scan)

### Context and definitions

Some context and definitions:

In this context, a `Signature` refers to a unique sequence or pattern of bytes used to identify a function or piece of code within a binary, such as specific instructions or constants that are unlikely to appear elsewhere. It serves as a recognizable "fingerprint" to locate a particular routine during reverse engineering or patching.

In contrast, a `Block of Bytes` is simply a contiguous sequence of raw data or instructions without any specific identification purpose. A block of bytes may or may not represent anything meaningful or unique, whereas a signature is carefully chosen to reliably distinguish a particular function or code segment.

`RIP (Instruction Pointer Register)` is a register in x86-64 architecture that holds the address of the next instruction to be executed. It plays a key role in managing program flow, enabling the CPU to keep track of where it is in the program code.

Now for each step in more detail (thanks for `TimeMaster` for these steps).

### Making a blank shipped game

1. Get your game UE version. UE4SS detects it. But it can also be checked by using right-click on the `.exe` in `Binaries`, opening properties and checking on the details tab
2. In the Epic Games launcher at the left side, go to Unreal Engine -> Library tab at the top and install engine version for the engine version for your game
3. Once installed launch Unreal Engine. Games tab -> Select Blank -> Uncheck Starter Content (Optional to set a Project Name / change location) -> Create
4. Press Platforms button on the top bar -> Packaging Settings -> Check `Include Debug Files in Shipping Builds`
5. Press Platforms button on the top bar -> Windows -> Select `Shipping` (or the one that applies to your game build) -> Package Project and select a folder
6. Check that the newly packaged blank project contains a `.exe` along with a `.pdb` in `Binaries` in the selected folder

### Reading the game's memory using x64dbg

1. Install [x64dbg](https://x64dbg.com/)
2. Run the `.exe` at the root folder of the newly packaged blank project (running the `.exe` in `Binaries` might throw an error, running from root works too either way)
3. Open x64dbg -> File -> Attach -> Select the newly packaged blank project `.exe` (the one with the path at `Binaries`)

### Look for the signature you need

1. (Optional but recommended) Connect Epic Games with Github. Login in the Epic Games Website -> Manage Account -> Apps and Accounts -> Github -> Once done, check email and accept invitation to the UE project
2. (Optional but recommended) Check the source code for the function that is intended to be found in memory. For example, to find the `FMemory::Free` function in a UE5.3.2 game, you would find [this](https://github.com/EpicGames/UnrealEngine/blob/5.3.2-release/Engine/Source/Runtime/Core/Public/HAL/FMemory.inl#L142)
3. In x64dbg go to Symbols tab -> In the left window select the `.exe` -> Under the right window search for the function (in this case `FMemory::Free`) -> Double click the found Function in the right window
4. You should be now back at the CPU tab with the address in memory of the start of the selected function

### Grab a copy of bytes from the function

1. (Optional but recommended) Install [Baymax ToOls](https://github.com/sicaril/BaymaxTools) plugin for x64dbg
2. Select some (This is where it is not the same for every game and required magic/"knowledge" starts) address lines -> Right Click -> Copy -> Selection or Selection (Bytes only)
3. If Baymax ToOls installed, while selecting all the addresses lines composing the function -> Right Click -> Baymax ToOls -> Copy Signature.
4. Might want to copy both selection types and save them in a file for comparison and reference

### Open your game's memory in x64dbg

1. Open the game you want to mod
2. Attach x64dbg as seen before with the blank project
3. Search for the saved block of bytes found in the last step
4. (If nothing found) Search for the pattern from Baymax ToOls
5. (If nothing found) Try searching parts of the block of bytes (or signature from Baymax ToOls) and compare the addresses block with the one from the blank project
6. If nothing found, it might be worth to ask for help on the UE4SS discord or Github issues. Make sure you post all your steps and as much detail as you can provide, otherwise no one will be inclined to help you!
7. If found a good match, create the lua script to retrieve the address of the function/variable required. Put it in `UE4SS_Signatures` folder in the `Binaries` of your game folder where UE4SS is installed
8. Run the game and UE4SS hopefully works now
For more in-depth instructions, see the [advanced guide](./fixing-compatibility-problems-advanced.md).

## How to setup your own AOB and callback

Expand Down

0 comments on commit 06da171

Please sign in to comment.