aboutsummaryrefslogtreecommitdiffstats
path: root/docs/RPC.md
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-08-07 23:16:30 +0200
committerblasty <blasty@local>2026-08-07 23:16:30 +0200
commit41b3710d5b6f9be24430fd55c46c83f9ae3b8d83 (patch)
treeed3517997a3248310c904c3a57ea053257162ac2 /docs/RPC.md
parentExport findings as markdown (Ctrl+E), and the journal that makes it true (diff)
downloadida-tui-41b3710d5b6f9be24430fd55c46c83f9ae3b8d83.tar.gz
ida-tui-41b3710d5b6f9be24430fd55c46c83f9ae3b8d83.tar.xz
ida-tui-41b3710d5b6f9be24430fd55c46c83f9ae3b8d83.zip
Ctrl+F: search the whole database, by text or by bytes
`/` only ever searched the lines of the view you were in. This adds the search you actually need on a binary: over the entire database, either through the rendered disassembly or through the image. * **text** matches the line as displayed, whitespace-normalised, so `call cs:` finds `call cs:getenv_ptr` (IDA's column padding is not something anyone types). Smartcase; `regex` available over RPC. * **bytes** is IDA's own `find_bytes`, so the pattern language people already know works unchanged: hex pairs, `?` wildcards for a whole byte or one nibble (`48 8? ?? 24`), quoted literals (`"Hello", 0`). Commas, no separators (`488B05C3`) and ragged spacing all normalise. **Which mode you meant is guessed, and the guess is biased on purpose.** `dead`, `add`, `cafe` and `ff` are valid hex AND ordinary things to search for, so a bare hex-looking word stays TEXT; nobody types `48 8b ?? c3` meaning prose. `hex:`/`text:` prefixes and F2 override it. The subtle case is a *typo* in a byte pattern. `48 zz c3` first fell through to a text search and reported "no match" — indistinguishable from "those bytes are not in this binary", which is the most misleading answer a search can give. Now any query whose tokens are all byte-sized is treated as bytes, and a bad token is refused BY NAME. IDA does the same thing quietly (find_bytes answers a malformed pattern with zero hits and no error), so the validation lives in Program.search, not just in the UI. Enter searches, then Enter opens the highlighted hit; the title says which it will do, because a database-wide scan is far too slow to run on every keystroke like the other palettes. Navigation goes to the item head — a byte match can start mid-instruction — and the status names the exact address. Also: the `find` RPC verb and `drive find`, which is the one an agent wants (`drive find '48 8b ?? c3'`). idatui/search.py holds the classification and is pure, so the whole question of "what did they mean" is tested offline: tests/test_search.py, 35 checks, 0.1s. Pilot scenario db_search covers the UI end to end. Full suite: 890 passed, 0 failed, 51.3s.
Diffstat (limited to 'docs/RPC.md')
-rw-r--r--docs/RPC.md28
1 files changed, 28 insertions, 0 deletions
diff --git a/docs/RPC.md b/docs/RPC.md
index 4e736f6..e8dc76b 100644
--- a/docs/RPC.md
+++ b/docs/RPC.md
@@ -102,6 +102,7 @@ predicate so the returned state is final.
| `xrefs` | — | `x`: open the xref picker. |
| `symbols` | `query?` | Ctrl+N palette, optionally pre-typed. |
| `structs` | — | Ctrl+T struct editor. |
+| `find` | `query`, `mode?=auto\|text\|bytes`, `limit?=500`, `regex?`, `case?` | search the **whole database** and return `{mode, query, truncated, hits:[{addr, head, line, func, seg}]}`. `mode=auto` (the default) guesses from the query. A byte pattern that does not parse is an error naming the bad token, never an empty result. |
| `export` | `path?`, `types?=true` | write the session's findings as **markdown** and return `{path, comments, names, types, functions, bytes}`. Not typed through a prompt: the point of this verb is the file it leaves behind, so a driver gets the path back rather than a screenshot. Defaults to `<binary>.findings.md`. See *Findings export* below. |
| `search` | `term`, `direction?=1` | `/` (or `?`) incremental search in the active code view. |
| `select` | `index?` | in an open modal list (xrefs/symbols) choose the highlighted (or nth) item and activate it. |
@@ -132,6 +133,33 @@ symbol file: each one costs a navigation (listing page + decompile) plus two
prompt round-trips, i.e. tens of minutes for a few hundred symbols, where
`rename_many` is one call and a few seconds.
+### Database-wide search
+
+`find` is Ctrl+F: two searches over the whole binary, not the current view.
+
+* **text** matches the rendered disassembly line, whitespace-normalised — so
+ `call cs:` matches `call cs:getenv_ptr`. `regex=true` switches to a Python
+ regex. Smartcase: an all-lowercase query is case-insensitive.
+* **bytes** is IDA's own pattern language via `find_bytes`: hex pairs, `?`
+ wildcards (whole byte *or* one nibble, `48 8? ?? 24`), and quoted literals
+ (`"Hello", 0`). Commas, no separators at all (`488B05C3`) and mixed spacing
+ all normalise to the same pattern.
+
+Mode is guessed unless you say otherwise, and the guess is deliberately biased:
+a hex-looking word (`dead`, `add`, `cafe`) is a *text* search, because those are
+words. A query whose tokens are all byte-sized but one is malformed (`48 zz c3`)
+is treated as bytes and **refused by name** — answering "no match" there would
+be indistinguishable from "not present".
+
+`head` is the item to navigate to (a byte match can land mid-instruction);
+`addr` is the exact match.
+
+```sh
+python -m idatui.drive find 'call cs:'
+python -m idatui.drive find '48 8b ?? c3'
+python -m idatui.drive raw find query='mov e?x' regex=true limit=20
+```
+
### Findings export
`export` writes what the session **worked out** -- comments, names, prototypes