Vector35 / Vector35/binaryninja-api

Undersizing array accesses due to liberal load/store split heuristics

Open
#5,415 10 comments 0 reactions 1 assignee View on GitHub

@emesare is already working on this.

Since Jul 1, 2024.

Component: Core Core: HLIL
Dominant language
C++
Stars
1.3k
Forks
298
Avg merge
5d 5h
Merged PRs (30d)
19

Description

Version and Platform (required):

  • Binary Ninja Version: 4.1.5272-dev, 3a057a87
  • OS: macos
  • OS Version: 14.4
  • CPU Architecture: arm64

Internal binary major dine favor.

Here's IDA Pro

uint64_t __fastcall DjiIdentityVerify_GetSerialNumber(
        struct CommandManager *mgr,
        struct CommandHeader *header,
        char *payload)
{
  ProductInfo info; // [xsp+10h] [xbp+10h] BYREF
  char *v5; // [xsp+2E8h] [xbp+2E8h]
  struct CommandHeader *header_1; // [xsp+2F0h] [xbp+2F0h]
  struct CommandManager *mgr_1; // [xsp+2F8h] [xbp+2F8h]
  ProductInfo info_1; // [xsp+300h] [xbp+300h] BYREF
  char payload_1[40]; // [xsp+5C8h] [xbp+5C8h] BYREF
  uint64_t err; // [xsp+5F0h] [xbp+5F0h]
  char *payload_2; // [xsp+5F8h] [xbp+5F8h]

  mgr_1 = mgr;
  header_1 = header;
  v5 = payload;
  payload_2 = payload;
  *(_QWORD *)payload_1 = 0x2000LL;
  memset(&payload_1[8], 0, 0x1B);
  DjiProductInfo_GetInfo(&info);
  memcpy(&info_1, &info, sizeof(info_1));
  *(_QWORD *)&payload_1[3] = *(_QWORD *)info_1.user_info.appKey;
  *(_QWORD *)&payload_1[11] = *(_QWORD *)&info_1.user_info.appKey[8];
  *(_QWORD *)&payload_1[19] = *(_QWORD *)&info_1.user_info.appKey[16];
  *(_QWORD *)&payload_1[27] = *(_QWORD *)&info_1.user_info.appKey[24];
  err = DjiCommand_SendAckData(mgr_1, header_1, payload_1, 0x23);
  if ( err )
    DjiLogger_Output(
      "auth",
      0,
      "[%s:%d) get serial number ack error:0x%08llX",
      "DjiIdentityVerify_GetSerialNumber",
      281LL,
      err);
  return err;
}

Here's the original BN. I tried to undefine the function but the result was the same.

0007bef0  uint64_t DjiIdentityVerify_GetSerialNumber(struct CommandManager* mgr, struct CommandHeader* header)

0007bf0c      int64_t x2
0007bf0c      int64_t var_8 = x2
0007bf14      int64_t payload = 0
0007bf14      int64_t s
0007bf14      __builtin_memset(s: &s, c: 0, n: 0x1b)
0007bf28      payload.b = 0
0007bf34      payload:1.w = 0x20
0007bf40      void info
0007bf40      DjiProductInfo_GetInfo(info: &info)
0007bf50      void var_300
0007bf50      memcpy(&var_300, &info, 0x2c4)
0007bf60      int64_t payload_1
0007bf60      payload = payload_1
0007bf60      int64_t s_1
0007bf60      s = s_1
0007bf68      int64_t var_2c0
0007bf68      int64_t var_28 = var_2c0
0007bf68      int64_t var_2b8
0007bf68      int64_t var_20 = var_2b8
0007bf80      uint64_t result = DjiCommand_SendAckData(mgr, header, payload: &payload, payload_size: 0x23)
0007bf90      if (result != 0)
0007bfc0          DjiLogger_Output(tag: "auth", level: 0, fmt: "[%s:%d) get serial number ack er…", "DjiIdentityVerify_GetSerialNumbe…", 0x119, result)
0007bfd0      return result

My ProductInfo type

struct ProductInfo __packed
{
    struct T_DjiUserInfo user_info;
    __padding char _297[1];
    char field_298[0x0];
    __padding char _298[4];
    char field_29c[0x0];
    __padding char _29c[1];
    __padding char _29d[1];
    __padding char _29e[1];
    __padding char _29f[1];
    __padding char _2a0[2];
    __padding char _2a2[0x1e];
    __padding char _2c0[4];
};

Typing the two product infos give me the following

0007bef0  uint64_t DjiIdentityVerify_GetSerialNumber(struct CommandManager* mgr, struct CommandHeader* header)

