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

Generalized `__ptr_offset` support in the type system

Open alexrp opened this issue 1 year ago • 1 comments

Suppose I have a type hierarchy looking like this:

struct S1ControllerBase __packed
{
    struct `S1ControllerBase::__vftable`* __vftable;
    // ... snip ...
};

struct __data_var_refs `S1ControllerBase::__vftable` __packed
{
    // ... snip ...
};

struct IS1AnimEventHandler __packed
{
    struct `IS1AnimEventHandler::__vftable`* __vftable;
    // ... snip ...
};

struct __data_var_refs `IS1AnimEventHandler::__vftable` __packed
{
    // ... snip ...
};

struct __base(S1ControllerBase, 0) __base(IS1AnimEventHandler, 0x8) S1SocialController __packed
{
    struct `S1SocialController::__vftable`* __vftable;
    struct `S1SocialController::__vftable_IS1AnimEventHandler`* __vftable_IS1AnimEventHandler;
    // ... snip ...
};

struct __base(`S1ControllerBase::__vftable`, 0) __data_var_refs `S1SocialController::__vftable` __packed
{
    // ... snip ...
};

struct __base(`IS1AnimEventHandler::__vftable`, 0) __data_var_refs `S1SocialController::__vftable_IS1AnimEventHandler` __packed
{
    // ... snip ...
};

Now, suppose I have a member function on S1SocialController's vtable for IS1AnimEventHandler. The this pointer in this member function is going to be offset (specifically, to 0x8). AFAIK, there are 3 ways I can handle this:

  1. Type it as void* __offset(S1SocialController, 0x8) this.
  2. Type it as IS1AnimEventHandler* __offset(S1SocialController, 0x8) this (or similar).
  3. Create a new type using __ptr_offset and type it as that.

These all have problems:

  • (1) isn't as precise as it could be.
  • (2) doesn't work as I hoped unless I use the exact type of the field that sits at the offset (i.e. S1SocialController::__vftable_IS1AnimEventHandler**), making it unwieldy and prone to becoming outdated as the types evolve.
  • (3) works but now requires me to define yet another thunk type (in which I also need to abuse __base to keep things sane).

As it stands, I always just use (1) when dealing with multiple inheritance. It gets mostly good results for minimal effort. Using __ptr_offset is just too much work for too little gain, and it still feels 'hacky' because of abusing __base like this:

struct __base(S1SocialController, 0) __ptr_offset(0x8) `S1SocialController::__thunk_IS1AnimEventHandler` __packed
{
    // ... snip ...
};

The intent behind __ptr_offset is great, but attaching it to type definitions seems to me like it misses the mark. I think BN should allow using it directly in type syntax, as in S1SocialController* __ptr_offset(0x8) this, similar to __offset. Then you get the benefits without defining an extra type and abusing __base.

alexrp avatar Mar 20 '24 00:03 alexrp

Has the team had a chance to contemplate this one? :eyes:

alexrp avatar May 30 '24 19:05 alexrp