Rumah > Artikel > Operasi dan penyelenggaraan > apa itu pic linux
Dalam Linux, makna pic dalam bahasa Cina bermaksud "kod bebas kedudukan", yang bermaksud kod itu boleh dilaksanakan secara normal tidak kira alamat mana ia dimuatkan. PIC digunakan untuk menjana pustaka kongsi bebas kedudukan Apa yang dipanggil bebas kedudukan bermakna bahawa segmen kod perpustakaan kongsi adalah baca sahaja dan disimpan dalam segmen kod ini pada masa yang sama tanpa meniru.
Persekitaran pengendalian tutorial ini: sistem linux7.3, komputer Dell G3.
Di Linux, nama penuh pic ialah "Kod Bebas Kedudukan", yang bermaksud "kod bebas kedudukan" dalam bahasa Cina.
1. Gambaran keseluruhan kod yang berkaitan dengan ruang alamat maya program dan lokasi
Apabila proses Linux dimuatkan dari cakera ke memori dan dijalankan, kernel akan Memperuntukkan ruang alamat maya kepada proses Ruang alamat maya dibahagikan kepada blok kawasan (Segmen) yang paling penting adalah seperti berikut:
Rajah). 1 - Perihalan ruang alamat maya Aplikasi
Ruang alamat kernel adalah sama untuk semua aplikasi Bahagian ruang alamat ini tidak boleh diakses secara langsung oleh aplikasi. Ruang alamat kernel bukan fokus artikel ini. Kami menumpukan pada beberapa SEGMEN penting aplikasi.
Jadual 1 - Penerangan tentang segmen penting aplikasi
Jika sistem tidak mendayakan rawak alamat (ASLR - Rawak Susun Atur Ruang Alamat, rawak alamat, teks kemudian (akan diperkenalkan), Linux akan meletakkan ruang alamat setiap segmen dalam jadual di atas pada alamat tetap.
Mari kita tulis program sebenar untuk melihat bagaimana alamat setiap segmen disusun pada mesin Linux X86_64 Program ini adalah seperti berikut, meliputi segmen yang kami minati.
Rajah 2 - Program Demonstrasi Ruang Alamat Maya
Kompilasi
gcc -o addr_test addr_test.c -static
(Pautan statik digunakan di sini supaya lokasi demo adalah relevan Ciri-ciri kod)
Apabila kita menjalankan program ini tiga kali, kita akan mendapati bahawa semua alamat adalah nilai tetap. Ini kerana apabila ciri ASLR tidak dihidupkan, sistem tidak memperuntukkan ruang alamat maya program secara rawak dan semua alamat program dijana mengikut peraturan tetap.
Rajah 3 - Pengedaran alamat segmen tetap
Selepas membuka melalui arahan objdump, anda boleh melihat bahawa untuk akses kepada pembolehubah global dan panggilan fungsi, pemasangan ikut arahan Alamat semuanya tetap, jadi kami memanggil kod tersebut berkaitan lokasi.
Rajah 4 - Contoh pernyataan pemasangan kod berkaitan kedudukan
Kod jenis ini, kerana alamatnya berkod keras, hanya boleh dimuatkan ke alamat dan jalankan yang ditentukan Setelah alamat pemuatan berubah, kerana alamat pembolehubah dan fungsi yang diakses dalam kod ditetapkan, program tidak dapat dilaksanakan secara normal selepas alamat pemuatan berubah.
Walaupun kaedah alamat tetap adalah mudah, ia tidak dapat melaksanakan beberapa ciri lanjutan seperti sokongan perpustakaan dinamik. Kod perpustakaan dinamik akan dipetakan ke ruang alamat maya proses melalui panggilan sistem mmap() Dalam proses yang berbeza, alamat maya yang dipetakan oleh perpustakaan dinamik yang sama tidak pasti. Jika kod berkaitan kedudukan digunakan dalam pelaksanaan perpustakaan dinamik, tujuan berjalan di mana-mana alamat tidak dapat dicapai Dalam kes ini, kita perlu memperkenalkan konsep PIC kod bebas kedudukan.
Selain itu, kita dapat melihat bahawa pada sistem yang ciri rawak alamat tidak dihidupkan, memandangkan alamat setiap segmen program ditetapkan, ia akan menjadi lebih mudah untuk penggodam menyerang (pelajar yang berminat boleh mencari untuk serangan Ret2shellcode atau Ret2libc), pada masa ini konsep PIE perlu diperkenalkan bersama ASLR untuk perlindungan.
2 Pelaksanaan kod bebas kedudukan PIC dan pustaka dinamik
Kod bebas kedudukan PIC bermakna tidak kira kod mana pun alamatnya. dimuatkan pada, Boleh dilaksanakan seperti biasa. Menambah -fPIC pada pilihan gcc akan menjana kod yang berkaitan.
PIC digunakan untuk menjana pustaka kongsi yang tidak bergantung pada kedudukan Yang dipanggil tidak bebas kedudukan bermaksud bahawa segmen kod perpustakaan kongsi adalah baca sahaja dan disimpan dalam segmen kod ini segmen pada masa yang sama tanpa salinan diperlukan. Pembolehubah (pembolehubah global dan pembolehubah statik) dalam perpustakaan diakses melalui jadual GOT, manakala fungsi dalam perpustakaan diakses melalui lokasi fungsi PLT->GOT->. Apabila menyusun pustaka dikongsi di bawah Linux, anda mesti menambah parameter -fPIC, jika tidak akan terdapat mesej ralat semasa memaut (sesetengah maklumat mengatakan bahawa ralat ini hanya berlaku pada mesin AMD64, tetapi ia juga berlaku pada mesin Inter saya).
Key point #1 - Offset antara segmen kod dan segmen data
Offset antara segmen kod dan segmen data diberikan oleh pemaut semasa memaut Keluar, ia sangat penting untuk PIC. Apabila pemaut menggabungkan semua p bagi setiap fail objek bersama-sama, pemaut mengetahui sepenuhnya saiz setiap p dan kedudukan relatif di antara mereka.
Rajah 5 - Contoh mengimbangi segmen kod dan segmen data
Seperti yang ditunjukkan dalam rajah di atas, dalam contoh, TEKS dan DATA berada berdekatan antara satu sama lain Malah, tanpa mengira DATA dan TEKS bersebelahan, penghubung boleh mengetahui offset kedua-dua segmen ini. Berdasarkan offset ini, offset relatif bagi mana-mana arahan dalam segmen TEXT berbanding alamat permulaan segmen DATA boleh dikira. Seperti yang ditunjukkan dalam rajah di atas, tidak kira alamat maya mana segmen TEXT diletakkan, dengan mengandaikan arahan mov berada pada offset 0xe0 di dalam TEXT, maka kita boleh tahu bahawa kedudukan offset relatif bagi segmen DATA ialah: saiz Segmen TEXT - arahan mov berada pada ofset Dalaman TEXT = 0xXXXXE000 - 0xXXXX00E0 = 0xDF20
Titik utama #2 - Pengiraan ofset relatif arahan pada X86
Jika anda menggunakan kedudukan relatif untuk pemprosesan, anda boleh melihat Kod boleh menjadi kedudukan bebas. Tetapi pada platform X86, arahan mov memerlukan alamat mutlak untuk rujukan data, jadi apa yang perlu kita lakukan?
Dari penerangan dalam "Key Point 1", jika kita tahu alamat arahan semasa, kita boleh mengira alamat segmen data. Tiada arahan untuk mendapatkan nilai IP daftar penunjuk arahan semasa pada platform X86 (RIP boleh diakses terus pada X64), tetapi ia boleh diperolehi melalui helah kecil. Mari lihat sekeping kod pseudo:
Rajah 6 - pemasangan alamat arahan pemerolehan platform X86
Apabila kod ini sebenarnya dijalankan, perkara berikut akan berlaku :
Apabila CPU melaksanakan panggilan STUB, ia akan menyimpan alamat arahan seterusnya kepada timbunan, dan kemudian melompat ke label STUB untuk pelaksanaan.
Arahan di STUB ialah pop ebx, jadi alamat arahan "pop ebx" muncul daripada tindanan ke dalam daftar ebx, sekali gus mendapat nilai daftar IP .
1 Jadual ofset global DAPAT
Setelah memahami perkara sebelumnya, mari kita lihat bagaimana kedudukan dilaksanakan pada rujukan data X86 Independent , ciri ini dilaksanakan melalui jadual ofset global (GOT).
GOT ialah jadual yang disimpan dalam data p, yang merekodkan banyak medan alamat (masuk). Katakan arahan ingin merujuk kepada pembolehubah Ia tidak secara langsung menggunakan alamat mutlak, tetapi merujuk kepada entri dalam GOT. Alamat jadual GOT dalam data p adalah jelas, dan kemasukan GOT mengandungi alamat mutlak pembolehubah.
Rajah 7 - Hubungan antara alamat kod dan entri jadual GOT
Seperti yang ditunjukkan dalam rajah di atas, mengikut "Key Point 1" dan "Key Titik 2", mula-mula kita boleh Dapatkan nilai IP semasa, dan kemudian mengira alamat mutlak jadual GOT. Memandangkan offset kemasukan alamat pembolehubah dalam jadual GOT juga diketahui, capaian data bebas kedudukan boleh dicapai .
Ambil pseudokod arahan mov alamat mutlak sebagai contoh (platform X86):
Rajah 8 - Contoh arahan mov berkaitan kedudukan
Jika anda ingin mengubahnya menjadi kod bebas kedudukan, anda memerlukan beberapa langkah lagi
Rajah 9 - Contoh arahan mov bebas kedudukan digabungkan dengan GOT
Melalui langkah di atas, anda boleh mencapai akses kod bebas alamat kepada pembolehubah. Tetapi terdapat satu lagi soalan, bagaimanakah nilai VAR_ADDR yang disimpan dalam jadual GOT menjadi alamat mutlak sebenar?
Andaikan terdapat libtest.so dan pembolehubah global g_var Selepas kita lulus readelf -r libtest.so, kita akan melihat output berikut
Rajah 10 - medan perihalan ubah hala global segmen rel.dyn
Pemuat dinamik akan menghuraikan segmen rel.dyn Apabila ia melihat bahawa jenis ubah hala ialah R_386_GLOB_DAT, ia akan melakukan perkara berikut: aktualisasikan simbol g_var Ganti. nilai alamat untuk mengimbangi 0x1fe4 (iaitu, gantikan nilai Sym.Value dengan nilai alamat sebenar)
2. Pelaksanaan panggilan fungsi yang tidak bergantung pada kedudukan
Secara teorinya, pelaksanaan PIC fungsi juga boleh menjadi bebas kedudukan dengan cara yang sama seperti jadual GOT rujukan data. Daripada menggunakan alamat fungsi secara langsung, alamat mutlak sebenar fungsi ditemui dengan mencari GOT. Tetapi sebenarnya, ciri PIC fungsi tidak melakukan ini, dan keadaan sebenar lebih rumit. Mengapa tidak ikut kaedah yang sama seperti rujukan data dan lihat dahulu konsep: pengikatan tertunda.
Untuk fungsi perpustakaan dinamik, alamat sebenar fungsi tidak diketahui sebelum ia dimuatkan ke dalam ruang alamat program Pemuat dinamik akan menangani masalah ini dan menyelesaikan alamat sebenar. Tindakan mengikat akan mengambil sedikit masa kerana pemuat perlu melalui carian jadual khas dan operasi penggantian.
如果动态库有成百上千个函数接口,而实际的进程只用到了其中的几十个接口,如果全部都在加载的时候进行绑定操作,没有意义并且非常耗时。因此提出了延迟绑定的概念,程序只有在使用到对应接口时才实时地绑定接口地址。
因为有了延迟绑定的需求,所以函数的PIC实现和数据访问的PIC有所区别。为了实现延迟绑定,就额外增加了一个间接表PLT(过程链接表)。
PLT搭配GOT实现延迟绑定的过程如下:
第一次调用函数
图11 - 首次调用PIC函数时PLT,GOT关系
首先跳到PLT表对应函数地址PLT[n],然后取出GOT中对应的entry。GOT[n]里保存了实际要跳转的函数的地址,首次执行时此值为PLT[n]的prepare resolver的地址,这里准备了要解析的函数的相关参数,然后到PLT[0]处调用resolver进行解析。
resolver函数会做几件事情:
(1)解析出代码想要调用的func函数的实际地址A
(2)用实际地址A覆盖GOT[n]保存的plt_resolve_addr的值
(3)调用func函数
首次调用后,上图的链接关系会变成下图所示:
图12 - 首次调用PIC函数后PLT,GOT关系
随后的调用函数过程,就不需要再走resolver过程了
三、位置无关可执行程序PIE
PIE,全称Position Independent Executable。2000年早期及以前,PIC用于动态库。对于可执行程序来讲,仍然是使用绝对地址链接,它可以使用动态库,但程序本身的各个segment地址仍然是固定的。随着ASLR的出现,可执行程序运行时各个segment的虚拟地址能够随机分布,这样就让攻击者难以预测程序运行地址,让缓存溢出攻击变得更困难。OS在使能ASLR的时候,会检查可执行程序是否是PIE的可执行程序。gcc选项中添加-fPIE会产生相关代码。
四、Linux ASLR机制和PIE的关系
ASLR的全称为 Address Space Layout Randomization。在Linux 2.6.12 中被引入到 Linux 系统,它将进程的某些虚拟地址进行随机化,增大了入侵者预测目的地址的难度,降低应用程序被攻击成功的风险。
在Linux系统上,ASLR有三个级别
表2 - ASLR级别描述
ASLR的级别通过两种方式配置:
echo level > /proc/sys/kernel/randomize_va_space
或
sysctl -w kernel.randomize_va_space=level
例子:
echo 0 > /proc/sys/kernel/randomize_va_space 关闭地址随机化
或
sysctl -w kernel.randomize_va_space=2 最大级别的地址随机化
我们还是以文章开头的那个程序来说明ASLR在不同级别下时如何表现的,首先在ASLR关闭的情况下,相关地址不变,输出如下:
图13 - ASLR=0时虚拟地址空间分配情况
我们把ASLR级别设置为1,运行两次,看看结果:
图14 - ASLR=1时虚拟地址空间分配情况
可以看到STACK和MMAP的地址发生了变化。堆、数据段、代码段仍然是固定地址。
接下来我们把ASLR级别设置为2,运行两次,看看结果:
图15 - ASLR=2,PIE不启用时虚拟地址空间分配情况
可以看到此时堆的地址也发生了变化,但是我们发现BSS,DATA,TEXT段的地址仍然是固定的,不是说ASLR=2的时候,是完全随机化吗?
这里就引出了PIE和ASLR的关系了。从上面的实验可以看出,如果不对可执行文件做一些特殊处理,ASLR即使在设置为完全随机化的时候,也仅能对STACK,HEAP,MMAP等运行时才分配的地址空间进行随机化,而可执行文件本身的BSS,DATA,TEXT等没有办法随机化。结合文章前面讲到的PIE相关知识,我们也很容易理解这一点,因为编译和链接过程中,如果没有PIE的选项,生成的可执行文件里都是位置相关的代码。如果OS不管这一点,ASLR=2时也将BSS,DATA,TEXT等随意排布,可想而知程序根本不能正常运行起来。
明白了原因,我们在编译时加入PIE选项,然后在ASLR=2时重新运行一下看看结果如何
图16 - ASLR=2,PIE启用时虚拟地址空间分配情况
Anda dapat melihat bahawa dengan PIE dihidupkan dan ASLR=2, alamat maya setiap segmen boleh rawak sepenuhnya.
Cadangan berkaitan: "Tutorial Video Linux"
Atas ialah kandungan terperinci apa itu pic linux. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!