0007bf0c      int64_t x2
0007bf0c      int64_t var_8 = x2
0007bf14      int64_t payload = 0
0007bf14      int64_t s
0007bf14      __builtin_memset(s: &s, c: 0, n: 0x1b)
0007bf28      payload.b = 0
0007bf34      payload:1.w = 0x20
0007bf40      struct ProductInfo info
0007bf40      DjiProductInfo_GetInfo(info: &info)
0007bf50      struct ProductInfo info_1
0007bf50      memcpy(&info_1, &info, 0x2c4)
0007bf5c      int64_t payload_1
0007bf5c      payload_1.b = info_1.user_info.appKey[0]
0007bf5c      payload_1:1.b = info_1.user_info.appKey[1]
0007bf5c      payload_1:2.b = info_1.user_info.appKey[2]
0007bf5c      payload_1:3.b = info_1.user_info.appKey[3]
0007bf5c      payload_1:4.b = info_1.user_info.appKey[4]
0007bf5c      payload_1:5.b = info_1.user_info.appKey[5]
0007bf5c      payload_1:6.b = info_1.user_info.appKey[6]
0007bf5c      payload_1:7.b = info_1.user_info.appKey[7]
0007bf5c      int64_t s_1
0007bf5c      s_1.b = info_1.user_info.appKey[8]
0007bf5c      s_1:1.b = info_1.user_info.appKey[9]
0007bf5c      s_1:2.b = info_1.user_info.appKey[0xa]
0007bf5c      s_1:3.b = info_1.user_info.appKey[0xb]
0007bf5c      s_1:4.b = info_1.user_info.appKey[0xc]
0007bf5c      s_1:5.b = info_1.user_info.appKey[0xd]
0007bf5c      s_1:6.b = info_1.user_info.appKey[0xe]
0007bf5c      s_1:7.b = info_1.user_info.appKey[0xf]
0007bf60      payload = payload_1
0007bf60      s = s_1
0007bf64      int64_t x0_2
0007bf64      x0_2.b = info_1.user_info.appKey[0x10]
0007bf64      x0_2:1.b = info_1.user_info.appKey[0x11]
0007bf64      x0_2:2.b = info_1.user_info.appKey[0x12]
0007bf64      x0_2:3.b = info_1.user_info.appKey[0x13]
0007bf64      x0_2:4.b = info_1.user_info.appKey[0x14]
0007bf64      x0_2:5.b = info_1.user_info.appKey[0x15]
0007bf64      x0_2:6.b = info_1.user_info.appKey[0x16]
0007bf64      x0_2:7.b = info_1.user_info.appKey[0x17]
0007bf64      int64_t x1_1
0007bf64      x1_1.b = info_1.user_info.appKey[0x18]
0007bf64      x1_1:1.b = info_1.user_info.appKey[0x19]
0007bf64      x1_1:2.b = info_1.user_info.appKey[0x1a]
0007bf64      x1_1:3.b = info_1.user_info.appKey[0x1b]
0007bf64      x1_1:4.b = info_1.user_info.appKey[0x1c]
0007bf64      x1_1:5.b = info_1.user_info.appKey[0x1d]
0007bf64      x1_1:6.b = info_1.user_info.appKey[0x1e]
0007bf64      x1_1:7.b = info_1.user_info.appKey[0x1f]
0007bf68      int64_t var_28 = x0_2
0007bf68      int64_t var_20 = x1_1
0007bf80      uint64_t result = DjiCommand_SendAckData(mgr, header, payload: &payload, payload_size: 0x23)
0007bf90      if (result != 0)
0007bfc0          DjiLogger_Output(tag: "auth", level: 0, fmt: "[%s:%d) get serial number ack er…", "DjiIdentityVerify_GetSerialNumbe…", 0x119, result)
0007bfd0      return result

I'm trying to set the size of payload used here

0007bf80      uint64_t result = DjiCommand_SendAckData(mgr, header, payload: &payload, payload_size: 0x23)

I was able to adjust payload in IDA by looking at the space available between err at stack offset 0x5F0 and payload_1 at stack offset 0x5C8. This is how I got the 40.

char payload_1[40]; // [xsp+5C8h] [xbp+5C8h] BYREF
 uint64_t err; // [xsp+5F0h] [xbp+5F0h]

I thought I'd try the same using the BN Stack View. Hovering over &payload below tells me that the variable is at stack offset -0x38. This is indeed the case per the Stack View. I don't see result anywhere near, though, and there's not enough space between adjacent variables to fit a 40-character buffer.

0007bf80      uint64_t result = DjiCommand_SendAckData(mgr, header, payload: &payload, payload_size: 0x23)

Very strange but maybe all is not lost. Maybe I should look at 0x5F0 and 0xFC8? The former offset holds info and there's nothing at the latter offset.

