66
66
67
67
#ifdef PLTHOOK_DEBUG_BIND
68
68
#define DEBUG_BIND (...) fprintf(stderr, __VA_ARGS__)
69
+ #define DEBUG_BIND_IF (cond , ...) if (cond) fprintf(stderr, __VA_ARGS__)
69
70
#else
70
71
#define DEBUG_BIND (...)
72
+ #define DEBUG_BIND_IF (cond , ...)
71
73
#endif
72
74
73
75
#ifdef PLTHOOK_DEBUG_ADDR
@@ -182,8 +184,8 @@ typedef struct {
182
184
} data_t ;
183
185
184
186
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 );
187
189
static int read_chained_fixups (data_t * d , const struct mach_header * mh , const char * image_name );
188
190
#ifdef PLTHOOK_DEBUG_FIXUPS
189
191
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)
328
330
static int plthook_open_real (plthook_t * * plthook_out , uint32_t image_idx , const struct mach_header * mh , const char * image_name )
329
331
{
330
332
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 ;
333
334
unsigned int nbind ;
334
335
data_t data = {NULL ,};
335
336
size_t size ;
@@ -353,7 +354,6 @@ static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const
353
354
cmd = (struct load_command * )((size_t )mh + sizeof (struct mach_header_64 ));
354
355
DEBUG_CMD ("CMD START\n" );
355
356
for (i = 0 ; i < mh -> ncmds ; i ++ ) {
356
- struct dyld_info_command * dyld_info ;
357
357
#ifdef PLTHOOK_DEBUG_CMD
358
358
struct segment_command * segment ;
359
359
#endif
@@ -447,8 +447,6 @@ static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const
447
447
break ;
448
448
case LC_DYLD_INFO_ONLY : /* (0x22|LC_REQ_DYLD) */
449
449
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 ;
452
450
DEBUG_CMD ("LC_DYLD_INFO_ONLY\n"
453
451
" offset size\n"
454
452
" rebase %8x %8x\n"
@@ -540,117 +538,131 @@ static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const
540
538
return rv ;
541
539
}
542
540
} 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 );
544
545
size = offsetof(plthook_t , entries ) + sizeof (bind_address_t ) * nbind ;
545
546
data .plthook = (plthook_t * )calloc (1 , size );
546
547
if (data .plthook == NULL ) {
547
548
set_errmsg ("failed to allocate memory: %" PRIuPTR " bytes" , size );
548
549
return PLTHOOK_OUT_OF_MEMORY ;
549
550
}
550
551
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 );
552
556
}
553
557
set_mem_prot (data .plthook );
554
558
555
559
* plthook_out = data .plthook ;
556
560
return 0 ;
557
561
}
558
562
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 )
560
564
{
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 ;
564
567
const char * sym_name ;
565
568
int seg_index = 0 ;
566
569
uint64_t seg_offset = 0 ;
570
+ int addend = 0 ;
567
571
int count , skip ;
568
- unsigned int idx = 0 ;
572
+ #ifdef PLTHOOK_DEBUG_BIND
573
+ int cond = data -> plthook != NULL ;
574
+ #endif
569
575
570
576
while (ptr < end ) {
571
577
uint8_t op = * ptr & BIND_OPCODE_MASK ;
572
578
uint8_t imm = * ptr & BIND_IMMEDIATE_MASK ;
573
579
int i ;
574
580
575
- DEBUG_BIND ( "0x%02x: " , * ptr );
581
+ DEBUG_BIND_IF ( cond , "0x%02x: " , * ptr );
576
582
ptr ++ ;
577
583
switch (op ) {
578
584
case BIND_OPCODE_DONE :
579
- DEBUG_BIND ( "BIND_OPCODE_DONE\n" );
585
+ DEBUG_BIND_IF ( cond , "BIND_OPCODE_DONE\n" );
580
586
break ;
581
587
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 );
583
589
break ;
584
590
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB :
585
591
#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 ));
587
593
#else
588
594
uleb128 (& ptr );
589
595
#endif
590
596
break ;
591
597
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM :
592
598
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" );
594
600
} 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 );
596
602
}
603
+ break ;
597
604
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM :
598
605
sym_name = (const char * )ptr ;
599
606
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 );
601
608
break ;
602
609
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 );
604
611
break ;
605
612
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 );
611
615
break ;
612
616
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB :
613
617
seg_index = imm ;
614
618
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 );
616
620
break ;
617
621
case BIND_OPCODE_ADD_ADDR_ULEB :
618
622
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 );
620
624
break ;
621
625
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" );
624
629
break ;
625
630
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 );
628
634
break ;
629
635
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" );
633
639
break ;
634
640
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB :
635
641
count = uleb128 (& ptr );
636
642
skip = uleb128 (& ptr );
637
643
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 * ) ;
640
646
}
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" );
642
648
break ;
649
+ default :
650
+ DEBUG_BIND_IF (cond , "op: 0x%x, imm: 0x%x\n" , op , imm );
643
651
}
644
652
}
645
653
return idx ;
646
654
}
647
655
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 )
649
657
{
650
658
if (data -> plthook != NULL ) {
651
659
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 );
654
666
}
655
667
(* idx )++ ;
656
668
}
@@ -1081,22 +1093,23 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
1081
1093
{
1082
1094
size_t funcnamelen = strlen (funcname );
1083
1095
unsigned int pos = 0 ;
1084
- const char * name ;
1085
- void * * addr ;
1096
+ plthook_entry_t entry ;
1086
1097
int rv ;
1087
1098
1088
1099
if (plthook == NULL ) {
1089
1100
set_errmsg ("invalid argument: The first argument is null." );
1090
1101
return PLTHOOK_INVALID_ARGUMENT ;
1091
1102
}
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 ;
1093
1106
if (strncmp (name , funcname , funcnamelen ) == 0 ) {
1094
1107
if (name [funcnamelen ] == '\0' || name [funcnamelen ] == '$' ) {
1095
1108
goto matched ;
1096
1109
}
1097
1110
}
1098
1111
if (name [0 ] == '@' ) {
1099
- /* Oracle libclntsh.dylib imports 'read' as '@_read' . */
1112
+ /* I doubt this code.. . */
1100
1113
name ++ ;
1101
1114
if (strncmp (name , funcname , funcnamelen ) == 0 ) {
1102
1115
if (name [funcnamelen ] == '\0' || name [funcnamelen ] == '$' ) {
@@ -1117,20 +1130,15 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
1117
1130
if (oldfunc ) {
1118
1131
* oldfunc = * addr ;
1119
1132
}
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 )) {
1126
1134
size_t page_size = sysconf (_SC_PAGESIZE );
1127
1135
void * base = (void * )((size_t )addr & ~(page_size - 1 ));
1128
1136
if (mprotect (base , page_size , PROT_READ | PROT_WRITE ) != 0 ) {
1129
1137
set_errmsg ("Cannot change memory protection at address %p" , base );
1130
1138
return PLTHOOK_INTERNAL_ERROR ;
1131
1139
}
1132
1140
* addr = funcaddr ;
1133
- mprotect (base , page_size , prot );
1141
+ mprotect (base , page_size , entry . prot );
1134
1142
} else {
1135
1143
* addr = funcaddr ;
1136
1144
}
0 commit comments