Co zawiera adres fizyczny 0 w systemie Linux x86?


12

Nie jestem pewien, czy to pytanie powinno się znaleźć tutaj, czy w reverseengineering.stackexchange.com

Cytowanie z wikipedii :

W procesorze 8086 tablica przerwań nosi nazwę IVT (tablica wektorów przerwań). IVT zawsze znajduje się w tym samym miejscu w pamięci, od 0x0000 do 0x03ff i składa się z 256 czterobajtowych dalekich wskaźników trybu rzeczywistego (256 × 4 = 1024 bajtów pamięci).

Oto, co znajduję w monitorze qemu:

(qemu) xp/128xw 0
0000000000000000: 0xf000ff53 0xf000ff53 0xf000e2c3 0xf000ff53
0000000000000010: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000020: 0xf000fea5 0xf000e987 0xf000d62c 0xf000d62c
0000000000000030: 0xf000d62c 0xf000d62c 0xf000ef57 0xf000d62c
0000000000000040: 0xc0005526 0xf000f84d 0xf000f841 0xf000e3fe
0000000000000050: 0xf000e739 0xf000f859 0xf000e82e 0xf000efd2
0000000000000060: 0xf000d648 0xf000e6f2 0xf000fe6e 0xf000ff53
0000000000000070: 0xf000ff53 0xf000ff53 0xf0006aa4 0xc0008930
0000000000000080: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000090: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000c0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000d0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000e0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000100: 0xf000ec59 0xf000ff53 0xf000ff53 0xc0006730
0000000000000110: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000120: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000130: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000140: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000150: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000160: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000170: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000180: 0x00000000 0x00000000 0x00000000 0x00000000
0000000000000190: 0x00000000 0x00000000 0x00000000 0xf000ff53
00000000000001a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001c0: 0xf000d611 0xf000ec4e 0xf000ec4e 0xf000ec4e
00000000000001d0: 0xf000d61a 0xf000d623 0xf000d608 0xf000ec4e
00000000000001e0: 0xf000ff53 0x00000000 0xf000ff53 0xf000ff53
00000000000001f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53

Nie jestem pewien, co sądzić o tych wartościach. Nie wygląda to na tablicę deskryptorów przerwań (dereferencja tych wartości daje wszystkie wartości null). Więc na co tak naprawdę tu patrzę?

Odpowiedzi:


9

Cokolwiek zawierało twoje oprogramowanie wewnętrzne.

W idealnym nowoczesnym systemie procesor nigdy nie przechodzi w tryb rzeczywisty, jak wyjaśniłem w odpowiedzi na pytania SU zatytułowane: W jakim trybie działają 64-bitowe komputery z procesorami Intel w sektorze rozruchowym? , pierwszy KiB pamięci fizycznej jest tak samo nieistotny, jak Johan Myréen podał tutaj inną odpowiedź. Ale wiele współczesnych oprogramowania sprzętowego (wciąż) ma obsługę zgodności , co oznacza, że

  • mogą cofać się (tak, wstecz , biorąc pod uwagę, że przeszli bezpośrednio z trybu nierealnego do trybu chronionego) z trybu chronionego do trybu rzeczywistego, aby uruchamiać oprogramowanie systemowe napisane dla trybu rzeczywistego, takie jak starsze programy rozruchowe PC / AT w MBR i VBR; i
  • zapewniają one stare interfejsy API oprogramowania układowego w trybie rzeczywistym i konfigurują wszystkie struktury danych dla tych interfejsów API, na których polegają wspomniane oprogramowanie systemowe.

Jedną z tych struktur danych jest IVT w trybie rzeczywistym. Stare interfejsy API oprogramowania układowego w trybie rzeczywistym opierają się na intinstrukcjach, a oprogramowanie IVT w trybie rzeczywistym jest zapełniane przez oprogramowanie układowe w ramach jego inicjalizacji za pomocą wskaźników do różnych procedur obsługi oprogramowania układowego dla tych instrukcji.

