Есть одна laba1, которую я типа взламываю. laba1 это программа на C, в ней есть функция write_secret, и мне нужно подавая определенный ввод этой проге, добиться, чтобы эта функция вызвалась.
Эта программа читает ввод с stdin, распознает ввод как число и пытается из массива указателей на функции выбрать функцию по индексу, равному этому числу. Функции write_secret в этом массиве нет, но там нет никаких проверок на out-of-bounds, короче я могу подобрать такое число, что программа сделает call (архитектура = x86) по адресу, который указывает на середину массива, читающегося с stdin. Соответственно мне надо записать какие-то инструкции через stdin, чтобы они вызвали функцию write_secret.
В описании этой лабы на курсере говорят, что туда надо впихнуть какие-то 4 числа по 3 байта
вида \xEE\xEE\xEE\xEE (вместо EE что-то подставлять), чтобы когда процессор вызовет CALL по адресу этих байтов, чтобы они вызвали нужную функцию.
А, эти \x хрени это кажется шестнадцатиричные чиселки, каждое из двух шестнадцатиричных цифр, то есть каждое число это 16*16 = 256 значений, то есть каждое \xEE это 3 байта.
Я тут гуглил, смотрел в gdb и просто получал ассемблерный код и смотрел, как там программа обычно вызывает функции, она их вызывает например вот так.
https://pp.vk.me/c627617/v627617612/22fed/OCMWTdAVCHM.jpg
Там видно, что строчка tmp(); в ассемблере это
MOV EAX, локальная переменная tmp
и затем CALL EAX.
А если на этом скриншотике посмотреть в низ лево, то там увидите, что я с помощью гдб посмотрел, че там в цифрах записано в этих двух ассемблерных строчках:
0x8048808 // это MOV
0x804880b // это CALL
Ну короче если это перевести в формат по 4 16-ричных числа, то это
[ ff d0 e9 3a ]
[ 8b 45 f4 ff ]
И действительно, я нагуглил онлайн дизассемблер https://www.onlinedisassembler.com/odaweb/
туда вбил 8b 45 f4 ff и получил то же самое, что ассемблером написано в гдб - mov eax,DWORD PTR [ebp-0xc]
а под ним получил .byte 0xff - то есть я так понимаю, что в этой команде нужен номер операции, и 2 каких-то числа, означающих номер регистра и какое-то там смещение наверное, а 4-ое число не нужно, поэтому там ff, который ничего не значит.
И еще я где-то нагуглил опкоды операции CALL: https://pp.vk.me/c627617/v627617612/22ff7/IBPjdUUmNUw.jpg значит CALL который начинается с 3 байтов ff это либо Call near, absolute indirect, address given in r/m16 ( и тут же такой же вариант с r/m32 в конце), либо Call far, absolute indirect, address given in m16:16 (либо опять же 32 в самом конце).
И вот видимо мне надо состряпать инструкции, чтобы вызвать функцию по адресу, известному мне (да, я знаю адрес write_secret - беру его из gdb
(gdb) print &write_secret
$4 = (void (*)(void)) 0x8048534 <write_secret>
Стоит заметить, что в коде на скриншотике fptr это указатель на функцию, принимающую void и возвращающую void.
А собственно почему мне так именно вызвать нужно? Ну в этом курсе там задают наводящие вопросы - сначала меня спрашивают, какое число надо подать на стандартный вход, чтобы с помощью переполнения буффера указатель, указывающий обычно на какую-нибудь функцию, указал на 65-ый байт переменной buf, которая собственно читается с stdin. Это я смог сделать. Но теперь мне надо придумать, какие байтики послать на 65-ый и следующие байты buf, чтобы когда процессор выполнял их, но выполнил эту самую функцию write_secret по адресу мне известному. И вот я пытаюсь понять, как в эти 65-ый и дальше байты засунуть CALL с адресом и наверное RET.