Chcę znaleźć adres fizyczny zmiennej zdefiniowanej w procesie przestrzeni użytkownika? Czy jest jakiś sposób, aby to zrobić, korzystając z uprawnień roota?Jak znaleźć adres fizyczny zmiennej z przestrzeni użytkownika w systemie Linux?
Odpowiedz
Po pierwsze, dlaczego chcesz to zrobić? Celem nowoczesnych systemów VM jest usunięcie programisty aplikacji ze złożoności układu pamięci fizycznej. Przesyłając im każdą własną, jednolitą przestrzeń adresową, aby ułatwić im życie.
Jeśli chcesz to zrobić, to prawie musisz użyć modułu jądra. Uzyskaj wirtualny adres zmiennej w normalny sposób, użyj jej do zindeksowania w tabelach stron procesów i odczytania znalezionej wartości (fizyczny adres ramki). Następnie dodaj przesunięcie strony, aby uzyskać pełny adres fizyczny. Pamiętaj, że nie będziesz mógł używać tego adresu, gdy włączona jest funkcja stronicowania.
(Jeśli masz szczęście być może uda się uzyskać adres ramki regionu VM z systemu plików/proc, a tym samym nie byłby wymagają, aby napisać moduł jądra.)
... i chyba że zablokujesz stronę w pamięci, aby adres fizyczny mógł się zmienić w dowolnym momencie. – caf
Nie musisz pisać modułu jądra: jak wyjaśniają inne przykłady, jest to już ujawnione przez '/ proc/$ pid/pagemap'. – poolie
W architekturze NUMA może być interesujące poznanie fizycznego adresu zmiennych – horro
(edit: Jeśli przez „adres fizyczny ", masz na myśli poziom" w którym moduł RAM są moje bity przechowywane ", a następnie odpowiedź jest niewłaściwa.)
Nie trzeba uprawnień root'a, aby to zrobić. Zamiast tego potrzebujesz debuggera. I oto idziemy (używając systemu Linux na x86_64):
Najpierw potrzebujemy małego programu do zabawy. Ten uzyskuje dostęp do zmiennej globalnej i drukuje ją dwa razy z rzędu. Ma dwie zmienne globalne, które znajdujemy w pamięci później.
#include <stdio.h> int a, b = 0; int main(void) { printf("a: "); if (fscanf("%d", &a) < 1) return 0; printf("a = %d\n", myglobal); printf("b: "); if (fscanf("%d", &b) < 1) return 0; printf("a = %d, b = %d\n", a, b); return 0; }
Krok 1: Kompilacja programu i rozebrać wszystkie informacje debugowania z niego, więc nie mamy żadnych wskazówek z debuggera, że nie dostanie się w sytuacji prawdziwym życiu.
$ gcc -s -W -Wall -Os -o ab ab.c
Krok 2: Uruchom program i wpisz jedną z dwóch liczb.
$ ./ab a: 123 a = 123 b: _
Krok 3: Znajdź proces.
$ ps aux | grep ab roland 21601 0.0 0.0 3648 456 pts/11 S+ 15:17 0:00 ./ab roland 21665 0.0 0.0 5132 672 pts/12 S+ 15:18 0:00 grep ab
Krok 4: Dołącz debugger do procesu (21601).
$ gdb ... (gdb) attach 21601 ... (gdb) where #0 0x00007fdecfdd2970 in read() from /lib/libc.so.6 #1 0x00007fdecfd80b40 in _IO_file_underflow() from /lib/libc.so.6 #2 0x00007fdecfd8230e in _IO_default_uflow() from /lib/libc.so.6 #3 0x00007fdecfd66903 in _IO_vfscanf() from /lib/libc.so.6 #4 0x00007fdecfd7245c in scanf() from /lib/libc.so.6 #5 0x0000000000400570 in ??() #6 0x00007fdecfd2f1a6 in __libc_start_main() from /lib/libc.so.6 #7 0x0000000000400459 in ??() #8 0x00007fffd827da48 in ??() #9 0x000000000000001c in ??() #10 0x0000000000000001 in ??() #11 0x00007fffd827f9a2 in ??() #12 0x0000000000000000 in ??()
Ciekawa rama ma numer 5, ponieważ jest między jakiegoś kodu wywołującego funkcję main
i funkcję scanf
, więc to musi być nasz main
funkcja. Kontynuując sesji debugowania:
(gdb) frame 5 ... (gdb) disassemble $pc $pc+50 ... 0x0000000000400570 : test %eax,%eax 0x0000000000400572 : jle 0x40058c <[email protected]+372> 0x0000000000400574 : mov 0x2003fe(%rip),%edx # 0x600978 <[email protected]+2098528> 0x000000000040057a : mov 0x2003fc(%rip),%esi # 0x60097c <[email protected]+2098532> 0x0000000000400580 : mov $0x40068f,%edi 0x0000000000400585 : xor %eax,%eax 0x0000000000400587 : callq 0x4003f8 <[email protected]> ...
Teraz wiemy, że funkcja printf
dostanie trzy parametry, a dwie są tylko cztery bajty z dala od siebie. To dobry znak, że te dwie są naszymi zmiennymi a
i b
. Tak więc adres a
to 0x600978 lub 0x60097c. Przekonajmy się, starając:
(gdb) x/w 0x60097c 0x60097c <[email protected]+2098532>: 0x0000007b (gdb) x/w 0x600978 0x600978 <[email protected]+2098528>: 0x00000000
Więc a
, zmienna, która jest odczytywana w pierwszym, jest pod adresem 0x60097c (bo 0x0000007B jest szesnastkowa reprezentacja 123, który weszliśmy) i b
jest 0x600978.
Nadal w debugerze możemy teraz modyfikować zmienną a
, a następnie kontynuować program.
(gdb) set *(int *)0x60097c = 1234567 (gdb) continue
Powrót w programie, który poprosił nas, by wprowadzić dwa numery:
$ ./ab a: 123 a = 123 b: 5 a = 1234567, b = 5 $
Daje to Wirtualny adres, a nie fizyczne. –
jako częściowo odpowiedział przed normalne programy nie ma potrzeby martwić się o adresach fizycznych, jak uruchomić w wirtualnej przestrzeni adresowej z wszystkie jego udogodnienia. Ponadto nie każdy adres wirtualny ma fizyczny adres, może należeć do zamapowanych plików lub zamienionych stron. Jednak czasami może być interesujące zobaczenie tego mapowania, nawet w przestrzeni użytkownika.
W tym celu jądro Linux udostępnia swoje mapowanie do przestrzeni użytkownika za pośrednictwem zestawu plików w pliku /proc
. Dokumentację można znaleźć pod numerem here. Krótkie podsumowanie:
/proc/$pid/maps
zawiera listę odwzorowań adresów wirtualnych wraz z dodatkowymi informacjami, takimi jak odpowiedni plik mapowanych plików./proc/$pid/pagemap
zawiera więcej informacji o każdej zmapowanej stronie, w tym adres fizyczny, jeśli istnieje.
This website dostarcza program w języku C, który zrzuca mapowania wszystkich uruchomionych procesów za pomocą tego interfejsu i wyjaśnia, co robi.
Minimalny przykład z testami: https://stackoverflow.com/questions/17021214/how-to-decode-proc-pid-pagemap-entries-in-linux/45126141#45126141 –
#include "stdio.h"
#include "unistd.h"
#include "inttypes.h"
uintptr_t vtop(uintptr_t vaddr) {
FILE *pagemap;
intptr_t paddr = 0;
int offset = (vaddr/sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
uint64_t e;
// https://www.kernel.org/doc/Documentation/vm/pagemap.txt
if ((pagemap = fopen("/proc/self/pagemap", "r"))) {
if (lseek(fileno(pagemap), offset, SEEK_SET) == offset) {
if (fread(&e, sizeof(uint64_t), 1, pagemap)) {
if (e & (1ULL << 63)) { // page present ?
paddr = e & ((1ULL << 54) - 1); // pfn mask
paddr = paddr * sysconf(_SC_PAGESIZE);
// add offset within page
paddr = paddr | (vaddr & (sysconf(_SC_PAGESIZE) - 1));
}
}
}
fclose(pagemap);
}
return paddr;
}
- 1. tłumaczyć adres wirtualny na adres fizyczny
- 2. Jak korzystać z ioctl() z przestrzeni jądra w systemie Linux?
- 3. Uzyskaj adres IP interfejsu w systemie Linux
- 4. uzyskać fizyczny adres bufora pod Linuksem
- 5. Jak sprawdzić, czy adres jest czytelny w aplikacji przestrzeni użytkownika dla systemu Linux?
- 6. Jak odszyfrować/proc/pid/pagemap wpisy w systemie Linux?
- 7. Zmień identyfikator użytkownika w systemie Linux
- 8. Jak zmapować bufor jądra Linux do przestrzeni użytkownika?
- 9. Słaba wydajność nagrywania w przestrzeni użytkownika dla mmap'ed pamięci fizycznej w systemie Linux
- 10. Bariery pamięci w przestrzeni użytkownika? (Linux, x86-64)
- 11. wskaźnik funkcji: adres fizyczny lub wirtualny
- 12. Przeniesienie kodu przestrzeni użytkownika do przestrzeni jądra
- 13. Jak uzyskać nazwę użytkownika w C/C++ w systemie Linux?
- 14. Sygnał modułu jądra Linux w procesie przestrzeni użytkownika zabity
- 15. Jak wyłączyć wolumin fizyczny LVM2 w celu usunięcia dysku?
- 16. Jak znaleźć dziury w przestrzeni adresowej?
- 17. W jakim kontekście wątek jądra działa w systemie Linux?
- 18. Jak znaleźć unikalne słowa z pliku linux
- 19. Jak wydrukować/zarejestrować adres zmiennej w NDK
- 20. Kompilowanie VLC w systemie Linux: Błąd nie mógł znaleźć Lua
- 21. Jak uzyskać adres fizyczny (adres MAC) adresu IP za pomocą C#?
- 22. Jak uzyskać listę otwartych gniazd w systemie Linux za pomocą C?
- 23. Jak uzyskać adres MAC interfejsu w systemie Linux przy użyciu programu C?
- 24. Jak mogę uzyskać adres pamięci zmiennej JavaScript?
- 25. Jak ustawić adres IP z C w linux
- 26. Czy pozycja pamięci podręcznej CPU zawiera adres fizyczny lub wirtualny?
- 27. Twarde ścieżki kodowania w systemie Linux
- 28. Usługa WCF w systemie Linux z Apache2
- 29. Błędy Tomcat w systemie Linux
- 30. jak uzyskać adres IP użytkownika w mvc
Prawdopodobnie z/dev/mem? – user2284570
Niektóre informacje powiązane na http://stackoverflow.com/questions/5748492/is-there-any-api-determining-the-physical-address-from-virtual-address-in-li –