ошибка доступа к памяти при чтении записей PT_DYNAMIC Elf32 на Android 6.0 - PullRequest
0 голосов
/ 15 марта 2019

Чтобы подключить функцию libc приложения Android (т.е. app_process32), я сначала читаю все адресное пространство, сохраненное в /proc/self/maps, и для каждого загруженного ELF я перезаписываю соответствующую запись о перемещении.

Чтение строки /proc/self/maps:

Elf32_Addr start, end;
sscanf(line, "%8x-%8x", &start, &end);

Тогда я проверяю, является ли это ЭЛЬФ, проверяя магию. Если это ELF, я читаю его сегмент PT_DYNAMIC и перебираю его записи:

Elf32_Ehdr *ehdr = (Elf32_Ehdr *) start;
Elf32_Phdr *phdr = (Elf32_Phdr *) ((unsigned char *) ehdr + ehdr->e_phoff);
Elf32_Half phnum = ehdr->e_phnum;
Elf32_Addr dynamic = 0;    

for (; phnum > 0; --phnum, ++phdr) {
    if (phdr->p_type == PT_DYNAMIC) {
        dynamic = start + phdr->p_vaddr;
        break;
    }
}

А вот как я перебираю динамические записи:

Elf32_Dyn *dyn;
for (dyn = (Elf32_Dyn *) dynamic; dyn->d_tag; dyn++) {
    Elf32_Addr addr = dyn->d_un.d_ptr;
    Elf32_Sword val = dyn->d_un.d_val;

    switch (dyn->d_tag) {
        // rest of the code.
    }
}

Для некоторых общих объектов это нормально, но для некоторых я получаю SIGSEGV при проверке условия цикла dyn->d_tag. Почему PT_DYNAMIC указывает на местоположение, которое я не могу прочитать? Также я заметил, что dynamic обычно > end, это нормально?

Я использую устройство под управлением 32-разрядной версии Android 6.0.

1 Ответ

1 голос
/ 16 марта 2019

Этот расчет:

dynamic = start + phdr->p_vaddr;

верно только для образов ELF, связанных по адресу 0, что типично для разделяемых библиотек и независимых от позиции исполняемых файлов, но не требуется.

Я предполагаю, что у вас есть общие библиотеки, которые были предварительно связаны с адресом, отличным от 0.

Эта библиотека не была предварительно связана:

readelf -Wl foo.so | egrep 'LOAD|DYNAMIC'
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000684 0x000684 R E 0x200000
  LOAD           0x000e40 0x0000000000200e40 0x0000000000200e40 0x0001e0 0x0001e8 RW  0x200000
  DYNAMIC        0x000e50 0x0000000000200e50 0x0000000000200e50 0x000190 0x000190 RW  0x8

Та же библиотека после prelink -r 0x120000 foo.so:

readelf -Wl foo.so | egrep 'LOAD|DYNAMIC'
  LOAD           0x000000 0x0000000012000000 0x0000000012000000 0x000684 0x000684 R E 0x200000
  LOAD           0x000e40 0x0000000012200e40 0x0000000012200e40 0x0001e0 0x0001e8 RW  0x200000
  DYNAMIC        0x000e50 0x0000000012200e50 0x0000000012200e50 0x000190 0x000190 RW  0x8

Если предварительно связанная библиотека загружается в ваше приложение по адресу, указанному по адресу (start==0x12200000), вы получите dynamic == 0x12200e50+0x12200000, что, очевидно, является поддельным.

Чтобы учесть это, вам необходимо:

dynamic = start + phdr->p_vaddr - first_pt_load->p_vaddr;

, где first_pt_load - самый низкий сегмент PT_LOAD (который будет иметь .p_vaddr == 0 для библиотеки без предварительной ссылки и 0x12000000 для библиотеки с предварительной ссылкой).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...