【问题标题】:Extend section in Mach-O fileMach-O 文件中的扩展部分
【发布时间】:2020-08-01 05:25:03
【问题描述】:

我正在尝试从 Dyld_shared_cache 中提取库,并且需要修复外部引用。

例如,__DATA.__objc_selrefs 部分中的指针通常指向 mach-o 文件之外的数据,为了解决这个问题,我必须从 dyld 复制相应的 c 字符串并将其附加到 __TEXT.__objc_methname 部分.

尽管根据我对 Mach-O 文件格式的理解,__TEXT.__objc_methname 的这个扩展名将移动它之后的所有部分,并迫使我修复所有引用它们的偏移量和指针。有没有办法在不破坏很多东西的情况下向一个部分添加数据?

谢谢!

【问题讨论】:

    标签: shared-libraries dyld conceptual mach-o


    【解决方案1】:

    更新
    在与 OP 澄清 __TEXT.__objc_methname 的扩展将在现有可执行文件的 Mach-O 后处理期间发生后,我对这个问题有了新的认识。

    另一种方法是创建一个新的加载命令LC_SEGMENT_64 和一个新的__TEXT_EXEC.__objc_methname 段/节条目(通常__TEXT_EXEC 用于一些内核内容,但本质上它与__TEXT 相同)。这里有一个快速 POC 来说明这个概念:

    #import <Foundation/Foundation.h>
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            printf("%lx",[NSObject new]);
        }
        return 0;
    }
    

    像这样编译:

    gcc main.m -c -o main.o 
    ld main.o -rename_section __TEXT __objc_methname __TEXT_EXEC __objc_methname -lobjc -lc 
    

    有趣的是,只有直到 High Sierra 10.14.6 的 ld 会生成 __TEXT.__objc_methname,在 Catalina 上没有任何痕迹,它的做法不同。

    UPDATE2
    玩弄它,我注意到__TEXT 段(和__TEXT_EXEC 就此而言)的执行权不需要__objc_methname 工作。 甚至不需要更好的特定段和部分名称:
    我可以成功:

    __DATA.__objc_methname   
    __DATA_CONST.__objc_methname 
    __ARBITRARY.__arbitrary 
    

    或者在我的情况下是最后一个__DATA 部分
    __DATA.__objc_classrefs,其中原始数据由选择器名称连接。 只要存在带有选择器名称的正确的以空结尾的 C 字符串,一切都很好。如果我故意在十六进制编辑器或 MachOView 中破坏“new\0”,我会得到 ​​p>

    "+[NSObject ne]: unrecognized selector sent to instance ..."
    

    在启动我的 POC 可执行文件时,肯定会使用该值。

    总而言之,__TEXT.__objc_methname 部分本身可能是链接器提供的一些调试器提示。应用程序运行时似乎只需要在内存中的任何位置将选择器名称命名为char*

    【讨论】:

    • 我的案例是案例 2,我在编译后重建一个 Mach-O 文件。情况 2,备选方案 A 可能不起作用(除非我误解了你),因为对于像 __TEXT.__objc_methname 这样的部分,它夹在部分之间,没有任何填充。替代方案 b 可能有效,但需要一些时间测试。
    • 我必须对此进行测试,但这是否可以推广到 __DATA 和 __DATA_CONST 等其他细分市场?
    • 我尝试添加一个全新的加载命令,数据位于文件末尾,但是当尝试将其加载到我的手机上时,我收到以下 NSError,/Library/Frameworks/TestMacho.framework/TestMacho: malformed mach-o image: __LINKEDIT must be last segment。跨度>
    • 您必须在__LINKEDIT 之前插入LC_SEGMENT_64。我能够将__TEXT.__objc_methname 压缩到__DATA.__objc_classrefs 中并且它仍然有效。为什么首先需要一个新的部分/段/加载命令?
    • 原来我只是想向部分添加更多数据。
    【解决方案2】:

    感谢 @Kamil.S 关于添加新加载命令和部分的想法。

    实现向节添加更多数据的一种方法是创建重复的段和节并将其插入到 __LINKEDIT 段之前。

    • 滑动 __LINKEDIT 部分,以便我们有空间添加新部分。
      1. 定义滑动量,这个必须是页面对齐的,所以我选择0x4000。
      2. 在相关加载命令中添加滑动量,包括但不限于:
        • __LINKEDIT 段(呵呵)
        • dyld_info_command
        • symtab_command
        • dysymtab_command
        • linkedit_data_commands
      3. 物理移动文件中的 __LINKEDIT。
    • 复制部分并更改以下内容1
      • size,应该是新数据的长度。
      • 地址,应该在空闲空间中。
      • 偏移量,应该在空闲空间中。
    • 复制段并更改以下内容1
      • fileoff,应该是空闲空间的开始。
      • vmaddr,应该是空闲空间的开始。
      • 文件大小,只要大于您的数据即可。
      • vmsize,必须与文件大小相同。
      • nsects,更改以反映您添加的部分。
      • cmdsize,更改以反映段命令及其段命令的大小。
    • 在 __LINKEDIT 段之前插入重复的段和部分
    • 更新 mach_header
      • ncmds
      • sizeofcmds
    • 在文件中物理写入额外数据。

    1. 您可以选择更改 segname 和 sectname 字段,但这不是必需的。谢谢卡米尔.S!

    【讨论】:

      猜你喜欢
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多