本文由 简悦 SimpRead转码, 原文地址 jon-gabilondo-angulo-7635.medium.com
在《如何在 Mach-O 应用程序中注入代码》系列中,我广泛介绍了动态编码的不同方法......。
在如何在Mach-O应用程序中注入代码系列中,我广泛介绍了不同的动态代码注入方法,其中最简单易行的方法是使用动态链接器 dyld 作为工具,在加载时注入dylib。dyld 被编程为注入在环境变量 DYLD_INSERT_LIBRARIES 中定义的库,而无需对应用程序进行任何修改。
在 Dynamic Code Injection(动态代码注入)的三部分系列文章中,我们介绍了注入成功的不同情况,深入探讨了 SIP、AMFI、entitlements、provision profiles 等问题,这些问题有时会导致无法注入代码。
在本文中,我想讨论另一种众所周知的技术--静态代码注入(Static Code Injection),由于它需要修改 Mach-O 二进制文件,因此复杂程度大大提高。这种操作需要一些工具来修改二进制文件,而这些工具确实存在,其中之一就是我的 macho-inject:
这项任务的主要动机是能够注入 Organismo iOS/Mac 仪器库。Organismo 是编程学生和用户界面爱好者学习应用程序内部结构的好工具。在学习过程中,我们还能了解到苹果公司的一些优秀安全机制,它们能让我们的电脑更加安全。
What is Static Code Injection
一般来说,"代码注入 "是指对二进制文件进行扩充,从而将非事先定义的代码加载到其进程内存地址中,以扩展其行为/功能,而无需经过代码创建者的意图或批准。
这可以通过两种方式实现、
- Dynamic。正如我们在使用 dyld 的三部分系列文章中所看到的,使用环境变量可以实现。
$ DYLD_INSERT_LIBRARIES=/path_to/Organismo-mac.framework/Versions/A/Organismo-mac /Applications/Calculator.app/Contents/MacOS/Calculator
- Static。修改二进制文件,使其承载新代码或 "新加载代码 "命令,以加载动态链接库。我们将重点关注后者。我们要修改二进制文件,添加一条新的 dylib 加载命令,将 "注入 "代码加载到 dylib 中。
What to Modify in the Mach-O Binary
Mach-O 的二进制文件非常丰富,可以在许多苹果文档和开发人员文章中找到。正是在这些文章中,我找到了了解 Mach-O 二进制结构的文档,以便能够修改它。因此,我将专门介绍向 Mach-O 二进制文件中注入库所必需的内容。
加载命令部分中的 LC_LOAD_DYLIB
二进制文件必须加载的 dylibs 定义在 "Load Commands(加载命令)"部分,描述为命令 LC_LOAD_DYLIB。我们要做的就是在该部分添加一个新的 LC_LOAD_DYLIB。最好是在 LC_CODE_SGINATURE 之前。
请参见下面的 LC_LOAD_DYLIB 命令:
计算器应用程序的 Mach-O-View 截图。显示 mach 头文件和加载命令。
二进制修补程序实现
macho-inject 工具是基于 C 代码实现的,它打开二进制文件并到达添加定义 LC_LOAD_DYLIB 的新结构的位置。
允许我们浏览和修改 Mach-O 内容的结构定义在文件 macho-headers.h 中。
这些结构用于创建 LC_LOAD_DYLIB 命令的数据:
struct dylib {
union lc_str name; /* library's path name */
uint32_t timestamp; /* library's build time stamp */
uint32_t current_version; /* library's current version number */
uint32_t compatibility_version; /* library's compatibility version number*/
};
struct dylib_command {
uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, LC_REEXPORT_DYLIB */
uint32_t cmdsize; /* includes pathname string */
struct dylib dylib; /* the library identification */
};
注入代码在 injection.cpp 中:
在二进制文件中添加 LC_LOAD_DYLIB 命令:
struct dylib_command dyld;
fread(&dyld, sizeof(struct dylib_command), 1, binaryFile);
ORGLOG_V("Attaching the library");
dyld.cmd = LC_LOAD_DYLIB;
dyld.cmdsize = load_dylib_size;
dyld.dylib.compatibility_version = DYLIB_COMPATIBILITY_VERSION;
dyld.dylib.current_version = DYLIB_CURRENT_VER;
dyld.dylib.timestamp = 2;
dyld.dylib.name.offset = sizeof(struct dylib_command);
fseek(binaryFile, -sizeof(struct dylib_command), SEEK_CUR);
fwrite(&dyld, sizeof(struct dylib_command), 1, binaryFile);
size_t bytes = fwrite(dylibPath.string().data(), dylibPath.string().length(), 1, binaryFile); // write the dylib load string
if (bytes==0) {
ORGLOG_V("ERROR writing the loading path to the loading commands. In inject_dylib.");
}
// 7. Pad position. Maybe dylibPath is not exactly falling into size of long.
if (dylibPath.string().length() % sizeof(long)) {
fseek(binaryFile, sizeof(long) - (dylibPath.string().length() % sizeof(long)), SEEK_CUR);
}
The Code Signature Will Be Broken
这种二进制修补的结果是,二进制文件(或应用程序)的代码签名将失效(如果它已被签名)。
正如我们在前几篇文章中所看到的,macho-inject 是一个强大的应用程序筛选工具,可以指示它重签名整个应用程序。重签名有很多陷阱,并不总是导致应用程序有效。请阅读之前的文章以了解其局限性。
Examples
$ macho_inject -s 'Apple Development: XXX (XXXX)' --hardened -v -f /pathto/Organismo.framework -o /pathto/AppSigning/Out /pathTo/WhatsApp.app
祝您在 macho-inject 中玩得开心!
谢谢 !