Oprogramowanie systemowe trybu chronionego nie potrzebuje starych interfejsów API oprogramowania trybu rzeczywistego i nigdy nie uruchamia procesora w trybie rzeczywistym, więc tryb IVT w trybie rzeczywistym w pierwszym 1 kB pamięci fizycznej nie jest używany. (Tryb chroniony v8086 nie adresuje adresu fizycznego 00000000 i więcej, pamiętaj. Adresy logiczne 00000000 i wyższe, które są tłumaczone przez tabele stron.) W nowoczesnych systemach EFI oprogramowanie układowe przekazuje mapę pamięci fizycznej pamięci do systemu operacyjnego bootstrap, informując go, które części są zarezerwowane dla oprogramowania wewnętrznego na potrzeby własnego interfejsu API trybu chronionego, a które części system operacyjny może swobodnie wykorzystać i wykorzystać w swojej puli pamięci fizycznej. Teoretycznie pierwsza strona pamięci fizycznej może należeć do tej drugiej kategorii.

W praktyce po pierwsze, oprogramowanie układowe często oznacza pierwszą stronę pamięci fizycznej jako „kod usług rozruchowych”, co oznacza, że ​​system operacyjny może ją przejąć i po prostu użyć go jako części swojej puli pamięci fizycznej, ale dopiero po rozruchu usługi czasowe oprogramowania układowego EFI zostały zamknięte przez system operacyjny, a oprogramowanie wewnętrzne zostało zredukowane do zapewniania wyłącznie usług uruchomieniowych. Przykład tego można zobaczyć w dzienniku jądra systemu Linux (z add_efi_memmapopcją) przedstawionym przez Finnbarr P. Murphy:

[0,000000] efi: mem00: typ = 3, attr = 0xf, zakres = [0x0000000000000000-0x0000000000001000) (0 MB)
który xe dekoduje za pomocą innego programu w bardziej czytelnej dla człowieka formie, jak:

