2012-01-18 11 views
19

Czy znając prototyp funkcji i jej adres w pamięci, można wywołać tę funkcję z innego procesu lub jakiegoś fragmentu kodu, który nic nie wie, oprócz prototypu i adres pamięci? Jeśli to możliwe, w jaki sposób można zwrócić zwracany typ w kodzie?Wywołanie funkcji za pośrednictwem jej adresu w pamięci w c/C++

+0

proces? lub wątek? – Cyan

+0

W C++ nie ma procesów. Musisz określić swoją platformę, jeśli potrzebujesz pomocy. –

+0

Z innego procesu? To bardzo szczególny przypadek. Czy naprawdę tego potrzebujesz? – jalf

Odpowiedz

36

W nowoczesnych systemach operacyjnych każdy proces ma własną przestrzeń adresową, a adresy są ważne tylko w procesie. Jeśli chcesz wykonać kod w jakiś inny sposób, albo trzeba wstrzyknąć wspólną bibliotekę lub dołączyć swój program jako debugger.

Gdy jesteś w przestrzeni adresowej innego programu, ten kod wywołuje funkcję w dowolnym adresie:

typedef int func(void); 
func* f = (func*)0xdeadbeef; 
int i = f(); 
+4

Dzięki @ R.Martinho dla [lepszego stylu prototypów funkcji typedef] (http://chat.stackoverflow.com/transcript/message/2400130#2400130). Nie wiedziałem nawet, że to działa! – sbi

+0

Bardzo ładne. Ta metoda jest znacznie łatwiejsza niż użycie wbudowanego zespołu, jeśli celem jest również proces C. +1 dla ciebie. –

+0

AFAIK, nie ma sposobu na * zapisanie * pamięci w przestrzeni adresowej innych programów w nowych systemach operacyjnych i powoduje to SEGFAULT. Ale nic nie stoi na przeszkodzie, aby program odczytywał dowolne miejsce w pamięci (stąd ten błąd jest przerażający w OpenSSL, ponieważ można w nim odczytać wszystko z pamięci). Więc, czy możesz wyjaśnić, dlaczego nie mogę uzyskać dostępu do przestrzeni adresowej innego programu i wymagać udostępnionych bibliotek lub debuggera? –

11

Tak - opisujesz wskaźnik funkcji. Oto prosty przykład;

int (*func)(void) = (int (*)(void))0x12345678; 
int x = func(); 

Prawdopodobnie nie będzie działać między procesami - w większości systemów operacyjnych procesy nie mają dostępu do pamięci drugiej osoby.

+0

Dlaczego rzutowanie na void (*) (void), aby przypisać int (*) (void)? To nielogiczne, nie? – Geoffroy

+0

@Geoffroy - literówka. I naprawione zanim nawet skomentowałeś ... –

+2

@CarlNorum: Takie błędy zdarzają się, gdy jesteś zbyt leniwy, aby wpisać "typedef". ':)' – sbi

1

W większości OP, każdy proces ma swoją własną pamięć, dzięki czemu można” t.

Przykładowy kod: A.c:

#include <stdio.h> 

int r() {return 2;} 
int main() { 
    printf("%p\n",r); 
    while(1); 
} 

b.c:

#include <stdio.h> 

int main() { 
int a,(*b)(); 
scanf("%p",&b); 
a=b(); 
printf("%d\n",a); 
return 0; 
} 

to uzyskać winy segmentacji.

+0

W C++ możesz uzyskać dostęp do dowolnej lokalizacji pamięci, dla lepszego lub gorszego – dtech

+0

@ddriver: C++ pozwala na dostęp do dowolnej lokalizacji pamięci _virtual_. Jednak wiele systemów operacyjnych nadaje każdemu procesowi własną pamięć wirtualną, dzięki czemu nie mogą one wpływać na siebie nawzajem. Istnieją wywołania specyficzne dla systemu operacyjnego, które można wykonać/wykorzystać w celu wpływania na pamięć innych procesów. –

+3

@ddriver - nie, nie możesz. Można uzyskać dostęp tylko do lokalizacji pamięci, do których dostęp zapewnia system operacyjny. Cały twój program wie, że jest środowiskiem pamięci wirtualnej, w którym działa, co normalnie nie ma żadnego związku z rzeczywistością fizyczną. –

1

wszystkie poprzednie odpowiedzi są ładne, ale zbyt długo ;-):

int i = ((int (*)(void))0xdeadbeef)(); 
+1

Nie, były świetne. Z drugiej strony Twoja jest bardzo słaba. Żadnego wyjaśnienia. –

+1

To fajna jedna linijka – BullyWiiPlaza

1

Kiedy trzeba bezpośredniego połączenia:

((void(*)(void))0x1234)(); 
Powiązane problemy