Whatsup - לינוקס, תוכנה חופשית וקוד פתוח בעברית

תיכנות בלינוקס - כתובת של ספריות טעונות דינאמית?

Ddorda - 26/05/2017 - 20:44
נושא ההודעה: כתובת של ספריות טעונות דינאמית?
אהלן!
קודם כל, שנים לא הייתי פה, ואני מודה שממש התגעגעתי!

לגבי השאלה:
אני מנסה למצוא כתובת של פונקציה של libc בזיכרון. עם gdb מאוד קל:
קוד:

$ gdb ./getaddr
...
(gdb) p system
$2 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>


אבל שמתי לב שאם אני הולך לתוכנה אחרת, הכתובת שונה!
קוד:

$ gdb ./getaddr2
...
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecbfb0 <__libc_system>


מסתכל עם ldd:
קוד:

$ ldd getaddr
   linux-gate.so.1 =>  (0xb7fe4000)
   libc.so.6 => /lib/libc.so.6 (0xb7e99000)
   /lib/ld-linux.so.2 (0xb7fe5000)
$ ldd getaddr2
   linux-gate.so.1 =>  (0xb7fe4000)
   libdl.so.2 => /lib/libdl.so.2 (0xb7fda000)
   libc.so.6 => /lib/libc.so.6 (0xb7e95000)
   /lib/ld-linux.so.2 (0xb7fe5000)

באמת libc נמצא במקומות שונים.

אז חשבתי פשוט למצוא את ה-offset, ובאמת:
קוד:
0xb7ecffb0-0xb7e99000 = 0x36fb0
0xb7ecbfb0-0xb7e95000 = 0x36fb0


אבל למרבה ההפתעה עם nm אני מקבל offset קצת שונה:
קוד:

$ nm -D /lib/libc.so.6 | grep system
00038fb0 T __libc_system
00038fb0 W system


המסקנה היחידה: עשיתי פה סמטוחה שלמה ואני לא מבין מה קורה פה. מישהו יכול להאיר את עייני?

שאלות ממוקדות:
1. למה הכתובות משתנות עבור כל תוכנה? מה המנגנון שעשוה את זה ולמה?
2. למה nm מצא לי כתובת טיפה שונה מה-offset שמצאתי בתוכנות?

הערות חשובות:
1. ASLR כבוי, אז זה (כנראה) לא זה.
2. חיפשתי כבר בגוגל, לא הייתי שואל פה בלי לחפש לפני. (אבל לגמרי זורם על לינקים שמסבירים את זה)

תודה רבה!
Anonymous - 27/05/2017 - 00:15
נושא ההודעה:
לא ברור לי מהי הכתובת ב־ldd. אפשר לבדוק את הכתובת בזכרון בזמן שהתהליך רץ בצורה יותר ישירה. אם כבר system, אז הרצתי pmap. כמובן שאפשר לקרוא ישירות את הקובץ ‎/proc/self/maps .
קוד:

cat <<EOF >test.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
   char buf[512];

   sprintf(buf, "pmap %d", getpid());
   system(buf);
   printf("\nAddress of the function systen(): %p\n", system);
}
EOF

$ gcc -otest -g -Wall test.c

$ setarch x86_64 -R ./test
26971:   ./test
0000555555554000      4K r-x-- test
0000555555754000      4K r---- test
0000555555755000      4K rw--- test
00007ffff7a3b000   1620K r-x-- libc-2.24.so
00007ffff7bd0000   2044K ----- libc-2.24.so
00007ffff7dcf000     16K r---- libc-2.24.so
00007ffff7dd3000      8K rw--- libc-2.24.so
00007ffff7dd5000     16K rw---   [ anon ]
00007ffff7dd9000    140K r-x-- ld-2.24.so
00007ffff7faa000      8K rw---   [ anon ]
00007ffff7ff5000     12K rw---   [ anon ]
00007ffff7ff8000      8K r----   [ anon ]
00007ffff7ffa000      8K r-x--   [ anon ]
00007ffff7ffc000      4K r---- ld-2.24.so
00007ffff7ffd000      4K rw--- ld-2.24.so
00007ffff7ffe000      4K rw---   [ anon ]
00007ffffffde000    132K rw---   [ stack ]
ffffffffff600000      4K r-x--   [ anon ]
 total             4040K

Address of the function systen(): 0x7ffff7a7a450

$ nm -D /lib/x86_64-linux-gnu/libc-2.24.so | grep system
000000000003f450 T __libc_system
0000000000115230 T svcerr_systemerr
000000000003f450 W system

ואכן 0x3f450 היא הכתובת היחסית של system: ההפרש בין כתובתה של הפונקציה בזכרון לתחילת אזור הקוד של libc במרחב הזיכרון.
Ddorda - 27/05/2017 - 02:02
נושא ההודעה:
קודם כל תודה רבה על התגובה, מעריך מאוד Smile
התגובה שלך עזרה לי להפיל כמה אסימונים...

קצת תשובות לעצמי:
1. הכתובת משתנה לפי גרסת libc ואיך התוכנה קומפלה. את התוכנה הראשונה קיפלתי בלי טעינה דינאמית, וזאת הסיבה.
2. לא ברור מה הסיפור של ldd, אבל באמת כשעשיתי את זה עם pmap קיבלתי את ה-offset הנכון כמו בהדגמה שלך.

דור.
כל הזמנים הם GMT + 2 שעות