跳转至

PatchELF

PatchELF用于修改ELF文件依赖的动态链接器和库路径,在Pwn中被用来解决动态链接库路径不匹配的问题。PatchELF最初是为了解决NixOS上的动态链接问题而开发的,是NixOS打包工具集的一部分。听起来好神奇,一个Pwn工具竟然来源于NixOS。

NixOS采用的Nix包管理器使用纯函数式编程范式来描述软件包和系统配置,确保了软件包的可重现性和隔离性。因此,NixOS上的可执行文件都被放在/nix/store目录下,这导致传统的动态链接二进制文件无法在NixOS上运行,因为它们期望库文件位于标准位置(如/lib/usr/lib)。为了解决这个问题,PatchELF被开发出来,用于修改ELF文件的动态链接器和库路径,使其能够在NixOS上运行。

PatchELF在2023年之后就没有发布过新版本。Arch Linux用户可以通过安装patchelf-gitAUR包来获取最新的PatchELF,带有zsh补全等功能。

基本用法

patchelf --set-interpreter <new-interpreter> <binary> # 设置新的动态链接器路径
patchelf --set-rpath <new-rpath> <binary> # 设置新的运行时库搜索路径
patchelf --remove-rpath <binary> # 移除运行时库搜索路径
patchelf --print-interpreter <binary> # 打印当前的动态链接器路径
patchelf --print-rpath <binary> # 打印当前的运行时库搜索路径

应用实例

假设我们有一个ELF二进制文件pwn,我们想要修改它的动态链接器和运行时库搜索路径。先使用ldd命令查看当前的设置:

ldd pwn

输出可能如下所示:

    linux-vdso.so.1 (0x00007f65a9c43000)
    libc.so.6 => /usr/lib/libc.so.6 (0x00007f65a9800000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f65a9c45000)

题目一般会给出libc.so供参考。为了找到合适的GLIBC版本,我们可以用strings命令查看文件中的字符串来找出GLIBC版本:

strings -t x libc.so.6 | grep 'GNU'

输出可能如下所示:

 1dc680 GNU C Library (Ubuntu GLIBC 2.35-0ubuntu3.11) stable release version 2.35.
 1dc793 Compiled by GNU CC version 11.4.0.

由输出可知,该GLIBC版本为2.35-0ubuntu3.11。接下来,通过glibc-all-in-oneGitHub获取合适版本的GLIBC,并使用PatchELF修改动态链接器和运行时库搜索路径。先创建副本,再进行修改:

cp pwn pwn_patched
patchelf --set-interpreter ~/glibc-all-in-one/libs/2.35-0ubuntu3.11_amd64/ld-linux-x86-64.so.2 pwn_patched
patchelf --set-rpath ~/glibc-all-in-one/libs/2.35-0ubuntu3.11_amd64 pwn_patched

最后,再次使用ldd命令验证修改是否成功:

ldd pwn_patched

输出可能如下所示:

    linux-vdso.so.1 (0x00007f7ac6d23000)
    libc.so.6 => /home/khyan/glibc-all-in-one/libs/2.35-0ubuntu3.11_amd64/libc.so.6 (0x00007f7ac6a00000)
    /home/khyan/glibc-all-in-one/libs/2.35-0ubuntu3.11_amd64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f7ac6d25000)

这样,我们就成功地使用PatchELF修改了ELF二进制文件的动态链接器和运行时库搜索路径,使其能够在当前系统上正确运行。接下来,便可以使用./pwn_patched来运行修改后的二进制文件了。