拦截动态链接库的静态链接依赖
Intercepting Statically Linked Dependencies of a Dynamically Linked Library
我正在尝试调试第三方应用程序正在使用的 API。
第三方应用程序有一个我认为不可能的配置:
应用程序二进制文件包含其共享库依赖项之一所需的导出。也就是说,它们动态链接了它们的依赖关系,但该依赖关系的依赖关系是静态链接的。
这发生在基于 linux 且具有古老内核的 MIPS 上。
我已经使用 Ghidra 反汇编 executable/shared 库确认了这一点。
基本上我们有二进制文件和共享对象
file initApp
initApp: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
file libhyCoreSdk.so
libhyCoreSdk.so: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, stripped
objdump -T libhyCoreSdk.so | grep -i IMP_ISP_Open
00047900 DF *UND* 00000000 IMP_ISP_Open
initApp 在 libhyCoreSdk.so 中调用“coreAvInit”,然后 libhyCoreSdk.so 在 initApp 内部调用 IMP_ISP_Open()。
您可能会想“这并不罕见,您可以通过回调、传递指针、调用 dlsym 等来做到这一点。”但这不是这些东西中的任何一个,这是一个直接的 import/export 符号,如果 libhyCoreSdk 依赖于另一个共享库,这正是您希望看到的。
除此之外,我真正的问题是我试图弄清楚 IMP_ISP_Open 正在传递哪些参数,而 LD_PRELOAD 对这种 strange/unique 情况没有帮助。我有另一个示例应用程序,它针对 API 的共享库版本调用相同的 APIs。当我针对该版本使用 LD_PRELOAD(加载我编写的一个小拦截器程序)时,效果很好。但是当我将它用于链接回二进制文件的这个版本时,它不起作用。
我希望有人知道如何拦截那些 API 电话。
部分解决方案:
Daniel Kleinstein 给了我一个良好的开端。我将目标函数从 IMP_... 重命名为 XMP_...(例如 IMP_ISP_DisableSensor-> XMP_ISP_DisableSensor)。现在我的 LD_PRELOAD 中的 IMP_ISP_DisableSensor 被正确命中了。不幸的是,我仍然 运行 遇到麻烦。无明显原因调用 dlsym(RTLD_DEFAULT, "XMP_ISP_DisableSensor") returns NULL...这意味着我无法重定向回原始函数。
尽管 objdump 显示:
objdump -T initApp_mod | grep -i XMP
0061fb5c g DF .text 00000338 Base XMP_FrameSource_CreateChn
00613c6c g DF .text 00000204 Base XMP_ISP_DisableSensor
006097f0 g DF .text 00000eb0 Base XMP_Encoder_CreateChn
您的动态依赖项不是静态链接到您的主要可执行文件。加载动态依赖项时,会搜索其导入并由可执行文件导出的符号解析 - 实际上,可执行文件的符号将始终在任何其他动态依赖项之前解析。
不幸的是,这也会阻止您使用 LD_PRELOAD
。
LD_PRELOAD
不起作用,因为其注入的库 不会 优先于主要可执行文件本身导出的符号 - 仅优先于共享库导出的符号。
如果您希望使用 LD_PRELOAD
拦截调用,一个粗略但有效的解决方案是将主要可执行文件的导出符号修补为不同的名称 - 这样当加载动态依赖项时它不会解析,您注入的库可以提供符号。
我正在尝试调试第三方应用程序正在使用的 API。 第三方应用程序有一个我认为不可能的配置:
应用程序二进制文件包含其共享库依赖项之一所需的导出。也就是说,它们动态链接了它们的依赖关系,但该依赖关系的依赖关系是静态链接的。
这发生在基于 linux 且具有古老内核的 MIPS 上。
我已经使用 Ghidra 反汇编 executable/shared 库确认了这一点。
基本上我们有二进制文件和共享对象
file initApp
initApp: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
file libhyCoreSdk.so
libhyCoreSdk.so: ELF 32-bit LSB shared object, MIPS, MIPS32 rel2 version 1 (SYSV), dynamically linked, stripped
objdump -T libhyCoreSdk.so | grep -i IMP_ISP_Open
00047900 DF *UND* 00000000 IMP_ISP_Open
initApp 在 libhyCoreSdk.so 中调用“coreAvInit”,然后 libhyCoreSdk.so 在 initApp 内部调用 IMP_ISP_Open()。
您可能会想“这并不罕见,您可以通过回调、传递指针、调用 dlsym 等来做到这一点。”但这不是这些东西中的任何一个,这是一个直接的 import/export 符号,如果 libhyCoreSdk 依赖于另一个共享库,这正是您希望看到的。
除此之外,我真正的问题是我试图弄清楚 IMP_ISP_Open 正在传递哪些参数,而 LD_PRELOAD 对这种 strange/unique 情况没有帮助。我有另一个示例应用程序,它针对 API 的共享库版本调用相同的 APIs。当我针对该版本使用 LD_PRELOAD(加载我编写的一个小拦截器程序)时,效果很好。但是当我将它用于链接回二进制文件的这个版本时,它不起作用。
我希望有人知道如何拦截那些 API 电话。
部分解决方案:
Daniel Kleinstein 给了我一个良好的开端。我将目标函数从 IMP_... 重命名为 XMP_...(例如 IMP_ISP_DisableSensor-> XMP_ISP_DisableSensor)。现在我的 LD_PRELOAD 中的 IMP_ISP_DisableSensor 被正确命中了。不幸的是,我仍然 运行 遇到麻烦。无明显原因调用 dlsym(RTLD_DEFAULT, "XMP_ISP_DisableSensor") returns NULL...这意味着我无法重定向回原始函数。
尽管 objdump 显示:
objdump -T initApp_mod | grep -i XMP
0061fb5c g DF .text 00000338 Base XMP_FrameSource_CreateChn
00613c6c g DF .text 00000204 Base XMP_ISP_DisableSensor
006097f0 g DF .text 00000eb0 Base XMP_Encoder_CreateChn
您的动态依赖项不是静态链接到您的主要可执行文件。加载动态依赖项时,会搜索其导入并由可执行文件导出的符号解析 - 实际上,可执行文件的符号将始终在任何其他动态依赖项之前解析。
不幸的是,这也会阻止您使用 LD_PRELOAD
。
LD_PRELOAD
不起作用,因为其注入的库 不会 优先于主要可执行文件本身导出的符号 - 仅优先于共享库导出的符号。
如果您希望使用 LD_PRELOAD
拦截调用,一个粗略但有效的解决方案是将主要可执行文件的导出符号修补为不同的名称 - 这样当加载动态依赖项时它不会解析,您注入的库可以提供符号。