Make dyld_chained_ptr_* parsing endian-independent (#3113)
Fixes test/db/cmd/cmd_tc and test/db/formats/mach0/arm64e on big endian
This commit is contained in:
parent
7685bfe90e
commit
9a379f345d
5 changed files with 245 additions and 58 deletions
|
|
@ -1483,6 +1483,14 @@ enum {
|
|||
DYLD_CHAINED_PTR_ARM64E_USERLAND24 = 12,
|
||||
};
|
||||
|
||||
#include <rz_util/rz_num.h>
|
||||
|
||||
#define READ_BITS(dst, count) \
|
||||
do { \
|
||||
dst = raw_val & rz_num_bitmask(count); \
|
||||
raw_val >>= count; \
|
||||
} while (0);
|
||||
|
||||
struct dyld_chained_ptr_arm64e_rebase {
|
||||
uint64_t target : 43,
|
||||
high8 : 8,
|
||||
|
|
@ -1491,6 +1499,14 @@ struct dyld_chained_ptr_arm64e_rebase {
|
|||
auth : 1; // == 0
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_arm64e_rebase_read(struct dyld_chained_ptr_arm64e_rebase *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->target, 43);
|
||||
READ_BITS(dst->high8, 8);
|
||||
READ_BITS(dst->next, 11);
|
||||
READ_BITS(dst->bind, 1);
|
||||
READ_BITS(dst->auth, 1);
|
||||
}
|
||||
|
||||
struct dyld_chained_ptr_arm64e_bind {
|
||||
uint64_t ordinal : 16,
|
||||
zero : 16,
|
||||
|
|
@ -1500,6 +1516,15 @@ struct dyld_chained_ptr_arm64e_bind {
|
|||
auth : 1; // == 0
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_arm64e_bind_read(struct dyld_chained_ptr_arm64e_bind *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->ordinal, 16);
|
||||
READ_BITS(dst->zero, 16);
|
||||
READ_BITS(dst->addend, 19);
|
||||
READ_BITS(dst->next, 11);
|
||||
READ_BITS(dst->bind, 1);
|
||||
READ_BITS(dst->auth, 1);
|
||||
}
|
||||
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase {
|
||||
uint64_t target : 32,
|
||||
diversity : 16,
|
||||
|
|
@ -1510,6 +1535,16 @@ struct dyld_chained_ptr_arm64e_auth_rebase {
|
|||
auth : 1; // == 1
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_arm64e_auth_rebase_read(struct dyld_chained_ptr_arm64e_auth_rebase *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->target, 32);
|
||||
READ_BITS(dst->diversity, 16);
|
||||
READ_BITS(dst->addrDiv, 1);
|
||||
READ_BITS(dst->key, 2);
|
||||
READ_BITS(dst->next, 11);
|
||||
READ_BITS(dst->bind, 1);
|
||||
READ_BITS(dst->auth, 1);
|
||||
}
|
||||
|
||||
struct dyld_chained_ptr_arm64e_auth_bind {
|
||||
uint64_t ordinal : 16,
|
||||
zero : 16,
|
||||
|
|
@ -1521,6 +1556,17 @@ struct dyld_chained_ptr_arm64e_auth_bind {
|
|||
auth : 1; // == 1
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_arm64e_auth_bind_read(struct dyld_chained_ptr_arm64e_auth_bind *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->ordinal, 16);
|
||||
READ_BITS(dst->zero, 16);
|
||||
READ_BITS(dst->diversity, 16);
|
||||
READ_BITS(dst->addrDiv, 1);
|
||||
READ_BITS(dst->key, 2);
|
||||
READ_BITS(dst->next, 11);
|
||||
READ_BITS(dst->bind, 1);
|
||||
READ_BITS(dst->auth, 1);
|
||||
}
|
||||
|
||||
struct dyld_chained_ptr_64_rebase {
|
||||
uint64_t target : 36,
|
||||
high8 : 8,
|
||||
|
|
@ -1529,6 +1575,14 @@ struct dyld_chained_ptr_64_rebase {
|
|||
bind : 1; // == 0
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_64_rebase_read(struct dyld_chained_ptr_64_rebase *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->target, 36);
|
||||
READ_BITS(dst->high8, 8);
|
||||
READ_BITS(dst->reserved, 7);
|
||||
READ_BITS(dst->next, 12);
|
||||
READ_BITS(dst->bind, 1);
|
||||
}
|
||||
|
||||
struct dyld_chained_ptr_64_bind {
|
||||
uint64_t ordinal : 24,
|
||||
addend : 8,
|
||||
|
|
@ -1537,6 +1591,14 @@ struct dyld_chained_ptr_64_bind {
|
|||
bind : 1; // == 1
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_64_bind_read(struct dyld_chained_ptr_64_bind *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->ordinal, 24);
|
||||
READ_BITS(dst->addend, 8);
|
||||
READ_BITS(dst->reserved, 19);
|
||||
READ_BITS(dst->next, 12);
|
||||
READ_BITS(dst->bind, 1);
|
||||
}
|
||||
|
||||
/* WARNING: this is guesswork based on trial and error */
|
||||
struct dyld_chained_ptr_arm64e_cache_rebase {
|
||||
uint64_t target : 43,
|
||||
|
|
@ -1545,6 +1607,13 @@ struct dyld_chained_ptr_arm64e_cache_rebase {
|
|||
auth : 1; // == 0
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_arm64e_cache_rebase_read(struct dyld_chained_ptr_arm64e_cache_rebase *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->target, 43);
|
||||
READ_BITS(dst->high8, 8);
|
||||
READ_BITS(dst->next, 12);
|
||||
READ_BITS(dst->auth, 1);
|
||||
}
|
||||
|
||||
struct dyld_chained_ptr_arm64e_cache_auth_rebase {
|
||||
uint64_t target : 32,
|
||||
diversity : 16,
|
||||
|
|
@ -1554,6 +1623,15 @@ struct dyld_chained_ptr_arm64e_cache_auth_rebase {
|
|||
auth : 1; // == 1
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_arm64e_cache_auth_rebase_read(struct dyld_chained_ptr_arm64e_cache_auth_rebase *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->target, 32);
|
||||
READ_BITS(dst->diversity, 16);
|
||||
READ_BITS(dst->addrDiv, 1);
|
||||
READ_BITS(dst->key, 2);
|
||||
READ_BITS(dst->next, 12);
|
||||
READ_BITS(dst->auth, 1);
|
||||
}
|
||||
|
||||
struct dyld_chained_ptr_arm64e_bind24 {
|
||||
uint64_t ordinal : 24,
|
||||
zero : 8,
|
||||
|
|
@ -1563,6 +1641,15 @@ struct dyld_chained_ptr_arm64e_bind24 {
|
|||
auth : 1; // == 0
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_arm64e_bind24_read(struct dyld_chained_ptr_arm64e_bind24 *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->ordinal, 24);
|
||||
READ_BITS(dst->zero, 8);
|
||||
READ_BITS(dst->addend, 19);
|
||||
READ_BITS(dst->next, 11);
|
||||
READ_BITS(dst->bind, 1);
|
||||
READ_BITS(dst->auth, 1);
|
||||
}
|
||||
|
||||
struct dyld_chained_ptr_arm64e_auth_bind24 {
|
||||
uint64_t ordinal : 24,
|
||||
zero : 8,
|
||||
|
|
@ -1574,4 +1661,19 @@ struct dyld_chained_ptr_arm64e_auth_bind24 {
|
|||
auth : 1; // == 1
|
||||
};
|
||||
|
||||
static inline void dyld_chained_ptr_arm64e_auth_bind24_read(struct dyld_chained_ptr_arm64e_auth_bind24 *dst, ut64 raw_val) {
|
||||
READ_BITS(dst->ordinal, 24);
|
||||
READ_BITS(dst->zero, 8);
|
||||
READ_BITS(dst->diversity, 16);
|
||||
READ_BITS(dst->addrDiv, 1);
|
||||
READ_BITS(dst->key, 2);
|
||||
READ_BITS(dst->next, 11);
|
||||
READ_BITS(dst->bind, 1);
|
||||
READ_BITS(dst->auth, 1);
|
||||
}
|
||||
|
||||
// When adding more structs/readers here, also add tests to test/unit/test_bin_mach0.c!
|
||||
|
||||
#undef READ_BITS
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -61,23 +61,23 @@ RZ_API void MACH0_(rebase_buffer)(struct MACH0_(obj_t) * obj, ut64 off, ut8 *buf
|
|||
case DYLD_CHAINED_PTR_ARM64E: {
|
||||
bool is_bind = IS_PTR_BIND(raw_ptr);
|
||||
if (is_auth && is_bind) {
|
||||
struct dyld_chained_ptr_arm64e_auth_bind *p =
|
||||
(struct dyld_chained_ptr_arm64e_auth_bind *)&raw_ptr;
|
||||
delta = p->next;
|
||||
struct dyld_chained_ptr_arm64e_auth_bind p;
|
||||
dyld_chained_ptr_arm64e_auth_bind_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
} else if (!is_auth && is_bind) {
|
||||
struct dyld_chained_ptr_arm64e_bind *p =
|
||||
(struct dyld_chained_ptr_arm64e_bind *)&raw_ptr;
|
||||
delta = p->next;
|
||||
struct dyld_chained_ptr_arm64e_bind p;
|
||||
dyld_chained_ptr_arm64e_bind_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
} else if (is_auth && !is_bind) {
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase *p =
|
||||
(struct dyld_chained_ptr_arm64e_auth_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ptr_value = p->target + obj->baddr;
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase p;
|
||||
dyld_chained_ptr_arm64e_auth_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ptr_value = p.target + obj->baddr;
|
||||
} else {
|
||||
struct dyld_chained_ptr_arm64e_rebase *p =
|
||||
(struct dyld_chained_ptr_arm64e_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ptr_value = ((ut64)p->high8 << 56) | p->target;
|
||||
struct dyld_chained_ptr_arm64e_rebase p;
|
||||
dyld_chained_ptr_arm64e_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ptr_value = ((ut64)p.high8 << 56) | p.target;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -85,15 +85,15 @@ RZ_API void MACH0_(rebase_buffer)(struct MACH0_(obj_t) * obj, ut64 off, ut8 *buf
|
|||
case DYLD_CHAINED_PTR_ARM64E_KERNEL: {
|
||||
stride = 4;
|
||||
if (is_auth) {
|
||||
struct dyld_chained_ptr_arm64e_cache_auth_rebase *p =
|
||||
(struct dyld_chained_ptr_arm64e_cache_auth_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ptr_value = p->target + obj->baddr;
|
||||
struct dyld_chained_ptr_arm64e_cache_auth_rebase p;
|
||||
dyld_chained_ptr_arm64e_cache_auth_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ptr_value = p.target + obj->baddr;
|
||||
} else {
|
||||
struct dyld_chained_ptr_arm64e_cache_rebase *p =
|
||||
(struct dyld_chained_ptr_arm64e_cache_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ptr_value = ((ut64)p->high8 << 56) | p->target;
|
||||
struct dyld_chained_ptr_arm64e_cache_rebase p;
|
||||
dyld_chained_ptr_arm64e_cache_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ptr_value = ((ut64)p.high8 << 56) | p.target;
|
||||
ptr_value += obj->baddr;
|
||||
}
|
||||
break;
|
||||
|
|
@ -101,15 +101,15 @@ RZ_API void MACH0_(rebase_buffer)(struct MACH0_(obj_t) * obj, ut64 off, ut8 *buf
|
|||
case DYLD_CHAINED_PTR_64:
|
||||
case DYLD_CHAINED_PTR_64_OFFSET: {
|
||||
stride = 4;
|
||||
struct dyld_chained_ptr_64_bind *bind =
|
||||
(struct dyld_chained_ptr_64_bind *)&raw_ptr;
|
||||
if (bind->bind) {
|
||||
delta = bind->next;
|
||||
struct dyld_chained_ptr_64_bind bind;
|
||||
dyld_chained_ptr_64_bind_read(&bind, raw_ptr);
|
||||
if (bind.bind) {
|
||||
delta = bind.next;
|
||||
} else {
|
||||
struct dyld_chained_ptr_64_rebase *p =
|
||||
(struct dyld_chained_ptr_64_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ptr_value = (((ut64)p->high8 << 56) | p->target);
|
||||
struct dyld_chained_ptr_64_rebase p;
|
||||
dyld_chained_ptr_64_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ptr_value = (((ut64)p.high8 << 56) | p.target);
|
||||
if (segment->pointer_format == DYLD_CHAINED_PTR_64_OFFSET) {
|
||||
ptr_value += obj->baddr;
|
||||
}
|
||||
|
|
@ -118,21 +118,21 @@ RZ_API void MACH0_(rebase_buffer)(struct MACH0_(obj_t) * obj, ut64 off, ut8 *buf
|
|||
}
|
||||
case DYLD_CHAINED_PTR_ARM64E_USERLAND24: {
|
||||
stride = 8;
|
||||
struct dyld_chained_ptr_arm64e_bind24 *bind =
|
||||
(struct dyld_chained_ptr_arm64e_bind24 *)&raw_ptr;
|
||||
if (bind->bind) {
|
||||
delta = bind->next;
|
||||
struct dyld_chained_ptr_arm64e_bind24 bind;
|
||||
dyld_chained_ptr_arm64e_bind24_read(&bind, raw_ptr);
|
||||
if (bind.bind) {
|
||||
delta = bind.next;
|
||||
} else {
|
||||
if (bind->auth) {
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase *p =
|
||||
(struct dyld_chained_ptr_arm64e_auth_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ptr_value = p->target + obj->baddr;
|
||||
if (bind.auth) {
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase p;
|
||||
dyld_chained_ptr_arm64e_auth_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ptr_value = p.target + obj->baddr;
|
||||
} else {
|
||||
struct dyld_chained_ptr_arm64e_rebase *p =
|
||||
(struct dyld_chained_ptr_arm64e_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ptr_value = obj->baddr + (((ut64)p->high8 << 56) | p->target);
|
||||
struct dyld_chained_ptr_arm64e_rebase p;
|
||||
dyld_chained_ptr_arm64e_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ptr_value = obj->baddr + (((ut64)p.high8 << 56) | p.target);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -254,24 +254,24 @@ RZ_BORROW RzSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) * bin) {
|
|||
int addend = -1;
|
||||
ut64 delta;
|
||||
if (is_auth && is_bind) {
|
||||
struct dyld_chained_ptr_arm64e_auth_bind *p =
|
||||
(struct dyld_chained_ptr_arm64e_auth_bind *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ordinal = p->ordinal;
|
||||
struct dyld_chained_ptr_arm64e_auth_bind p;
|
||||
dyld_chained_ptr_arm64e_auth_bind_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ordinal = p.ordinal;
|
||||
} else if (!is_auth && is_bind) {
|
||||
struct dyld_chained_ptr_arm64e_bind *p =
|
||||
(struct dyld_chained_ptr_arm64e_bind *)&raw_ptr;
|
||||
delta = p->next;
|
||||
ordinal = p->ordinal;
|
||||
addend = p->addend;
|
||||
struct dyld_chained_ptr_arm64e_bind p;
|
||||
dyld_chained_ptr_arm64e_bind_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
ordinal = p.ordinal;
|
||||
addend = p.addend;
|
||||
} else if (is_auth && !is_bind) {
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase *p =
|
||||
(struct dyld_chained_ptr_arm64e_auth_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
struct dyld_chained_ptr_arm64e_auth_rebase p;
|
||||
dyld_chained_ptr_arm64e_auth_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
} else {
|
||||
struct dyld_chained_ptr_arm64e_rebase *p =
|
||||
(struct dyld_chained_ptr_arm64e_rebase *)&raw_ptr;
|
||||
delta = p->next;
|
||||
struct dyld_chained_ptr_arm64e_rebase p;
|
||||
dyld_chained_ptr_arm64e_rebase_read(&p, raw_ptr);
|
||||
delta = p.next;
|
||||
}
|
||||
if (ordinal != -1) {
|
||||
if (ordinal >= n_threaded_binds) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ if get_option('enable_tests')
|
|||
'base64',
|
||||
'big',
|
||||
'bin_lines',
|
||||
'bin_mach0',
|
||||
'bitmap',
|
||||
'bitvector',
|
||||
'buf',
|
||||
|
|
|
|||
84
test/unit/test_bin_mach0.c
Normal file
84
test/unit/test_bin_mach0.c
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// SPDX-FileCopyrightText: 2022 Florian Märkl <info@florianmaerkl.de>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_util.h>
|
||||
#include "../../librz/bin/format/mach0/mach0_defines.h"
|
||||
#include "minunit.h"
|
||||
|
||||
/*
|
||||
* In real dyld, the dyld_chained_ptr_* structs are parsed by simply
|
||||
* reinterpreting a 64bit value as the respective bitfield struct. This of
|
||||
* course only works on little endian hosts, but we want to be
|
||||
* endian-independent, so we define or own readers.
|
||||
* The tests below compare the output of our readers against the dyld-style
|
||||
* reinterpretation to make sure we are parsing correctly. For adding tests for
|
||||
* a new struct, simply add a TEST_READ_DEF(...) and
|
||||
* mu_run_test(test_dyld_chained_..._read); line.
|
||||
*/
|
||||
|
||||
#if !RZ_SYS_ENDIAN
|
||||
|
||||
#define SAMPLES 10000
|
||||
|
||||
static ut64 rand_ut64() {
|
||||
ut64 r = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
r = (rand() % 0xff) | (r << 8);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#define TEST_READ_DEF(name) \
|
||||
bool test_##name##_read() { \
|
||||
RZ_STATIC_ASSERT(sizeof(struct name) == sizeof(ut64)); \
|
||||
for (int i = 0; i < SAMPLES; i++) { \
|
||||
ut64 raw_val = rand_ut64(); /* this is the value we want to parse */ \
|
||||
\
|
||||
/* Parse with our endian-independent function */ \
|
||||
struct name s; \
|
||||
ut64 *s_direct = (ut64 *)&s; \
|
||||
*s_direct = rand_ut64(); /* init with garbage */ \
|
||||
name##_read(&s, raw_val); \
|
||||
\
|
||||
/* Compare our parsed value against a direct copy into the struct. */ \
|
||||
/* This only works on little endian hosts! */ \
|
||||
if (*s_direct != raw_val) { /* manual check to avoid rz_strf below */ \
|
||||
char message[128]; \
|
||||
snprintf(message, sizeof(message), #name "_read(0x%" PFMT64x ")", raw_val); \
|
||||
mu_assert_eq(*s_direct, raw_val, message); \
|
||||
} \
|
||||
} \
|
||||
mu_end; \
|
||||
}
|
||||
|
||||
TEST_READ_DEF(dyld_chained_ptr_arm64e_rebase)
|
||||
TEST_READ_DEF(dyld_chained_ptr_arm64e_bind)
|
||||
TEST_READ_DEF(dyld_chained_ptr_arm64e_auth_rebase)
|
||||
TEST_READ_DEF(dyld_chained_ptr_arm64e_auth_bind)
|
||||
TEST_READ_DEF(dyld_chained_ptr_64_rebase)
|
||||
TEST_READ_DEF(dyld_chained_ptr_64_bind)
|
||||
TEST_READ_DEF(dyld_chained_ptr_arm64e_cache_rebase)
|
||||
TEST_READ_DEF(dyld_chained_ptr_arm64e_cache_auth_rebase)
|
||||
TEST_READ_DEF(dyld_chained_ptr_arm64e_bind24)
|
||||
TEST_READ_DEF(dyld_chained_ptr_arm64e_auth_bind24)
|
||||
|
||||
#endif
|
||||
|
||||
bool all_tests() {
|
||||
srand(time(0));
|
||||
#if !RZ_SYS_ENDIAN
|
||||
mu_run_test(test_dyld_chained_ptr_arm64e_rebase_read);
|
||||
mu_run_test(test_dyld_chained_ptr_arm64e_bind_read);
|
||||
mu_run_test(test_dyld_chained_ptr_arm64e_auth_rebase_read);
|
||||
mu_run_test(test_dyld_chained_ptr_arm64e_auth_bind_read);
|
||||
mu_run_test(test_dyld_chained_ptr_64_rebase_read);
|
||||
mu_run_test(test_dyld_chained_ptr_64_bind_read);
|
||||
mu_run_test(test_dyld_chained_ptr_arm64e_cache_rebase_read);
|
||||
mu_run_test(test_dyld_chained_ptr_arm64e_cache_auth_rebase_read);
|
||||
mu_run_test(test_dyld_chained_ptr_arm64e_bind24_read);
|
||||
mu_run_test(test_dyld_chained_ptr_arm64e_auth_bind24_read);
|
||||
#endif
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
||||
mu_main(all_tests)
|
||||
Loading…
Reference in a new issue