[# 00] Typ: EfiBootServicesCode Attr: 0xF
      Phys: 0000000000000000-0000000000001000
      Virt: 0000000000000000-0000000000001000

W praktyce, po drugie, Linux wyraźnie ignoruje ten zakres pamięci fizycznej, nawet jeśli oprogramowanie układowe mówi, że może go używać i korzystać z niego. Przekonasz się, że zarówno w oprogramowaniu sprzętowym EFI, jak i nie-EFI, gdy Linux ma fizyczną mapę pamięci, łata ją ( w funkcji o nazwietrim_bios_range ), co powoduje komunikaty dziennika jądra, takie jak:

[0,000000] e820: aktualizacja [mem 0x00000000-0x00000fff] użyteczny ==> zarezerwowany

Nie jest to tak bardzo do radzenia sobie ze współczesnymi oprogramowaniem sprzętowym EFI, w którym IVT w trybie rzeczywistym nie jest częścią interfejsu API oprogramowania układowego, jak ma do czynienia ze starymi oprogramowaniem układowym PC98, gdzie jest częścią interfejsu API oprogramowania układowego, ale oprogramowanie sprzętowe to zgłasza (za pośrednictwem ten sam interfejs API) jako pamięć fizyczna dostępna do beztroskiego nadpisania przez system operacyjny.

A zatem teoretycznie ten zakres pamięci fizycznej może zawierać dowolny kod lub dane, w zależności od chwilowych potrzeb alokatorów pamięci jądra i pamięci wirtualnej stronicowanej na żądanie; w praktyce Linux po prostu pozostawia go nietkniętym, ponieważ oprogramowanie układowe pierwotnie go konfigurowało.

A w twoim systemie oprogramowanie układowe zapełniło go pozycjami IVT trybu rzeczywistego. Pozycje IVT w trybie rzeczywistym mają oczywiście tylko wskaźniki 16:16, a jeśli spojrzysz na swoją pamięć za pomocą 2-bajtowego zrzutu heksadecymalnego, możesz to zobaczyć całkiem wyraźnie. Kilka przykładów:

  • Większość wpisów IVT wskazuje na F000: FF53, adres w obszarze pamięci ROM oprogramowania układowego w trybie rzeczywistym. Jest to prawdopodobnie manekin, który nie robi nic więcej niż tylko iret.
  • Pozycja IVT 1E wskazuje na F000: 6AA4, tabelę w tym samym obszarze ROM.
  • Pozycja IVF 1F wskazuje na C000: 8930, tabelę w obszarze oprogramowania ROM ROM w trybie rzeczywistym.
  • Pozycja IVT 43 wskazuje na C000: 6730, kolejną tabelę w obszarze oprogramowania ROM ROM w trybie rzeczywistym.

Dalsza lektura


Nie, mam na myśli to, co napisałem. Podręcznik dla programistów architektury Intel, tom 3, rozdział 20, § 2.
JdeBP,

Cóż, masz teraz, bo tak jest; jak wyjaśnia pierwsze zdanie tej sekcji. Podejrzewam, że nieuznawanie powszechnego skrótu „v8086” jest rodzajem shibboleth. (-:
JdeBP

Musisz nauczyć się czytać rzeczowniki przypisujące. Albo naucz się żyć bez zupy grzybowej.
JdeBP

7

Oryginalna architektura procesora 8086 (zaimplementowana jako tryb rzeczywisty w procesorach 80286+) nie ma znaczenia dla systemu Linux, który działa w trybie chronionym. Nie ma tablicy wektorów przerwań pod adresem fizycznym 0, zamiast tego używana jest tablica deskryptorów przerwań zawierająca deskryptory przerwań. IDT może znajdować się w dowolnym miejscu w pamięci.

Jądro Linux pobiera fizyczną mapę pamięci z oprogramowania układowego (BIOS lub EFI), która informuje, które ramki stron pamięci fizycznej są użyteczne, a które są zarezerwowane, a które nie. Zakres użytecznych ramek stron nie jest ciągły, ale zwykle ma w nim ogromne dziury. Tradycyjnie jądro Linuksa x86 pomijało początek pamięci fizycznej, nawet jeśli jest oznaczona jako użyteczna. Dlatego fizyczny adres 0 nie jest używany przez jądro Linuksa.


To ma sens. Masz pojęcie, z czego pochodzi resztka tej nieużywanej strony?
rhodeo,

Googling 53 ffujawnia, że ​​jest to najprawdopodobniej tak naprawdę tablica wektorów przerwań 8086 trybu rzeczywistego skonfigurowana przez oprogramowanie układowe lub moduł ładujący.
Johan Myréen,

4

Zrzucanie pamięci

Oto alternatywny sposób na zrzucenie zawartości pamięci w systemie w porównaniu z koniecznością wykonania tego na zewnątrz:

$ head /dev/mem | hexdump -C
00000000  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
00000010  53 ff 00 f0 53 ff 00 f0  cc e9 00 f0 53 ff 00 f0  |S...S.......S...|
00000020  a5 fe 00 f0 87 e9 00 f0  53 ff 00 f0 46 e7 00 f0  |........S...F...|
00000030  46 e7 00 f0 46 e7 00 f0  57 ef 00 f0 53 ff 00 f0  |F...F...W...S...|
00000040  22 00 00 c0 4d f8 00 f0  41 f8 00 f0 fe e3 00 f0  |"...M...A.......|
00000050  39 e7 00 f0 59 f8 00 f0  2e e8 00 f0 d4 ef 00 f0  |9...Y...........|
00000060  a4 f0 00 f0 f2 e6 00 f0  6e fe 00 f0 53 ff 00 f0  |........n...S...|
00000070  ed ef 00 f0 53 ff 00 f0  c7 ef 00 f0 ed 57 00 c0  |....S........W..|
00000080  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
...
...
000afea0  00 00 00 00 00 00 00 00  aa aa aa 00 aa aa aa 00  |................|
000afeb0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000b0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
000c0000  55 aa 40 e9 62 0a 00 00  00 00 00 00 00 00 00 00  |U.@.b...........|
000c0010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 49 42  |..............IB|

Analiza

Górna część powyżej 000c0000 może być związana z programem ładującym. Dlaczego miałbym to podejrzewać? Kod 55aah w lokalizacji 000c0000może zwykle oznaczać w pamięci takie rzeczy, jak wyzwalacz dla BIOS-u do uruchomienia dodatkowego programu ładującego.

Odniesienie: Boot Signature - BIOS

  ss # 1

Jednak biorąc pod uwagę, że 55aah występuje w zakresie c0000h-effffh, bardziej prawdopodobne jest, że ta część jest nagłówkiem rozszerzenia PNP:

Odniesienie: specyfikacja rozruchu systemu BIOS

3.3 Urządzenia z nagłówkami rozszerzającymi PnP

Wszystkie urządzenia IPL z opcjonalną pamięcią ROM muszą zawierać prawidłowy nagłówek opcji ROM, który znajduje się między adresami pamięci systemowej C0000h i EFFFFh na granicy 2k i zaczyna się od 55AAh. Rozruch urządzenia można kontrolować tylko wtedy, gdy ma on nagłówek rozszerzeń PnP. Nagłówek rozszerzenia, którego adres znajduje się w standardowym nagłówku opcji ROM przy przesunięciu + 1 Ah, zawiera ważne informacje używane do konfiguracji urządzenia. Zawiera także wskaźniki do zakodowania w opcji ROM urządzenia (BCV lub BEV), które BIOS wywoła w celu uruchomienia z urządzenia. Struktura dodatku PnP Expansion Header znajduje się w załączniku A. Istnieją dwa sposoby uruchomienia urządzenia IPL z rozszerzeniem PnP. Musi zawierać BCV lub BEV.

53ff ...

Jeśli chodzi o dane 53ffh, które są na początku. Nie jest dla mnie jasne, co to właściwie jest. Dalsze badania to prawdopodobnie coś, co napisał tam jądro Linux po załadowaniu systemu MBR przez MBR do jądra Linuxa w celu uruchomienia.

Zwykle program ładujący ładuje jądro do pamięci, a następnie przeskakuje do jądra. Jądro będzie wtedy w stanie odzyskać pamięć używaną przez bootloader (ponieważ już wykonał swoje zadanie). Możliwe jest jednak włączenie kodu systemu operacyjnego do sektora rozruchowego i zachowanie go jako rezydentnego po uruchomieniu systemu operacyjnego

Kopiąc dalej, udało mi się znaleźć ten akapit z pracy badawczej zatytułowanej: Wstrzyknięcie złośliwego kodu przez / dev / mem :

1 Urządzenie pamięci

/ dev / mem jest interfejsem sterownika do fizycznie adresowalnej pamięci. Pierwotnym celem zarówno mem, jak i kmem była pomoc w debugowaniu jądra. Możemy używać urządzenia jak zwykłego urządzenia znakowego, używając lseek () do wyboru przesunięcia adresu. Urządzenie kmem jest podobne, ale zapewnia obraz pamięci jądra w kontekście wirtualnego adresowania. Serwer Xorg korzysta z urządzenia pamięci w celu uzyskania dostępu do pamięci wideo VESA, a także tablicy wektorów przerwań ROM ROM (IVT) znajdującej się pod adresem fizycznym 0x00000000 do manipulowania trybami wideo w trybie VM86. DOSEMU korzysta również z tego, aby uzyskać dostęp do BIOS IVT, aby móc przerwać BIOS dla różnych zadań (odczyt dysku, drukowanie na konsoli itp.).

Bibliografia

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.