### Extract FFXIV Version Example Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/INDEX.md Provides an example of how to retrieve the version and build date of the FFXIV executable. ```csharp var (version, date) = FfxivVersionChecker.GetVersion( new FileInfo(@"ffxiv_dx11.exe") ); ``` -------------------------------- ### Example Usage of GetSlice Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Demonstrates how to obtain a byte slice and iterate through its contents. Ensure the start and length parameters are within the buffer bounds to avoid exceptions. ```csharp var slice = scanner.GetSlice(0x100, 16); for (int i = 0; i < slice.Length; i++) { Console.WriteLine($"Byte {i:X2}: {slice[i]:X2}"); } ``` -------------------------------- ### Pattern Syntax Example Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/INDEX.md Illustrates the basic format for defining search patterns, including hex bytes and wildcards. ```plaintext 48 8D 0D ?? ?? ?? ?? Add 3 TraceRelative ``` -------------------------------- ### Search Buffer Example Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/INDEX.md Demonstrates how to search a byte buffer for a given pattern using the PatternSearcher class. ```csharp var data = File.ReadAllBytes("section.bin"); var scanner = new PatternSearcher(data, new IntPtr(0x1000)); var result = scanner.Search("48 8B 0D ?? ?? ?? ??"); ``` -------------------------------- ### Zero-Allocation I/O Example Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/README.md Shows how to perform file I/O using stack-allocated buffers and direct file handles to avoid heap allocations. ```C# Span buffer = stackalloc byte[0x50]; RandomAccess.Read(handle, buffer, offset); // No heap allocation ``` -------------------------------- ### Parse PE File Example Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/INDEX.md Shows how to extract PE headers and specifically the .text section from an executable file. ```csharp var peInfo = PeHeaderParser.GetPeHeaders("app.exe"); var textSection = peInfo.TextSection; ``` -------------------------------- ### Get FFXIV Version (Pattern Based) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Get the version and date of the FFXIV executable using a pattern-based approach, which is more robust to layout changes. ```csharp // Or pattern-based (more robust to layout changes) var (v, d) = FfxivVersionChecker.GetVersionPattern(exe); ``` -------------------------------- ### Multi-Pattern Scanning Example Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/README.md Illustrates scanning for multiple patterns simultaneously. The scanner returns the first match for each pattern, aligned with the input array. ```C# var results = scanner.Search(new[] { pattern1, pattern2, pattern3 }); // Returns first match for each, index-aligned with input ``` -------------------------------- ### Get FFXIV Version (Direct Read) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Get the version and date of the FFXIV executable by directly reading file information. ```csharp // Simple direct read var exe = new FileInfo(@"C:\FFXIV\ffxiv_dx11.exe"); var (version, date) = FfxivVersionChecker.GetVersion(exe); ``` -------------------------------- ### PeHeaderInfo Usage Example Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/types.md Demonstrates how to retrieve PE header information for an executable file and iterate through its sections. Requires the PeHeaderParser class. ```csharp var peInfo = PeHeaderParser.GetPeHeaders("app.exe"); Console.WriteLine($"Image Base: 0x{peInfo.ImageBase:X}"); foreach (var section in peInfo.Sections) { Console.WriteLine($" {section.Name} at 0x{section.VirtualAddress:X}"); } ``` -------------------------------- ### Example: Scanning PE .text Section and Raw Buffers Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Demonstrates scanning a PE .text section with a specific RVA and scanning raw bytes with no offset. Ensure correct byte array and IntPtr usage for memory regions. ```csharp // Scanning a PE .text section at RVA 0x1000 var bytes = File.ReadAllBytes("app.exe"); var textData = bytes.AsSpan(0x1000, 0x5000); var scanner = new PatternSearcher(textData, new IntPtr(0x1000)); // Or, scanning with no offset var scanner2 = new PatternSearcher(bytes, IntPtr.Zero); ``` -------------------------------- ### Example: Wrapping Unmanaged Memory with UnmanagedMemoryManager Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/unmanaged-memory-manager.md Demonstrates how to allocate unmanaged memory, wrap it using UnmanagedMemoryManager, and then use the resulting Memory with a Memory-consuming API like PatternSearcher. Remember to free the allocated memory in a finally block. ```csharp unsafe { // Allocate unmanaged memory byte* ptr = (byte*)Marshal.AllocHGlobal(1024); try { // Wrap as Memory var manager = new UnmanagedMemoryManager(ptr, 1024); var memory = manager.Memory; // Use with PatternSearcher or any Memory-consuming API var scanner = new PatternSearcher(memory, new IntPtr(0x1000)); var result = scanner.Search("48 8B 0D ?? ?? ?? ??"); } finally { Marshal.FreeHGlobal((IntPtr)ptr); } } ``` -------------------------------- ### SimpleSectionHeader Usage Example Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/types.md Shows how to access specific section details, such as the .text section, from a PeHeaderInfo object. This example checks for the existence of the text section before accessing its properties. ```csharp var peInfo = PeHeaderParser.GetPeHeaders("app.exe"); var textSection = peInfo.TextSection; if (textSection.HasValue) { var section = textSection.Value; Console.WriteLine($"Name: {section.Name}"); Console.WriteLine($"RVA: 0x{section.VirtualAddress:X}"); Console.WriteLine($"File Offset: 0x{section.PointerToRawData:X}"); Console.WriteLine($"Size: 0x{section.SizeOfRawData:X}"); } ``` -------------------------------- ### Running Synchronous Search in Async Context Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Provides an example of how to execute synchronous search methods within an asynchronous context using Task.Run to prevent blocking. ```csharp var result = await Task.Run(() => scanner.Search(pattern)); ``` -------------------------------- ### Catch various exceptions for PeHeaderParser.GetPeHeaders(string) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/errors.md This example demonstrates catching multiple potential exceptions when parsing PE headers, including FileNotFoundException, UnauthorizedAccessException, InvalidDataException, and IOException, to handle file access and data integrity issues. ```csharp try { var peInfo = PeHeaderParser.GetPeHeaders(@"C:\nonexistent\app.exe"); } catch (FileNotFoundException) { Console.WriteLine("Executable not found"); } catch (UnauthorizedAccessException) { Console.WriteLine("Access denied"); } catch (InvalidDataException) { Console.WriteLine("Not a valid PE file"); } catch (IOException ex) { Console.WriteLine($"I/O error: {ex.Message}"); } ``` -------------------------------- ### Get FFXIV Version and Date using Pattern Scanning Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/ffxiv-version-checker.md Extracts version by pattern-scanning the .text section for a version pointer, then reading from .data. This method is more robust to layout changes than direct offset reading. Returns "0" for both if extraction fails. ```csharp var exePath = new FileInfo(@"C:\Program Files\FFXIV\ffxiv_dx11.exe"); var (version, date) = FfxivVersionChecker.GetVersionPattern(exePath); Console.WriteLine($"Version: {version}, Date: {date}"); ``` -------------------------------- ### Get FFXIV Executable Version with Exception Handling Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/errors.md Retrieves the version and build date of the FFXIV executable. Handles various exceptions including NullReferenceException, FileNotFoundException, UnauthorizedAccessException, and InvalidDataException. Returns ("0", "0") for specific non-exception error conditions like corrupted PE headers or missing version markers. ```csharp var (version, date) = FfxivVersionChecker.GetVersion(ffxivExe); ``` ```csharp var exe = new FileInfo(@"C:\FFXIV\ffxiv_dx11.exe"); try { var (version, date) = FfxivVersionChecker.GetVersion(exe); if (version == "0") { Console.WriteLine("Version marker not found (file exists but is corrupted or unsupported)"); } else { Console.WriteLine($"Version: {version}, Date: {date}"); } } catch (FileNotFoundException) { Console.WriteLine("Executable not found"); } catch (UnauthorizedAccessException) { Console.WriteLine("No read permission"); } catch (InvalidDataException) { Console.WriteLine("Invalid PE file structure"); } ``` -------------------------------- ### Get FFXIV Version and Date from Executable Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/ffxiv-version-checker.md Reads the FFXIV executable and extracts the embedded revision and date values using direct file I/O. Returns "0" for both if extraction fails. Ensure the FileInfo points to a valid ffxiv_dx11.exe. ```csharp var exePath = new FileInfo(@"C:\Program Files\FFXIV\ffxiv_dx11.exe"); var (version, date) = FfxivVersionChecker.GetVersion(exePath); if (version != "0") { Console.WriteLine($"FFXIV Version: {version}, Date: {date}"); } else { Console.WriteLine("Failed to extract version"); } ``` -------------------------------- ### Get FFXIV Executable Version Pattern with Error Handling Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/errors.md Retrieves the version pattern and date from the FFXIV executable. Propagates exceptions from underlying parsing methods and may throw ArgumentException or InvalidDataException for invalid version patterns or PE structures. ```csharp var (version, date) = FfxivVersionChecker.GetVersionPattern(ffxivExe); ``` -------------------------------- ### Optimize Pattern Search with Distinctive Bytes First Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Demonstrates how placing distinctive bytes at the beginning of a search pattern can improve performance compared to patterns with leading wildcards. ```csharp // Slower: many wildcards at start var slow = scanner.Search("?? ?? ?? ?? 48 8B 0D"); // Faster: distinctive byte first var fast = scanner.Search("48 8B 0D ?? ?? ?? ??"); ``` -------------------------------- ### Handle FFXIV Version Checker Errors Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/ffxiv-version-checker.md Demonstrates how to handle potential exceptions when checking the FFXIV executable version, including file not found, unauthorized access, and version marker not found. ```csharp var exePath = new FileInfo(@"ffxiv_dx11.exe"); try { var (version, date) = FfxivVersionChecker.GetVersion(exePath); if (version == "0") { // File exists but version marker was not found Console.WriteLine("Version marker not found in executable"); } else { Console.WriteLine($"Version: {version}, Date: {date}"); } } catch (FileNotFoundException) { Console.WriteLine("Executable not found"); } catch (UnauthorizedAccessException) { Console.WriteLine("No read permission for executable"); } catch (Exception ex) { Console.WriteLine($"Unexpected error: {ex.Message}"); } ``` -------------------------------- ### Get Specific PE Section Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pe-header-parser.md Retrieves a specific section (e.g., .text) from the parsed PE headers. Throws an exception if the section is not found. ```csharp var section = peInfo.TextSection ?? throw new InvalidDataException("No .text section"); ``` -------------------------------- ### Multi-Pattern Scanning in C# Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Demonstrates how to search for multiple patterns simultaneously using an array of pattern strings in C#. ```csharp var patterns = new[] { "48 8B 0D ?? ?? ?? ??", "48 8D 05 ?? ?? ?? ??", "48 89 45 F8" }; var results = scanner.Search(patterns); ``` -------------------------------- ### Search within a Bounded Range Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/isearcher-interface.md Scans a specified sub-range of the memory region for the first pattern match. The start parameter is a zero-based buffer offset. ```csharp // Find all occurrences var first = searcher.Search("90 90 90"); if (first != IntPtr.Zero) { var next = searcher.Search("90 90 90", first + 1, int.MaxValue); if (next != IntPtr.Zero) { Console.WriteLine("Found second occurrence"); } } ``` -------------------------------- ### Hex Byte and Wildcard Patterns Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Illustrates different ways to specify patterns using hex bytes and wildcards for matching behavior. ```plaintext 48 8B 0D ?? ?? ?? ?? // Literal 0x48, 0x8B, 0x0D; wildcard rest 4? 8B ?D ?? ?? ?? ?? // Half-byte wildcards ?? ?? ?? ?? ?? ?? ?? ?? // Full wildcard (matches anything) ``` -------------------------------- ### Post-Match Command Patterns Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Shows how to append commands to patterns to control actions after a match, such as advancing bytes or resolving references. ```plaintext 48 8B 0D ?? ?? ?? ?? // Raw match only 48 8B 0D ?? ?? ?? ?? Add 3 // Advance by 3 bytes 48 8B 0D ?? ?? ?? ?? TraceRelative // Resolve RIP-relative reference ``` -------------------------------- ### Catch ArgumentNullException and ArgumentException for PatternSearcher.Search(string) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/errors.md Catch ArgumentNullException when the pattern is null, and ArgumentException for invalid pattern syntax. This example demonstrates handling these specific errors. ```csharp try { var result = searcher.Search("48 8B"); } catch (ArgumentNullException) { Console.WriteLine("Pattern is null"); } catch (ArgumentException ex) { Console.WriteLine($"Invalid pattern: {ex.Message}"); } ``` -------------------------------- ### Initialize PatternSearcher with byte array Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Creates a scanner from a managed byte array. Use this when you have the assembly data loaded into a byte array. ```csharp var bytes = File.ReadAllBytes("section.bin"); var scanner = new PatternSearcher(bytes, new IntPtr(0x1000)); ``` -------------------------------- ### Getting a Mutable Span from Unmanaged Memory Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/unmanaged-memory-manager.md Obtain a mutable Span that directly accesses the unmanaged memory region. This is useful for efficient, direct manipulation of the memory. ```csharp public override Span GetSpan() ``` ```csharp var manager = new UnmanagedMemoryManager(ptr, 256); var span = manager.GetSpan(); for (int i = 0; i < span.Length; i++) { span[i] = (byte)(i & 0xFF); } ``` -------------------------------- ### Utilities: GetMask Extension Method Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/types.md Gets the 8-bit mask for a 2-character hex token, supporting potential wildcards. Part of the Utilities static class for hex parsing. ```csharp public static byte GetMask(this ReadOnlySpan tok) { ... } ``` -------------------------------- ### Initialize PatternSearcher with Memory and unmanaged memory Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Creates a scanner from a Memory that wraps unmanaged memory. No copy is made; the memory is used directly. This is useful for performance-critical scenarios involving raw pointers. ```csharp // Wrap a raw IntPtr as Memory unsafe { var manager = new UnmanagedMemoryManager((byte*)ptr, length); var memory = manager.Memory; var scanner = new PatternSearcher(memory, imageBase); } ``` -------------------------------- ### Catch ArgumentOutOfRangeException for PatternSearcher.GetSlice(int, int) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/errors.md Handle ArgumentOutOfRangeException when the start index or length is negative, or when the slice extends beyond the buffer size. This ensures valid slice operations. ```csharp try { var slice = searcher.GetSlice(10000, 100); // Out of bounds } catch (ArgumentOutOfRangeException ex) { Console.WriteLine($"Invalid slice: {ex.Message}"); } ``` -------------------------------- ### Get Data Slice Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/isearcher-interface.md Returns a read-only view of a sub-region without allocation. The returned span is a ref struct and cannot be stored in fields, boxed, or passed across async/await boundaries. Consume synchronously. ```csharp public ReadOnlySpan GetSlice(int start, int length) ``` ```csharp var slice = searcher.GetSlice(0x100, 64); for (int i = 0; i < slice.Length; i++) { Console.Write($"{slice[i]:X2} "); } ``` -------------------------------- ### Reading and Scanning a PE Section Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pe-header-parser.md Shows how to parse PE headers, access the .text section, read its data from disk, and scan it using PatternSearcher. Ensure the file path is correct and necessary classes are imported. ```csharp var peInfo = PeHeaderParser.GetPeHeaders("app.exe"); var textSection = peInfo.TextSection; if (textSection != null) { var section = textSection.Value; // Read the section from disk var fileBytes = File.ReadAllBytes("app.exe"); var sectionData = fileBytes.AsMemory( checked((int)section.PointerToRawData), checked((int)section.SizeOfRawData)); // Scan the section with PatternSearcher var scanner = new PatternSearcher(sectionData, new IntPtr(section.VirtualAddress)); var result = scanner.Search("48 8B ?? ?? ?? ?? ??"); } ``` -------------------------------- ### Get PE Headers and Convert RVA to File Offset Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Utilize the static PeHeaderParser class to retrieve PE headers from a file path and convert Relative Virtual Addresses (RVAs) to file offsets using the section information. ```csharp var peInfo = PeHeaderParser.GetPeHeaders(filePath); var fileOffset = PeHeaderParser.RvaToFileOffset(rva, peInfo.Sections); ``` -------------------------------- ### Add Llama.Memory Package (CLI) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Add the Llama.Memory NuGet package to your project using the .NET CLI. ```bash dotnet add package Llama.Memory ``` -------------------------------- ### Get PE Headers from File Path Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pe-header-parser.md Parses a PE file to retrieve its image base and section headers. This method performs synchronous I/O and should be wrapped in Task.Run if called from an async or UI context. The underlying FileStream is opened with FileShare.ReadWrite. ```csharp public static unsafe PeHeaderInfo GetPeHeaders(string filePath) ``` ```csharp var peInfo = PeHeaderParser.GetPeHeaders(@"C:\Program Files\App\app.exe"); Console.WriteLine($"Image Base: 0x{peInfo.ImageBase:X}"); Console.WriteLine($"Sections: {peInfo.Sections.Length}"); var textSection = peInfo.TextSection; if (textSection != null) { Console.WriteLine($".text at RVA 0x{textSection.Value.VirtualAddress:X}, size 0x{textSection.Value.SizeOfRawData:X}"); } ``` -------------------------------- ### Initialize PatternSearcher with Data and Image Base Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Instantiate PatternSearcher with the memory region to scan and the virtual address offset. Use Span-based overloads for efficiency or Memory for direct usage. ```csharp var scanner = new PatternSearcher(data, imageBase); ``` -------------------------------- ### Scan PE File Text Section Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md This snippet demonstrates how to parse a PE file, extract the .text section's data and virtual address, and then use it to initialize a PatternSearcher for scanning. ```csharp // Parse PE file var peInfo = PeHeaderParser.GetPeHeaders("target.exe"); var textSection = peInfo.TextSection ?? throw new Exception("No .text"); // Read section from disk var bytes = File.ReadAllBytes("target.exe"); var sectionData = bytes.AsMemory( checked((int)textSection.Value.PointerToRawData), checked((int)textSection.Value.SizeOfRawData)); // Scan with proper RVA offset var scanner = new PatternSearcher(sectionData, new IntPtr(textSection.Value.VirtualAddress)); // Search var result = scanner.Search("48 8D 0D ?? ?? ?? ?? Add 3 TraceRelative"); ``` -------------------------------- ### UnmanagedMemoryManager C# Class Definition Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/types.md A generic, sealed class providing a safe wrapper for unmanaged pointers. It implements MemoryManager and requires T to be an unmanaged type. The constructor takes a raw pointer and length. Methods allow getting a span, pinning memory, and managing lifetime (though Unpin and Dispose are no-ops for unmanaged memory). ```csharp public sealed unsafe class UnmanagedMemoryManager : MemoryManager where T : unmanaged ``` -------------------------------- ### FfxivVersionChecker Methods Source: https://github.com/nt153133/llama.memory/blob/master/README.md Methods for checking the version and date of FFXIV executable files. ```APIDOC ## FfxivVersionChecker Methods ### `(string Version, string Date) GetVersion(FileInfo ffxivExe)` Reads the expected version marker directly from the data section of the FFXIV executable file and returns the version and date. - **`ffxivExe`** (FileInfo) - Information about the FFXIV executable file. ### `(string Version, string Date) GetVersionPattern(FileInfo ffxivExe)` Locates the version marker using pattern scanning within the FFXIV executable file, then reads and parses it to return the version and date. - **`ffxivExe`** (FileInfo) - Information about the FFXIV executable file. ``` -------------------------------- ### Extract FFXIV Version and Date Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/README.md Use FfxivVersionChecker to extract the version and build date directly from the FFXIV executable file. ```csharp var exe = new FileInfo(@"C:\FFXIV\ffxiv_dx11.exe"); var (version, date) = FfxivVersionChecker.GetVersion(exe); Console.WriteLine($"Version: {version}, Date: {date}"); ``` -------------------------------- ### Check FFXIV Version in C# Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/README.md Checks the version of the FFXIV executable against an expected version. Use this to ensure compatibility. ```csharp var (version, date) = FfxivVersionChecker.GetVersion(new FileInfo(ffxivExePath)); if (version != ExpectedVersion) { Console.WriteLine($"Unsupported FFXIV version: {version}"); } ``` -------------------------------- ### Disposing UnmanagedMemoryManager and Freeing Memory Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/unmanaged-memory-manager.md Demonstrates the correct procedure for managing the lifecycle of an UnmanagedMemoryManager and its associated unmanaged memory. Disposing the manager does not free the memory; manual deallocation is required. ```csharp protected override void Dispose(bool disposing) ``` ```csharp unsafe { var ptr = (byte*)Marshal.AllocHGlobal(1024); var manager = new UnmanagedMemoryManager(ptr, 1024); try { // Use memory var memory = manager.Memory; // ... } finally { manager.Dispose(); // Dispose the manager (no-op) Marshal.FreeHGlobal((IntPtr)ptr); // Free the pointer } } ``` -------------------------------- ### PatternSearcher(Memory, IntPtr) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Creates a scanner from a Memory. No copy is made; the memory is used directly. ```APIDOC ## PatternSearcher(Memory, IntPtr) ### Description Creates a scanner from a Memory. No copy is made; the memory is used directly. ### Parameters #### Path Parameters - **assemblyData** (Memory) - Required - Memory backing the scan data (can wrap unmanaged memory via UnmanagedMemoryManager) - **imageBase** (IntPtr) - Required - Virtual address offset for results ### Request Example ```csharp // Wrap a raw IntPtr as Memory unsafe { var manager = new UnmanagedMemoryManager((byte*)ptr, length); var memory = manager.Memory; var scanner = new PatternSearcher(memory, imageBase); } ``` ``` -------------------------------- ### Add Llama.Memory Package (XML) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Add the Llama.Memory NuGet package to your project using the PackageReference element in your .csproj file. ```xml ``` -------------------------------- ### Search(string) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Scans the entire buffer for the first match of a given pattern. The pattern is a string of space-separated hex bytes, optionally including post-match commands. ```APIDOC ## Search(string) ### Description Scans the entire buffer for the first match of the pattern. ### Method `public IntPtr Search(string pattern)` ### Parameters #### Path Parameters - **pattern** (string) - Required - Space-separated hex bytes and optional post-match commands ### Response #### Success Response (IntPtr) - Returns the transformed address of the first match, or `IntPtr.Zero` if no match is found. ### Throws - `ArgumentNullException` — pattern is null - `ArgumentException` — pattern syntax is invalid or contains no byte tokens ### Request Example ```csharp var result = scanner.Search("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ??"); if (result != IntPtr.Zero) { Console.WriteLine($"Found at 0x{result.ToInt64():X}"); } ``` ``` -------------------------------- ### Scan Raw Buffer with Zero Offset Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md Scan a raw binary buffer using PatternSearcher, initializing it with the byte data and IntPtr.Zero for the offset when there is no PE context. ```csharp // No PE context: raw buffer with zero offset var data = File.ReadAllBytes("raw.bin"); var scanner = new PatternSearcher(data, IntPtr.Zero); var matches = scanner.SearchMany("AA BB CC"); ``` -------------------------------- ### Wrapping Native Pointers with UnmanagedMemoryManager Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/unmanaged-memory-manager.md Demonstrates how to wrap a native pointer obtained from P/Invoke into an UnmanagedMemoryManager for use with PatternSearcher. Ensure the native pointer is valid and the size is correct. ```csharp unsafe { // Receive a native pointer from P/Invoke IntPtr nativeBuffer = NativeMethods.GetBuffer(out int size); // Convert to Memory for use with PatternSearcher var manager = new UnmanagedMemoryManager((byte*)nativeBuffer, size); var scanner = new PatternSearcher(manager.Memory, new IntPtr(0x140000000)); var result = scanner.Search("48 8B 0D ?? ?? ?? ??"); } ``` -------------------------------- ### Error Handling for FFXIV Version Extraction Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/errors.md Shows how to handle potential errors when extracting version information from FFXIV executables. It specifically catches file-related and general exceptions, providing user-friendly messages. ```csharp var exe = new FileInfo(filePath); try { var (version, date) = FfxivVersionChecker.GetVersion(exe); if (version == "0") { Console.WriteLine("Version marker not found"); } else { Console.WriteLine($"Version: {version}, Date: {date}"); } } catch (FileNotFoundException) { Console.WriteLine($"Executable not found: {filePath}"); } catch (Exception ex) when (ex is UnauthorizedAccessException or InvalidDataException or IOException) { Console.WriteLine($"Error reading executable: {ex.Message}"); } ``` -------------------------------- ### Search for All Pattern Matches Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/isearcher-interface.md Scans the entire memory region and returns an array of all matches. Returns an empty array if no matches are found. ```csharp var allNops = searcher.SearchMany("90"); Console.WriteLine($"Found {allNops.Length} NOP instructions"); ``` -------------------------------- ### FfxivVersionChecker Static Class Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/INDEX.md Provides functionality to extract version information from FFXIV game files. ```APIDOC ## FfxivVersionChecker Static Class ### Description Provides functionality to extract version information from FFXIV game files. ### Methods - `GetVersion(FileInfo)`: Extracts the game version directly from the .data file. - `GetVersionPattern(FileInfo)`: Extracts the game version using pattern matching on the .data file. ### Return Value - Returns a tuple containing version information. ``` -------------------------------- ### Error Handling for PE File Parsing Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/errors.md Illustrates comprehensive error handling for parsing PE (Portable Executable) files. It catches specific exceptions like FileNotFoundException, InvalidDataException, and UnauthorizedAccessException. ```csharp try { var peInfo = PeHeaderParser.GetPeHeaders(filePath); var textSection = peInfo.TextSection; if (textSection == null) { Console.WriteLine("No .text section found"); return; } // Use textSection.Value... } catch (FileNotFoundException) { Console.WriteLine($"File not found: {filePath}"); } catch (InvalidDataException) { Console.WriteLine("File is not a valid PE executable"); } catch (UnauthorizedAccessException) { Console.WriteLine("Access denied"); } ``` -------------------------------- ### Validate FFXIV Version Before Patching Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/ffxiv-version-checker.md Checks if the FFXIV executable is running a supported version before proceeding with a patch. It compares the detected version against a predefined supported version string. ```csharp var exePath = new FileInfo(@"ffxiv_dx11.exe"); var (version, date) = FfxivVersionChecker.GetVersionPattern(exePath); const string SupportedVersion = "2024"; if (version != SupportedVersion) { Console.WriteLine($"Unsupported version {version}. Expected {SupportedVersion}"); return; } Console.WriteLine("Version check passed. Proceeding with patch."); ``` -------------------------------- ### ParseVersion Internal Helper Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/ffxiv-version-checker.md Parses version bytes to extract version and date components. Returns ('0', '0') if parsing fails. Marked with AggressiveInlining for performance. ```csharp private static (string Version, string Date) ParseVersion(ReadOnlySpan version) ``` -------------------------------- ### Using UnmanagedMemoryManager with Memory-Mapped Files Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/unmanaged-memory-manager.md Shows how to use UnmanagedMemoryManager with memory-mapped files. This allows pattern searching within large files without loading the entire content into managed memory. Ensure proper disposal of MemoryMappedFile and its accessor. ```csharp unsafe { using (var mmf = MemoryMappedFile.CreateFromFile("data.bin")) using (var accessor = mmf.CreateViewAccessor()) { // Get unsafe pointer accessor.SafeMemoryMappedViewHandle.AcquirePointer(out byte* ptr); try { var manager = new UnmanagedMemoryManager(ptr, (int)mmf.CreateViewAccessor().Capacity); var scanner = new PatternSearcher(manager.Memory, IntPtr.Zero); var matches = scanner.SearchMany("90"); } finally { accessor.SafeMemoryMappedViewHandle.ReleasePointer(); } } } ``` -------------------------------- ### FfxivVersionChecker Source: https://github.com/nt153133/llama.memory/blob/master/Llama.Memory/README.md Provides methods for checking the version of the FFXIV executable. ```APIDOC ## FfxivVersionChecker Methods ### `(string Version, string Date) GetVersion(FileInfo ffxivExe)` Reads the expected version marker directly from the data section of the FFXIV executable. - **ffxivExe** (FileInfo) - Information about the FFXIV executable file. ### `(string Version, string Date) GetVersionPattern(FileInfo ffxivExe)` Locates the version marker using pattern scanning, then reads and parses it from the FFXIV executable. - **ffxivExe** (FileInfo) - Information about the FFXIV executable file. ``` -------------------------------- ### Accessing PE Header Text Section Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pe-header-parser.md Demonstrates how to retrieve and display information about the .text section from a PeHeaderInfo object. ```csharp var textSection = peInfo.TextSection; if (textSection.HasValue) { var section = textSection.Value; Console.WriteLine($"Code section: RVA 0x{section.VirtualAddress:X}, " + $"Size 0x{section.SizeOfRawData:X}, " + $"File offset 0x{section.PointerToRawData:X}"); } ``` -------------------------------- ### ISearcher.Search(string) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/isearcher-interface.md Scans the entire memory region for the first match of a pattern. ```APIDOC ## Search(string) ### Description Scans the entire memory region for the first match of a pattern. ### Method `IntPtr Search(string pattern)` ### Parameters #### Path Parameters - **pattern** (`string`) - Required - Space-separated hex bytes with optional post-match commands ### Returns `IntPtr` — transformed address of the first match (with `ImageBase` applied), or `IntPtr.Zero` if no match. ### Remarks See "Pattern Format" section below. ### Example ```csharp var result = searcher.Search("48 8B 0D ?? ?? ?? ??"); if (result != IntPtr.Zero) { Console.WriteLine($"Found mov rcx, [rip+disp] at 0x{result.ToInt64():X}"); } ``` ``` -------------------------------- ### FfxivVersionChecker Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/types.md Provides static methods for extracting version information from FFXIV executables. ```APIDOC ## FfxivVersionChecker ### Description Static utility for FFXIV executable version extraction. ### Methods #### GetVersion - **Signature**: `static (string Version, string Date) GetVersion(FileInfo ffxivExe)` - **Description**: Extracts the version and date from the .data section of an FFXIV executable. - **Parameters**: - `ffxivExe` (FileInfo) - Information about the FFXIV executable file. #### GetVersionPattern - **Signature**: `static (string Version, string Date) GetVersionPattern(FileInfo ffxivExe)` - **Description**: Extracts the version and date from an FFXIV executable via pattern scanning. - **Parameters**: - `ffxivExe` (FileInfo) - Information about the FFXIV executable file. ``` -------------------------------- ### ISearcher.SearchMany(string) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/isearcher-interface.md Scans the entire memory region and returns every match of a pattern. ```APIDOC ## SearchMany(string) ### Description Scans the entire memory region and returns **every** match of a pattern. ### Method `IntPtr[] SearchMany(string pattern)` ### Parameters #### Path Parameters - **pattern** (`string`) - Required - Space-separated hex bytes and post-match commands ### Returns `IntPtr[]` — array of all matches (transformed) in ascending address order. Empty array if no matches (never null). ### Remarks Significantly slower than `Search(string)` because no early exit is possible. Budget accordingly for large (40+ MB) regions. ### Example ```csharp var allNops = searcher.SearchMany("90"); Console.WriteLine($"Found {allNops.Length} NOP instructions"); ``` ``` -------------------------------- ### PatternSearcher(Span, IntPtr) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Creates a scanner from a stack or heap-allocated span. The span is copied to an internal Memory for storage. ```APIDOC ## PatternSearcher(Span, IntPtr) ### Description Creates a scanner from a stack or heap-allocated span. The span is copied to an internal Memory for storage. ### Parameters #### Path Parameters - **assemblyData** (Span) - Required - Span view of data to scan - **imageBase** (IntPtr) - Required - Virtual address offset for results ``` -------------------------------- ### Wrap Raw Memory Allocation Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/unmanaged-memory-manager.md Shows how to wrap a raw memory allocation using UnmanagedMemoryManager. This allows treating the unmanaged memory as a managed Span for easier manipulation and integration with other libraries like PatternSearcher. ```csharp unsafe { const int BufferSize = 65536; var ptr = (byte*)Marshal.AllocHGlobal(BufferSize); try { var manager = new UnmanagedMemoryManager(ptr, BufferSize); var memory = manager.Memory; // Fill memory File.OpenRead("data.bin").ReadExactly(memory.Span); // Scan var scanner = new PatternSearcher(memory, IntPtr.Zero); var result = scanner.Search("?? AA BB ??"); } finally { Marshal.FreeHGlobal((IntPtr)ptr); } } ``` -------------------------------- ### Parse PE File Headers Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pe-header-parser.md Parses the PE headers from an executable file. This is the first step in extracting PE file information. ```csharp var peInfo = PeHeaderParser.GetPeHeaders("target.exe"); ``` -------------------------------- ### PatternSearcher Constructors Source: https://github.com/nt153133/llama.memory/blob/master/README.md Constructors for the PatternSearcher class, used to initialize the searcher with assembly data and an image base. ```APIDOC ## PatternSearcher Constructors ### `PatternSearcher(byte[] assemblyData, IntPtr imageBase)` Initializes a new instance of the `PatternSearcher` class with byte array assembly data. ### `PatternSearcher(Span assemblyData, IntPtr imageBase)` Initializes a new instance of the `PatternSearcher` class with a span of byte assembly data. ### `PatternSearcher(ref ReadOnlySpan assemblyData, IntPtr imageBase)` Initializes a new instance of the `PatternSearcher` class with a read-only span of byte assembly data. ### `PatternSearcher(ReadOnlySpan assemblyData, IntPtr imageBase)` Initializes a new instance of the `PatternSearcher` class with a read-only span of byte assembly data. ### `PatternSearcher(Memory assemblyData, IntPtr imageBase)` Initializes a new instance of the `PatternSearcher` class with memory of byte assembly data. ``` -------------------------------- ### Pattern Syntax Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Defines the syntax for creating patterns used in searching, including hex bytes, wildcards, and post-match commands for transforming match results. ```APIDOC ## Pattern Syntax Patterns are space-separated tokens. Each token is either a hex byte or a wildcard. ### Hex Bytes Two-character hexadecimal values (case-insensitive): - `48` — the byte 0x48 - `8B` or `8b` — the byte 0x8B - `FF` — the byte 0xFF ### Wildcards - `??` — matches any single byte - `?` — matches any single byte (equivalent to `??`) - `4?` — matches 0x40–0x4F (lower nibble wildcard) - `?F` — matches 0x0F, 0x1F, 0x2F, …, 0xFF (upper nibble wildcard) ### Post-Match Commands After the hex bytes, append zero or more commands separated by spaces. Commands are executed sequentially to transform the raw match address before returning. | Command | Operand | Effect | |---------|---------|--------| | `Add` | `` | Advance the result pointer forward by the operand (decimal or hex, e.g., `Add 3` or `Add 0x10`) | | `Sub` | `` | Move the result pointer backward by the operand | | `Read8` | — | Dereference and return the byte value at the result pointer | | `Read16` | — | Dereference and return the little-endian `Int16` at the result pointer | | `Read32` | — | Dereference and return the little-endian `Int32` at the result pointer | | `Read64` | — | Dereference and return the little-endian `Int64` at the result pointer | | `TraceRelative` | — | Read the `Int32` at the result pointer; return `pointer + 4 + value`. Used for RIP-relative lea/mov. | | `TraceCall` | — | Read the `Int32` at `pointer + 1`; return `pointer + 5 + value`. Used for E8 call instructions. | ### Pattern Examples **Simple pattern:** ``` 48 8B 0D ?? ?? ?? ?? ``` Matches `mov rcx, [rip + disp32]`. **Pattern with Add:** ``` 48 8D 0D ?? ?? ?? ?? Add 3 TraceRelative ``` Matches a LEA instruction, advances past the opcode and displacement, then resolves the RIP-relative reference. **Pattern with Read:** ``` 48 C7 45 F8 ?? ?? ?? ?? Read32 Add 8 ``` Matches a MOV instruction, reads the DWORD operand, then advances by 8. ``` -------------------------------- ### Search(string, IntPtr, int) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Scans a specified bounded range of the buffer for the first match of a pattern. This method is useful for continuing searches from a previous match or limiting the search scope. ```APIDOC ## Search(string, IntPtr, int) ### Description Scans a bounded range of the buffer for the first match. ### Method `public IntPtr Search(string pattern, IntPtr start, int maxSearchLength)` ### Parameters #### Path Parameters - **pattern** (string) - Required - Space-separated hex bytes and post-match commands - **start** (IntPtr) - Required - Zero-based buffer offset to begin scanning (not an RVA) - **maxSearchLength** (int) - Required - Maximum number of bytes to examine from `start` ### Response #### Success Response (IntPtr) - Returns the transformed address of the first match within the specified range, or `IntPtr.Zero` if no match is found. ### Request Example ```csharp // Find the second occurrence by continuing from the first match var first = scanner.Search("AA BB CC"); if (first != IntPtr.Zero) { var next = scanner.Search("AA BB CC", first + 1, int.MaxValue); } ``` ``` -------------------------------- ### Utilities: GetByte Extension Method Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/types.md Parses a 2-character hex token to its corresponding byte value. This method is part of the Utilities static class. ```csharp public static byte GetByte(this ReadOnlySpan tok) { ... } ``` -------------------------------- ### Wrap Synchronous Search in Task.Run Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/configuration.md When in an async context, wrap synchronous Llama.Memory search operations in Task.Run to avoid blocking the calling thread. ```csharp // Async context: wrap in Task.Run await Task.Run(() => searcher.Search(pattern)); ``` -------------------------------- ### GetVersion Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/ffxiv-version-checker.md Reads the FFXIV executable and extracts the embedded revision and date values using direct file I/O. Returns ('0', '0') if the file is invalid or the marker cannot be found. ```APIDOC ## GetVersion(FileInfo) ### Description Reads the FFXIV executable and extracts the embedded revision and date values using direct file I/O. ### Method `public static (string Version, string Date) GetVersion(FileInfo ffxivExe)` ### Parameters #### Path Parameters - **ffxivExe** (`FileInfo`) - Required - Target `ffxiv_dx11.exe` file to inspect ### Returns Tuple `(string Version, string Date)` - `Version` — numeric revision parsed from the version marker (e.g., "2024") - `Date` — date/token segment from the marker (e.g., "20240101") - Both return "0" if the file doesn't exist, PE headers are invalid, or the marker cannot be found/parsed ### Throws - `NullReferenceException` — ffxivExe is null - `UnauthorizedAccessException` — process lacks read permission - `FileNotFoundException` — executable path becomes unavailable between existence check and open - `DirectoryNotFoundException` — a segment of the executable path cannot be found - `PathTooLongException` — executable path exceeds platform maximum - `NotSupportedException` — executable path format is invalid - `IOException` — I/O error while opening, seeking, or reading - `EndOfStreamException` — stream ends before buffers are filled - `ObjectDisposedException` — stream is disposed before read completes - `InvalidDataException` — PE headers are malformed or missing expected structure ### Example ```csharp var exePath = new FileInfo(@"C:\Program Files\FFXIV\ffxiv_dx11.exe"); var (version, date) = FfxivVersionChecker.GetVersion(exePath); if (version != "0") { Console.WriteLine($"FFXIV Version: {version}, Date: {date}"); } else { Console.WriteLine("Failed to extract version"); } ``` ``` -------------------------------- ### SearchMany(string) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/pattern-searcher.md Scans the entire buffer and returns an array of all matches found for the given pattern. The pattern is a string of space-separated hex bytes, optionally including post-match commands. ```APIDOC ## SearchMany(string) ### Description Scans the entire buffer and returns every match of the pattern. ### Method `public IntPtr[] SearchMany(string pattern)` ### Parameters #### Path Parameters - **pattern** (string) - Required - Space-separated hex bytes and post-match commands ### Response #### Success Response (IntPtr[]) - Returns an array of every match (transformed), in ascending order. Returns an empty array if no matches are found. ### Throws - `ArgumentNullException` — pattern is null - `ArgumentException` — pattern syntax is invalid ### Request Example ```csharp var allMatches = scanner.SearchMany("90"); // Find all NOP instructions foreach (var match in allMatches) { Console.WriteLine($"NOP at 0x{match.ToInt64():X}"); } ``` ``` -------------------------------- ### ISearcher.Search(string, IntPtr, int) Source: https://github.com/nt153133/llama.memory/blob/master/_autodocs/api-reference/isearcher-interface.md Scans a bounded sub-range of the memory region. ```APIDOC ## Search(string, IntPtr, int) ### Description Scans a bounded sub-range of the memory region. ### Method `IntPtr Search(string pattern, IntPtr start, int maxSearchLength)` ### Parameters #### Path Parameters - **pattern** (`string`) - Required - Space-separated hex bytes and post-match commands - **start** (`IntPtr`) - Required - Zero-based buffer offset to begin scanning (not an RVA) - **maxSearchLength** (`int`) - Required - Maximum number of bytes to examine from `start` ### Returns `IntPtr` — transformed address of the first match within the range, or `IntPtr.Zero`. ### Remarks Useful for incremental scanning or finding subsequent occurrences. The `start` parameter is a **zero-based buffer offset**, not an absolute address with `ImageBase` applied. ### Example ```csharp // Find all occurrences var first = searcher.Search("90 90 90"); if (first != IntPtr.Zero) { var next = searcher.Search("90 90 90", first + 1, int.MaxValue); if (next != IntPtr.Zero) { Console.WriteLine("Found second occurrence"); } } ``` ``` -------------------------------- ### PatternSearcher Search Methods Source: https://github.com/nt153133/llama.memory/blob/master/README.md Methods for searching within the assembly data using patterns. ```APIDOC ## PatternSearcher Search Methods ### `IntPtr Search(string pattern)` Searches for the first occurrence of a pattern and returns its transformed match. Returns `IntPtr.Zero` if not found. ### `IntPtr Search(string pattern, IntPtr start, int maxSearchLength)` Searches for the first occurrence of a pattern within a specified sub-range of the raw buffer. Returns the transformed match or `IntPtr.Zero`. - **`start`** (IntPtr) - The zero-based buffer offset to start the search from. - **`maxSearchLength`** (int) - The maximum number of bytes to search. ### `IntPtr[] SearchMany(string pattern)` Searches for all occurrences of a pattern and returns an array of all transformed matches. ### `IntPtr[] Search(string[] patterns)` Searches for the first occurrence of each pattern in the provided array and returns an array of transformed matches. The results are index-aligned with the input patterns. ### `IntPtr[][] SearchMany(string[] patterns)` Searches for all occurrences of each pattern in the provided array and returns a 2D array of all transformed matches. The results are index-aligned with the input patterns. ```