在加载的 ELF(.so 共享库)中挂钩并替换导出函数

2024-02-23

我正在编写一些 C 代码来将 .so ELF (共享库)的某些函数加载到内存中。

我的 C 代码应该能够重定向另一个加载到应用程序/程序内存中的 .so 库的导出函数。

这里有一些详细说明:

Android 应用程序将加载多个 .so 文件。我的 C 代码必须查看属于另一个共享 .so 库(在本例中称为 target.so)的导出函数

这不是常规的 dlsym 方法,因为我不仅想要函数的地址,而且想用我自己的函数替换它;其中:当另一个库调用它自己的函数时,我的 hook_func 会被调用,然后我应该从我的 hook_func 调用original_func。

对于导入功能,这可以工作。但对于导出功能我不知道该怎么做。 导入函数在符号表中具有相应的条目,在重定位表中具有相应的条目,最终给出全局偏移表(GOT)中的条目地址。 但对于导出函数,符号的 st_value 元素本身具有过程的地址,而不是 GOT 地址(如果我错了,请纠正我)。

我如何执行挂钩export功能?

理论上来说,我应该得到的内存位置st_value动态符号表条目的元素(Elf32_Sym)的导出功能。如果我获得该位置,那么我应该能够用我的 hook_func 的地址替换该位置中的值。但是,到目前为止我还无法写入该位置。我必须假设动态符号表的内存是只读的。如果这是真的那么这种情况下的解决方法是什么?

非常感谢您的阅读和帮助我。

Update:LD_PRELOAD只能用我自己的函数替换原来的函数,但是我不确定是否有任何方法可以调用原来的函数。 以我为例:

应用程序通过调用初始化音频引擎Audio_System_Create并传递一个引用AUDIO_SYSTEM反对Audio_System_Create(AUDIO_SYSTEM **);AUDIO API 分配此结构/对象并返回函数。 现在如果我能访问它就好了AUDIO_SYSTEM对象,我可以轻松地将回调附加到该对象并开始接收音频数据。 因此,我的最终目标是获得参考AUIOD_SYSTEM目的;根据我的理解,只有当我拦截该对象首先通过分配的调用时,我才能得到这一点Audio_System_Create(AUIOD_SYSTEM **)。 目前,在 android 上没有直接的方法来获取输出音频。 (所有示例都讨论仅录制来自麦克风的音频)

Update2:正如 Basile 在他的回答中所建议的,我使用了 dladdr() 但奇怪的是,它给了我与我传递给它的地址相同的地址。

void *pFunc=procedure_addr;  //procedure address calculated from the st_value of symbol from symbol table in ELF file (not from loaded file)

        int  nRet;

            // Lookup the name of the function given the function pointer
            if ((nRet = dladdr(pFunc, &DlInfo)) != 0)
            {
                LOGE("Symbol Name is: %s", DlInfo.dli_sname);
                if(DlInfo.dli_saddr==NULL)
                    LOGE("Symbol Address is: NULL");
                else
                    LOGE("Symbol Address is: 0x%x", DlInfo.dli_saddr);
            }
            else
                LOGE("dladdr failed");

这是我得到的结果:

条目地址=0x75a28cfc

Entry_addr_through_dlysm =0x75a28cfc

符号名称为:AUDIO_System_Create

符号地址为:0x75a28cfc

这里通过dlysm得到的地址或者通过ELF文件计算得到的地址就是程序的地址;虽然我需要这个地址本身所在的位置;这样我就可以用我的地址替换这个地址hook_func地址。dladdr()没有做我认为会做的事情。


你应该详细阅读 Drepper 的论文:如何编写共享库 http://www.akkadia.org/drepper/dsohowto.pdf- 特别是要理解为什么使用LD_PRELOAD是不足够的。您可能想研究动态链接器的源代码(ld-linux.so)在你的里面libc。你可以尝试改变保护(2) http://man7.org/linux/man-pages/man2/mprotect.2.html and/or mmap(2) http://man7.org/linux/man-pages/man2/mmap.2.html and/or 重映射(2) http://man7.org/linux/man-pages/man2/mremap.2.html相关页面。您可以通过以下方式查询内存映射proc(5) http://man7.org/linux/man-pages/man5/proc.5.html using /proc/self/maps & /proc/self/smaps。然后你可以,在一个特定于架构的方式,替换起始字节(也许使用asmjit https://github.com/kobalicek/asmjit or GNU 闪电 http://www.gnu.org/software/lightning/)的代码original_func通过跳转到你的hook_func函数(您可能需要更改其尾声,将覆盖的指令放在原来的位置)original_func- 那里...)

