Как получить конкретный адрес памяти с помощью C - PullRequest
8 голосов
/ 07 июня 2009

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

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

int mmap_lena(void)
{
    FILE *fd = NULL;
    size_t lena_size;
    void *addr = NULL;

    fd = fopen("lena.png", "r");

    fseek(fd, 0, SEEK_END);
    lena_size = ftell(fd);

    addr = mmap((void *) 0x12345678, (size_t) lena_size, (int) PROT_READ, (int) MAP_SHARED, (int) fileno(fd), (off_t) 0);
    fprintf(stdout, "Addr = %p\n", addr);
    munmap((void *) addr, (size_t) lena_size);
    fclose(fd);
    fclose(fd_log);
    return EXIT_SUCCESS;
}

Я пропустил проверку возвращаемых значений для ясности.

Итак, после mmap я пытался каким-то образом получить адрес, но у меня обычно возникает ошибка сегментации, так как, как я понимаю, память защищена моей операционной системой.

int fetch_lena(void)
{
    FILE *fd = NULL;
    FILE *fd_out = NULL;
    size_t lenna_size;
    FILE *addr = (FILE *) 0x12346000;

    fd = fopen("lena.png", "r");
    fd_out = fopen("lena_out.png", "rw");

    fseek(fd, 0, SEEK_END);
    lenna_size = ftell(fd);

    // Segfault 
    fwrite((FILE *) addr, (size_t) 1, (size_t) lenna_size, (FILE *) fd_out);

    fclose(fd);
    fclose(fd_out);

    return 0;

}

Обратите также внимание, что я жестко закодировал адреса в этом примере, поэтому всякий раз, когда вы запускаете mmap_lena, значение, которое я использую в fetch_lena, может быть неправильным, поскольку операционная система принимает первый параметр в mmap только как подсказку (в моей системе это всегда по умолчанию 0x12346000).

Если есть какая-либо тривиальная ошибка кодирования, я прошу прощения, поскольку мои навыки C не полностью развиты.

Я бы хотел, чтобы, если есть какой-то способ получить нужные данные, не применяя перехватчики malloc или хаки распределения памяти.

Заранее спасибо, David

Ответы [ 6 ]

20 голосов
/ 07 июня 2009

Одна из проблем, с которой вы столкнулись, заключается в том, что вы получаете виртуальный адрес, а не физический адрес, в котором находится память. При следующей загрузке сопоставление, вероятно, будет прежним.

Это определенно может быть сделано в модуле ядра в Linux, но я не думаю, что есть какой-либо API в пользовательском пространстве, который вы можете использовать.

Если у вас есть разрешение (и я предполагаю, что вы можете быть пользователем root на этом компьютере, если перезагрузите его), то вы можете заглянуть в / dev / mem, чтобы увидеть фактическую структуру phyiscal. Возможно, вам следует попробовать выбрать значения, перезагрузиться и посмотреть, сколько из этих значений сохранилось.

11 голосов
/ 07 июня 2009

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

Тем не менее, AFAIR они считывают память без предварительной загрузки ОС и, следовательно, не должны связываться с защитой памяти ОС. Возможно, вам следует попробовать это тоже, чтобы избежать перезаписи или очистки памяти ОС после загрузки.

(Также посмотрите видео на сайте, оно довольно впечатляющее;)

5 голосов
/ 08 июня 2009

В вопросе Прямой доступ к памяти в Linux мы разработали большинство основ, необходимых для достижения этой цели. Обратите внимание, что mmap () не является ответом на это точно по причинам, которые были указаны другими. Вам нужен реальный адрес, а не виртуальный, который вы можете получить только внутри ядра (или написав драйвер для его передачи в пользовательское пространство). ).

Самым простым способом было бы написать драйвер символьного устройства, которое можно читать или записывать, с помощью ioctl, чтобы дать вам действительный начальный или конечный адрес. Опять же, если вы хотите, чтобы указатели на функции управления памятью использовались в ядре, посмотрите вопрос, на который я ссылался ... большая часть его была проработана в комментариях в первом (и принятом) ответе.

2 голосов
/ 08 июня 2009

Вы, вероятно, хотите для этой цели как можно меньше ОС; чем больше загружаемого программного обеспечения, тем больше шансов перезаписать то, что вы хотите изучить.

DOS может быть хорошей ставкой; он использует <640К памяти. Если вы не загружаете HIMEM и вместо этого пишете свою собственную (требуется сборка) подпрограмму, чтобы перейти в pmode, скопировать блок с высокой памятью в нехватку памяти, а затем вернуться в реальный режим, вы можете написать программу в основном в реальном режиме, которая может сбросить физическую память (за исключением того, сколько BIOS, DOS и ваше приложение используют). Он может записать его на флэш-диск или что-то в этом роде. </p>

Конечно, реальная проблема может заключаться в том, что BIOS очищает память во время POST.

2 голосов
/ 07 июня 2009

Ваш тестовый код выглядит странно

FILE * addr = (FILE *) 0x12346000;
fwrite ((FILE *) fd_out, (size_t) 1, (size_t) lenna_size, (FILE *) addr);

Вы не можете просто привести целое число к указателю FILE и ожидать получить что-то вменяемое. Вы также переключили первый и последний аргумент на fwrite? Предполагается, что последним аргументом будет ФАЙЛ * для записи.

1 голос
/ 07 июня 2009

Я не знаком с Linux, но вам, вероятно, потребуется написать драйвер устройства. Драйверы устройств должны иметь возможность преобразовывать адреса виртуальной памяти в адреса физической памяти для целей DMA (контроллеры DMA работают только с адресами физической памяти). Вы должны быть в состоянии использовать эти интерфейсы для работы непосредственно с физической памятью.

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