Vector35 / binaryninja-api

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

`__based` is applied to every level of a multi-level pointer #5896

Open WeiN76LQh opened 1 month ago

WeiN76LQh commented 1 month ago

Version and Platform (required):

Bug Description: I think there's a bug with based pointers. If I create a type from C source, via the UI or the API and I specify a struct with a pointer like so:

struct Foo {
    struct Bar ** __based(var) bar;
};

For some reason Foo always becomes:

struct Foo
{
    struct Bar* __based(var)* __based(var) bar;
};

What I am declaring is a pointer which is a variable relative pointer and it points to a location in memory where there is an absolute pointer. However the type is getting converted to the destination type also being a variable relative pointer.

Doing the following with the API will result in the correct type being created so it seems its just an issue with the code that converts C source to types:

bar = binaryninja.PointerBuilder.pointer_of_width(8, binaryninja.Type.pointer_of_width(8, bv.types["Bar"]))
bar.pointer_base_type = binaryninja.PointerBaseType.RelativeToVariableAddressPointerBaseType
bar.immutable_copy()

No matter how I write the pointer type I can't get it to end up being how I want it; a variable relative pointer to an absolute pointer to a struct of type Bar.

Expected Behavior: __based(var) should not be applied to the 2nd level pointer unless specified like so:

struct Foo {
    struct Bar * __based(var)* __based(var) bar;
};

Additional Information: This does not appear to be a problem with __ptr32. So in the case of the following:

struct Foo {
    struct Bar **__ptr32 bar;
};

The first level pointer will be 4 bytes in size and the second level pointer will be 8 bytes in size.

Doing the following:

struct Foo {
    struct Bar * __ptr32* __ptr32 bar;
};

Results in both the first level and second level pointer being 4 bytes in size.

CouleeApps commented 2 weeks ago

Can confirm this is the case. This is probably due to the __based attribute being decl-based instead of type-based in our clang extensions. This should be pretty easy to fix now that our handleTypeAttribute patches have been implemented. Note to future self: Copy the implementation from bn_ptr_width and bn_location and mark the based status with an AnnotateTypeAttr.

CouleeApps commented 2 weeks ago

As a workaround for this for now, you can split each level of pointer in your type into a separate typedef and apply the annotations where they matter:

typedef Bar* pBar;
struct Foo {
    struct pBar * __based(var) bar;
};