Skip to content

Commit 14491c0

Browse files
committed
Update plthook_osx.c for LC_DYLD_INFO_ONLY (before chained fixups)
1 parent 0b56b19 commit 14491c0

File tree

1 file changed

+61
-53
lines changed

1 file changed

+61
-53
lines changed

plthook_osx.c

+61-53
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@
6666

6767
#ifdef PLTHOOK_DEBUG_BIND
6868
#define DEBUG_BIND(...) fprintf(stderr, __VA_ARGS__)
69+
#define DEBUG_BIND_IF(cond, ...) if (cond) fprintf(stderr, __VA_ARGS__)
6970
#else
7071
#define DEBUG_BIND(...)
72+
#define DEBUG_BIND_IF(cond, ...)
7173
#endif
7274

7375
#ifdef PLTHOOK_DEBUG_ADDR
@@ -182,8 +184,8 @@ typedef struct {
182184
} data_t;
183185

184186
static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const struct mach_header *mh, const char *image_name);
185-
static unsigned int set_bind_addrs(data_t *d, uint32_t lazy_bind_off, uint32_t lazy_bind_size);
186-
static void set_bind_addr(data_t *d, unsigned int *idx, const char *sym_name, int seg_index, int seg_offset);
187+
static unsigned int set_bind_addrs(data_t *data, unsigned int idx, uint32_t bind_off, uint32_t bind_size, char weak);
188+
static void set_bind_addr(data_t *d, unsigned int *idx, const char *sym_name, int seg_index, int seg_offset, int addend, char weak);
187189
static int read_chained_fixups(data_t *d, const struct mach_header *mh, const char *image_name);
188190
#ifdef PLTHOOK_DEBUG_FIXUPS
189191
static const char *segment_name_from_addr(data_t *d, size_t addr);
@@ -328,8 +330,7 @@ int plthook_open_by_address(plthook_t **plthook_out, void *address)
328330
static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const struct mach_header *mh, const char *image_name)
329331
{
330332
struct load_command *cmd;
331-
uint32_t lazy_bind_off = 0;
332-
uint32_t lazy_bind_size = 0;
333+
const struct dyld_info_command *dyld_info = NULL;
333334
unsigned int nbind;
334335
data_t data = {NULL,};
335336
size_t size;
@@ -353,7 +354,6 @@ static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const
353354
cmd = (struct load_command *)((size_t)mh + sizeof(struct mach_header_64));
354355
DEBUG_CMD("CMD START\n");
355356
for (i = 0; i < mh->ncmds; i++) {
356-
struct dyld_info_command *dyld_info;
357357
#ifdef PLTHOOK_DEBUG_CMD
358358
struct segment_command *segment;
359359
#endif
@@ -447,8 +447,6 @@ static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const
447447
break;
448448
case LC_DYLD_INFO_ONLY: /* (0x22|LC_REQ_DYLD) */
449449
dyld_info= (struct dyld_info_command *)cmd;
450-
lazy_bind_off = dyld_info->lazy_bind_off;
451-
lazy_bind_size = dyld_info->lazy_bind_size;
452450
DEBUG_CMD("LC_DYLD_INFO_ONLY\n"
453451
" offset size\n"
454452
" rebase %8x %8x\n"
@@ -540,117 +538,131 @@ static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const
540538
return rv;
541539
}
542540
} else {
543-
nbind = set_bind_addrs(&data, lazy_bind_off, lazy_bind_size);
541+
nbind = 0;
542+
nbind = set_bind_addrs(&data, nbind, dyld_info->bind_off, dyld_info->bind_size, 0);
543+
nbind = set_bind_addrs(&data, nbind, dyld_info->weak_bind_off, dyld_info->weak_bind_size, 1);
544+
nbind = set_bind_addrs(&data, nbind, dyld_info->lazy_bind_off, dyld_info->lazy_bind_size, 0);
544545
size = offsetof(plthook_t, entries) + sizeof(bind_address_t) * nbind;
545546
data.plthook = (plthook_t*)calloc(1, size);
546547
if (data.plthook == NULL) {
547548
set_errmsg("failed to allocate memory: %" PRIuPTR " bytes", size);
548549
return PLTHOOK_OUT_OF_MEMORY;
549550
}
550551
data.plthook->num_entries = nbind;
551-
set_bind_addrs(&data, lazy_bind_off, lazy_bind_size);
552+
nbind = 0;
553+
nbind = set_bind_addrs(&data, nbind, dyld_info->bind_off, dyld_info->bind_size, 0);
554+
nbind = set_bind_addrs(&data, nbind, dyld_info->weak_bind_off, dyld_info->weak_bind_size, 1);
555+
nbind = set_bind_addrs(&data, nbind, dyld_info->lazy_bind_off, dyld_info->lazy_bind_size, 0);
552556
}
553557
set_mem_prot(data.plthook);
554558

555559
*plthook_out = data.plthook;
556560
return 0;
557561
}
558562

