Mach_header 64bit и __PAGEZERO сегмент 64 бит

const struct mach_header *mach = _dyld_get_image_header(0);
struct load_command *lc;
struct segment_command_64 *sc64;
struct segment_command *sc;

if (mach->magic == MH_MAGIC_64) {
    lc = (struct load_command *)((unsigned char *)mach + sizeof(struct mach_header_64));
    printf("[+] detected 64bit ARM binary in memory.\n");
} else {
    lc = (struct load_command *)((unsigned char *)mach + sizeof(struct mach_header));
    printf("[+] detected 32bit ARM binary in memory.\n");
}

for (int i = 0; i < mach->ncmds; i++) {

    if (lc->cmd == LC_SEGMENT) {
        sc = (struct segment_command *)lc;
        NSLog(@"32Bit: %s (%x - 0x%x)",sc->segname,sc->vmaddr,sc->vmsize);
    } else if (lc->cmd == LC_SEGMENT_64) {
        sc64 = (struct segment_command_64 *)lc;
        NSLog(@"64Bit: %s (%llx - 0x%llx)",sc64->segname,sc64->vmaddr,sc64->vmsize);
    }
    lc = (struct load_command *)((unsigned char *)lc+lc->cmdsize);
}

Когда я запускаю этот код в 32Bit, я получаю нормальные выходы:

__PAGEZERO (0 - 0x1000) 
But on 64Bit: __PAGEZERO (0 - 0x100000000) 

__PAGEZERO goes from 0x1000 to over 0x100000000 по размеру, есть ли какое-либо исправление для него или любое решение, почему это происходит?

Ответ 1

Создание большой __PAGEZERO в 64-битной архитектуре имеет много смысла. Диапазон адресов 64-разрядной системы, даже когда верхние 16 бит "обрезаны", как и у x86_64, позволяет использовать огромный объем памяти (48-разрядное адресное пространство x86_64 составляет 256 ТБ адресного пространства памяти). Весьма вероятно, что это будет считаться "маленьким" в какой-то момент в будущем, но сейчас самые большие серверы имеют 1-4 ТБ, поэтому есть много возможностей для роста, а более обычные машины имеют 16-32 ГБ.

Обратите внимание также, что на самом деле память не была OCCUPIED. Это просто "зарезервированное виртуальное пространство" (то есть "оно никогда не будет использоваться" ). Он занимает абсолютно нулевые ресурсы, потому что он не отображается в таблице страниц, он не существует физически. Это просто запись в файле, в которой говорится, что загрузчик резервирует это пространство, и никогда не может быть использован и, таким образом, "защищен". Фактические "данные" этого раздела равны нулю по размеру, поскольку, опять же, там фактически ничего нет, просто "убедитесь, что это не используется". Таким образом, размер вашего фактического файла не будет больше или меньше, если этот раздел будет изменен в размере. Это было бы на несколько байт меньше (размер описания раздела), если он вообще не существовал. Но это действительно единственное, что могло бы иметь значение вообще.

Цель __PAGEZERO состоит в том, чтобы перехватывать NULL-указатели. Сохраняя большой раздел памяти в начале памяти, любой доступ через указатель NULL будет пойман и приложение будет прервано. В 32-битной архитектуре что-то вроде:

int *p = NULL;
int x = p[0x100000]; 

вероятно, преуспеет, потому что на 0x400000 (4 МБ) начинается пробел кода (попытка записи в такое место, скорее всего, потерпит крах, но чтение будет работать - предполагая, конечно, что кодовое пространство действительно начинается там, а не где-то иначе в диапазоне адресов.

Изменить:

Эта презентация показывает, что ARM, последний участник в 64-разрядном процессоре, также использует 48-битное виртуальное адресное пространство и применяет канонические адреса (первые 16 бит должны быть одинаковыми), поэтому их можно расширить в будущем. Другими словами, виртуальное пространство, доступное на 64-битном процессоре ARM, также составляет 256 ТБ.