![是否可以修改已经运行的可执行文件?](https://linux22.com/image/185668/%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E4%BF%AE%E6%94%B9%E5%B7%B2%E7%BB%8F%E8%BF%90%E8%A1%8C%E7%9A%84%E5%8F%AF%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6%EF%BC%9F.png)
我有一个在嵌入式系统中运行的Linux系统。由于各种原因我无法进入(否则我会被解雇),我无法通过键盘或 SSH 等正常方式直接访问该系统。我知道,我知道,更改正在执行的文件是邪恶的,但请相信,如果我有替代方案,我会接受它。
在这个围绕 ARM CPU 构建的系统上,有一个纯 ARM 机器代码(从 C++ 编译)的可执行文件。在此代码中发现了一个错误。我发现可以通过用 UXTH 指令替换 UXTB 指令来修复该错误。对我来说幸运的是,这需要将操作码字节从 0xEF 更改为 0xFF。只需运行以下命令即可执行此补丁:
printf '\xff' | dd of=path/to/executable bs=1 seek=$((0x01ce22)) conv=notrunc
被修改的字节是函数的一部分,仅当该嵌入式系统接收到特定命令时才会调用该函数。我绝对可以保证在执行此补丁时不会发送此命令。因此,RAM 和存储中不存在涉及不同版本代码的危险。
不幸的是,需要更改的程序(再次在系统启动时启动)也是我所依赖的程序,它允许我对该系统进行很少的访问。所以我不能终止该进程,以免失去访问权限。
我是否有可能修改可执行文件的这个字节,这个没有直接使用的小字节?
也许最好的解决方案是使用 shell 脚本来终止主进程,更改字节,然后激活重新启动?理想情况下,我希望系统保持活动状态,以便我可以看到更改成功。
我有一个在相同系统上运行的测试用例脚本,我可以直接通过 SSH 访问该系统。测试脚本是一个 C++ 脚本,它仅以 0.1 秒的增量向文件输出一个值 1000 次。我将其反汇编并找到了保存该常量值的字节,与上面的 printf | 类似。 dd 命令,我可以修改该常量 - 但仅限于程序未运行时。对我来说,一个理想的解决方案是我可以动态修改该常量,以便输出文件保存 500 左右的 C++ 原始值,以及 500 左右的我已打入正确字节的值。
感谢您提供的任何帮助或建议。
答案1
Linux 和大多数其他 Unix 操作系统不允许您实际修改正在执行的二进制文件。如果您尝试打开此类文件进行写入,您将收到ETXTBSY
错误(文本文件忙)。这是因为二进制文件可能是内存映射的,并且修改文件会修改二进制文件,几乎肯定会以不期望的方式修改。内核也可能无法妥善处理这种情况。
但是,您可以将文件复制到一侧,在那里修改它,然后调用rename(2)
(或使用它的东西,例如mv(1)
)以将新二进制文件重命名为旧二进制文件。这是有效的,因为旧的二进制文件仍然在磁盘上,但无法通过任何名称的文件系统访问,并且一直保持到最后一个用户关闭它为止。如果您重新执行二进制文件,它将获取新版本。