Şimdiye kadar, sadece durumu olmayan calıştırılabilir kod iceren nesne dosyalarıyla uğraşıyorduk. Yani, ice aktarılan işlevler cıktılarını yalnızca girdilere gore hesaplayabilir. İce aktarılan kodumuza bazı sabit veriler ve global değişken bağımlılıkları eklersek ne olacağını gorelim. İlk olarak, şunlara birkac işlev daha ekliyoruz obj.o:
Kod:
obj.c : ... const char *get_hello(void) static int var = 5; int get_var(void) void set_var(int num) get_hellosabit bir dizge dondurur ve get_var/ set_varget ve sırasıyla global bir değişken ayarlar. Ardından, obj.oyukleyicimizi yeniden derleyip calıştıralım: $ gcc -c obj.c $ ./loader Calculated relocation: 0xffffffdc Calculated relocation: 0xffffffcf No runtime base address for section .rodata
Gorunuşe gore yukleyicimiz daha fazla yer değiştirmeyi denedi, ancak .rodatabolum icin calışma zamanı adresini bulamadı . Daha once bir .rodatabolumumuz bile yoktu , ancak şimdi eklendi cunku obj.osabit dizeyi saklamak icin bir yere ihtiyacımız var.Hello, world!:
Kod:
$ readelf --sections obj.o There are 13 section headers, starting at offset 0x478: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .text PROGBITS 0000000000000000 00000040 000000000000005f 0000000000000000 AX 0 0 1 [ 2] .rela.text RELA 0000000000000000 00000320 0000000000000078 0000000000000018 I 10 1 8 [ 3] .data PROGBITS 0000000000000000 000000a0 0000000000000004 0000000000000000 WA 0 0 4 [ 4] .bss NOBITS 0000000000000000 000000a4 0000000000000000 0000000000000000 WA 0 0 1 [ 5] .rodata PROGBITS 0000000000000000 000000a4 000000000000000d 0000000000000000 A 0 0 1 [ 6] .comment PROGBITS 0000000000000000 000000b1 000000000000001d 0000000000000001 MS 0 0 1 [ 7] .note.GNU-stack PROGBITS 0000000000000000 000000ce 0000000000000000 0000000000000000 0 0 1 [ 8] .eh_frame PROGBITS 0000000000000000 000000d0 00000000000000b8 0000000000000000 A 0 0 8 [ 9] .rela.eh_frame RELA 0000000000000000 00000398 0000000000000078 0000000000000018 I 10 8 8 [10] .symtab SYMTAB 0000000000000000 00000188 0000000000000168 0000000000000018 11 10 8 [11] .strtab STRTAB 0000000000000000 000002f0 000000000000002c 0000000000000000 0 0 1 [12] .shstrtab STRTAB 0000000000000000 00000410 0000000000000061 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), l (large), p (processor specific)
Ayrıca daha fazla .textyer değiştirmemiz var:
Kod:
$ readelf --relocs obj.o Relocation section '.rela.text' at offset 0x320 contains 5 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000000020 000a00000004 R_X86_64_PLT32 0000000000000000 add5 - 4 00000000002d 000a00000004 R_X86_64_PLT32 0000000000000000 add5 - 4 00000000003a 000500000002 R_X86_64_PC32 0000000000000000 .rodata - 4 000000000046 000300000002 R_X86_64_PC32 0000000000000000 .data - 4 000000000058 000300000002 R_X86_64_PC32 0000000000000000 .data - 4 ...
Derleyici R_X86_64_PC32bu sefer uc yer değiştirme daha yayınladı. Sembollere indeksli referans veriyorlar 3ve 5bu yuzden ne olduklarını oğrenelim:
Kod:
$ readelf --symbols obj.o Symbol table '.symtab' contains 15 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS obj.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 5: 0000000000000000 0 SECTION LOCAL DEFAULT 5 6: 0000000000000000 4 OBJECT LOCAL DEFAULT 3 var 7: 0000000000000000 0 SECTION LOCAL DEFAULT 7 8: 0000000000000000 0 SECTION LOCAL DEFAULT 8 9: 0000000000000000 0 SECTION LOCAL DEFAULT 6 10: 0000000000000000 15 FUNC GLOBAL DEFAULT 1 add5 11: 000000000000000f 36 FUNC GLOBAL DEFAULT 1 add10 12: 0000000000000033 13 FUNC GLOBAL DEFAULT 1 get_hello 13: 0000000000000040 12 FUNC GLOBAL DEFAULT 1 get_var 14: 000000000000004c 19 FUNC GLOBAL DEFAULT 1 set_var
Girişler 3ve 5herhangi bir isim eklenmemiş, ancak sırasıyla 3ve dizinli bolumlerdeki bir şeye başvuruyorlar 5. Yukarıdaki bolum tablosunun cıkışı olarak, dizinden ile bolum olduğunu gorebilirsiniz 3olduğunu .datave indeksi bolum 5olduğunu .rodata. Bir ELF dosyasındaki en yaygın bolumleri tazelemek icin onceki gonderimize goz atın . Yeni eklenen kodumuzu ice aktarmak ve calışmasını sağlamak icin, bolume ek olarak harita .datave .rodatabolumler de yapmamız .textve bu R_X86_64_PC32yer değiştirmeleri işlememiz gerekiyor.
Yine de bir uyarı var. Spesifikasyonu kontrol edersek, R_X86_64_PC32yeniden konumlandırmanın yeniden konumlandırmaya benzer 32 bitlik bir cıktı urettiğini goreceğiz R_X86_64_PLT32. Bu, icinde yamalanmış konum ile .textreferans verilen sembol arasındaki bellekteki "mesafenin" 32 bitlik bir değere sığacak kadar kucuk olması gerektiği anlamına gelir (pozitif / negatif işaret icin 1 bit ve gercek veriler icin 31 bit, dolayısıyla daha az 2147483647 bayttan daha fazla). Bizim loaderprogramın kullandığı sistem cağrısı mmap nesne bolumu kopyalar icin bellek ayrılamadı, ama mmap neredeyse her işlem adres alanında eşleme tahsis edebilir. loaderProgramı her bolum icin ayrı ayrı mmap'i cağıracak şekilde değiştirirsek, sonucta .rodataveya.databolum, .textbolumden cok uzakta haritalandı ve R_X86_64_PC32yer değiştirmeleri işleyemeyecek . Başka bir deyişle, calışma zamanında bolumlerin .datave .rodatabolumlerin gorece yakın bir yerde bulunduğundan emin olmalıyız .text:
Bunu başarmanın bir yolu, tum bolumler icin ihtiyacımız olan belleği tek bir mmap cağrısıyla ayırmaktır . Ardından, onu parcalara ayırır ve her bir parcaya uygun erişim izinleri atarız. loaderProgramımızı tam da bunu yapacak şekilde değiştirelim :
Kod:
loader.c : ... /* runtime base address of the imported code */ static uint8_t *text_runtime_base; /* runtime base of the .data section */ static uint8_t *data_runtime_base; /* runtime base of the .rodata section */ static uint8_t *rodata_runtime_base; ... static void parse_obj(void) /* find the `.data` entry in the sections table */ const Elf64_Shdr *data_hdr = lookup_section(".data"); if (!data_hdr) /* find the `.rodata` entry in the sections table */ const Elf64_Shdr *rodata_hdr = lookup_section(".rodata"); if (!rodata_hdr) /* allocate memory for `.text`, `.data` and `.rodata` copies rounding up each section to whole pages */ text_runtime_base = mmap(NULL, page_align(text_hdr->sh_size) + page_align(data_hdr->sh_size) + page_align(rodata_hdr->sh_size), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (text_runtime_base == MAP_FAILED) /* .data will come right after .text */ data_runtime_base = text_runtime_base + page_align(text_hdr->sh_size); /* .rodata will come after .data */ rodata_runtime_base = data_runtime_base + page_align(data_hdr->sh_size); /* copy the contents of `.text` section from the ELF file */ memcpy(text_runtime_base, obj.base + text_hdr->sh_offset, text_hdr->sh_size); /* copy .data */ memcpy(data_runtime_base, obj.base + data_hdr->sh_offset, data_hdr->sh_size); /* copy .rodata */ memcpy(rodata_runtime_base, obj.base + rodata_hdr->sh_offset, rodata_hdr->sh_size); do_text_relocations(); /* make the `.text` copy readonly and executable */ if (mprotect(text_runtime_base, page_align(text_hdr->sh_size), PROT_READ | PROT_EXEC)) /* we don't need to do anything with .data - it should remain read/write */ /* make the `.rodata` copy readonly */ if (mprotect(rodata_runtime_base, page_align(rodata_hdr->sh_size), PROT_READ)) } ...
Şimdi calışma zamanı adreslerine sahip olduklarından .datave .rodatabiz taşınma zamanı adres arama fonksiyonunu guncelleyebilirsiniz:
Kod:
loader.c : ... static uint8_t *section_runtime_base(const Elf64_Shdr *section)
Son olarak yeni fonksiyonlarımızı ice aktarabilir ve calıştırabiliriz:
Kod:
/* pointers to imported functions */ int (*add5)(int); int (*add10)(int); const char *(*get_hello)(void); int (*get_var)(void); void (*set_var)(int num); ... printf("add10(%d) = %dn", 42, add10(42)); get_hello = lookup_function("get_hello"); if (!get_hello) puts("Executing get_hello..."); printf("get_hello() = %sn", get_hello()); get_var = lookup_function("get_var"); if (!get_var) puts("Executing get_var..."); printf("get_var() = %dn", get_var()); set_var = lookup_function("set_var"); if (!set_var) puts("Executing set_var(42)..."); set_var(42); puts("Executing get_var again..."); printf("get_var() = %dn", get_var()); } ... Hadi deneyelim: $ gcc -o loader loader.c $ ./loader Calculated relocation: 0xffffffdc Calculated relocation: 0xffffffcf Executing add5... add5(42) = 47 Executing add10... add10(42) = 52 Executing get_hello... get_hello() = ]�UH�� Executing get_var... get_var() = 1213580125 Executing set_var(42)... Segmentation fault
Uh-oh! Yeni R_X86_64_PC32yer değiştirme turunu uygulamayı unuttuk . Yer değiştirme formulu burada S + A - P. Ve hakkında zaten bilgi Asahibiyiz P. S( Spesifikasyondan alıntı yaparak) gelince :
"Dizini yeniden konumlandırma girişinde bulunan sembolun değeri"
Genişletmek icin tıkla ...
Bizim durumumuzda, aslında aynıdır Licin R_X86_64_PLT32. Yalnızca uygulamayı yeniden kullanabilir ve işlemdeki hata ayıklama cıktısını kaldırabiliriz:
Kod:
loader.c : ... /* from https://elixir.bootlin.com/linux/v5.11.6/source/arch/x86/include/asm/elf.h#L51 */ #define R_X86_64_PC32 2 #define R_X86_64_PLT32 4 ... static void do_text_relocations(void) int num_relocations = rela_text_hdr->sh_size / rela_text_hdr->sh_entsize; const Elf64_Rela *relocations = (Elf64_Rela *)(obj.base + rela_text_hdr->sh_offset); for (int i = 0; i < num_relocations; i++) } } ...
Cloudflare global değişkenleri işleme
Site & Server Administration0 Mesaj
●5 Görüntüleme
- ReadBull.net
- Domain & Sunucu & Web Hosting
- Site & Server Administration
- Cloudflare global değişkenleri işleme
-
05-09-2022, 16:43:22