【问题标题】:Self-modifying code on Darwin 10.15 resulting in "malformed mach-o image"?Darwin 10.15 上的自修改代码导致“畸形的 mach-o 图像”?
【发布时间】:2020-06-15 06:47:57
【问题描述】:

我有一个生成自修改代码的程序(如果您有兴趣,请参阅https://tigress.wtf/selfModify.html)。它在 x86 Darwin 和 Linux 上运行。在达尔文,我用

编译
gcc -g -segprot __TEXT rwx rwx self_modifying.c -o self_modifying.exe

最近好像不行,我明白了

dyld: malformed mach-o image: __TEXT segment maps start of file but is writable

当我运行程序时。

我在 MacOS 10.15.3 上运行 clang 版本 6.0.1。任何帮助将不胜感激。

【问题讨论】:

    标签: macos dyld mach-o malformed self-modifying


    【解决方案1】:

    @AlexDenisov 非常接近,但该限制不仅适用于在 Catalina 上运行且最低 macOS 10.15.0 及更高版本的可执行文件。

    有 2 种格式的 Mach-O 加载命令指示可执行文件本身可以使用的最小 MacOS:
    - LC_BUILD_VERSION(如果我没记错的话,新版本是在 10.14 左右推出的)
    - LC_VERSION_MIN_MACOSX(旧版)

    即使使用 LC_VERSION_MIN_MACOSX 回退到旧的 MacOS 版本:

    gcc -segprot __TEXT rwx rwx -mmacosx-version-min=10.6 self_modifying.c 
    

    我们遇到了同样的问题。

    绕过检查我发现一个可行的解决方案是完全摆脱 min macos 版本。我不知道有任何gccld 标志可以实现这一点。幸运的是,我们可以在 Jonathan Levin 的 jtool2 的帮助下链接可执行文件后进行处理

    所以命令链变成:

    gcc -segprot __TEXT rwx rwx self_modifying.c 
    jtool2 -l a.out                             
        LC 00: LC_SEGMENT_64             Mem: 0x000000000-0x100000000   __PAGEZERO
        LC 01: LC_SEGMENT_64             Mem: 0x100000000-0x100001000   __TEXT
            Mem: 0x100000f60-0x100000f83        __TEXT.__text   (Normal)
            Mem: 0x100000f84-0x100000f8a        __TEXT.__stubs  (Symbol Stubs)
            Mem: 0x100000f8c-0x100000fa6        __TEXT.__stub_helper    (Normal)
            Mem: 0x100000fa6-0x100000fb2        __TEXT.__cstring    (C-String Literals)
            Mem: 0x100000fb4-0x100000ffc        __TEXT.__unwind_info    
        LC 02: LC_SEGMENT_64             Mem: 0x100001000-0x100002000   __DATA_CONST
            Mem: 0x100001000-0x100001008        __DATA_CONST.__got  (Non-Lazy Symbol Ptrs)
        LC 03: LC_SEGMENT_64             Mem: 0x100002000-0x100003000   __DATA
            Mem: 0x100002000-0x100002008        __DATA.__la_symbol_ptr  (Lazy Symbol Ptrs)
            Mem: 0x100002008-0x100002010        __DATA.__data   
        LC 04: LC_SEGMENT_64             Mem: 0x100003000-0x100004000   __LINKEDIT
        LC 05: LC_DYLD_INFO             
               Rebase info: 8     bytes at offset 12288 (0x3000-0x3008)
               Bind info:   24    bytes at offset 12296 (0x3008-0x3020)
            No Weak info
               Lazy info:   16    bytes at offset 12320 (0x3020-0x3030)
               Export info: 48    bytes at offset 12336 (0x3030-0x3060)
        LC 06: LC_SYMTAB                
        LC 07: LC_DYSYMTAB              
                1 local symbols at index     0
                2 external symbols at index  1
                2 undefined symbols at index 3
               No TOC
               No modtab
                3 Indirect symbols at offset 0x30b8
        LC 08: LC_LOAD_DYLINKER         /usr/lib/dyld
        LC 09: LC_UUID                  UUID: 6AE91487-DB61-3FA8-8DBE-686FEC1DA8FC
        LC 10: LC_BUILD_VERSION         Build Version:           Platform: MacOS 10.15.0 SDK: 10
        LC 11: LC_SOURCE_VERSION        Source Version:          0.0.0.0.0
        LC 12: LC_MAIN                  Entry Point:             0xf60 (Mem: 0x100000f60)
        LC 13: LC_LOAD_DYLIB            /usr/lib/libSystem.B.dylib
        LC 14: LC_FUNCTION_STARTS       Offset:     12384, Size:      8 (0x3060-0x3068)
        LC 15: LC_DATA_IN_CODE          Offset:     12392, Size:      0 (0x3068-0x3068)
    jtool2 -rc 10 --inplace a.out
    

    现在您的 a.out 应该可以正确启动了 :-)

    【讨论】:

    • ??? 脱帽致敬!
    【解决方案2】:

    您观察到的问题是 macOS Catalina 的限制,与您的编译器无关。

    查看 dyld 源代码(可在此处找到https://opensource.apple.com/release/macos-1015.html)错误消息来自此代码:

    if ( (segCmd->initprot & VM_PROT_WRITE) == VM_PROT_WRITE ) {
      if ( context.strictMachORequired )
        dyld::throwf("malformed mach-o image: %s segment maps start of file but is writable", segCmd->segname);
    }
    

    仅当 strictMachORequired 时抛出异常,在 macOS 10.15 或更高版本上始终为 true,基于来自 dyld 源的其他 sn-p:

    #if __MAC_OS_X_VERSION_MIN_REQUIRED
      gLinkContext.strictMachORequired = false;
      // <rdar://problem/22805519> be less strict about old macOS mach-o binaries
      ((dyld3::MachOFile*)mainExecutableMH)->forEachSupportedPlatform(^(dyld3::Platform platform, uint32_t minOS, uint32_t sdk) {
        if ( (platform == dyld3::Platform::macOS) && (sdk >= DYLD_PACKED_VERSION(10,15,0)) ) {
          gLinkContext.strictMachORequired = true;
        }
      });
      if ( gLinkContext.iOSonMac )
        gLinkContext.strictMachORequired = true;
    #else
      // simulators, iOS, tvOS, watchOS, are always strict
      gLinkContext.strictMachORequired = true;
    #endif
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-11
      • 2020-02-18
      • 1970-01-01
      • 1970-01-01
      • 2018-11-20
      • 2017-10-30
      • 1970-01-01
      • 2011-05-26
      相关资源
      最近更新 更多