Lua:AOBScanUnique
function AOBScanUnique(AOBString, ProtectionFlags OPTIONAL, AlignmentType OPTIONAL, AlignmentParam HALFOPTIONAL)
Scans the entire process memory for a byte pattern and returns the address if exactly one unique match is found.
Returns: The address as an integer if a unique match is found, or nil if no match or multiple matches are found.
Note: Unlike AOBScan, this function returns a single integer address (or nil) instead of a StringList, so there's no need to call destroy().
Implementation: This function is equivalent to calling AOBScanModuleUnique("", AOBString, ...) with an empty module name.
Contents
Function Parameters
Parameter | Type | Description |
---|---|---|
AOBString | string | A hex byte pattern with space/comma/dash separators. Use ?? or * for full-byte wildcards. Supports nibble wildcards like 7? or ?A |
ProtectionFlags | string | Optional. Memory protection filter. Default: "*X*W*C" (scan all memory regions) |
AlignmentType | integer | Optional. Alignment mode: 0=None, 1=Divisible, 2=Last digits. Default: 0 |
AlignmentParam | string | Optional. Hex value for alignment checking. Default: "1" |
Protection Flags
The ProtectionFlags parameter filters memory regions based on protection attributes:
Syntax: Prefix each flag with:
- + = Region MUST have this flag set
- - = Region MUST NOT have this flag set
- * = Don't care (default)
Flags:
- X = Executable
- W = Writable
- C = Copy On Write
- D = Dirty (macOS only)
Examples:
"+X" All executable memory (recommended for code patterns) "+W-C" Writable memory excluding copy-on-write "+X-W-C" Readonly executable memory (code sections) "" Uses default "*X*W*C" (scan all memory)
Alignment Parameters
AlignmentType values:
- 0 = fsmNotAligned - No alignment check (default)
- 1 = fsmAligned - Address must be divisible by AlignmentParam
- 2 = fsmLastDigits - Address must end with specific hex digits
AlignmentParam:
- Interpreted as a hexadecimal value
- For AlignmentType=1: Alignment boundary (e.g., "10" = 16-byte aligned, "4" = 4-byte aligned)
- For AlignmentType=2: Required ending hex digits (e.g., "00" = addresses ending in ...00)
Usage Examples
Basic unique scan:
local address = AOBScanUnique("48 8B 05 ?? ?? ?? 89") if address then print(string.format("Found at: %X", address)) -- Use address directly for reading/writing writeBytes(address, 0x90, 0x90, 0x90) else print("Pattern not found or not unique") end
Scan executable memory only (faster):
local address = AOBScanUnique("55 8B EC 83 EC", "+X") if address then print("Function found at: " .. address) end
With alignment checking:
local address = AOBScanUnique("FF 15 ?? ?? ?? ??", "+X", 1, "10") -- Only matches on 16-byte aligned addresses
Register the result as a symbol:
local addr = AOBScanUnique("48 89 5C 24 ?? 57", "+X") if addr then registerSymbol("MyFunction", addr) print("Registered MyFunction at " .. addr) end
Conditional execution based on pattern:
local patchAddr = AOBScanUnique("74 ?? 8B 45", "+X") if patchAddr then -- Apply patch only if pattern is unique writeBytes(patchAddr, 0xEB) -- Change JE to JMP print("Patched at: " .. patchAddr) else print("ERROR: Pattern not unique or not found!") return false end
Find and calculate relative offset:
local callAddr = AOBScanUnique("E8 ?? ?? ?? ??", "+X") if callAddr then local offset = readInteger(callAddr + 1) local target = callAddr + 5 + offset print(string.format("Call target: %X", target)) end
Return Value
- Success (unique match): Returns the address as an integer
- Failure: Returns nil in these cases:
- Pattern not found anywhere in memory
- Multiple matches found (not unique)
- Empty AOBString parameter
Performance Tips
- Use +X protection flag when scanning for code to dramatically reduce scan time
- For module-specific scans, use AOBScanModuleUnique instead (much faster)
- The scan stops after finding more than one match to ensure uniqueness
- More specific patterns (fewer wildcards) are faster and more likely to be unique
When to Use AOBScanUnique
Use AOBScanUnique when:
- You expect exactly one match in the entire process
- You want automatic validation that the pattern is unique
- You need a simple integer address for immediate use
- You're looking for a specific global function or unique code sequence
Use AOBScan when:
- You expect or want multiple matches
- You need to analyze all occurrences of a pattern
- The pattern might appear in multiple locations
Comparison with Related Functions
Function | Return Type | Scope | Uniqueness |
---|---|---|---|
AOBScanUnique | Integer or nil | All memory | Yes (returns nil if multiple matches) |
AOBScanModuleUnique | Integer or nil | Single module | Yes (returns nil if multiple matches) |
AOBScan | StringList or nil | All memory | No (returns all matches) |
AOBScanModule | StringList or nil | Single module | No (returns all matches) |
Common Pitfalls
Pattern too generic:
-- This will likely fail because "90 90" appears many times local addr = AOBScanUnique("90 90") -- Returns nil (multiple matches)
Solution - Make pattern more specific:
local addr = AOBScanUnique("90 90 90 C3 48 89 5C") -- More unique context
Not checking for nil:
-- WRONG - will crash if pattern not found local addr = AOBScanUnique("48 8B") writeBytes(addr, 0x90) -- ERROR if addr is nil!
Solution - Always check return value:
local addr = AOBScanUnique("48 8B") if addr then writeBytes(addr, 0x90) else print("Pattern not found or not unique") end
See Also
- AOBScanModuleUnique - Scan within a specific module (faster)
- AOBScan - Scan all memory and return all matches
- registerSymbol - Register found addresses as symbols
- writeBytes - Write bytes to found addresses