加入可执行文件及其所有库

加入可执行文件及其所有库

假设我有一个/bin/cat使用以下共享库的可执行文件:

linux-vdso.so.1
libc.so.6
/lib64/ld-linux-x86-64.so.2

是否有可能以某种方式将这些东西“加入”在一起(可执行存档或类似的东西)?

我没有想要执行此操作的程序的代码,因此我不能仅使用 -static 标志来编译它。

答案1

您可以将其所有库从系统位置复制到可执行文件所在的子目录中并使用帕切尔夫,使可执行文件在那里查找其 libdependency,而不是系统 lib 目录。

例如:

相对化库:

#!/bin/bash -e
[ -n "$1" ] || set -- a.out
mkdir -p ./lib/ #<copy the libraries here
#use ldd to resolve the libs and use `patchelf --print-needed to filter out
# "magic" libs kernel-interfacing libs such as linux-vdso.so, ld-linux-x86-65.so or libpthread
# which you probably should not relativize anyway
join \
    <(ldd "$1" |awk '{if(substr($3,0,1)=="/") print $1,$3}' |sort) \
    <(patchelf --print-needed "$1" |sort) |cut -d\  -f2 |

#copy the lib selection to ./lib
xargs -d '\n' -I{} cp --copy-contents {} ./lib 
#make the relative lib paths override the system lib path
patchelf --set-rpath "\$ORIGIN/lib" "$1"

(我相信与LD_LIBRARY_PATH黑客攻击不同,这也应该适用于 setuid 可执行文件)。

之后,您所要做的就是将该./lib目录与可执行文件一起移动。

答案2

取决于你所说的“加入”是什么意思。最好的方法是将原始源代码重新编译为静态二进制文件。

但是,您可以将所有库包含在由应用程序控制的子目录中(/usr/share/myapp例如),然后将该目录放入库搜索顺序中。一种方法是(在 Linux 中)使用LD_LIBRARY_PATH

LD_LIBRARY_PATH=/usr/share/myapp/lib:/usr/local/lib:/usr/lib/i686-linux-gnu:/lib/i686-linux-gnu

在 Linux 中,您可以修改该/etc/ld.so.conf文件来执行相同的操作 - Ubuntu也会将*.conf文件添加到目录中/etc/ld.so.conf.d

答案3

将一堆共享对象和共享库 ELF 可执行文件转换为一个静态链接的 blob 并不简单。

可执行档案你提到的也许是可能的。假设“可执行存档”是指一个文件,该文件在运行时会自行解压并运行一个程序,而不依赖于系统上的其他文件。

这可以非常简单地使用 shell 脚本和大多数 Linux 发行版中的实用程序来完成(但是它增加了对 shell 和实用程序的依赖)。尽管原理是相同的,但制作 ELF“可执行存档”可能会涉及更多内容。如果您希望频繁执行您的程序版本,则应修改脚本以将其“安装”到用户系统上,如下所示大卫詹内布

使用基于 shell 脚本的可执行存档的示例

收集执行所需的文件,使用cat程序的示例将具有以下内容:

fachas_cat_files/cat
fachas_cat_files/lib/libc.so.6

对 tgz 文件进行 Base64 编码并制作cat.b64,可以在设置fachas_cat_files目录后这样做。

tar -cz fachas_cat_files | base64 > cat.b64

这会用可打印字符表示 tar 文件,以便将其包含在脚本中。

记下您正在打包的文件的 md5sum,您可以在 shell 脚本中使用它来验证解压的文件是否是您自己的。

find fachas_cat_files/ -type f -exec md5sum {} \; > cat.md5

创建如下所示的 shell 脚本,并将其命名为新的“归档”程序。

#!/bin/bash

TEMP_DIR=/tmp

# Check Md5sum
md5sum -c --quiet >/dev/null 2>&1 <<EOF 
--- Paste contents of cat.md5 here. ---
EOF

# Untar from base64 encoded tarball.
test $? -eq 0 || base64 -d <<EOF | tar -xz -C ${TEMP_DIR}
--- Paste contents of cat.b64 here. ---
EOF

# Execute the binary.
LD_LIBRARY_PATH=${TEMP_DIR}/fachas_cat_files/lib/ ${TEMP_DIR}/fachas_cat_files/cat $*

# Optionally remove the temporary files, if you do, the whole md5sum set of steps is 
# not necessary.
# rm -fr ${TEMP_DIR}/fachas_cat_files

答案4

我想说,如果您愿意为可执行存档编写一个修改后的类似“ld-linux”的引导加载程序,那么这应该是可能的。如果您检查 /proc/xxx/maps 文件系统中正在运行的动态可执行文件,您可以看到正在运行的动态可执行文件只不过是映射到进程内存空间中的一堆文件。这些映射文件可以是可执行存档的区域,而不是单独的文件,并且仍然具有对进程可见的完全相同的数据。您必须使可执行存档中的区域与 PAGE_SIZE 对齐。除了在 ld-linux 中查找和映射文件(可执行文件和库)之外,大多数其他功能都可以保持不变。

当您的可执行文件使用 dlopen 等 API 时,会出现复杂情况。如果您还需要将它们包含在可执行存档中,那么您还必须修改 libdl.so 并将其包含在存档中,而不是系统 libdl.so 中。

可执行存档需要是“bootstrap ld-linux replacement”(静态二进制文件)的 PAGE_SIZE 连接,包含的文件及其偏移量的列表,以便引导程序可以找到它们和文件本身。

我认为如果有人愿意接受的话,这将是一个有用的项目。比 docker 容器重量轻得多。

相关内容