From 0aba8653f4b585165d06714be32a0560ec5d5341 Mon Sep 17 00:00:00 2001 From: blasty Date: Thu, 23 Jul 2026 01:53:36 +0200 Subject: app: 'a' — make string literal in the listing (M4 richness) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- server/patch_server.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'server/patch_server.py') 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 @@ -185,6 +185,41 @@ def file_regions() -> dict: return {"regions": out} +@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( -- cgit v1.3.1-sl0p