Maybe BN will just do the right thing if I set the size of payload? I do know it's 40 characters after all!

What about this assignment, though? Should I take the offset of payload_1 instead? Can't because BN says it's in register X0.

0007bf60      payload = payload_1

I'm just gonna go ahead and set the type of payload_1 to char[40] and cross my fingers. And...

How do I get out of this mess I got myself into?

And how do I use the Stack View in this case?

0007bef0  uint64_t DjiIdentityVerify_GetSerialNumber(struct CommandManager* mgr, struct CommandHeader* header)

0007bf0c      int64_t x2
0007bf0c      int64_t var_8 = x2
0007bf14      int64_t payload = 0
0007bf14      int64_t s
0007bf14      __builtin_memset(s: &s, c: 0, n: 0x1b)
0007bf28      payload.b = 0
0007bf34      payload:1.w = 0x20
0007bf40      struct ProductInfo info
0007bf40      DjiProductInfo_GetInfo(info: &info)
0007bf50      struct ProductInfo info_1
0007bf50      memcpy(&info_1, &info, 0x2c4)
0007bf5c      char payload_1[0x28]
0007bf5c      payload_1[0] = info_1.user_info.appKey[0]
0007bf5c      payload_1[1] = info_1.user_info.appKey[1]
0007bf5c      payload_1[2] = info_1.user_info.appKey[2]
0007bf5c      payload_1[3] = info_1.user_info.appKey[3]
0007bf5c      payload_1[4] = info_1.user_info.appKey[4]
0007bf5c      payload_1[5] = info_1.user_info.appKey[5]
0007bf5c      payload_1[6] = info_1.user_info.appKey[6]
0007bf5c      payload_1[7] = info_1.user_info.appKey[7]
0007bf5c      int64_t s_1
0007bf5c      s_1.b = info_1.user_info.appKey[8]
0007bf5c      s_1:1.b = info_1.user_info.appKey[9]
0007bf5c      s_1:2.b = info_1.user_info.appKey[0xa]
0007bf5c      s_1:3.b = info_1.user_info.appKey[0xb]
0007bf5c      s_1:4.b = info_1.user_info.appKey[0xc]
0007bf5c      s_1:5.b = info_1.user_info.appKey[0xd]
0007bf5c      s_1:6.b = info_1.user_info.appKey[0xe]
0007bf5c      s_1:7.b = info_1.user_info.appKey[0xf]
0007bf60      payload = payload_1
0007bf60      s = s_1
0007bf64      int64_t x0_2
0007bf64      x0_2.b = info_1.user_info.appKey[0x10]
0007bf64      x0_2:1.b = info_1.user_info.appKey[0x11]
0007bf64      x0_2:2.b = info_1.user_info.appKey[0x12]
0007bf64      x0_2:3.b = info_1.user_info.appKey[0x13]
0007bf64      x0_2:4.b = info_1.user_info.appKey[0x14]
0007bf64      x0_2:5.b = info_1.user_info.appKey[0x15]
0007bf64      x0_2:6.b = info_1.user_info.appKey[0x16]
0007bf64      x0_2:7.b = info_1.user_info.appKey[0x17]
0007bf64      int64_t x1_1
0007bf64      x1_1.b = info_1.user_info.appKey[0x18]
0007bf64      x1_1:1.b = info_1.user_info.appKey[0x19]
0007bf64      x1_1:2.b = info_1.user_info.appKey[0x1a]
0007bf64      x1_1:3.b = info_1.user_info.appKey[0x1b]
0007bf64      x1_1:4.b = info_1.user_info.appKey[0x1c]
0007bf64      x1_1:5.b = info_1.user_info.appKey[0x1d]
0007bf64      x1_1:6.b = info_1.user_info.appKey[0x1e]
0007bf64      x1_1:7.b = info_1.user_info.appKey[0x1f]
0007bf68      int64_t var_28 = x0_2
0007bf68      int64_t var_20 = x1_1
0007bf80      uint64_t result = DjiCommand_SendAckData(mgr, header, payload: &payload, payload_size: 0x23)
0007bf90      if (result != 0)
0007bfc0          DjiLogger_Output(tag: "auth", level: 0, fmt: "[%s:%d) get serial number ack er…", "DjiIdentityVerify_GetSerialNumbe…", 0x119, result)
0007bfd0      return result

How do I get rid of

0007bf5c      int64_t s_1
...
0007bf60      payload = payload_1
0007bf60      s = s_1
0007bf64      int64_t x0_2
...
0007bf64      int64_t x1_1
...
0007bf68      int64_t var_28 = x0_2
0007bf68      int64_t var_20 = x1_1

and make sure just payload is used?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.