2016-06-16 2 views
1

Я читаю документацию для uprobe tracer и есть инструкция, как вычислить смещение функции в памяти. Я цитирую его здесь.Вычисление смещения функции в памяти

В следующем примере показано, как сбросить указатель инструкции и% ax зарегистрироваться на зондированный текстовый адрес. Зонд функции zfree в/бен/Zsh:

# cd /sys/kernel/debug/tracing/ 
# cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp 
00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh 
# objdump -T /bin/zsh | grep -w zfree 
0000000000446420 g DF .text 0000000000000012 Base  zfree 

0x46420 это смещение в zfree объекта/бен/Zsh, который загружен в 0x00400000.

Я не знаю, почему, но они взяли вывод 0x446420 и вычитали 0x400000, чтобы получить 0x46420. Это было для меня ошибкой. Почему 0x400000?

Я попытался сделать то же самое на своей Fedora 23 с ядром 4.5.6-200.

Сначала я выключил памяти адрес рандомизации

echo 0 > /proc/sys/kernel/randomize_va_space 

Тогда я понял, где двоичная в памяти

$ cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp 
555555554000-55555560f000 r-xp 00000000 fd:00 2387155     /usr/bin/zsh 

Принимал смещение

[email protected]:~ $ objdump -T /bin/zsh | grep -w zfree 
000000000005dc90 g DF .text 0000000000000012 Base  zfree 

И понял, где zfree является через gdb

$ gdb -p 21067 --batch -ex 'p zfree' 
$1 = {<text variable, no debug info>} 0x5555555b1c90 <zfree> 

[email protected]:~ $ python 
Python 2.7.11 (default, Mar 31 2016, 20:46:51) 
[GCC 5.3.1 20151207 (Red Hat 5.3.1-2)] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> hex(0x5555555b1c90-0x555555554000) 
'0x5dc90' 

Видите ли, у меня есть тот же результат, что и в objdump, не вычитая ничего.

Но тогда я попробовал то же самое на другой машине с SLES, и там это то же самое, что и в документации по шкафам.

Почему существует такая разница? Как мне вычислить правильное смещение?

+0

Документ говорит об этом: в объекте/bin/zsh, который загружается в 0x00400000. Предполагается, что смещение должно относиться к адресу загрузки программы, поэтому вам нужно вычесть адрес загрузки программы из абсолютного адреса функции. – dbrank0

+1

Что касается базового адреса на многих системах: 0x400000 - см. [Почему адреса виртуальной памяти для Linux-файлов начинаются с 0x8048000] (http://stackoverflow.com/questions/2966426). Fedora 23 создает свои пакеты с '-fPIC -shared', поэтому смещение нагрузки равно 0, а базовый адрес либо произвольный (с ASLR), либо 0x555555554000. –

ответ

1

Насколько я вижу, разница может быть вызвана только тем, как была построена изученная бинарная система. Говоря более точно - если ELF имеет фиксированный адрес загрузки или нет. Давайте проведем простой эксперимент. У нас есть простой тестовый код:

int main(void) { return 0; } 

Затем построить двумя способами:

$ gcc -o t1 t.c  # create image with fixed load address 
$ gcc -o t2 t.c -pie # create load-base independent image 

Теперь, позволяет базовые адреса проверки нагрузки для этих двух изображений:

$ readelf -l --wide t1 | grep LOAD 
    LOAD   0x000000 0x0000000000400000 0x0000000000400000 0x00067c 0x00067c R E 0x200000 
    LOAD   0x000680 0x0000000000600680 0x0000000000600680 0x000228 0x000230 RW 0x200000 
$ readelf -l --wide t2 | grep LOAD 
    LOAD   0x000000 0x0000000000000000 0x0000000000000000 0x0008cc 0x0008cc R E 0x200000 
    LOAD   0x0008d0 0x00000000002008d0 0x00000000002008d0 0x000250 0x000258 RW 0x2000 

Здесь вы можете см., что для первого изображения требуется адрес фиксированной нагрузки - 0x400000, а второй - вообще никаких требований к адресу.

И теперь мы можем сравнивать адреса, objdump говорит о main:

$ objdump -t t1 | grep ' main' 
00000000004004b6 g  F .text 000000000000000b    main 
$ objdump -t t2 | grep ' main' 
0000000000000710 g  F .text 000000000000000b    main 

Как мы видим, адрес полный виртуальный адрес, который первый байт main будет занимать, если изображение загружается по адресу, хранится в заголовок программы.И, конечно, второе изображение никогда не будет загружено в 0x0, а вместо этого в другом, случайно выбранном месте, которое будет смещать реальную позицию функции.

+0

Спасибо! Что такое использование пирога для исполняемого файла? –

+0

@MarkoKevac Полезно в целях безопасности. Использование произвольного адреса загрузки затрудняет использование разных уязвимостей. Так как локальные объекты и код изменяются время от времени, злоумышленник не может пересылать по постоянным адресам. Например. по этой причине Android запрещает использование неиспользуемых исполняемых файлов с версии 5.0 (Lollipop) – Sergio

+0

Как и что? AFAIK, вы не можете писать в .text в запущенном процессе, так что это не тот случай, когда фиксированный адрес функции может вам помочь. Нет? –