2009-11-20 16 views
8

Próbuję wykonać kilka eksperymentów z użyciem różnych segmentów oprócz domyślnego segmentu kodu i danych użytkownika oraz jądra. Mam nadzieję, że uda się to osiągnąć poprzez użycie lokalnej tabeli deskryptorów i wywołania systemowego modify_ldt. Poprzez wywołanie systemowe utworzyłem nowy wpis w LDT, który jest deskryptorem segmentu z adresem bazowym zmiennej globalnej, którą chcę "izolować" i limitem 4 bajtów.Korzystanie z LDT (lokalnej tablicy deskryptorów)

Próbuję załadować rejestr segmentów danych za pomocą selektora segmentów mojego niestandardowego wpisu LDT za pomocą wbudowanego zestawu w programie C, ale gdy spróbuję uzyskać dostęp do zmiennej, otrzymuję błąd segmentacji.

Podejrzewam, że występuje problem z przesunięciem mojej zmiennej globalnej, a kiedy adres jest obliczany, przekracza limit mojego segmentu niestandardowego, powodując błąd seg.

Czy ktoś wie o pracy w tej sytuacji?

Och, przy okazji, jest to na architekturze x86 w Linuksie. Po raz pierwszy zadaję takie pytanie na forum, więc jeśli są jakieś inne informacje, które mogą okazać się przydatne, proszę dać mi znać.

Z góry dziękuję.

Edit: I sobie sprawę, że prawdopodobnie powinien zawierać kod źródłowy :)

struct user_desc* table_entry_ptr = NULL; 

/* Allocates memory for a user_desc struct */ 
table_entry_ptr = (struct user_desc*)malloc(sizeof(struct user_desc)); 

/* Fills the user_desc struct which represents the segment for mx */ 
table_entry_ptr->entry_number = 0; 
table_entry_ptr->base_addr = ((unsigned long)&mx); 
table_entry_ptr->limit = 0x4; 
table_entry_ptr->seg_32bit = 0x1; 
table_entry_ptr->contents = 0x0; 
table_entry_ptr->read_exec_only = 0x0; 
table_entry_ptr->limit_in_pages = 0x0; 
table_entry_ptr->seg_not_present = 0x0; 
table_entry_ptr->useable = 0x1; 

/* Writes a user_desc struct to the ldt */ 
num_bytes = syscall(__NR_modify_ldt, 
        LDT_WRITE, // 1 
        table_entry_ptr, 
        sizeof(struct user_desc) 
        ); 

asm("pushl %eax"); 
asm("movl $0x7, %eax"); /* 0111: 0-Index 1-Using the LDT table 11-RPL of 3 */ 
asm("movl %eax, %ds"); 
asm("popl %eax"); 

mx = 0x407CAFE; 

Usterka seg występuje w tej ostatniej instrukcji.

Odpowiedz

6

Mogę tylko zgadywać, ponieważ nie mam do dyspozycji zespołu.

Zgaduję, że linia, na której można uzyskać segfault jest kompilowany do czegoś podobnego:

mov ds:[offset mx], 0x407cafe 

Gdzie offset mx jest przesunięcie do mx w segmencie danych programu (jeśli jest to zmienna statyczna) lub w stosie (jeśli jest to zmienna automatyczna). Tak czy inaczej, to przesunięcie jest obliczane w czasie kompilacji i to będzie używane bez względu na to, na co wskazuje DS.

Teraz co zrobiłeś tutaj jest stworzenie nowego segmentu, którego podstawa jest pod adresem mx i którego granica jest albo 0x4 lub 0x4fff (w zależności od G-bit których nie określono).

Jeśli G-bit wynosi 0, wówczas limit wynosi 0x4, a ponieważ jest to bardzo mało prawdopodobne, że mx znajduje się między adresami 0x0 i 0x4 oryginalnego DS, gdy masz dostęp do offsetu do mx wewnątrz nowego segmentu jesteś przejście limit.

Jeśli wartość G-bit wynosi 1, limit wynosi 0x4fff. Teraz dostaniesz segfault tylko wtedy, gdy oryginalny mx znajdował się powyżej 0x4fff.

Biorąc pod uwagę, że baza nowy segment jest w mx, można uzyskać dostęp mx wykonując:

mov ds:[0], 0x407cafe 

nie wiem jak pójdę o pisaniu, że w C, choć.

+0

To prawda. Adres 'mx' * w stosunku do nowego' DS' * jest teraz '0'. Zamiast ładować nowy deskryptor segmentu do 'DS', należy go załadować do' ES' i użyć nadpisań segmentów, aby uzyskać do niego dostęp (ładowanie 'DS' wpłynie na * wszystkie * dostępy do danych w twoim kodzie C). – caf

+0

To co mam, kiedy demontować ELF z objdump: 8048a48: c7 05 8c 9e 04 08 fe movl $ 0x3424cafe, 0x8049e8c 8048a4f: ca 24 34 Jest to dość nowy materiał podlega dla mnie, więc jestem nie wiem, który z bajtów jest używany dla modyfikatora zastąpienia rejestru segmentu. Czy adres wyświetlony w kodzie zespołu jest przesunięty w domyślnym segmencie danych? Jeśli tak jest, czy muszę zmienić adres miejsca, w którym zainicjowano zmienną? – Brian

+0

To jest podział: 'c7' to kod operacji dla' MOV r/m32, imm32'. '05' to bajt MOD/RM, który mówi, że operand pamięci jest adresowany tylko przez przemieszczenie. Przesunięcie występuje w następujących czterech bajtach: '0x08049e8c'. Następne cztery bajty to natychmiastowe '0x3424cafe'. Oznacza to, że przesunięcie 'mx' wewnątrz domyślnego segmentu danych to' 0x08049e8c', i jest to przesunięcie wewnątrz nowego 'DS', do którego uzyskujesz dostęp. –

Powiązane problemy