2009-09-20 15 views
43

Więc każdy prawdopodobnie wie, że glibc's /lib/libc.so.6 może być wykonany w powłoce jak normalny plik wykonywalny, w którym to przypadkach drukuje informacje o wersji i kończy pracę. Odbywa się to poprzez zdefiniowanie punktu wejścia w .so. W niektórych przypadkach może to być interesujące dla innych projektów. Niestety, punkt wejścia niskiego poziomu, który można ustawić za pomocą opcji ld--e, jest nieco zbyt niski: dynamiczny program ładujący nie jest dostępny, więc nie można wywoływać żadnych właściwych funkcji bibliotecznych. glibc z tego powodu implementuje wywołanie systemowe write() poprzez nagłe wywołanie systemowe w tym punkcie wejścia.budowanie .so, który jest również wykonywalny

Moje pytanie brzmi, czy ktokolwiek może wymyślić ładny sposób, w jaki można załadować pełny dynamiczny linker z tego punktu wejścia, aby uzyskać dostęp do funkcji z innych .so?

+5

'/ lib/ld-linux.so.2' to tylko kolejny przykład :) –

Odpowiedz

43

Budowanie udostępnionej biblioteki za pomocąOpcjawydaje się zapewniać wszystko, czego potrzebujesz:

/* pie.c */ 
#include <stdio.h> 
int foo() 
{ 
    printf("in %s %s:%d\n", __func__, __FILE__, __LINE__); 
    return 42; 
} 
int main() 
{ 
    printf("in %s %s:%d\n", __func__, __FILE__, __LINE__); 
    return foo(); 
} 


/* main.c */ 
#include <stdio.h> 

extern int foo(void); 
int main() 
{ 
    printf("in %s %s:%d\n", __func__, __FILE__, __LINE__); 
    return foo(); 
} 


$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E 
$ gcc main.c ./pie.so 


$ ./pie.so 
in main pie.c:9 
in foo pie.c:4 
$ ./a.out 
in main main.c:6 
in foo pie.c:4 
$ 

P.S. glibc implementuje write(3) przez wywołanie systemowe, ponieważ nie ma nigdzie innego połączenia (jest to poziom najniższy). Nie ma to nic wspólnego z możliwością wykonania libc.so.6.

+0

Zauważyłem, że opcja' -shared' może uniemożliwić to działanie i daje błąd segmentacji. Musisz upewnić się, że nie ma opcji '-shared' lub wstawić jej przed' -pie', więc zostanie zignorowana. –

1

Niezbyt przyjemny sposób, ale utworzyłem mały plik wykonywalny otoki wokół .so, który wywołuje funkcję punktu wejścia, którą chcę uruchomić.

0

Przypuszczam, że masz swój punkt ld -e do punktu wejścia, który następnie używałby rodziny funkcji dlopen() do znajdowania i ładowania pozostałej części dynamicznego linkera. Oczywiście trzeba by upewnić się, że została sama dlopen() albo statycznie związane lub konieczne może być wdrożenie dosyć własnego łącznikowej odgałęzienie uzyskać na nim (za pomocą interfejsu wywołań systemowych, takich jak mmap() tak libc sobie robi.

Nic z tego nie brzmi "miło" dla mnie, w rzeczywistości tylko myśl o odczytaniu źródeł glibc (i kodu źródłowego ld-linux, jako jednego przykładu) wystarczającego do oceny wielkości pracy brzmi dla mnie dosyć oszałamiająco. Przenoszenie koszmaru może się znacznie różnić w zależności od implementacji Linuksa ld-linux i tego, jak powiązania są wykonywane w ramach OpenSolaris, FreeBSD i tak dalej. (Nie wiem).