Vector35 / binaryninja-api

Public API, examples, documentation and issues for Binary Ninja
https://binary.ninja/
MIT License
928 stars 209 forks source link

Regression in DataRenderer string representation (can't double-click) #4717

Closed fuzyll closed 9 months ago

fuzyll commented 1 year ago

Version and Platform (required):

Bug Description:

I have a DataRenderer for CFString in Mach-O files and until recently, when I'd double click at the C string representation, Binary Ninja would take me there. Did we change this?

I am using an instruction text token:

class CFStringRenderer(DataRenderer):
    """Tell the Linear View how to render CoreFoundation string structures
    """

    def __init__(self):
        DataRenderer.__init__(self)

    def perform_is_valid_for_data(self, ctxt, view, addr, type, context):
        for name in CFSTR_TYPE_NAMES:
            if DataRenderer.is_type_of_struct_name(type, name, context):
                return True
        return False

    def perform_get_lines_for_data(self, ctxt, view, addr, type, prefix, width, context):
        cfstr = CFString(view, addr)
        cfstr.undefine_auto_symbol()
        token = InstructionTextToken(InstructionTextTokenType.StringToken, cfstr.escaped, cfstr.cstr)
        prefix.append(token)
        return [DisassemblyTextLine(prefix, addr)]

CFStringRenderer().register_type_specific()

You can repro with the above DataRenderer and the Objective-C workflow. The above renderer is missing a global var that you can replace with this:

CFSTR_TYPE_NAMES = ['CFString']

Steps To Reproduce: An easy repro is to open a Mach-O binary that has CFStrings and analyze it with the Obj-C workflow.

Expected Behavior: Double-clicking the rendered CFString C string should take you to the C string like in 3.4 stable.

Additional Information: Reported by noar on Slack.

negasora commented 9 months ago

The provided DataRenderer is breaking on cfstr = CFString(view, addr) since CFString isn't defined anywhere

0cyn commented 9 months ago

Run this as a plugin or script w/ the python workflow enabled on a binary w/ Objective-C to reproduce this bug

from binaryninja import DataRenderer, InstructionTextToken, InstructionTextTokenType, DisassemblyTextLine

class CFString:
    def __init__(self, view, addr):
        self.view = view
        self.addr = addr 
        self.cstr = view.read_int(addr + view.arch.address_size * 2, view.arch.address_size)
        self.escaped = "\"" + ''.join(chr(c) for c in view.get_string_at(view.read_int(addr + view.arch.address_size * 2, view.arch.address_size)).raw) + "\""

    def undefine_auto_symbol(self):
        if self.view.get_symbol_at(self.addr) is None:
            return # ??????
        self.view.undefine_auto_symbol(self.view.get_symbol_at(self.addr))
        self.view.undefine_user_symbol(self.view.get_symbol_at(self.addr))

class CFStringRenderer(DataRenderer):
    """Tell the Linear View how to render CoreFoundation string structures
    """

    def __init__(self):
        DataRenderer.__init__(self)

    def perform_is_valid_for_data(self, ctxt, view, addr, type, context):
        for name in ['CFString']:
            if DataRenderer.is_type_of_struct_name(type, name, context):
                return True
        return False

    def perform_get_lines_for_data(self, ctxt, view, addr, type, prefix, width, context):
        cfstr = CFString(view, addr)
        cfstr.undefine_auto_symbol()
        token = InstructionTextToken(InstructionTextTokenType.StringToken, cfstr.escaped, cfstr.cstr)
        prefix.append(token)
        return [DisassemblyTextLine(prefix, addr)]

CFStringRenderer().register_type_specific()

CoreServicesInternal.zip Structs start at 0x1de65a4c0

negasora commented 9 months ago

Solved by passing cfstr.cstr as the address param instead of value to InstructionTextToken