Skip to main content
Pattern scanning (also called signature scanning) is essential for locating functions and data structures in memory when addresses change between versions or sessions.

Signature Scanning

Signature scanning allows you to search for byte patterns with wildcards, making it perfect for finding functions even after game updates.

Godmode Example

This real-world example from the README demonstrates scanning for a function signature and patching it to implement godmode in a game:
use libmem::*;

fn godmode() -> Option<()> {
    let game_process = find_process("game_linux64")?;
    let client_module = find_module_ex(&game_process, "libclient.so")?;

    let fn_update_health = sig_scan_ex(
        &game_process,
        "55 48 89 E5 66 B8 ?? ?? 48 8B 5D FC",
        client_module.base,
        client_module.size,
    )?;
    println!(
        "[*] Signature scan result for 'update_health' function: {}",
        fn_update_health
    );

    let shellcode = assemble_ex("mov rbx, 1337; mov [rdi], rbx; ret", Arch::X64, 0)?;
    write_memory_ex(&game_process, fn_update_health + 8, &shellcode.as_slice())?;
    println!("[*] Patched 'update_health' function to always set health to 1337!");

    Some(())
}

fn main() {
    godmode();
}

How It Works

1

Find the Target Process

Use find_process to locate the running game process by name.
2

Locate the Module

Find the specific module (DLL/SO) that contains the function you’re looking for using find_module_ex.
3

Scan for the Signature

Use sig_scan_ex with a byte pattern. The ?? wildcards match any byte, allowing the pattern to work even if some bytes vary between versions.
4

Patch the Function

Once found, assemble custom shellcode and write it to the function, effectively modifying its behavior.

Pattern Syntax

Signature Format

Signatures use hexadecimal bytes separated by spaces:
  • 55 48 89 E5 - Exact bytes that must match
  • ?? - Wildcard that matches any byte
  • Example: "DE AD ?? ?? 13 37" matches DE AD followed by any 2 bytes, then 13 37

Data Scanning

For scanning exact data without wildcards, use LM_DataScan or LM_DataScanEx:
lm_byte_t pattern[] = {0xDE, 0xAD, 0xBE, 0xEF};
lm_address_t result = LM_DataScan(pattern, sizeof(pattern), start_addr, scan_size);

Pattern Scanning vs Mask Scanning

Libmem also supports pattern scanning with explicit masks using LM_PatternScan:
lm_byte_t pattern[] = {0xDE, 0xAD, 0x00, 0x00, 0x13, 0x37};
lm_string_t mask = "xx??xx";
lm_address_t result = LM_PatternScan(pattern, mask, start_addr, scan_size);
In the mask:
  • x means the byte must match exactly
  • ? means the byte is a wildcard

Best Practices

Choose signatures that are unlikely to appear elsewhere in memory. Include enough context bytes while keeping wildcards minimal.
Always scan within a specific module’s range rather than the entire process to improve performance and avoid false positives.
Always check if the scan returned LM_ADDRESS_BAD (C) or None (Rust/Python) before using the result.
Game updates may change function code. Keep signatures flexible with strategic wildcards or be prepared to update them.

Next Steps

Hook Functions

Learn to hook and intercept function calls

Memory API

Explore all memory scanning functions

Build docs developers (and LLMs) love