Как перезапустить KDE Plasma из tty?

Вызов вашего кода exit () заканчивается тем, что связывается с функцией библиотеки C (libc) exit () , которая на самом деле может не выполнять int $ 0x80 .

Вызов из вашего кода при вызове функции exit () фактически компилируется как инструкция call в Таблицу Связи Программы или PLT. Динамический компоновщик времени выполнения заботится о отображении файла /usr/lib/libc.so в память. Это библиотека C. Динамический компоновщик во время выполнения также исправляет записи в PLT, чтобы в конечном итоге вызвать код, отображаемый из /usr/lib/libc.so .

Насколько я могу судить (я использую Arch linux), ваши вторые 3 инструкции - это запись PLT, которая gdb вызывает "exit @ plt", когда я вхожу в нее. jmp 0x80482c0 переходит на другой адрес, который, наконец, переходит в код libc.so .

Вы можете продемонстрировать это себе с помощью довольно сложного упражнения. Во-первых, у вас есть адрес записи в таблице PLT, независимо от того, что gdb сообщает вам, это адрес jmp * 0x8049698 - это адрес «exit @ plt». На моем Linux-сервере с архитектурой x86:

(gdb) disassemble 0x8048310,+20
Dump of assembler code from 0x8048310 to 0x8048324:
   0x08048310 <exit@plt+0>:     jmp    *0x80496e8
   0x08048316 <exit@plt+6>:     push   $0x10
   0x0804831b <exit@plt+11>:    jmp    0x80482e0

Затем выполните readelf -e _program_> elf.headers . Посмотрите файл elf.headers . Вы найдете строку текста с надписью «Заголовки разделов:» Где-то в заголовках разделов вы увидите что-то вроде этого:

  [ 9] .rel.dyn          REL             08048290 000290 000008 08   A  5   0  4
  [10] .rel.plt          REL             08048298 000298 000020 08  AI  5  12  4
  [11] .init             PROGBITS        080482b8 0002b8 000023 00  AX  0   0  4
  [12] .plt              PROGBITS        080482e0 0002e0 000050 04  AX  0   0 16

«exit @ plt» находится по адресу 0x8048310. Это прямо в разделе ".rel.plt". ".rel.plt", вероятно, означает "таблица привязки программы перемещения".

Теперь мы переходим к той части, где int $ 0x80 может даже не существовать. Выполните ldd _program_ . Опять же, Arch linux x86 говорит следующее:

linux-gate.so.1 (0xb77d9000)
libc.so.6 => /usr/lib/libc.so.6 (0xb7603000)
/lib/ld-linux.so.2 (0xb77da000)

Видите "linux-gate.so.1"? Он содержит фактический код, выполняющий системный вызов. Это может быть int $ 0x80 , или это может быть инструкция sysenter , либо что-то еще. Предполагается, что ядро ​​Linux помещает «небольшую разделяемую библиотеку» в адресное пространство процесса с реальным кодом, а затем передает адрес этой небольшой разделяемой библиотеки в «вспомогательный вектор» ELF. У man vdso некоторые подробности. Динамический компоновщик, /lib/ld-linux.so.2 знает детали вспомогательного вектора ELF и в конечном итоге помещает адрес linx-gate.so.1 в PLT где-то, поэтому фактические вызовы функций C могут в конечном итоге привести к эффективным системным вызовам.

Если вы выполните несколько вызовов ldd _program_ , вы увидите, что адрес linux-gate.so.1 отличается от вызова к вызову. На самом деле ядро ​​не помещает вершину стека в один и тот же адрес каждый раз, чтобы попытаться запутать вредоносное ПО, которому необходимо знать расположение стека для выполнения своего собственного кода.

0
08.02.2019, 01:56
0 ответов

Теги

Похожие вопросы