Главная страница
Навигация по странице:

  • 0x285 Указатели на функции

  • 0x286 Псевдослучайные числа

  • Хакинг. Хакинг__искусство_эксплоита_2_е_469663841. Книга дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах


    Скачать 2.5 Mb.
    НазваниеКнига дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах
    АнкорХакинг
    Дата16.06.2022
    Размер2.5 Mb.
    Формат файлаpdf
    Имя файлаХакинг__искусство_эксплоита_2_е_469663841.pdf
    ТипКнига
    #595131
    страница14 из 51
    1   ...   10   11   12   13   14   15   16   17   ...   51

    time_example2.c
    #include
    #include
    void dump_time_struct_bytes(struct tm *time_ptr, int size) {
    int i;
    unsigned char *raw_ptr;
    printf(“bytes of struct located at 0x%08x\n”, time_ptr);
    raw_ptr = (unsigned char *) time_ptr;
    for(i=0; i < size; i++)

    118
    0x200 Программирование
    {
    printf(“%02x “, raw_ptr[i]);
    if(i%16 == 15) // Начинать новую строку через каждые 16 байт.
    printf(“\n”);
    }
    printf(“\n”);
    }
    int main() {
    long int seconds_since_epoch;
    struct tm current_time, *time_ptr;
    int hour, minute, second, i, *int_ptr;
    seconds_since_epoch = time(0); // Передать функции time в качестве
    // аргумента нулевой указатель.
    printf(“time() - seconds since epoch: %ld\n”, seconds_since_epoch);
    time_ptr = ¤t_time; // Поместить в time_ptr адрес
    // структуры current_time.
    localtime_r(&seconds_since_epoch, time_ptr);
    // Три способа доступа к элементам структуры:
    hour = current_time.tm_hour; // Прямой доступ minute = time_ptr->tm_min; // Доступ по указателю second = *((int *) time_ptr); // Хакерский доступ по указателю printf(“Current time is: %02d:%02d:%02d\n”, hour, minute, second);
    dump_time_struct_bytes(time_ptr, sizeof(struct tm));
    minute = hour = 0; // Очистить минуты и часы.
    int_ptr = (int *) time_ptr;
    for(i=0; i < 3; i++) {
    printf(“int_ptr @ 0x%08x : %d\n”, int_ptr, *int_ptr);
    int_ptr++; // Прибавление 1 к int_ptr увеличивает адрес на 4,
    } // так как int занимает 4 байта.
    }
    Результат компиляции и выполнения time_example2.c:
    reader@hacking:

    /booksrc $ gcc -g time_example2.c reader@hacking:/booksrc $ ./a.out time() - seconds since epoch: 1189311744
    Current time is: 04:22:24
    bytes of struct located at 0xbffff7f0 18 00 00 00 16 00 00 00 04 00 00 00 09 00 00 00 08 00 00 00 6b 00 00 00 00 00 00 00 fb 00 00 00 00 00 00 00 00 00 00 00 28 a0 04 08
    int_ptr @ 0xbffff7f0 : 24
    int_ptr @ 0xbffff7f4 : 22

    0x280 Опираясь на основы
    119
    int_ptr @ 0xbffff7f8 : 4
    reader@hacking:/booksrc $
    Такой способ доступа к памяти структуры основан на допущениях в от- ношении типа переменных, содержащихся в структуре, и отсутствии вставок между отдельными переменными. Поскольку структура хра- нит также сведения о типах образующих ее переменных, гораздо про- ще пользоваться правильными методами.
    0x285 Указатели на функции
    Указатель всего лишь содержит адрес памяти и сообщает тип данных, хранящихся по этому адресу. Обычно указатели используются с пере- менными, но могут также указывать на функции. Программа funcptr_
    example.c иллюстрирует применение указателей на функции.
    funcptr_example.c
    #include
    int func_one() {
    printf(“This is function one\n”);
    return 1;
    }
    int func_two() {
    printf(“This is function two\n”);
    return 2;
    }
    int main() {
    int value;
    int (*function_ptr) ();
    function_ptr = func_one;
    printf(“function_ptr is 0x%08x\n”, function_ptr);
    value = function_ptr();
    printf(“value returned was %d\n”, value);
    function_ptr = func_two;
    printf(“function_ptr is 0x%08x\n”, function_ptr);
    value = function_ptr();
    printf(“value returned was %d\n”, value);
    }
    В этой программе в main() объявляется указатель на функцию, он так и называется – function_ptr. Затем он получает значение, указываю- щее на функцию func_one(), и вызывается. После этого он получает но- вое значение и позволяет вызвать func_two(). Ниже приведен результат компиляции и выполнения этого исходного кода.

    120
    0x200 Программирование reader@hacking:/booksrc $ gcc funcptr_example.c reader@hacking:/booksrc $ ./a.out function_ptr is 0x08048374
    This is function one value returned was 1
    function_ptr is 0x0804838d
    This is function two value returned was 2
    reader@hacking:/booksrc $
    0x286 Псевдослучайные числа
    Поскольку компьютеры – это детерминированные машины, они не в состоянии генерировать действительно случайные числа. Но во мно- гих приложениях в той или иной форме требуется случайность. Эту по- требность удовлетворяют функции-генераторы псевдослучайных чи- сел, вырабатывающие поток чисел, являющихся псевдослучайными.
    Они могут генерировать последовательность чисел, которые выглядят случайными начиная с некоторого исходного числа; при этом, если взять то же самое начальное число, будет сгенерирована та же самая последовательность. Детерминированные машины не могут обеспе- чить полную случайность, но если не знать начальное число генератора псевдослучайных чисел, производимая им последовательность кажет- ся случайной. Генератору нужно задать начальное значение, получен- ное с помощью функции srand(), после этого функция rand() будет воз- вращать псевдослучайные числа в диапазоне от 0 до RAND_MAX. Эти функ- ции и RAND_MAX определены в stdlib.h. Хотя числа, возвращаемые rand(), кажутся случайными, они зависят от начального значения, передан- ного srand(). Чтобы сохранять псевдослучайность при каждом вызове программы, генератору случайных чисел нужно каждый раз задавать новое начальное значение. Часто для этого берут количество секунд, истекших с начала эпохи (его возвращает функция time()). Этот прием иллюстрирует программа rand_example.c.
    rand_example.c
    #include
    #include
    int main() {
    int i;
    printf(“RAND_MAX is %u\n”, RAND_MAX);
    srand(time(0));
    printf(“random values from 0 to RAND_MAX\n”);
    for(i=0; i < 8; i++)
    printf(“%d\n”, rand());
    printf(“random values from 1 to 20\n”);
    for(i=0; i < 8; i++)

    0x280 Опираясь на основы
    121
    printf(“%d\n”, (rand()%20)+1);
    }
    Обратите внимание на способ получения случайных чисел от 1 до 20 с помощью оператора деления по модулю.
    reader@hacking:/booksrc $ gcc rand_example.c reader@hacking:/booksrc $ ./a.out
    RAND_MAX is 2147483647
    random values from 0 to RAND_MAX
    815015288 1315541117 2080969327 450538726 710528035 907694519 1525415338 1843056422
    random values from 1 to 20 2
    3 8
    5 9
    1 4
    20
    reader@hacking:/booksrc $ ./a.out
    RAND_MAX is 2147483647
    random values from 0 to RAND_MAX
    678789658 577505284 1472754734 2134715072 1227404380 1746681907 341911720 93522744
    random values from 1 to 20 6
    16 12 19 8
    19 2
    1
    reader@hacking:/booksrc $
    Эта программа просто выводит случайные числа. Псевдослучайность можно применять в более сложных программах, о чем свидетельствует сценарий, завершающий эту главу.

    122
    0x200 Программирование
    0x287 Азартная игра
    Последняя программа этой главы представляет собой набор азартных игр, в которых используются многие из обсуждавшихся идей. Элемент случайности в этой программе обеспечивают функции-генераторы псевдослучайных чисел.
    Там есть три разных игровых функции, которые вызываются с помо- щью единого глобального указателя на функцию, а данные, относящи- еся к игроку, записываются в структуры, хранящиеся в файле. Права доступа и идентификаторы пользователей дают возможность несколь- ким игрокам играть и сохранять собственные данные. Код программы
    game_of_chance.c содержит много комментариев и должен быть вам понятен.
    game_of_chance.c
    #include
    #include
    #include
    #include
    #include
    #include
    #include “hacking.h”
    #define DATAFILE “/var/chance.data” // Файл для хранения
    // пользовательских данных
    // Специальная структура user хранит сведения о пользователях struct user {
    int uid;
    int credits;
    int highscore;
    char name[100];
    int (*current_game) ();
    };
    // Прототипы функций int get_player_data();
    void register_new_player();
    void update_player_data();
    void show_highscore();
    void jackpot();
    void input_name();
    void print_cards(char *, char *, int);
    int take_wager(int, int);
    void play_the_game();
    int pick_a_number();
    int dealer_no_match();
    int find_the_ace();
    void fatal(char *);

    0x280 Опираясь на основы
    123
    // Глобальные переменные struct user player; // Структура с данными игрока int main() {
    int choice, last_game;
    srand(time(0)); // Начальное значение генератора
    // случайных чисел определяется текущим временем.
    if(get_player_data() == -1) // Попытка прочитать данные игрока из файла.
    register_new_player(); // Если данных нет,
    // зарегистрировать нового игрока.
    while(choice != 7) {
    printf(“-=[ Game of Chance Menu ]=-\n”);
    printf(“1 - Play the Pick a Number game\n”);
    printf(“2 - Play the No Match Dealer game\n”);
    printf(“3 - Play the Find the Ace game\n”);
    printf(“4 - View current high score\n”);
    printf(“5 - Change your user name\n”);
    printf(“6 - Reset your account at 100 credits\n”);
    printf(“7 - Quit\n”);
    printf(“[Name: %s]\n”, player.name);
    printf(“[You have %u credits] -> “, player.credits);
    scanf(“%d”, &choice);
    if((choice < 1) || (choice > 7))
    printf(“\n[!!] The number %d is an invalid selection.\n\n”, choice);
    else if (choice < 4) { // Если была выбрана та или иная игра.
    if(choice != last_game) { // Если указатель на функцию
    // не определен,
    if(choice == 1) // задать указатель на выбранную игру player.current_game = pick_a_number;
    else if(choice == 2)
    player.current_game = dealer_no_match;
    else player.current_game = find_the_ace;
    last_game = choice; // и запомнить последнюю выбранную игру.
    }
    play_the_game(); // Сыграть в игру.
    }
    else if (choice == 4)
    show_highscore();
    else if (choice == 5) {
    printf(“\nChange user name\n”);
    printf(“Enter your new name: “);
    input_name();
    printf(“Your name has been changed.\n\n”);
    }
    else if (choice == 6) {
    printf(“\nYour account has been reset with 100 credits.\n\n”);

    124
    0x200 Программирование player.credits = 100;
    }
    }
    update_player_data();
    printf(“\nThanks for playing! Bye.\n”);
    }
    // Эта функция читает данные игрока для текущего uid
    // из файла. Она возвращает -1, если не может найти данные игрока
    // для текущего uid.
    int get_player_data() {
    int fd, uid, read_bytes;
    struct user entry;
    uid = getuid();
    fd = open(DATAFILE, O_RDONLY);
    if(fd == -1) // Не получается открыть файл; возможно, он не существует.
    return -1;
    read_bytes = read(fd, &entry, sizeof(struct user)); // Прочитать
    // первый блок.
    while(entry.uid != uid && read_bytes > 0) { // Повторять в цикле
    // до обнаружения нужного uid.
    read_bytes = read(fd, &entry, sizeof(struct user)); // Продолжать
    // чтение.
    }
    close(fd); // Закрыть файл.
    if(read_bytes < sizeof(struct user)) // Это означает,
    // что достигнут конец файла.
    return -1;
    else player = entry; // Копировать считанный объект в структуру player.
    return 1; // Если успех, вернуть 1.
    }
    // Функция регистрации нового пользователя.
    // Создает учетную запись для нового игрока и дописывает ее в файл.
    void register_new_player() {
    int fd;
    printf(“-=-={ New Player Registration }=-=-\n”);
    printf(“Enter your name: “);
    input_name();
    player.uid = getuid();
    player.highscore = player.credits = 100;
    fd = open(DATAFILE, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if(fd == -1)
    fatal(“in register_new_player() while opening file”);
    write(fd, &player, sizeof(struct user));

    0x280 Опираясь на основы
    125
    close(fd);
    printf(“\nWelcome to the Game of Chance %s.\n”, player.name);
    printf(“You have been given %u credits.\n”, player.credits);
    }
    // Эта функция записывает в файл сведения о текущем игроке.
    // В основном служит для обновления результатов после завершения игры.
    void update_player_data() {
    int fd, i, read_uid;
    char burned_byte;
    fd = open(DATAFILE, O_RDWR);
    if(fd == -1) // Если не удалось открыть файл, есть серьезные проблемы.
    fatal(“in update_player_data() while opening file”);
    read(fd, &read_uid, 4); // Прочитать uid из первой структуры.
    while(read_uid != player.uid) { // Повторять, пока не отыщется нужный uid.
    for(i=0; i < sizeof(struct user) - 4; i++) // Прочитать остаток read(fd, &burned_byte, 1); // структуры.
    read(fd, &read_uid, 4); // Прочитать uid
    // из следующей структуры.
    }
    write(fd, &(player.credits), 4); // Обновить результаты.
    write(fd, &(player.highscore), 4); // Обновить лучший результат.
    write(fd, &(player.name), 100); // Обновить имя.
    close(fd);
    }
    // Эта функция выводит текущий лучший результат
    // и имя лучшего игрока.
    void show_highscore() {
    unsigned int top_score = 0;
    char top_name[100];
    struct user entry;
    int fd;
    printf(“\n====================| HIGH SCORE |====================\n”);
    fd = open(DATAFILE, O_RDONLY);
    if(fd == -1)
    fatal(“in show_highscore() while opening file”);
    while(read(fd, &entry, sizeof(struct user)) > 0) { // Повторять, пока
    // не закончится файл.
    if(entry.highscore > top_score) { // Если есть лучший результат,
    top_score = entry.highscore; // записать его в top_score strcpy(top_name, entry.name); // и имя пользователя в top_name.
    }
    }
    close(fd);
    if(top_score > player.highscore)
    printf(“%s has the high score of %u\n”, top_name, top_score);
    else

    126
    0x200 Программирование printf(“You currently have the high score of %u credits!\n”, player.highscore);
    printf(“======================================================\n\n”);
    }
    // Эта функция присуждает джекпот для игры Pick a Number (выбери число).
    void jackpot() {
    printf(“*+*+*+*+*+* JACKPOT *+*+*+*+*+*\n”);
    printf(“You have won the jackpot of 100 credits!\n”);
    player.credits += 100;
    }
    // Эта функция вводит имя игрока, поскольку
    // scanf(“%s”, &whatever) прекращает ввод на первом пробеле.
    void input_name() {
    char *name_ptr, input_char=’\n’;
    while(input_char == ‘\n’) // Сбросить оставшиеся scanf(“%c”, &input_char); // символы перевода строки.
    name_ptr = (char *) &(player.name); // name_ptr = адрес имени игрока while(input_char != ‘\n’) { // Повторять до перевода строки.
    *name_ptr = input_char; // Поместить введенный символ в поле name.
    scanf(“%c”, &input_char); // Получить следующий символ.
    name_ptr++; // Увеличить указатель.
    }
    *name_ptr = 0; // Завершить строку.
    }
    // Эта функция выводит три карты в игре Find the Ace.
    // Она принимает сообщение, которое нужно вывести, указатель на массив карт
    // и карту, которую пользователь выбрал для ввода.
    // Если user_pick равен -1, отображаются номера выбора.
    void print_cards(char *message, char *cards, int user_pick) {
    int i;
    printf(“\n\t*** %s ***\n”, message);
    printf(“ \t._.\t._.\t._.\n”);
    printf(“Cards:\t|%c|\t|%c|\t|%c|\n\t”, cards[0], cards[1], cards[2]);
    if(user_pick == -1)
    printf(“ 1 \t 2 \t 3\n”);
    else {
    for(i=0; i < user_pick; i++)
    printf(“\t”);
    printf(“ ^-- your pick\n”);
    }
    }
    // Эта функция вводит ставки для игр No Match Dealer
    // и Find the Ace. Она принимает в качестве аргументов имеющиеся
    // очки и предыдущую ставку. previous_wager имеет значение только
    // для второй ставки в игре Find the Ace.
    // Функция возвращает -1, если ставка слишком велика или слишком мала,

    0x280 Опираясь на основы
    127
    // и размер ставки в противном случае.
    int take_wager(int available_credits, int previous_wager) {
    int wager, total_wager;
    printf(“How many of your %d credits would you like to wager? “, available_credits);
    scanf(“%d”, &wager);
    if(wager < 1) { // Проверить, что ставка больше 0.
    printf(“Nice try, but you must wager a positive number!\n”);
    return -1;
    }
    total_wager = previous_wager + wager;
    if(total_wager > available_credits) { // Подтвердить имеющиеся очки.
    printf(“Your total wager of %d is more than you have!\n”, total_wager);
    printf(“You only have %d available credits, try again.\n”, available_credits);
    return -1;
    }
    return wager;
    }
    // В этой функции есть цикл, позволяющий снова сыграть
    // текущую игру. Он также записывает в файл новую сумму очков
    // после каждой сыгранной игры.
    void play_the_game() {
    int play_again = 1;
    int (*game) ();
    char selection;
    while(play_again) {
    printf(“\n[DEBUG] current_game pointer @ 0x%08x\n”, player.current_game);
    if(player.current_game() != -1) { // Если игра сыграна успешно if(player.credits > player.highscore) // и установлен новый рекорд,
    player.highscore = player.credits; // обновить рекорд.
    printf(“\nYou now have %u credits\n”, player.credits);
    update_player_data(); // Записать новую сумму
    // очков в файл.
    printf(“Would you like to play again? (y/n) “);
    selection = ‘\n’;
    while(selection == ‘\n’) // Сбросить лишние
    // переводы строки.
    scanf(“%c”, &selection);
    if(selection == ‘n’)
    play_again = 0;
    }
    else // Это значит, что игра вернула ошибку,
    play_again = 0; // поэтому вернуться в главное меню.
    }
    }

    128
    0x200 Программирование
    // Эта функция реализует игру Pick a Number.
    // Она возвращает -1, если у игрока недостаточно очков.
    int pick_a_number() {
    int pick, winning_number;
    printf(“\n####### Pick a Number ######\n”);
    printf(“This game costs 10 credits to play. Simply pick a number\n”);
    printf(“between 1 and 20, and if you pick the winning number, you\n”);
    printf(“will win the jackpot of 100 credits!\n\n”);
    winning_number = (rand() % 20) + 1; // Выбрать число от 1 до 20.
    if(player.credits < 10) {
    printf(“You only have %d credits. That’s not enough to play!\n\n”, player.credits);
    return -1; // Недостаточно очков для игры
    }
    player.credits -= 10; // Вычесть 10 очков.
    printf(“10 credits have been deducted from your account.\n”);
    printf(“Pick a number between 1 and 20: “);
    scanf(“%d”, &pick);
    printf(“The winning number is %d\n”, winning_number);
    if(pick == winning_number)
    jackpot();
    else printf(“Sorry, you didn’t win.\n”);
    return 0;
    }
    // Это игра No Match Dealer.
    // Она возвращает -1, если у игрока 0 очков.
    int dealer_no_match() {
    int i, j, numbers[16], wager = -1, match = -1;
    printf(“\n::::::: No Match Dealer :::::::\n”);
    printf(“In this game, you can wager up to all of your credits.\n”);
    printf(“The dealer will deal out 16 random numbers between 0 and 99.\n”);
    printf(“If there are no matches among them, you double your money!\n\n”);
    if(player.credits == 0) {
    printf(“You don’t have any credits to wager!\n\n”);
    return -1;
    }
    while(wager == -1)
    wager = take_wager(player.credits, 0);
    printf(“\t\t::: Dealing out 16 random numbers :::\n”);
    for(i=0; i < 16; i++) {
    numbers[i] = rand() % 100; // Выбрать число от 0 до 99.
    printf(“%2d\t”, numbers[i]);
    if(i%8 == 7) // С новой строки через каждые 8 чисел.
    printf(“\n”);

    0x280 Опираясь на основы
    1   ...   10   11   12   13   14   15   16   17   ...   51


    написать администратору сайта