修改已编译的 ELF 可执行文件中的静态字节数组

3

我有一个情景,想要为我的用户提供一种实用程序来创建压缩自解压可执行文件(类似于UPX但具有其他属性)。

目前的方法是通过压缩可执行文件,然后生成包含一个字节数组的c源代码来完成的:

#include "exdata.c"

exdata.c:

const unsigned char compressedData[] = { 0x28,0xB5... }
const size_t uncompressedSize =  3697664;

问题在于我想能够更改这个字节数组,而不需要重新编译程序,以使我的用户可以使用该实用程序,而无需安装C编译器。
我可以使用“占位符”字节数组,在编译后的二进制文件中找到该值并将其替换为实际数据吗?或者我可以将数据添加到自定义“段”中,然后只修改那个部分?
编辑:我发现了一个名为lief的Python库,似乎可以修改段落内容,但是修改比已有数据更多的段落似乎非常复杂,因为所有其他段落和地址+偏移量都需要处理。

1
看起来你需要能够指示你正在使用的压缩方法排除字节数组的过程。然后你可以进行修补。在压缩流中进行修补并获得可预测的结果似乎不可行。 - 500 - Internal Server Error
2
我不认为你可以这样做,但你可能可以添加一个自定义段或其他内容。@500-InternalServerError 我理解数组的内容是压缩的,而不是将数组插入的可执行文件。 - user253751
1
@user253751 您是正确的,“wrapper”可执行文件没有被压缩。 - Richard
2
@CraigEstey 那是一种选择,但理想情况下希望避免使用 Docker 以便提高方便性和编译时间。 - Richard
1
@Nierusek 64位,但同时支持ARM64和x86-64。 - Richard
显示剩余4条评论
3个回答

2

我认为gcc和objcopy可以解决你很多问题:

  • 使用gcc的__attribute__扩展将默认压缩图像放在自己的部分中

  • 制作一个包含用户压缩图像的文件。

  • 用户脚本运行objcopy以用用户的文件替换您的部分

$ more replaceable_contents.c 
#include <stdio.h>

struct {
    unsigned char sz;
    const char data[];
} datablob __attribute__((section("COMPRESSEDDATA"))) = {12, "Hello World!"};

int global_counter = 0;


int main(int argc, const char* argv[]) {

    for (int i;i<argc;i++) {
        printf("printing %d characters: ", datablob.sz);
        printf("%.*s\n", datablob.sz, datablob.data);
    }
}

$ gcc replaceable_contents.c && ./a.out 2
printing 12 characters: Hello World!
printing 12 characters: Hello World!

$ more text.txt
2This is a test of the emergency compression system

$ objcopy --update-section COMPRESSEDDATA=text.txt a.out a2.out
objcopy: a2.out: section .bss lma 0x201020 adjusted to 0x201044

$ ./a2.out 2
printing 50 characters: This is a test of the emergency compression system
printing 50 characters: This is a test of the emergency compression system

1
@CraigEstey 这是一个替代方案,但理想情况下希望避免使用Docker以便于编译时间 - Richard。
好的,所以不使用容器。但是,许多商业安装程序使用sh脚本作为初始提取程序。
这是我自己使用的格式:
#!/usr/bin/bash -
# ovcbin/ovcext.sh -- shell based extractor
#
# this is a self extracting archive
#
# INSTALL:
# (1) save this block to a file (e.g.) /tmp/archive
# (2) create a directory (e.g.) /tmp/extract
# (3) cd to /tmp/extract
# (4) For a dry run, if you wish to see what the archive contains, type:
#       bash /tmp/archive
# (5) To actually extract the archive, type:
#       bash /tmp/archive -go
# (6) This will create the following subdirs under /tmp/extract:
#       hello_package

function ovcopt()
{
    local opt
    local match
    local tmp="/tmp/ovcopt.$$"

    cp /dev/null $tmp

    for opt in $*
    do
        match=$(_ovcopt $opt)
        ovcdbg "ovcopt: TRY match=$match opt=$opt"
    done

    source $tmp

    rm -f $tmp
}

function _ovcopt
{
    local opt=$1
    local sym
    local match=0

    case $opt in
        -*)
            sym=$(echo $opt | sed -e s/-/opt_/ -e '/=/!s/$/=1/')
            ovcdbg "ovcopt: EVAL opt='$opt' sym='$sym'"
            echo "$sym" >> $tmp
            match=1
        ;;
    esac

    echo "$match"
}

function ovcext()
{
    local file=$1
    local opt_chmod
    local opt_b64
    local opt_z
    local dir
    local found=0
    local go=0

    ovcopt $*

    ovcdbg "ovcext: DEBUG_CAE opt_go='$opt_go'"

    if [ -n "$opt_go" ]; then
        go=1
    else
        exit 99
    fi

    while [ 1 ]
    do
        if [ -e "$file" ]; then
            found=1

            if [ -n "$opt_f" ] ; then
                echo "file already exists -- $file (overwriting!)"
                break
            fi

            echo "file already exists -- $file (rerun with -f to force)"
            go=0
            file=/dev/null
            break
        fi

        if [ $go -gt 0 ]; then
            echo "extracting file $file ..."
            dir=$(dirname $file)
            mkdir -p $dir
            break
        fi

        echo "extracting $file (DRY RUN)"
        file=/dev/null
        break
    done

    if [ -n "$zipflg_spl" ]; then
        base64 -d | $zipflg_cmd -d > $file
    else
        cat > $file
    fi

    if [ $go -ne 0 ]; then
        if [ -n "$opt_chmod" ]; then
            chmod $opt_chmod $file
        fi
    fi
}

function ovcdbg()
{

    if [ -n "$ZPXHOWOVC" ]; then
        echo "$*" 1>&2
    fi
}

ovcopt $*
zipflg_spl=1; zipflg_cmd="gzip";

ovcext hello_package/hello.c -b64 -zgzip << '%%%EOF%%%'
H4sICO3/Y2QCA292Y2V4dF96aXBfMQBTzsxLzilNSVWwKS5JyczXy7Dj4srMK+HKTczM0yjLz0zR
5Krm4uIsKAIKpmkoZaTm5OQrlOcX5aTE5ClpWgOlilJLSovyFAysuWq5AKqxSQ1OAAAA
%%%EOF%%%

ovcext hello_package/hello -b64 -zgzip -chmod=755 << '%%%EOF%%%'
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
FK5vv+zfyzPiKLlQAAA=
%%%EOF%%%

1

这是一个简单愚蠢的方法。

  1. 让可执行文件知道它的长度。简单的方法是使用 const 并构建、测量、再次构建。但自动化会很麻烦。

  2. 将压缩流连接到可执行文件中。

  3. 在可执行文件源代码中,打开 /proc/self/exe,定位到指定的字节并开始读取。

我已经按照这些步骤完成了,并提供了一个小工具来执行第二步。我称这个工具为第四步。


听起来很有趣。这会导致额外的文件读取吗(虚拟机中的磁盘非常慢)? - Richard
1
@Richard:不,分页的成本也类似。 - Joshua
我使用这种方法启动时间大约是之前的两倍,所以不可行。 - Richard
@Richard:是的,你可能会这样认为。将exe文件编写到/tmp并运行它将非常糟糕,除非你像我一样使用它来导入类似于100mb的东西,并且每次调用都要使用其中的大部分内容。 - Joshua

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接