21

将功能插入二进制应用程序(3d 方,封闭源代码)的最佳方式是什么。

目标应用程序在 OSX 上,似乎是使用 gcc 3+ 编译的。我可以看到在二进制文件中实现的函数列表,并且已经调试和隔离了一个我想远程调用的特定函数。

zoomByFactor(x,y)具体来说,当我从复杂的 HIDevice 接收到某些数据时,我想调用这个函数——我们称之为 void 。

我可以轻松地修改或将指令注入二进制文件本身(即修补不需要只在 RAM 中进行)。

你会推荐什么作为“很好”这样做的方式?

编辑:

我确实需要整个应用程序。所以我不能放弃它并使用图书馆。(对于那些需要道德解释的人:这是一个专有的 CAD 软件,其公司网站自 2006 年以来就没有更新过。我已经为这个产品付了钱(真的花了很多钱)并且有项目我无法轻易从中迁移的数据。该产品非常适合我,但我想使用我最近获得的新 HID。我已经检查了应用程序的内部结构,我相当有信心我可以使用相关数据调用正确的函数并使其正常工作)。

到目前为止,这是我所做的,而且非常贫民窟。

我已经通过这个过程修改了部分应用程序:

xxd -g 0 二进制 > binary.hex
cat 二进制.hex | awk '替代工作' > modified.hex
xxd -r modified.hex > newbinary
chmod 777 新二进制

我正在做这种跳跃,因为二进制文件几乎有 100 兆大。

我在想的主要是我会在主应用程序循环中的某个地方跳转,启动一个线程,然后返回到主函数。

现在,问题是:我可以在哪里插入新代码?我需要修改符号表吗?或者,我怎样才能使 dylib 自动加载,以便我需要做的唯一“黑客”操作就是将对正常加载的 dylib 的调用插入到主函数中?

4

6 回答 6

11

对于那些对我最终所做的事情感兴趣的人,这里有一个摘要:

我已经研究了几种可能性。它们分为运行时补丁和静态二进制文件补丁。

就文件修补而言,我基本上尝试了两种方法:

  1. 修改二进制代码段 (__TEXT) 中的程序集。

  2. 修改 mach 标头中的加载命令。

第一种方法需要有可用空间,或者您可以覆盖的方法。它还具有极差的可维护性。任何新的二进制文件都需要再次手动修补它们,特别是如果它们的源代码发生了轻微的变化。

第二种方法是尝试将 LC_LOAD_DYLIB 条目添加到 mach 标头中。那里没有很多 mach-o 编辑器,所以很麻烦,但我实际上修改了结构,以便我的条目可以通过otool -l. 然而,这实际上并没有工作,因为dyld: bad external relocation length在运行时有一个。我假设我需要处理导入表等。如果没有编辑器,这太费力了。

第二条路径是在运行时注入代码。没有太多可以做到这一点。即使对于您可以控制的应用程序(即您启动的子应用程序)。也许有一种方法可以fork()启动初始化过程,但我从不这样做。

有 SIMBL,但这要求您的应用程序是 Cocoa,因为 SIMBL 将作为系统范围的 InputManager 并选择性地加载包。我驳回了这一点,因为我的应用程序不是 Cocoa,此外,我不喜欢系统范围的东西。

接下来是 mach_inject 和 mach_star 项目。还有一个名为 PlugSuit 的新项目托管在 google,它似乎只不过是 mach_inject 的一个薄包装器。

Mach_inject 提供了一个 API 来做顾名思义。我确实在代码中发现了一个问题。在 10.5.4 上,mach_inject.c 文件中的 mmap 方法要求存在 MAP_SHARED 或与 MAP_READ 一起使用,否则 mmap 将失败。

除此之外,整个事情实际上像宣传的那样工作。我最终使用 mach_inject_bundle 来完成我原本打算将 DYLIB 静态添加到 mach 标头中的操作:即在模块 init 上启动一个新线程来执行其肮脏的业务。

不管怎样,我已经把它变成了一个wiki。随意添加、更正或更新信息。在 OSX 上几乎没有关于此类工作的信息。信息越多越好。

于 2008-11-08T21:17:15.963 回答
4

在 10.5 之前的 MacOS X 版本中,您可以使用输入管理器扩展来执行此操作。输入管理器旨在处理诸如非罗马语言的输入之类的事情,其中​​扩展程序可以弹出一个窗口来输入适当的字形,然后将完成的文本传递给应用程序。该应用程序只需要确保它是 Unicode 干净的,而不必担心每种语言和地区的确切细节。

输入管理器被广泛滥用以将各种不相关的功能修补到应用程序中,并且经常破坏应用程序的稳定性。它也正在成为特洛伊木马的攻击媒介,例如“Oompa-Loompa”。MacOS 10.5 收紧了对输入管理器的限制:它不会在 root 或 wheel 拥有的进程中运行它们,也不会在修改了其 uid 的进程中运行它们。最重要的是,10.5 不会将输入管理器加载到 64 位进程中,并且表明即使使用 32 位也是不支持的,并且将在未来的版本中删除。

因此,如果您可以忍受这些限制,那么输入管理器可以做您想做的事情。未来的 MacOS 版本几乎肯定会引入另一种(更安全、更有限)的方式来做到这一点,因为语言输入支持确实需要该功能。

于 2008-11-04T17:36:12.463 回答
3

我相信您也可以使用DYLD_INSERT_LIBRARIES 方法

这篇文章也与您尝试做的事情有关;

于 2010-09-18T22:59:11.300 回答
1

mach_star我最近尝试使用源代码进行注入/覆盖。我最终为它写了一个教程,因为这些东西的文档总是很粗略而且经常过时。

http://soundly.me/osx-injection-override-tutorial-hello-world/

于 2014-05-06T14:45:14.540 回答
0

有趣的问题。如果我对您的理解正确,您希望添加在正在运行的可执行文件中远程调用函数的功能。

如果你真的不需要整个应用程序,你可以去掉 main 函数,把它变成你可以链接的库文件。由您决定如何确保所有必需的初始化都发生。

另一种方法可能是像病毒一样行事。注入一个处理远程调用的函数,可能在另一个线程中。您需要通过将一些代码注入主函数或其他任何合适的地方来启动此线程。您很可能会在初始化、线程安全和/或维护正确的程序状态方面遇到重大问题。

最好的选择(如果可用)是让您的应用程序供应商公开一个插件 API,让您以受支持的方式干净可靠地执行此操作。

如果您采用任何一种破解二进制路线,这将是耗时且脆弱的,但您会在此过程中学到很多东西。

于 2008-11-04T17:19:07.083 回答
0

在 Windows 上,这很容易做到,实际上被广泛采用,被称为 DLL/代码注入。

有一个用于 OSX 的商业 SDK 允许这样做:Application Enhancer(非商业用途免费)。

于 2009-10-11T16:07:36.467 回答