In onceki yazı biz bir nesne dosyasını ayrıştırmak ve ithalat ve ondan bazı fonksiyonlarını yurutmek oğrendi. Bununla birlikte, oyuncak nesne dosyamızdaki işlevler basit ve bağımsızdı: cıktılarını yalnızca girdilerine gore hesapladılar ve herhangi bir harici koda veya veri bağımlılığına sahip değillerdi. Bu yazıda , bazı bağımlılıkları olan kodu işlemek icin gereken ek adımları keşfederek, 1. bolumdeki kodu temel alacağız .
Ornek olarak, add10işlevimizi kullanarak işlevimizi gercekten yeniden yazabileceğimizi fark edebiliriz add5:
Kod:
obj.c : int add5(int num) int add10(int num)
Nesne dosyasını yeniden derleyip loaderprogramımızla kitaplık olarak kullanmaya calışalım :
Kod:
$ gcc -c obj.c $ ./loader Executing add5... add5(42) = 47 Executing add10... add10(42) = 42
Whoa! Burada doğru olmayan bir şey var. add5yine de doğru sonucu verir, ancak uretmez add10. Ortamınıza ve kod kompozisyonunuza bağlı olarak, loaderyanlış sonuclar vermek yerine programın coktuğunu bile gorebilirsiniz . Ne olduğunu anlamak icin derleyici tarafından uretilen makine kodunu inceleyelim. Bunu objdump aracından.text bolumu aşağıdaki bolumden sokmesini isteyerek yapabiliriz obj.o:
Kod:
$ objdump --disassemble --section=.text obj.o obj.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 : 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: 89 7d fc mov %edi,-0x4(%rbp) 7: 8b 45 fc mov -0x4(%rbp),%eax a: 83 c0 05 add $0x5,%eax d: 5d pop %rbp e: c3 retq 000000000000000f : f: 55 push %rbp 10: 48 89 e5 mov %rsp,%rbp 13: 48 83 ec 08 sub $0x8,%rsp 17: 89 7d fc mov %edi,-0x4(%rbp) 1a: 8b 45 fc mov -0x4(%rbp),%eax 1d: 89 c7 mov %eax,%edi 1f: e8 00 00 00 00 callq 24 24: 89 45 fc mov %eax,-0x4(%rbp) 27: 8b 45 fc mov -0x4(%rbp),%eax 2a: 89 c7 mov %eax,%edi 2c: e8 00 00 00 00 callq 31 31: c9 leaveq 32: c3 retq
Yukarıdaki cıktının tamamını anlamanıza gerek yok. Burada yalnızca iki ilgili satır vardır: 1f: e8 00 00 00 00ve 2c: e8 00 00 00 00. Bunlar add5, kaynak kodda sahip olduğumuz iki işlev cağrısına karşılık gelir ve objdump , bizim icin talimatı uygun bir şekilde cozer callq. Acıklamaları bakarak callq daha ayrıntılı nedeniyle, bir "yakın akraba cağrı" ile uğraşıyoruz gorebilirsiniz 0xe8oneki:
Bir sonraki talimata gore yakın, goreceli, yer değiştirme cağırın.
Genişletmek icin tıkla ...
Gore acıklama , bu varyant callq: talimatı 5 bayt icerir 0xe8oneki ve bir 4 baytlık (32 bit) bir arguman. "Goreli" nin geldiği yer burasıdır: arguman cağırmak istediğimiz fonksiyon ile mevcut konum arasındaki "mesafeyi" icermelidir - cunku x86'nın bu mesafenin calışma şekli mevcut callqtalimatımızdan değil bir sonraki komuttan hesaplanır . objdump , yukarıdaki cıktıdaki her makine komutunun ofsetini uygun bir şekilde cıkarır , boylece gerekli argumanı kolayca hesaplayabiliriz. Orneğin, ilk callqkomut ( 1f: e8 00 00 00 00) icin sonraki komut ofsettir 0x24. Ofsette başlayan add5işlevi cağırmamız gerektiğini biliyoruz 0x0(bizim.textBolum). Yani goreli ofset 0x0 - 0x24 = -0x24. Dikkat edin, olumsuz bir argumanımız var, cunku add5fonksiyon cağırma talimatımızdan once yer alıyor, bu yuzden CPU'ya mevcut konumundan "geriye doğru atlamasını" soyleyeceğiz. Son olarak, negatif sayıların - en azından x86 sistemlerinde - ikisinin tumleyicileri tarafından sunulduğunu hatırlamalıyız , bu nedenle 4 baytlık (32 bit) temsili -0x24olacaktır 0xffffffdc. Aynı şekilde callq, ikinci add5cağrı icin argumanı da hesaplayabiliriz :, 0x0 - 0x31 = -0x31ikinin tumleyicisi - 0xffffffcf:
Gorunuşe gore derleyici callqbizim icin doğru argumanları uretmiyor . Biz beklenen argumanlar olarak hesaplanmıştır ettik 0xffffffdcve 0xffffffcfancak derleyici sadece bırakmıştır 0x00000000iki yerde de. Calıştırmaya .textcalışmadan once yuklediğimiz kopyayı yamalayarak beklentilerimizin doğru olup olmadığını kontrol edelim :
Kod:
loader.c : ... static void parse_obj(void) { ... /* copy the contents of `.text` section from the ELF file */ memcpy(text_runtime_base, obj.base + text_hdr->sh_offset, text_hdr->sh_size); /* the first add5 callq argument is located at offset 0x20 and should be 0xffffffdc: * 0x1f is the instruction offset + 1 byte instruction prefix */ *((uint32_t *)(text_runtime_base + 0x1f + 1)) = 0xffffffdc; /* the second add5 callq argument is located at offset 0x2d and should be 0xffffffcf */ *((uint32_t *)(text_runtime_base + 0x2c + 1)) = 0xffffffcf; /* make the `.text` copy readonly and executable */ if (mprotect(text_runtime_base, page_align(text_hdr->sh_size), PROT_READ | PROT_EXEC)) { ...
Ve şimdi deneyelim:
Kod:
$ gcc -o loader loader.c $ ./loader Executing add5... add5(42) = 47 Executing add10... add10(42) = 52
Acıkca maymun yamamız yardımcı oldu: add10şimdi iyi calışıyor ve doğru cıktıyı uretiyor. Bu callq, hesapladığımız beklenen argumanlarımızın doğru olduğu anlamına gelir . Oyleyse derleyici neden yanlış callqargumanlar verdi?
Cloudflare nesne dosyası nasıl calıştırılır ?
Site & Server Administration0 Mesaj
●2 Görüntüleme
- ReadBull.net
- Domain & Sunucu & Web Hosting
- Site & Server Administration
- Cloudflare nesne dosyası nasıl calıştırılır ?
-
05-09-2022, 16:43:33