diff options
| author | blasty <blasty@local> | 2026-07-23 01:53:36 +0200 |
|---|---|---|
| committer | blasty <blasty@local> | 2026-07-23 01:53:36 +0200 |
| commit | 0aba8653f4b585165d06714be32a0560ec5d5341 (patch) | |
| tree | 6f66c42fb8f0067dd1d94880ade26932293aa342 /server/patch_server.py | |
| parent | perf: derive segment map from file_regions, not survey_binary (hex open ~3400x) (diff) | |
| download | ida-tui-0aba8653f4b585165d06714be32a0560ec5d5341.tar.gz ida-tui-0aba8653f4b585165d06714be32a0560ec5d5341.tar.xz ida-tui-0aba8653f4b585165d06714be32a0560ec5d5341.zip | |
app: 'a' — make string literal in the listing (M4 richness)
IDA's 'A' key. New make_string server tool (ida_bytes.create_strlit, auto-length
to the terminator, undefines items in the way first, returns size + decoded
contents). Program.make_string wraps it; 'a' on a listing head routes through
the existing edit plumbing (EditItemRequested kind=string -> _do_edit_item ->
make_string -> bump_items -> reopen).
Verified: make_string at a .rodata addr creates the literal and IDA auto-names
it (aUsage for 'usage'). New listing_make_string scenario drives it through the
UI; listing suite 15/0. Needs a supervisor restart.
Diffstat (limited to 'server/patch_server.py')
| -rw-r--r-- | server/patch_server.py | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/server/patch_server.py b/server/patch_server.py index 4b2661f..e283cab 100644 --- a/server/patch_server.py +++ b/server/patch_server.py @@ -187,6 +187,41 @@ def file_regions() -> dict: @tool @idasync +def make_string( + addr: Annotated[str, "Address of the string start"], + length: Annotated[int, "Length in bytes (0 = auto-detect to the terminator)"] = 0, + kind: Annotated[str, "String kind: c | c16 | c32 | pascal"] = "c", +) -> dict: + """Create a string literal at ``addr`` (IDA's 'A'). ``length`` 0 auto-detects + to the terminator. Undefines any items in the way first, like the UI does. + Returns the created byte size and the decoded contents.""" + import ida_bytes + import ida_nalt + + ea = parse_address(addr) + strtype = { + "c": ida_nalt.STRTYPE_C, + "c16": ida_nalt.STRTYPE_C_16, + "c32": ida_nalt.STRTYPE_C_32, + "pascal": ida_nalt.STRTYPE_PASCAL, + }.get(str(kind).lower(), ida_nalt.STRTYPE_C) + n = max(int(length), 0) + # Free any existing item(s) so create_strlit can carve the literal. + ida_bytes.del_items(ea, ida_bytes.DELIT_SIMPLE, n if n > 0 else 1) + ok = bool(ida_bytes.create_strlit(ea, n, strtype)) + if not ok: + return {"addr": addr, "ok": False, "error": "create_strlit failed"} + size = int(ida_bytes.get_item_size(ea)) + try: + raw = ida_bytes.get_strlit_contents(ea, -1, strtype) + text = raw.decode("utf-8", "replace") if raw else "" + except Exception: + text = "" + return {"addr": addr, "ok": True, "size": size, "text": text} + + +@tool +@idasync def read_raw( addr: Annotated[str, "Start address (hex or name)"], size: Annotated[int, "Number of bytes to read"], |
