Usecase:
Our application parses the dependent binary and fetches some data from different segments of dependent binary.
Due to the introduction of LC_DYLD_CHAINED_FIXUPS, our application is failing to get correct address due to which it is failing to fetch correct data. The same works fine if the dependent binary is built with '-no_fixup_chains' linker flag.
Sample program to demonstrate the same:
/* This is a program to access different locations in the dependent binary called 'myBinary' */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
/* Parent structure */
typedef struct
{
unsigned int tag;
uintptr_t childAddr; /* Child location */
} ParentStructure;
int main(int argc, char **argv) {
unsigned int k = 0;
char * childPtr = NULL;
ParentStructure * parentLoc = NULL;
/* Dissect the binary 'myBinary' to find Parent and Child */
int fd = open("myBinary", O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
off_t length = lseek(fd, 0, SEEK_END);
/* Map the binary 'myBinary' into current process */
void *map = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
perror("mmap");
return 1;
}
struct mach_header_64 *hdr = (struct mach_header_64 *) map;
struct load_command *lc = (struct load_command *) (hdr + 1);
for (int i = 0; i < hdr->ncmds; i++) {
if (lc->cmd == LC_SEGMENT_64) {
struct segment_command_64 *seg = (struct segment_command_64 *) lc;
if (strcmp(seg->segname, "__DATA") == 0) {
struct section_64 *sec = (struct section_64 *) (seg + 1);
for (int j = 0; j < seg->nsects; j++) {
/* Find the 'childPtr' which is at the location __find_Child */
if (strcmp(sec->sectname, "__find_Child") == 0) {
childPtr = (char *) map + sec->offset;
}
/* Find the 'ParentStructure' in __find_Parent section */
if (strcmp(sec->sectname, "__find_Parent") == 0) {
parentLoc = (ParentStructure *) map + sec->offset;
}
}
if ((parentLoc->childAddr) >= seg.vmaddr && (parentLoc->childAddr) < seg.vmaddr + seg.vmsize){
printf("SUCCESS\n");
}
else {
printf("FAILED\n");
}
}
}
lc = (struct load_command *) ((char *) lc + lc->cmdsize);
}
munmap(map, length);
close(fd);
return 0;
}
Output:
With '-no_fixup_chains'
SUCCESS
Without '-no_fixup_chains'
FAILED
Queries:
- Why the seg.vmaddr remain unchanged, but the pointers of that segment have huge values?
- How to fix this?