1. 程式人生 > 其它 >linux更換題目(可執行檔案)libc版本問題

linux更換題目(可執行檔案)libc版本問題

0x00 前言

本文主要記錄了在做pwn題目由於libc版本問題需要替換ELF檔案動態連線libc庫的解決方法,此方法同時可以推而廣之到linux下的任何ELF檔案連線庫的修改。

0x01 如何獲取不同的glibc

獲取不同的glibc版本這裡建議直接使用現有的開源工具glibc-all-in-one,其比較好的一點是可以下載符號表,同時將符號表存入對應版本libc的.debug資料夾中。

0x02 為什麼要下載對應版本的glibc

這個問題也是開始一直困擾的疑問,為什麼不直接使用手頭分發的glibc,設定環境變數LD_PRELOAD=./libc.so.6 ./xxx直接讓載入指定的libc執行,而要去下載一個對應版本的glibc重新編譯呢?

首先第一個原因是如果系統中的ld.solibc.so不匹配的話,使用LD_PRELOAD很可能會直接導致程式崩潰,如下所示

$ LD_PRELOAD=./libc.so.6 ./test
段錯誤 (核心已轉儲)

找到問題所在就可以對應解決問題了,這時候只需要解決執行時候的ld.so的連結就可以了

$ LD_PRELOAD=/path/to/libc.so.6;
$ /path/to/ld.so ./test

0x03 使用patchelf修改ELF檔案

上述的方法每一次執行都需要指定環境變數,比較麻煩,這裡強烈安利一款工具patchelf來更改ELF中硬編碼的ldlibc

一般 ELF 檔案的 lddfile

結果與下面類似,可以看到 libc 等動態庫的路徑被寫死在檔案中,而 libc.so.6 是一個符號連結,所指向的檔案是真正的 libc。

$ ldd /usr/local/bin/patchelf
    linux-vdso.so.1 (0x00007ffc497e5000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f2d46aee000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f2d4696b000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f2d46951000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2d46790000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f2d46caf000)

$ file /usr/local/bin/patchelf
/usr/local/bin/patchelf: ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=cfa182b059312c4c03e401efc8efe47a373d348c, with debug_info, not stripped

$ file /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6: symbolic link to libc-2.28.so

我們通過 patchelf 修改 ELF 檔案達到載入指定版本 libc。我們先用 --set-interpreter 這個選項來將舊的 ld.so 替換為要載入的 ld.so,然後使用 --replace-needed這個選項將舊的 libc.so 替換成要載入的 libc.so。在使用 --replace-needed 時,第 2 個引數是程式原本的動態庫的路徑,可以由 ldd $目標檔案 得到,第 3 個引數是新的動態庫的路徑,第 4 個引數為要修改檔案的路徑。

這裡我們修改 "./patchelf" 這個檔案的的 libc.so 和 ld.so。根據上面 ldd 的結果,可以知道 ELF 中的 libc 的路徑為 "libc.so.6",所以替換 libc 時所使用的第 2 個引數為 "libc.so.6"

$ patchelf --set-interpreter /opt/libs/2.27-3ubuntu1_amd64/ld-2.27.so ./patchelf
$ patchelf --replace-needed libc.so.6 /opt/libs/2.27-3ubuntu1_amd64/libc-2.27.so ./patchelf

然後再用 ldd 和 file 命令檢視程式,可以看到 libc 和 ld 都修改成功了。

$ ldd ./patchelf
    linux-vdso.so.1 (0x00007fff785a0000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb408672000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb4084ef000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb4084d5000)
    /opt/libs/2.27-3ubuntu1_amd64/libc-2.27.so (0x00007fb4080e4000)
    /opt/libs/2.27-3ubuntu1_amd64/ld-2.27.so => /lib64/ld-linux-x86-64.so.2 (0x00007fb408a67000)

$ file ./patchelf
./patchelf: ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /opt/libs/2.27-3ubuntu1_amd64/ld-2.27.so, for GNU/Linux 3.2.0, BuildID[sha1]=cfa182b059312c4c03e401efc8efe47a373d348c, with debug_info, not stripped

注:本文大部分內容參考看雪富強民主和諧帖子,原連結