find_bytes returns zero matches for any pattern with a ?? wildcard (IDA 9.x)
Summary
find_bytes returns zero matches for any pattern containing a ?? wildcard, even though the tool advertises wildcard support (docstring: "Search byte patterns (supports ??)", example 48 8B ?? ??). Fully-concrete patterns work correctly; adding a single ?? anywhere makes the same pattern match nothing.
This effectively makes find_bytes unusable for signature-style searches (the main reason to use a masked byte search).
Reproduction
Pick any location whose bytes you know. Search a concrete run, then wildcard exactly one byte that you know is present:
# concrete – 1 match (correct)
find_bytes(["8B 5C 24 24 8B 7C 24 20 3B 46 04 74 0D 39 58 10 74 54"])
-> matches: ["0xd65e1b"], n: 1
# same pattern, one byte wildcarded (the byte there is 0x74) – WRONG
find_bytes(["8B 5C 24 24 8B 7C 24 20 3B 46 04 ?? 0D 39 58 10 74 54"])
-> matches: [], n: 0
# trailing wildcard (the byte there is 0x54) – WRONG
find_bytes(["8B 5C 24 24 8B 7C 24 20 3B 46 04 74 0D 39 58 10 74 ??"])
-> matches: [], n: 0Every ??-containing variant should still match 0xd65e1b; all return n: 0.
Expected
A pattern with ?? wildcards matches the same locations as the concrete pattern, with the wildcarded positions ignored (standard masked search).
Actual
Any ?? (or ?) token → zero matches. Only fully-concrete patterns match.
Environment
- IDA 9.x (the
IDA_GE_90code path) - HTTP transport (unified server,
127.0.0.1:13337/mcp)
Likely root cause
src/ida_pro_mcp/ida_mcp/compat.py, make_bytes_searcher, IDA 9.0+ branch:
if IDA_GE_90:
normalized = " ".join("?" if t in ("??", "?") else t for t in tokens)
def _search_modern(ea: int, max_ea: int) -> int:
return ida_bytes.find_bytes(normalized, ea, range_end=max_ea)
return _search_modern, NoneThe wildcard tokens are collapsed to ? and the string is handed directly to ida_bytes.find_bytes(...). That path does not appear to interpret ? as a wildcard (concrete strings match, wildcarded strings match nothing), so the mask is effectively lost. The legacy branch below it builds an explicit pat/msk and calls ida_bytes.bin_search(...), which is the behaviour the 9.0+ branch should reproduce.
Suggested fix: on the 9.0+ path, build a compiled pattern via ida_bytes.parse_binpat_str(...) / compiled_binpat_vec_t (or reuse the legacy pat/msk + ida_bytes.bin_search) so ?? is honoured as a masked nibble/byte, rather than passing a raw ?-string to find_bytes.
Notes
find_regexmay be a usable workaround, but masked byte search is the natural tool for sigmaker-style patterns.- Concrete (
??-free) searches are unaffected and work correctly.
Source: mrexodia/ida-pro-mcp