|
| 1 | +# Fixing Missing AOBs (Advanced & In-Depth) |
| 2 | + |
| 3 | +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. |
| 4 | + |
| 5 | +## Prerequisites |
| 6 | + |
| 7 | +- **Knowledge of Basic Reverse Engineering Concepts:** |
| 8 | + You should have a general idea of what a signature (AOB) is, how to use a debugger, and how to navigate memory in x64dbg. |
| 9 | + |
| 10 | +- **Understanding ‘root directory’ and ‘working directory’:** |
| 11 | + - **Root directory:** The directory containing `ue4ss.dll`. |
| 12 | + - **Working directory:** This can be either the root directory **or** a game-specific directory such as `<root directory>/SatisfactoryEarlyAccess`. |
| 13 | + |
| 14 | +- **Familiarity with UE4SS Setup & Directories:** |
| 15 | + 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). |
| 16 | + |
| 17 | +- **Preparation and Tools Installed:** |
| 18 | + - **Epic Games Launcher & Unreal Engine:** For creating a “blank shipped game” environment with the correct engine version. |
| 19 | + - **x64dbg:** A debugger tool for Windows (https://x64dbg.com/). |
| 20 | + - **(Optional) Baymax Tools:** A plugin to help generate signatures easily. |
| 21 | + - **(Optional) Swiss Army Knife (by Nukem9):** For extracting signatures. |
| 22 | + |
| 23 | +## Why Create Your Own AOBs? |
| 24 | + |
| 25 | +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. |
| 26 | + |
| 27 | +## High-Level Overview |
| 28 | + |
| 29 | +1. **Identify Which Signatures Are Missing:** Determine which functions or variables UE4SS cannot find (e.g., GUObjectArray, GMalloc, FName or FText constructors). |
| 30 | +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. |
| 31 | +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. |
| 32 | +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. |
| 33 | +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`). |
| 34 | + |
| 35 | +## Finding AOBs: A More Detailed Explanation |
| 36 | + |
| 37 | +> [!CAUTION] |
| 38 | +> 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. |
| 39 | +
|
| 40 | +### Step 1: Determine Your Game’s Unreal Engine Version |
| 41 | + |
| 42 | +UE4SS tries to detect the engine version automatically. If you need to verify: |
| 43 | + |
| 44 | +- Right-click on the game’s `.exe` file (often in `Binaries` folder). |
| 45 | +- Select **Properties** -> **Details** tab. |
| 46 | +- Look for the “File Version” or “Product Version” field, which often correlates to the Unreal Engine version. |
| 47 | + |
| 48 | +For example: If it says `5.3.2.0`, it likely corresponds to UE 5.3.2. |
| 49 | + |
| 50 | +### Step 2: Installing the Matching Unreal Engine Version |
| 51 | + |
| 52 | +- Create an [Epic Games](https://www.epicgames.com/) account and install the **Epic Games Launcher**. |
| 53 | +- In the launcher, go to **Unreal Engine** -> **Library** tab and install the engine version matching your game’s version (e.g., UE 5.3.2). |
| 54 | + |
| 55 | +### Step 3: Creating a Blank Shipped Game with PDBs |
| 56 | + |
| 57 | +1. Launch the installed Unreal Engine version. |
| 58 | +2. In the New Project window, select the **Games** tab -> **Blank** template. |
| 59 | + - Uncheck “Starter Content” if you prefer a minimal project. |
| 60 | + - Name your project and specify a directory. |
| 61 | +3. Once created, open **Platforms** -> **Packaging Settings**, and enable “Include Debug Files in Shipping Builds”. |
| 62 | +4. From **Platforms** -> **Windows**, select “Shipping” configuration (or whichever build matches your target game’s build type). |
| 63 | +5. **Package Project** -> Choose a folder. |
| 64 | +6. After packaging completes, verify that the output folder’s `Binaries` directory contains both a `.exe` and a `.pdb`. The `.pdb` file provides symbolic information for reverse engineering. |
| 65 | + |
| 66 | +### Step 4: Using x64dbg to Analyze the Blank Project |
| 67 | + |
| 68 | +1. Install x64dbg from [https://x64dbg.com/](https://x64dbg.com/). |
| 69 | +2. Run the `.exe` of your newly packaged blank project from its root directory. |
| 70 | +3. Open x64dbg. |
| 71 | + - Go to **File** -> **Attach** -> Select the blank project `.exe`. |
| 72 | + - Ensure you’re attaching to the shipped `.exe` located in `Binaries` or root (whichever works). |
| 73 | + |
| 74 | +### Step 5: Identifying the Function of Interest |
| 75 | + |
| 76 | +You need to know which function or variable you’re trying to match in your target game. For example, if UE4SS fails on `GMalloc`, you must find `FMemory::Free` as a reference to locate `GMalloc`. |
| 77 | + |
| 78 | +**Optional Steps:** |
| 79 | +- Connect your Epic Games account with GitHub to access the Unreal Engine source code. |
| 80 | + - **Epic Games Website** -> **Manage Account** -> **Apps and Accounts** -> **GitHub** |
| 81 | + - Accept invitation via email. |
| 82 | +- Browse the Unreal Engine source for the function you need. For `FMemory::Free` in UE5.3.2, you might look at: |
| 83 | + [FMemory::Free in UE source](https://github.com/EpicGames/UnrealEngine/blob/5.3.2-release/Engine/Source/Runtime/Core/Public/HAL/FMemory.inl#L142) |
| 84 | + |
| 85 | +### Step 6: Locating the Function in x64dbg |
| 86 | + |
| 87 | +1. In x64dbg, switch to the **Symbols** tab. |
| 88 | +2. In the left pane, select the `.exe`. |
| 89 | +3. In the right pane, search for the function name (e.g., `FMemory::Free`). |
| 90 | +4. Double-click the found function to navigate back to the CPU view, positioning the instruction pointer at the start of the function in memory. |
| 91 | + |
| 92 | +### Step 7: Extracting a Signature |
| 93 | + |
| 94 | +Once you’ve identified the start of the function, you need to copy a unique sequence of bytes: |
| 95 | + |
| 96 | +1. Consider installing [Baymax Tools](https://github.com/sicaril/BaymaxTools) for x64dbg to ease signature extraction. |
| 97 | +2. Highlight a set of instructions at the start of the function. |
| 98 | + - Right-click -> **Copy** -> **Selection (Bytes only)** to get a raw byte sequence. |
| 99 | + - With Baymax Tools: Right-click -> **Baymax Tools** -> **Copy Signature** for a ready-made signature pattern. |
| 100 | +3. Save these bytes or patterns for later comparison. You may want to store them in a file to easily refer back. |
| 101 | + |
| 102 | +### Understanding Terminology |
| 103 | + |
| 104 | +- **Signature:** A carefully chosen sequence of bytes that uniquely identifies a function or code snippet. |
| 105 | +- **Block of Bytes:** A simple, possibly unstructured, segment of raw data without inherent uniqueness. |
| 106 | +- **RIP (Instruction Pointer):** The CPU register that holds the address of the next instruction to execute. |
| 107 | + |
| 108 | +### Step 8: Searching in the Actual Target Game |
| 109 | + |
| 110 | +Now that you have a reference signature, you need to find it in your target game: |
| 111 | + |
| 112 | +1. Launch the target game `.exe`. |
| 113 | +2. Attach x64dbg as before: **File** -> **Attach** -> Select the game’s `.exe`. |
| 114 | +3. In x64dbg, search memory for the signature you extracted from the blank project. |
| 115 | + - If direct search fails, try partial sequences of bytes. |
| 116 | + - Try patterns generated by Baymax Tools. |
| 117 | + - Compare and contrast instructions between the blank project and the actual game to locate a similar code region. |
| 118 | + |
| 119 | +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). |
| 120 | + |
| 121 | +### Step 9: Applying the Signature in UE4SS |
| 122 | + |
| 123 | +Once you have a working AOB: |
| 124 | + |
| 125 | +1. Create the `UE4SS_Signatures` directory in your working directory (if it doesn’t already exist). |
| 126 | +2. Make a `.lua` file corresponding to the missing AOB (e.g., `GMalloc.lua` if you’re fixing GMalloc). |
| 127 | +3. Inside this `.lua` file, define the `Register` and `OnMatchFound` functions. |
| 128 | + |
| 129 | +**Register function:** Returns your AOB signature as a string (spaces optional), e.g.: |
| 130 | + |
| 131 | +```lua |
| 132 | +function Register() |
| 133 | + return "48 8B D9 48 8B 0D ?? ?? ?? ?? 48 85 C9 75 0C E8 ?? ?? ?? ??" |
| 134 | +end |
| 135 | +``` |
| 136 | + |
| 137 | +**OnMatchFound function:** Receives the match address and must return the exact memory address of the target function or variable. Use `DerefToInt32` if needed to resolve relative addresses. |
| 138 | + |
| 139 | +```lua |
| 140 | +function OnMatchFound(MatchAddress) |
| 141 | + local MovInstr = MatchAddress + 0x03 |
| 142 | + local Offset = DerefToInt32(MovInstr + 0x3) |
| 143 | + local RIP = MovInstr + 0x7 |
| 144 | + local GMallocAddress = RIP + Offset |
| 145 | + return GMallocAddress |
| 146 | +end |
| 147 | +``` |
| 148 | + |
| 149 | +### Verifying Your Work |
| 150 | + |
| 151 | +- Run the game with UE4SS again. If successful, UE4SS now uses your custom script to find the previously missing address. |
| 152 | +- If it fails silently, confirm: |
| 153 | + - That the Lua script is in the correct directory. |
| 154 | + - That your AOB is correct and unique. |
| 155 | + - That `OnMatchFound` returns the correct final address. |
| 156 | + |
| 157 | +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. |
| 158 | + |
| 159 | +## What ‘OnMatchFound’ Should Return |
| 160 | + |
| 161 | +Recap of the required returns for each known signature type: |
| 162 | + |
| 163 | +- **GUObjectArray:** Return the exact address of the `GUObjectArray` global variable. |
| 164 | +- **FName_ToString:** Return the start address of the `FName::ToString` function. |
| 165 | +- **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. |
| 166 | +- **FText_Constructor:** Return the start address of `FText::FText`. |
| 167 | +- **StaticConstructObject:** Return the start address of the `StaticConstructObject_Internal` global function. |
| 168 | +- **GMalloc:** Return the address of the global `GMalloc` variable. Typically found by scanning around `FMemory::Free` and resolving a MOV instruction. |
| 169 | + |
| 170 | +## Example Scripts |
| 171 | + |
| 172 | +### Direct Scan Example |
| 173 | + |
| 174 | +```lua |
| 175 | +function Register() |
| 176 | + return "48 8B C4 57 48 83 EC 70 80 3D ?? ?? ?? ?? ?? 48 89" |
| 177 | +end |
| 178 | + |
| 179 | +function OnMatchFound(MatchAddress) |
| 180 | + return MatchAddress |
| 181 | +end |
| 182 | +``` |
| 183 | + |
| 184 | +### Indirect Scan Example |
| 185 | + |
| 186 | +```lua |
| 187 | +function Register() |
| 188 | + return "41 B8 01 00 00 00 48 8D 15 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? E9" |
| 189 | +end |
| 190 | + |
| 191 | +function OnMatchFound(MatchAddress) |
| 192 | + local InstrSize = 0x05 |
| 193 | + local JmpInstr = MatchAddress + 0x14 |
| 194 | + local Offset = DerefToInt32(JmpInstr + 0x1) |
| 195 | + local Destination = JmpInstr + Offset + InstrSize |
| 196 | + return Destination |
| 197 | +end |
| 198 | +``` |
| 199 | + |
| 200 | +## Tips, Tricks, and Troubleshooting |
| 201 | + |
| 202 | +- **Patience & Iteration:** Extracting and refining AOBs can be trial-and-error. If a signature doesn’t work, try a different sequence of bytes or look elsewhere in the function. |
| 203 | +- **Partial Signatures:** If the full function signature isn’t found, try unique parts of it. |
| 204 | +- **Community Help:** If stuck, show your steps, scripts, and logs on the UE4SS Discord or GitHub Issues. |
| 205 | +- **Check Offsets Carefully:** Off-by-one or incorrect indexing is a common issue. Double-check your calculations. |
| 206 | +- **Manual Verification:** Sometimes running the blank project again in x64dbg and comparing with the target game’s memory can highlight discrepancies. |
| 207 | + |
| 208 | +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. |
0 commit comments