编译glibc,以期源码调试
一、编译安装
我在这里下载了libc的源代码:wget http://ftp.gnu.org/gnu/glibc/glibc-2.31.tar.gz
(可以下载不同的版本,比如,把glibc-2.31换为glibc-2.27即可)
然后我们解压它,拿到源代码: tar -zxvf glibc-2.31.tar.gz
创建目录等:
cd glibc-2.31
mkdir build && cd build
接着就是编译安装:
CFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error" \
CXXFLAGS="-g -g3 -ggdb -gdwarf-4 -Og -Wno-error"
sudo ../configure --prefix=/home/zq/Desktop/glibc-2.31/64 --disable-werror
sudo make
sudo make install
二、报错和解决方案
在编译的过程中遇到了如下问题:
(1)使用ubuntu 16 ,编译libc-2.23和libc-2.27没有问题,但是在libc-2.31的时候报错:
*** These critical programs are missing or too old: compiler
应该是gcc的版本太低,升级的命令是这样的:
sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-9 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 100 sudo update-alternatives --config gcc
(2)*** These critical programs are missing or too old: gawk
解决办法是:sudo apt-get install gawk
(3)
/tmp/ccD0p2ka.s: Assembler messages:
/tmp/ccD0p2ka.s: Error: `loc1@GLIBC_2.2.5' can't be versioned to common symbol 'loc1'
/tmp/ccD0p2ka.s: Error: `loc2@GLIBC_2.2.5' can't be versioned to common symbol 'loc2'
/tmp/ccD0p2ka.s: Error: `locs@GLIBC_2.2.5' can't be versioned to common symbol 'locs'
解决办法:把misc目录下的regexp.c做些修改
@@ -29,14 +29,18 @@ #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_23) -/* Define the variables used for the interface. */ -char *loc1; -char *loc2; +#include <stdlib.h> /* Get NULL. */ + +/* Define the variables used for the interface. Avoid .symver on common + symbol, which just creates a new common symbol, not an alias. */ +char *loc1 = NULL; +char *loc2 = NULL; + compat_symbol (libc, loc1, loc1, GLIBC_2_0); compat_symbol (libc, loc2, loc2, GLIBC_2_0); /* Although we do not support the use we define this variable as well. */ -char *locs; +char *locs = NULL; compat_symbol (libc, locs, locs, GLIBC_2_0);
把如上代码保存为reg.patch文件
然后修改regexp.c文件:patch ./glibc-2.23/misc/regexp.c < ./reg.patch
(4)我在ubuntu 20 总不能编译成 glibc-2.23,于是我在ubuntu 16 编译了glibc-2.23,打包拷贝到ubuntu 20 然后解压
三、测试
现在我们不使用默认的libc,而是用刚刚安装的libc来编译一个程序,看看有没有安装成功:
写一个简单的程序:
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main(){ puts("hello world!"); char * s1=malloc(0x20); read(0,s1,0x10); return 0; }
我们使用指定的libc来编译:
gcc -g -L /home/zq/Desktop/glibc-2.31/64/lib -Wl,--rpath=/home/zq/Desktop/glibc-2.31/64/libs -Wl,-I /home/zq/Desktop/glibc-2.31/64/lib/ld-2.31.so hello.c -o hello
我们现在去调试,程序里有malloc这个函数,我们就看一下它的源代码:
gdb hello
b malloc
r
但是我们做pwn题的时候,一般没有源代码,只是一个elf文件
当靶机libc版本和我们本地机器上libc版本不同的时候,就需要加载指定的libc,比如2.27 、2.31等
还是刚才那个程序,默认libc去编译它:gcc hello.c -o hello1
我们用ida看一下它是怎样寻找libc的,这里出现了ld-linux-x86-64.so.2的路径,估计会通过它,找到待加载的libc.so
我们试着把这个路径换为,我们期望加载的libc对应的ld-linux.so.2所在的目录,本来是想把它换为绝对路径(/home/zq/Desktop/glibc-2.31/64/lib/ld-linux-x86-64.so.2),但是好像行不通,于是缩减字符个数,换为相对路径
我们把elf文件挪到 /home/zq/Desktop/glibc-2.31/64 ,然后相对路径就是 ./lib/d-linux-x86-64.so.2 。
用ida去patch:
如果patch之后,运行报错: No such file or directory
可以使用这个工具来patch:https://github.com/NixOS/patchelf
在hello1文件所在目录(即/home/zq/Desktop/glibc-2.31/64)写个脚本,看能不能正常调试:
from pwn import * sh=gdb.debug("./hello1") sh.interactive()
我们在read函数下断点,看下read的源代码:
再看一下堆块的情况:
程序加载了libc-2.31.so