事情可能会稍微容易一些,如果original_func众所周知,而且总是一样的。然后,您可以研究它的源代码和汇编代码,并编写修补函数和您的hook_func只为它。

也许使用dladdr(3) http://man7.org/linux/man-pages/man3/dladdr.3.html可能也有帮助(但可能没有)。

或者,修改您的动态链接器以根据您的需要进行更改。你可以研究一下源代码musl-libc 库 http://musl-libc.org/

请注意,您可能需要覆盖机器码在地址original_func(如给出的dlsym on "original_func")。或者,您需要relocate http://en.wikipedia.org/wiki/Relocation_%28computing%29在所有已加载的共享对象中每次调用该函数(我相信这更难;如果你坚持看到dl_iterate_phdr(3) http://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html).

如果你想要一个通用的解决方案(对于任意original_func)您需要实现一些二进制代码分析器(或反汇编器)来修补该函数。如果你只是想破解某个特定的original_func你应该反汇编它,并修补它的机器代码,然后让你的hook_func做一部分original_func你已经覆盖了。

如此可怕且耗时的黑客(你需要几周的时间才能使其发挥作用)让我更喜欢使用自由软件 http://en.wikipedia.org/wiki/Free_software(从此以后,修补共享库的源并重新编译就简单多了)。

当然,这一切并不容易。你需要详细了解什么ELF http://en.wikipedia.org/wiki/Executable_and_Linkable_Format共享对象是,另请参见elf(5) http://man7.org/linux/man-pages/man5/elf.5.html并阅读莱文的书:链接器和加载器 http://www.iecc.com/linker/


