暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

查看/修改ELF的动态链接器

青衣十三楼飞花堂 2019-07-04
2047

不想看全文的,就一句话,用patchelf查看、修改ELF的动态链接器。

关于动态链接器,Linux用户可以看ld.so(8)。

动态链接版ELF从内核态获得执行时控制权首先交给ELF的动态链接器,而不是e_entry,更不是main()。

除非在编译链接时给ld(1)指定了-static选项,否则Linux程序必需动态链接器。

有两种动态链接器,ld.so用于处理a.out格式(很古老的一种格式),ld-linux.so*用于处理ELF格式。

Debian的ld-linux.so*是可以单独执行的,但FreeBSD 6.1的/libexec/ld-elf.so.1就不行。可以单独执行的动态链接器在某些特定场景有意义,比如:

《动态链接器符号链接被破坏后的灾难恢复》
http://scz.617.cn:8/unix/201809191202.txt

本文对ELF的动态链接器本身不多解释,假设读者对ELF是了解的。说一个真实案例。

受组织之托逆向分析一个设备,千辛万苦之后确认这个设备是基于x86/FreeBSD 6.1改的。

TK推荐过:

https://www.osboxes.org/freebsd/

这里有现成的FreeBSD 10.3/12.0的VMware映像。没有6.1,只好在VMware中自己装x86/FreeBSD 6.1,这样可以自己编译某些静态版本的工具,比如xxd、lrzsz、gdb等等。

有一天想弄个lsof到目标设备上。多说一句,如果只是想知道端口与进程的映射关系,或许有替代方案,参看:

《x64/FreeBSD 10.3/12.0中lsof的替代方案》
http://scz.617.cn:8/unix/201906131429.txt

在FreeBSD 6.1中用ports自编译lsof,TK帮我找到了精确匹配版本:

http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/ports/distfiles/lsof_4.77D.freebsd.tar.bz2

这个链接居然没有被Google爬到,简直了。

在目标设备上执行时报错:

$ /tmp/lsof -lnPR -i4
ELF interpreter /libexec/ld-elf.so.1 not found
Abort

从错误提示看出,lsof所用动态链接器是:

/libexec/ld-elf.so.1

在目标设备上找了一圏,只有:

$ ls -l /libexec/ld-elf32.so.1
/libexec/ld-elf32.so.1 -> /usr/libexec/ld-elf.so.1

受制于只读文件系统,无法通过创建符号链接解决:

$ ln -s /libexec/ld-elf32.so.1 /libexec/ld-elf.so.1
ln: /libexec/ld-elf.so.1: Read-only file system

至此,产生了两个需求:

a) 查看指定ELF的动态链接器
b) 修改指定ELF的动态链接器

FreeBSD 6.1的ELF工具不够强大,在Debian中检查自编译得到的lsof:

$ readelf -p .interp lsof
$ readelf -x .interp lsof
$ readelf -x1 lsof
$ objdump -j .interp -hs lsof
$ readelf -Wl lsof
$ patchelf --print-interpreter lsof

$ file -b lsof
ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, stripped

前面这些命令都可以查看指定ELF的动态链接器。Debian上"file -b <ELF>"是最简查看动态链接器的办法,有些系统的file命令不会显示动态链接器,比如FreeBSD 6.1
的:

$ file -b lsof
ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), stripped

FreeBSD 10.3/12.0的file命令会显示动态链接器,FreeBSD 6.1实在太老了。

此外,Linux的"ldd <ELF>"输出中包含动态链接器,但FreeBSD的如下命令输出中并不包含动态链接器:

$ ldd <ELF>
$ LD_TRACE_LOADED_OBJECTS=1 <ELF>

在Debian上检查目标设备中的id命令,确认其动态链接器是:

/usr/libexec/ld-elf.so.1

我们需要将自编译得到的lsof的动态链接器改成上面这个。

有两种办法,一种是用patchelf直接修改ELF,另一种是在编译链接阶段指定动态链接器。

$ cp lsof lsof-test
$ patchelf --set-interpreter "/usr/libexec/ld-elf.so.1" lsof-test



$ cd /usr/ports/sysutils/lsof
$ make CC=gcc

注意到最后一条命令是:


$ cd work/lsof_4.77D.freebsd/
$ gcc -Wl,-dynamic-linker,/usr/libexec/ld-elf.so.1 -o lsof-test ...

两种办法提到的lsof-test在目标设备上均可执行。由于FreeBSD 6.1上存在:

/usr/libexec/ld-elf.so.1

于是lsof-test既可以在目标设备上运行,也可以在FreeBSD 6.1虚拟机上运行。

一般来说,尽可能向目标设备上传静态链接版本ELF,可以避免很多麻烦,但我没有找到编译静态链接版本lsof的办法。

前面演示的patchelf还可以修改ELF的其他内容:

--set-interpreter INTERPRETER
--print-interpreter

--print-soname
--set-soname SONAME

--set-rpath RPATH
--remove-rpath
--shrink-rpath
--allowed-rpath-prefixes PREFIXES
--print-rpath
--force-rpath

--add-needed LIBRARY
--replace-needed LIB_ORIG LIB_NEW
--remove-needed LIBRARY

--no-default-lib

Debian中可以这样安装patchelf:

$ aptitude install patchelf

文章转载自青衣十三楼飞花堂,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论