逆向做linker的注入,非常有意思。
linker是在程序运行的时候,在OS层面上链接程序所需动态库的程序,C程序通常由GLIBC在/usr/lib
或/lib
下的ld.so
担当。一个通常的,基于Linux x64架构的程序,file abc
的信息会是
abc: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=0b7e41efb88e9213eb3244793a7928bafdd20654, stripped
其中interpreter /lib64/ld-linux-x86-64.so.2
指明了将要使用的linker路径。
由于linker是在程序运行最开始时优先运行,因此,通过在linker中做手脚,可以获得程序运行时才能抓取到的信息。
如何从头到尾伪造一个linker呢?
- 下载glibc源码,在GNU C Library下载对应版本最纯正的源码。由于glibc版本众多,因此应找到对应可执行二进制文件的glibc版本。新的glibc可能会添加一些新的功能,如果在二进制文件中用到了这些功能,则需要下载较新的版本。本次实验下载的是2.25版本。
-
编译glibc。其中有些坑,包括:
- 解压glibc-2.25.tar.gz后,在
glibc-2.25/
的目录中需要手工新建文件夹,比如glibc-build
,然后进入glibc-build
,运行../configure --prefix=~/eshard-re/3-ARE/glibc-225-compiled
,以告知configure程序,未来的glibc安装目录路径,并按当前系统环境配置make选项。 - 接着在
glibc-2.25/glibc-build
路径下运行make all
,第一次编译大约需要十分钟。 - 编译完成后,在
glibc-2.25/glibc-build
路径下运行make install
,将编译好的文件“安装”到prefix指定的路径下。 - 理论上来说,诸如在
abc
路径下运行./glibc-225-compiled/lib/ld-2.25.so ./abc
,或ld-2.25.so
路径下运行./ld-2.25.so ../../abc
,就可以感受新linker中做的手脚了。 - 然而至少在Ubuntu 16.04环境中并不这么简单
- 解压glibc-2.25.tar.gz后,在
- patch目标二进制。由于目标二进制很可能使用了不只glibc中生成的libc动态库,而编译生成的
glibc-225-compile/
下的linker并不知道其他动态库的位置,因此还需要对目标文件abc
进行patch。sudo apt install patchelf
安装patch工具- 将abc复制一份,重命名为abcnew
patchelf --set-interpreter ~/eshard-re/3-ARE/glibc-225-compiled/lib/ld-linux-x86-64.so.2 --set-rpath ~/eshard-re/3-ARE/glibc-225-compiled/lib:/usr/lib/x86_64-linux-gnu/:/lib/x86_64-linux-gnu/ abcnew
运行patchelf,对目标文件进行修改。其中--set-interpreter
设定linker的位置,--set-rpath
设定所有需要用到的动态库路径,以英文冒号分隔。- 需要注意的是,刚开始可能并不知道所有需要的库有哪些,只能通过一次次试错,然后用
locate xxx.so
的方式定位所需动态库路径的方式,慢慢加到rpath中。
- patch完成后就可以按照第2点中最后一条的方式,运行动过手脚的linker和目标二进制了。
-
按照某些解释,往
/etc/ld.so.conf.d/
下添加*.conf配置文件,并使用ldconfig
重载linker配置也是可以完成类似的功能。但是对于目前的练习来说,有几个问题:
(1) 本例中重新编译的是glibc,如果放到conf中,会影响系统目前所有使用glibc的程序,包括命令行指令sudo, ls, mv等
(2) 非常不凑巧的是,Ubuntu 16.04默认glibc版本是2.23,当用2.25的glibc通过conf覆盖后,所有的命令行指令,包括sudo, ls, mv, rm等都出现了异常,并且无法执行。这时候如果想改回原样,既无法修改/删除原有conf(因为sudo不能用),也无法修改新linker的路径(rm, mv不能用,否则可以让指向失效),试到最后,发现GUI操作不受终端命令影响,轻点鼠标右键-重命名,把文件夹重命名,甚至直接用gedit修改conf文件即可。最后少不了ldconfig
,一切恢复如初。
(3) 总结:平常不要装13,应该用GUI的操作系统。
玩底层真是顶有意思的一件事!