注意:如果您正在攻击专有库(例如unity3d http://unity3d.com/),您想要实现的目标可能是非法的。询问律师。从技术上讲,您违反了共享库提供的大多数抽象。如果可能的话,请共享库的作者提供帮助,也许可以在其中实现一些插件机制。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在加载的 ELF(.so 共享库)中挂钩并替换导出函数 的相关文章

随机推荐

  • Flash Builder 4 用空格代替制表符?

    是否可以将 Flash Builder 4 配置为使用空格而不是制表符缩进 我已启用Preferences gt General gt Editors gt Text Editors gt Insert spaces for tabs但它仍
  • 在测试中的 Spring 环境中使用 @EnabledIf 和 spring.profiles.active 属性

    根据文档 https docs spring io spring framework docs current javadoc api org springframework test context junit jupiter Enabl
  • PHP 标签关闭——什么时候需要?

    推荐的是 http framework zend com manual en coding standard php file formatting html不应在文件末尾放置 PHP 结束标记 以避免出现各种不良错误 但是有没有什么情况需
  • 没有 Mac 的 Xamarin Visual Studio IOS 开发?

    我是一名 NET 开发人员 想用 C 编写 IOS 和 Android 应用程序 我读过有关 Xamarin for Visual Studio 的文章 它看起来很有趣 如果不是有点贵的话 您需要 Mac 来调试代码吗 您是否只需要一台联网
  • 将字符串从 datagridview 传递到另一种形式的文本框

    我设置了 2 个表单 第一个表单加载 datagridview 用户单击视图来选择他们想要的值 我可以在与 datagridview 相同的表单上获取消息框中显示的值 但是当我尝试将其传递到另一个表单时 它显示为 NULL 我如何让它显示在
  • Spring MVC 3:如何向 HTTP 404 错误的错误页面提供动态内容?

    我想要的是 我想为 HTTP 404 错误页面提供一个模型 我不想编写在 web xml 中指定的静态错误页面 而是使用 异常控制器 处理 HTTP 404 错误 我做了什么 从 web xml 中删除了错误页面标签
  • Spring工具套件中maven使用的settings.xml在哪里?

    我想设置 ftp 服务器以从 STS 进行部署 如下所述 http maven apache org plugins maven deploy plugin examples deploy ftp html http maven apach
  • 改造多个 POST 参数

    我正在尝试向需要 2 组信息的服务器提交调用 这是我的界面 POST venues get by location void getByLocation Body Coordinates coordinates Body MaxDistan
  • React-native:如何控制键盘向上推

    该应用程序的结构相当简单 底部有一个搜索栏 一个列表视图和react native tabs 问题 如果我点击 Android 上的搜索栏 它会将整个应用程序向上推 因此我可以直接在键盘上看到选项卡 但在 iOS 上 键盘覆盖了整个应用程序
  • 调用从 EDN 文件读取的函数

    我有一个 EDN 配置文件 其中的条目引用现有功能 例如 attribute modules content class lohan extractors content process schema class lohan extract
  • 查询超慢...我做错了什么?

    你们太棒了 在过去的几天里 我已经在这里发帖两次 作为一个新用户 我对这些帮助感到震惊 因此 我想我应该采用软件中最慢的查询 看看是否有人可以帮助我加快速度 我使用此查询作为视图 因此速度快很重要 但事实并非如此 首先 我有一个联系人表 用
  • 我们应该在数据库表命名约定中使用前缀吗?

    我们正在工作中的开发团队决定表 列 过程等的命名约定 单复数表命名已经决定了 我们使用单数 我们正在讨论是否为每个表名使用前缀 我想阅读有关是否使用前缀以及原因的建议 它是否提供任何安全性 至少为可能的入侵者多了一个障碍 我认为用前缀命名它
  • 通过 Python 在 Selenium 中使用 WebDriverWait for link_text “TypeError: 'str' object is not callable”

    这是我在 Stack Overflow 上的第一篇文章 我一直在浏览和搜索这个问题的每一个可能的答案 我想在这一点上我应该问一个问题 因为我已经在这堵墙上呆了好几天了 我目前正在使用 Python 中的 Selenium 开发一个网络抓取项
  • 强制编码风格[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 几年前 当我开始一个小型开发项目时 我和其他开发人员坐下来就折衷的大括号和缩进样式达成了一致 它不是任何人的最爱 但却是没有人真正讨厌的东西 我
  • 如何在 PHP 中查找单词组合

    我有一个数组 new array array c a m t p 现在我想找到单词表中存在的单词组合 我曾尝试实现但没有成功 这是我的 php 代码 words array set powerSet new array 2 mysql ne
  • Webstorm 关闭匿名函数声明中的新空格

    例如我有这个 exports getsertHexId function table hex Webstorm 8 的自动缩进在关键字之间创建空格function和开括号 其设置空间选项包括 函数声明括号 函数调用括号 如果 括号 很困惑
  • 如何定期唤醒我的应用程序

    我想在Android中做一个功能 比如提醒 我想在我的应用程序 活动未运行或者其 UI 不可见时启动它 它类似于提醒 在所需的时间唤醒应用程序 我没有使用过任何类型的后台任务或服务 所以我不知道该怎么办 或者我应该学习什么类型的课程或演示
  • 在 SQLite 中的 GROUP_CONCAT 函数中使用 ORDER BY 子句

    我不认为我可以使用ORDER BY里面的子句GROUP CONCAT功能 有谁知道一种棘手的方法来完成这种行为SQLite 我看到了这个question https stackoverflow com questions 1897352 s
  • 如何将由东北坐标和西南坐标组成的特定边界拟合到可见地图视图中?

    我需要在地图内适应特定的边界 我通过调用谷歌地理编码器并读取视口属性来获取边界 如下所示 northeast lat 30 4212235 lng 97 486942 southwest lat 30 1128403 lng 97 9991
  • 在加载的 ELF(.so 共享库)中挂钩并替换导出函数

    我正在编写一些 C 代码来将 so ELF 共享库 的某些函数加载到内存中 我的 C 代码应该能够重定向另一个加载到应用程序 程序内存中的 so 库的导出函数 这里有一些详细说明 Android 应用程序将加载多个 so 文件 我的 C 代