linker的奥秘

逆向做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呢?

  1. 下载glibc源码,在 GNU C Library 下载对应版本最纯正的源码。由于glibc版本众多,因此应找到对应可执行二进制文件的glibc版本。新的glibc可能会添加一些新的功能,如果在二进制文件中用到了这些功能,则需要下载较新的版本。本次实验下载的是2.25版本。
  2. 编译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环境中并不这么简单
  3. 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中。
  4. patch完成后就可以按照第2点中最后一条的方式,运行动过手脚的linker和目标二进制了。
  5. 按照 某些解释 ,往/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的操作系统。

玩底层真是顶有意思的一件事!

Comments
Write a Comment