binaryninja-api icon indicating copy to clipboard operation
binaryninja-api copied to clipboard

Unable to change structure member type using API.

Open notdeclan opened this issue 1 year ago • 1 comments

Version and Platform (required):

  • Binary Ninja Version: Tested on Enterprise 4.1.5747 and 4.0.5336.
  • OS: Mac OS X
  • OS Version: 14
  • CPU Architecture: AARCH64

Bug Description: Unable to change type of inlined StructureTypes present within already defined StructureType.

This was discovered when attempting to fix up a load of inline types which are present from DWARF debug info. (Likely related to: https://github.com/Vector35/binaryninja-api/issues/5328).

Steps To Reproduce: Can recreate issue by creating the following two types within a new BinaryView:

struct test_struct_a __packed
{
    int32_t lol;
    int32_t lol_b;
    struct
    {
        int32_t a;
        int32_t b;
    } inlined_test_struct_b;
};
struct test_struct_b __packed
{
    int32_t a;
    int32_t b;
};

To demonstrate issue with API:

original = bv.types['test_struct_a']
mutable = original.mutable_copy()
mutable.replace(mutable.index_by_offset(0x8), bv.types['test_struct_b'], 'replaced_test_struct_b')
bv.define_user_type('test_struct_a', mutable)

The following code will rename the "inlined_test_struct_b" member to "replaced_test_struct_b", but the type remains inlined and does not change. The same behaviour is exhibited when also replacing inlined EnumerationTypes.

I have also completed further testing, including trying mutable.remove followed by mutable.insert/mutable.add_member_at_offset, which results in the same unexpected behaviour.

Expected Behavior: The type of "replaced_test_struct_b" should be test_struct_b. However it remains the inlined type.

The resulting final struct should resemble:

struct test_struct_a __packed
{
    int32_t lol;
    int32_t lol_b;
    struct test_struct_b replaced_test_struct_b;
};

Binary: Not applicable, can be replicated on empty BinaryView.

notdeclan avatar Aug 05 '24 13:08 notdeclan

So with further testing, I was able to achieve the expected behaviour by using the Type.registered_name field.

>>> original = bv.types['test_struct_a']
... mutable = original.mutable_copy()
... mutable.replace(mutable.index_by_offset(0x8), bv.types['test_struct_b'].registered_name, 'replaced_test_struct_b')
... bv.define_user_type('test_struct_a', mutable)
... 

Not sure if this issue is just due to my API misusage?

notdeclan avatar Aug 06 '24 14:08 notdeclan