Vector35 / Vector35/binaryninja-api
Undersizing array accesses due to liberal load/store split heuristics
@emesare is already working on this.
Since Jul 1, 2024.
- 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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.