пытаясь понять C, это устанавливает функцию, равную char [] для выполнения char []? - PullRequest
0 голосов
/ 19 сентября 2010
static char yes[80]; 

int main(int argc, char *argv[])
{
    void (*point)();
    // ... sets yes[] = to input
    point = (void*) yes;
    (*point)();
}

так это создает функцию и выполняет команды, которые находятся в yes []? как узнать, читать команды в да? мне ввести c, или это должна быть сборка?

Ответы [ 4 ]

7 голосов
/ 19 сентября 2010

То, что некоторые вещи будут скомпилированы, не означает, что они будут давать корректно определенные результаты.

Вы создаете массив символов (80 из них), а затем приводите его как указатель на функцию изапустить его.Скорее всего, ваша программа потерпит крах, но ее результаты не определены.

3 голосов
/ 20 сентября 2010

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

  • Как Карлговорит, вам нужно поместить машинные инструкции в буфер, а не в C или сборку.
    • Это означает, что вы выполняете всю работу по соблюдению ABI самостоятельно.
    • Это также означает, что вы получаете никакой переносимости .Код, который делает подобные вещи, должен быть написан N раз - один раз для каждой комбинации CPU + OS, которая вас интересует.Компиляторы «точно в срок» обычно используют резервный интерпретатор байт-кода для еще не поддерживаемых платформ.
  • По соображениям безопасности вы не можете просто выгрузить машинный код вбуферизуйтесь и переходите к нему;Вы должны сообщить ОС, что вы делаете.

Как это случилось, у меня есть пример, лежащий рядом.Это проверено только для работы на (x86 или x86-64) / Linux.Если вы хотите, чтобы это делало что-то более интересное, вам нужно заменить memset кодом, который заполнил буфер, машинным кодом для более интересной операции.

Это не будет работает на любом другом процессоре, поскольку он жестко связывает машинную кодировку x86 с инструкцией возврата.Он , вероятно, не будет работать на любой другой ОС x86, потому что он игнорирует минное поле переносимости, окружающее mmap и mprotect: - (

#define _GNU_SOURCE 1
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static void __attribute__((noreturn))
perror_exit(const char *msg)
{
    perror(msg);
    exit(1);
}
int main(void)
{
    /* allocate one writable page */
    size_t pagesize = getpagesize();
    void *rgn = mmap(0, pagesize, PROT_READ|PROT_WRITE,
                     MAP_PRIVATE|MAP_ANON, -1, 0);
    if (rgn == MAP_FAILED)
        perror_exit("mmap");

    /* fill it with return instructions */
    memset(rgn, 0xC3, pagesize);

    /* now switch the page from writable to executable */
    if (mprotect((caddr_t)rgn, pagesize, PROT_READ|PROT_EXEC))
        perror_exit("mprotect");

    /* now we can call it */
    ((void (*)(void))rgn)();
    return 0;
}
2 голосов
/ 19 сентября 2010

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

Не забывайте, что указатели кода и указатели данных должны быть несовместимы.

2 голосов
/ 19 сентября 2010

Вы, вероятно, могли бы заставить этот код работать так, как вы хотите, но он будет сильно зависеть от машины / компилятора / системы. Материал, который вы вводите в yes, должен быть машинными инструкциями, а не сборкой C или . Я постараюсь проработать пример.

Edit: Мои несколько быстрых тестов не дали ничего полезного. Я думаю, в Mac OS X происходит слишком много защиты памяти / безопасности / безопасности. Ваш код, безусловно, может быть настроен для работы в менее защищенной среде - встроенные системы, BIOS и т. Д.

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