559-
static unsigned int set_bind_addrs(data_t *data, uint32_t lazy_bind_off, uint32_t lazy_bind_size)
563+
static unsigned int set_bind_addrs(data_t *data, unsigned int idx, uint32_t bind_off, uint32_t bind_size, char weak)
560564
{
561-
const struct segment_command_64 *linkedit = data->segments[data->linkedit_segment_idx];
562-
const uint8_t *ptr = (uint8_t*)(linkedit->vmaddr - linkedit->fileoff + data->slide + lazy_bind_off);
563-
const uint8_t *end = ptr + lazy_bind_size;
565+
const uint8_t *ptr = fileoff_to_vmaddr_in_segment(data, data->linkedit_segment_idx, bind_off);
566+
const uint8_t *end = ptr + bind_size;
564567
const char *sym_name;
565568
int seg_index = 0;
566569
uint64_t seg_offset = 0;
570+
int addend = 0;
567571
int count, skip;
568-
unsigned int idx = 0;
572+
#ifdef PLTHOOK_DEBUG_BIND
573+
int cond = data->plthook != NULL;
574+
#endif
569575

570576
while (ptr < end) {
571577
uint8_t op = *ptr & BIND_OPCODE_MASK;
572578
uint8_t imm = *ptr & BIND_IMMEDIATE_MASK;
573579
int i;
574580

575-
DEBUG_BIND("0x%02x: ", *ptr);
581+
DEBUG_BIND_IF(cond, "0x%02x: ", *ptr);
576582
ptr++;
577583
switch (op) {
578584
case BIND_OPCODE_DONE:
579-
DEBUG_BIND("BIND_OPCODE_DONE\n");
585+
DEBUG_BIND_IF(cond, "BIND_OPCODE_DONE\n");
580586
break;
581587
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
582-
DEBUG_BIND("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: ordinal = %u\n", imm);
588+
DEBUG_BIND_IF(cond, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: ordinal = %u\n", imm);
583589
break;
584590
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
585591
#ifdef PLTHOOK_DEBUG_BIND
586-
DEBUG_BIND("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: ordinal = %llu\n", uleb128(&ptr));
592+
DEBUG_BIND_IF(cond, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: ordinal = %llu\n", uleb128(&ptr));
587593
#else
588594
uleb128(&ptr);
589595
#endif
590596
break;
591597
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
592598
if (imm == 0) {
593-
DEBUG_BIND("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: ordinal = 0\n");
599+
DEBUG_BIND_IF(cond, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: ordinal = 0\n");
594600
} else {
595-
DEBUG_BIND("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: ordinal = %u\n", BIND_OPCODE_MASK | imm);
601+
DEBUG_BIND_IF(cond, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: ordinal = %u\n", BIND_OPCODE_MASK | imm);
596602
}
603+
break;
597604
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
598605
sym_name = (const char*)ptr;
599606
ptr += strlen(sym_name) + 1;
600-
DEBUG_BIND("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: sym_name = %s\n", sym_name);
607+
DEBUG_BIND_IF(cond, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: sym_name = %s\n", sym_name);
601608
break;
602609
case BIND_OPCODE_SET_TYPE_IMM:
603-
DEBUG_BIND("BIND_OPCODE_SET_TYPE_IMM: type = %u\n", imm);
610+
DEBUG_BIND_IF(cond, "BIND_OPCODE_SET_TYPE_IMM: type = %u\n", imm);
604611
break;
605612
case BIND_OPCODE_SET_ADDEND_SLEB:
606-
#ifdef PLTHOOK_DEBUG_BIND
607-
DEBUG_BIND("BIND_OPCODE_SET_ADDEND_SLEB: ordinal = %lld\n", sleb128(&ptr));
608-
#else
609-
sleb128(&ptr);
610-
#endif
613+
addend = sleb128(&ptr);
614+
DEBUG_BIND_IF(cond, "BIND_OPCODE_SET_ADDEND_SLEB: ordinal = %lld\n", addend);
611615
break;
612616
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
613617
seg_index = imm;
614618
seg_offset = uleb128(&ptr);
615-
DEBUG_BIND("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: seg_index = %u, seg_offset = 0x%llx\n", seg_index, seg_offset);
619+
DEBUG_BIND_IF(cond, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: seg_index = %u, seg_offset = 0x%llx\n", seg_index, seg_offset);
616620
break;
617621
case BIND_OPCODE_ADD_ADDR_ULEB:
618622
seg_offset += uleb128(&ptr);
619-
DEBUG_BIND("BIND_OPCODE_ADD_ADDR_ULEB: seg_offset = 0x%llx\n", seg_offset);
623+
DEBUG_BIND_IF(cond, "BIND_OPCODE_ADD_ADDR_ULEB: seg_offset = 0x%llx\n", seg_offset);
620624
break;
621625
case BIND_OPCODE_DO_BIND:
622-
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset);
623-
DEBUG_BIND("BIND_OPCODE_DO_BIND\n");
626+
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset, addend, weak);
627+
seg_offset += sizeof(void*);
628+
DEBUG_BIND_IF(cond, "BIND_OPCODE_DO_BIND\n");
624629
break;
625630
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
626-
seg_offset += uleb128(&ptr);
627-
DEBUG_BIND("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: seg_offset = 0x%llx\n", seg_offset);
631+
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset, addend, weak);
632+
seg_offset += uleb128(&ptr) + sizeof(void*);
633+
DEBUG_BIND_IF(cond, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: seg_offset = 0x%llx\n", seg_offset);
628634
break;
629635
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
630-
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset);
631-
seg_offset += imm * sizeof(void *);
632-
DEBUG_BIND("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
636+
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset, addend, weak);
637+
seg_offset += imm * sizeof(void *) + sizeof(void*);
638+
DEBUG_BIND_IF(cond, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
633639
break;
634640
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
635641
count = uleb128(&ptr);
636642
skip = uleb128(&ptr);
637643
for (i = 0; i < count; i++) {
638-
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset);
639-
seg_offset += skip;
644+
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset, addend, weak);
645+
seg_offset += skip + sizeof(void*);
640646
}
641-
DEBUG_BIND("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB\n");
647+
DEBUG_BIND_IF(cond, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB\n");
642648
break;
649+
default:
650+
DEBUG_BIND_IF(cond, "op: 0x%x, imm: 0x%x\n", op, imm);
643651
}
644652
}
645653
return idx;
646654
}
647655

648-
static void set_bind_addr(data_t *data, unsigned int *idx, const char *sym_name, int seg_index, int seg_offset)
656+
static void set_bind_addr(data_t *data, unsigned int *idx, const char *sym_name, int seg_index, int seg_offset, int addend, char weak)
649657
{
650658
if (data->plthook != NULL) {
651659
size_t vmaddr = data->segments[seg_index]->vmaddr;
652-
data->plthook->entries[*idx].name = sym_name;
653-
data->plthook->entries[*idx].addr = (void**)(vmaddr + data->slide + seg_offset);
660+
bind_address_t *bind_addr = &data->plthook->entries[*idx];
661+
bind_addr->name = sym_name;
662+
bind_addr->addend = addend;
663+
bind_addr->weak = weak;
664+
bind_addr->addr = (void**)(vmaddr + data->slide + seg_offset);
665+
DEBUG_BIND("bind_address[%u]: %s, %d, %d, %p, %p, %p\n", *idx, sym_name, seg_index, seg_offset, (void*)vmaddr, (void*)data->slide, bind_addr->addr);
654666
}
655667
(*idx)++;
656668
}
@@ -1081,22 +1093,23 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
10811093
{
10821094
size_t funcnamelen = strlen(funcname);
10831095
unsigned int pos = 0;
1084-
const char *name;
1085-
void **addr;
1096+
plthook_entry_t entry;
10861097
int rv;
10871098

10881099
if (plthook == NULL) {
10891100
set_errmsg("invalid argument: The first argument is null.");
10901101
return PLTHOOK_INVALID_ARGUMENT;
10911102
}
1092-
while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) {
1103+
while ((rv = plthook_enum_entry(plthook, &pos, &entry)) == 0) {
1104+
const char *name = entry.name;
1105+
void **addr = entry.addr;
10931106
if (strncmp(name, funcname, funcnamelen) == 0) {
10941107
if (name[funcnamelen] == '\0' || name[funcnamelen] == '$') {
10951108
goto matched;
10961109
}
10971110
}
10981111
if (name[0] == '@') {
1099-
/* Oracle libclntsh.dylib imports 'read' as '@_read'. */
1112+
/* I doubt this code... */
11001113
name++;
11011114
if (strncmp(name, funcname, funcnamelen) == 0) {
11021115
if (name[funcnamelen] == '\0' || name[funcnamelen] == '$') {
@@ -1117,20 +1130,15 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
11171130
if (oldfunc) {
11181131
*oldfunc = *addr;
11191132
}
1120-
int prot = get_mem_prot(plthook, addr);
1121-
if (prot == 0) {
1122-
set_errmsg("Could not get the process memory permission at %p", addr);
1123-
return PLTHOOK_INTERNAL_ERROR;
1124-
}
1125-
if (!(prot & PROT_WRITE)) {
1133+
if (!(entry.prot & PROT_WRITE)) {
11261134
size_t page_size = sysconf(_SC_PAGESIZE);
11271135
void *base = (void*)((size_t)addr & ~(page_size - 1));
11281136
if (mprotect(base, page_size, PROT_READ | PROT_WRITE) != 0) {
11291137
set_errmsg("Cannot change memory protection at address %p", base);
11301138
return PLTHOOK_INTERNAL_ERROR;
11311139
}
11321140
*addr = funcaddr;
1133-
mprotect(base, page_size, prot);
1141+
mprotect(base, page_size, entry.prot);
11341142
} else {
11351143
*addr = funcaddr;
11361144
}

0 commit comments

Comments
 (0)