Итак, вы хотите, чтобы программа выполнила ваш шеллкод. Он уже в машинной форме, поэтому готов к выполнению системой. Вы сохранили его в буфере. Итак, вопрос будет: «Как система узнает, как выполнить мой код?» Точнее, «Как система узнает, где искать следующий код для выполнения?» Ответ в этом случае - обратный адрес, о котором вы говорите.
По сути, вы на правильном пути. Вы пытались выполнить код? Одна вещь, которую я заметил при выполнении этого типа эксплойта, это то, что это не точная наука. Иногда в памяти есть другие вещи, которых вы не ожидаете, поэтому вам нужно увеличить количество байтов, которые вы добавляете в свой буфер, чтобы правильно выровнять адрес возврата в соответствии с тем, чего ожидает система.
Я не специалист по безопасности, но могу рассказать вам несколько вещей, которые могут помочь. Во-первых, я обычно включаю «NOP Sled» - по сути, просто серию байтов 0x90, которые не выполняют ничего, кроме выполнения инструкций «NOP» на процессоре. Другой трюк заключается в том, чтобы повторить адрес возврата в конце буфера, так что если хотя бы один из них перезапишет адрес возврата в стеке, вы получите успешный возврат туда, куда вы хотите.
Итак, ваш буфер будет выглядеть так:
| NOP SLED | SHELLCODE | ПОВТОРНЫЙ ВОЗВРАТ АДРЕС |
(Примечание: это не мои идеи, я получил их от Jack Erickson от Hacking: The Art of Exploration. Я рекомендую эту книгу, если вам интересно узнать больше об этом).
Для вычисления адреса вы можете использовать что-то похожее на следующее:
unsigned long sp(void)
{ __asm__("movl %esp, %eax");} // returns the address of the stack pointer
int main(int argc, char *argv[])
{
int i, offset;
long esp, ret, *addr_ptr;
char* buffer;
offset = 0;
esp = sp();
ret = esp - offset;
}
Теперь ret будет содержать адрес возврата, на который вы хотите вернуться, при условии, что вы выделите буфер для кучи.