编辑 .so 文件

逆向工程 拆卸 小精灵 二进制编辑
2021-06-20 02:15:41

我这里有一个包含语言包的 .so 文件,我想编辑它们。我的问题是我并不总是有足够的空间来进行干净的翻译。我知道我可以更改文本,如果它们保持相同的长度或变短(用 NULL 填充其余部分)。是否可以创造更多空间?占位符并调整文件大小并跳转到二进制文件的末尾?或者可能是对 .txt 文件的引用?

2个回答

对的,这是可能的。虽然您可以通过多种方式解决您的问题,但我会为您提供我认为最简单的一种。您可以使用的工具是objcopy它允许您更改 ELF 文件的内容,我将向您展示如何使用它来实现您的目标的分步示例。在下面提供的示例中,我在 64 位 Linux 机器上工作。

考虑以下 C 程序:

#include <stdio.h>
#include <stdlib.h>

#define NUM_OF_LANGUAGES 5
#define MAX_STR_LENGTH 21

const char LANGUAGES_TABLE[NUM_OF_LANGUAGES][MAX_STR_LENGTH] = {
    "stringInEnglish",
    "stringInPolish",
    "stringInSpanish",
    "stringInItalian",
    "stringInFrench"
};

char* someOtherData = "some other data";
char* lastString = "last string in file";

int main(int argc, char** argv)
{
    int langID = atoi(argv[1]);
    printf("%s\n", LANGUAGES_TABLE[langID]);
    return 0;
}

让我们暂时假设我们没有它的源代码(因为我想让它尽可能简单,这里没有错误检查)。如您所见,它在开始时接受参数(语言索引)并以给定语言打印字符串。但是我们想添加一个额外的字符串,比如说stringInYourFavouriteLanguage让我们的程序也能够打印它。

我们的第一步将是找到包含不同语言的所有字符串的 ELF 部分。为此,您可以使用objdump - 只需查看部分名称,即可在其中看到这些字符串。就我而言,.rodata如下所示: 在此处输入图片说明 请注意,我们在这里遇到了额外的问题 - 每个字符串LANGUAGES_TABLE只占用 21 个字节,而stringInYourFavouriteLanguage使用 30个字节。我稍后会返回。

现在,我们想要准备一个文件,比如说langData,包含我们想要在新.rodata部分中拥有的数据我建议你只复制现有的,然后用不同的语言附加字符串的修补版本——这样你就可以避免更改.rodata代码访问中的所有偏移量您只需要更改与语言相关的这些。

在我们的示例中,我们还需要将 的第二维更改LANGUAGES_TABLE为 30,因此我们将在此数组中的每个字符串的末尾添加 9 个 NULL 字节。然后我们将stringInYourFavouriteLanguage+NULL附加到文件的末尾。附加到文件从包含整个数据之前.rodata,我们的文件是这样的: 在此处输入图片说明 现在,我们可以拼接这些文件,并得到一个文件-langData包含要添加到新的数据.rodata然后我们像这样使用objcopy:

objcopy --update-section .rodata=langData langPack langPackPatched

langPack我们要修改的ELF文件在哪里langPackPatched是输出文件。您现在可以使用 objdump 检查此文件并查看确实进行了更改。

所以现在,我们有了.rodata想要的内容。现在我们想让我们的可执行文件也能够打印stringInYourFavouriteLanguage

为了实现这一点,我们需要在我们的程序中实际更改一些代码 - 首先,我们必须更改偏移量,以便每次内存访问都LANGUAGES_TABLE将使用我们附加的数据,其次,我们需要更改缩放比例,以便而不是打印PATCHED_LANGUAGES_TABLE[21*arg],我们的程序将打印PATCHED_LANGUAGES_TABLE[30*arg]. 这是整个过程中最棘手的部分。

首先,您需要找到要修补的代码段。在我们的例子中是: 在此处输入图片说明 注意从offset开始的21个字节0x6e8实际上负责将arg乘以21并将其加载LANGUAGES_TABLE到RDX的地址在这里,lea使用 RIP 计算此偏移量。我们需要做的是确定我们想要添加到 RIP 中的偏移量来实现LANGUAGES_TABLE_PATCHED

在这里,请记住一件重要的事情——我们必须根据修补 文件中这lea条指令的地址来确定这个偏移量

所以,要么我们把它留在原地,只改变偏移量(即操作码的最后 4 个字节),以便它指向我们的补丁表,要么我们只写我们的代码,然后添加相关数量的nops(然后我们可以写leaaslea [rip]然后简单地用调试器检查所需的偏移量并将其更改为lea [rip+offset]) - 这就是我所做的。尽管如此,我们修补后的代码可能如下所示: 在此处输入图片说明

它负责计算 的地址LANGUAGES_TABLE_PATCHED[30*arg]

就是这样了!我们现在可以测试它;如果我们运行./langPackPatched 5,我们得到:

stringInYourFavouriteLanguage,

根据需要,而其他参数的程序行为保持不变。

注意:我的原始答案是在没有访问您要修改的文件的情况下制定的,因此根据您上传的文件,这里有另一个答案。

如果您想修改程序中的数据,则必须掌握如何(以及在​​哪里)访问它。在您的情况下,涉及三个部分:

  • .data
  • .data.rel.ro
  • .rodata

.data

文件中的所有字符串都通过该.data部分引用,该部分包含一个数组,该数组带有指向 in 条目的指针.data.rel.ro,其中.rodata存储了指向 in中的字符串的实际指针在分析之后radare2.data看起来像: 节数据

因此,它只是包含每个字符串项的指针索引对数组这是前面提到的三个部分中唯一不需要更改的部分。

.rodata

它包含文件中使用的所有字符串,包括英文和中文版本。 截面数据

这是我建议首先更改的部分 - 将所有中文字符串替换为德语字符串。您可以按照我之前的回答中描述的方式进行操作,即用之前创建的文件的内容替换整个部分。

.data.rel.ro

这是您要修改的最后一部分。它包含指向.rodata在您修改之前位于该部分中的字符串的指针节数据RelRo

因此,现在您需要修复此处包含的所有指针以指向.rodata您刚刚创建的新部分中的字符串请注意,这里的每个条目只是一个指针(即包含4字节,因此它具有固定长度),因此您可以立即修补它,而无需使用objcopy.

完成这些步骤后,您应该已翻译所有字符串。