Mach_header 64 бит и __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 ГБ.
Также обратите внимание, что память на самом деле не занята. Это просто "зарезервированное виртуальное пространство" (то есть "оно никогда не будет использовано"). Он занимает абсолютно нулевые ресурсы, потому что он не отображается в таблице страниц, его нет физически. Это просто запись в файле, которая сообщает загрузчику, что зарезервировать это пространство, чтобы оно никогда не использовалось и, таким образом, "защищалось". Фактические "данные" этого раздела имеют нулевой размер, так как, опять же, там на самом деле ничего нет, просто "убедитесь, что это не используется". Таким образом, фактический размер файла не будет больше или меньше, если этот раздел будет изменен в размере. Он был бы на несколько байтов меньше (размер описания раздела), если бы его вообще не было. Но это действительно единственное, что могло бы иметь значение.
Цель __PAGEZERO
это поймать разыменования нулевого указателя. Резервируя большой раздел памяти в начале памяти, любой доступ через указатель NULL будет перехвачен, и приложение будет прервано. В 32-битной архитектуре что-то вроде:
int *p = NULL;
int x = p[0x100000];
скорее всего, удастся, потому что при 0x400000 (4 МБ) начинается кодовое пространство (попытка записи в такое место может привести к сбою, но чтение будет работать - при условии, конечно, что кодовое пространство действительно начинается там, а не где-то еще в диапазон адресов.
Редактировать:
Эта презентация показывает, что ARM, последний участник процесса 64-битного процессора, также использует 48-битное виртуальное адресное пространство и применяет канонические адреса (старшие 16 бит должны иметь одинаковое значение), поэтому его можно расширить в будущее. Другими словами, виртуальное пространство, доступное на 64-битном процессоре ARM, также составляет 256 ТБ.