Vector35 / binaryninja-api

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

Xref widget should show xrefs to the entire range covered by the child structure if a field of a structure is a structure itself #5502

Open comex opened 1 month ago

comex commented 1 month ago

Version and Platform (required):

Bug Description: Let's say I have a struct outer that contains another struct inner:

struct inner {
    int x, y;
};
struct outer {
    char pad[0x10];
    struct inner inner;
};

Some code takes a pointer to the outer struct and accesses one of the fields of the inner struct. After marking up types, the HLIL looks like this:

000007ec      do_something_with(outer->inner.x)
000007f8      do_something_with(outer->inner.y)

If I go to the types view and look at cross-references to the x and y fields of inner, I see one reference to each, as expected.

But if I look at xrefs to the inner field of outer, I see only the reference to outer->inner.x, not outer->inner.y.

It seems like Binary Ninja only shows references to the first field of the inner struct - in other words, references that point to the beginning of the inner field.

You don't actually need nested structs to encounter this problem. The same behavior occurs if a field is a primitive type but the reference points partway through it. For example, if I change struct outer's definition to:

struct outer {
    char pad[0x10];
    int64_t inner; // changed to `int64_t` from `struct inner`
};

then the HLIL becomes:

000007ec      do_something_with(outer->inner.d)
000007f8      do_something_with(outer->inner:4.d)

but again, listing references to inner shows only the first one.

Steps To Reproduce:

Open this binary and go to function foo. Add types as described earlier.

Expected Behavior: I want the xrefs view to list all references to any of the inner struct fields.

In other words, whenever the HLIL output contains the field name, it should show up as a reference to that field.

xusheng6 commented 1 month ago

I think our underlying xref tracking mechanism has no bug, the problem is the UI and the presentation. When you click the outer.inner in the types view, what the xref widget is really doing is pulling all the xrefs to the start of the inner, which, as you have figured out, only collects xrefs to the x field. This is because the code is written and tested with scalar structure members in mind, and I did not consider the case of a compound structure member.

I guess the fix is relatively easy, when you select a structure member, and if the member is itself a structure, then we should collect all xrefs to the entire range of the member, not only the start

xusheng6 commented 1 month ago

Right now we only have the API get_code_refs_for_type_field which, for a given structure and an offset, returns all the code refs to it. We need a new API that can return all the refs into the structure, not a single offset

xusheng6 commented 1 month ago

@comex Thanks for filing the bug report and formulating it in very readable way, and good catch for figuring out the likely cause of the bug, along with providing the binary. These make triaging this issue much easier, which is indeed a little complex