【问题标题】:How can I sections out of __TEXT and into a new segment for a mach-o binary?如何将 __TEXT 分段并放入 mach-o 二进制文件的新段?
【发布时间】:2017-12-19 22:33:06
【问题描述】:

如何将部分移出 __TEXT 段并进入 mach-o 二进制文件的新段?我问的原因是我试图让我的 iPhone 应用程序更小,并且 iOS App Store 在压缩之前加密它的 __TEXT 部分,以便它根本不压缩。如果我可以将所有不可执行的部分移出该段并进入一个新的只读段,那么我可以将我的应用程序的大小减少大约 9%。

【问题讨论】:

    标签: ios mach-o


    【解决方案1】:

    在链接器级别

    正如@meisel 回答中已经提到的,这可以通过以下方式完成: 所以要设置的值是:

    -Wl,-rename_section,__TEXT,__sectionName,__NEW_SEGMENT_NAME,__newSectionName
    

    如果段权限需要调整

    -segprot,__NEW_SEGMENT_NAME,rx,rx
    

    注意rwx 的可执行代码,如果检测到rxw 运行代码,应用程序将立即被iOS XNU 内核杀死。 x86-64 模拟器还是可以的。此博客post 涵盖了一些使用示例。

    在函数原型层面

    假设您使用的是 Objective-C(或 C),您可以使用 __attribute__ section(...)
    语法:
    __attribute__ ((section("segmentName,sectionName,[optional]sectionType,[optional]sectionAttribute,[optional]stubSize")))
    来自https://opensource.apple.com/source/clang/clang-137/src/lib/MC/MCSectionMachO.cpp 允许sectionTypes

      { "regular",                  "S_REGULAR" },                    // 0x00
      { 0,                          "S_ZEROFILL" },                   // 0x01
      { "cstring_literals",         "S_CSTRING_LITERALS" },           // 0x02
      { "4byte_literals",           "S_4BYTE_LITERALS" },             // 0x03
      { "8byte_literals",           "S_8BYTE_LITERALS" },             // 0x04
      { "literal_pointers",         "S_LITERAL_POINTERS" },           // 0x05
      { "non_lazy_symbol_pointers", "S_NON_LAZY_SYMBOL_POINTERS" },   // 0x06
      { "lazy_symbol_pointers",     "S_LAZY_SYMBOL_POINTERS" },       // 0x07
      { "symbol_stubs",             "S_SYMBOL_STUBS" },               // 0x08
      { "mod_init_funcs",           "S_MOD_INIT_FUNC_POINTERS" },     // 0x09
      { "mod_term_funcs",           "S_MOD_TERM_FUNC_POINTERS" },     // 0x0A
      { "coalesced",                "S_COALESCED" },                  // 0x0B
      { 0, /*FIXME??*/              "S_GB_ZEROFILL" },                // 0x0C
      { "interposing",              "S_INTERPOSING" },                // 0x0D
      { "16byte_literals",          "S_16BYTE_LITERALS" },            // 0x0E
      { 0, /*FIXME??*/              "S_DTRACE_DOF" },                 // 0x0F
      { 0, /*FIXME??*/              "S_LAZY_DYLIB_SYMBOL_POINTERS" }, // 0x10
      { "thread_local_regular",     "S_THREAD_LOCAL_REGULAR" },       // 0x11
      { "thread_local_zerofill",    "S_THREAD_LOCAL_ZEROFILL" },      // 0x12
      { "thread_local_variables",   "S_THREAD_LOCAL_VARIABLES" },     // 0x13
      { "thread_local_variable_pointers",
        "S_THREAD_LOCAL_VARIABLE_POINTERS" },                         // 0x14
      { "thread_local_init_function_pointers",
        "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS"},                     // 0x15
    

    允许section attributes:

    ENTRY("pure_instructions",   S_ATTR_PURE_INSTRUCTIONS)
    ENTRY("no_toc",              S_ATTR_NO_TOC)
    ENTRY("strip_static_syms",   S_ATTR_STRIP_STATIC_SYMS)
    ENTRY("no_dead_strip",       S_ATTR_NO_DEAD_STRIP)
    ENTRY("live_support",        S_ATTR_LIVE_SUPPORT)
    ENTRY("self_modifying_code", S_ATTR_SELF_MODIFYING_CODE)
    ENTRY("debug",               S_ATTR_DEBUG)
    ENTRY("" /*FIXME*/,          S_ATTR_SOME_INSTRUCTIONS)
    ENTRY("" /*FIXME*/,          S_ATTR_EXT_RELOC)
    ENTRY("" /*FIXME*/,          S_ATTR_LOC_RELOC)
    

    一些例子:

    //Variable in brand new segment & section, segment VM access defaults to read/write
    int intInCustomPlace __attribute__ ( (section ("__DATA2,__data2") ));
    
    //Read only string constant outside of __TEXT in readonly __LINKEDIT
    char *kString __attribute__ ( (section ("__LINKEDIT,__customSection") )) = "value";
            
    //C function in custom segment & section
    void foo() __attribute__ ( (section ("__TEXT_EXEC,__customSection") ));
    
            
    //obj-c method in custom section
    @interface YourClass
    - (void) foo:(NSInteger)someArg  __attribute__ ( (section ("__TEXT, __customSection") ));
    @end
    
    @interface YourClass ()
    - (void) foo2:(NSInteger)someArg  __attribute__ ( (section ("__TEXT, __customSection") ));
    @end
    

    [新] 在函数/方法级别使用范围

    #pragma clang attribute push(__attribute__ ( (section ("__TEXT_EXEC,__customSection") )), apply_to=objc_method)
    @interface AppDelegate ()
    -(void)test;
    -(void)test2;
    @end
    
    @interface AppDelegate ()
    -(void)test3;
    -(void)test4;
    @end
    #pragma clang attribute pop
    
    #pragma clang attribute push(__attribute__ ( (section ("__TEXT,__customTextSection") )), apply_to=objc_method)
    @interface AppDelegate
    -(void)test5;
    -(void)test6;
    @end
    #pragma clang attribute pop
    
    #pragma clang attribute push(__attribute__ ( (section ("__TEXT_EXEC,__customSection") )), apply_to=function)
    void func1();
    void func2();
    #pragma clang attribute pop
    

    请记住,您可以轻松破坏内容,MachOView 是检查二进制文件的便捷工具。自定义("__TEXT,__cstring") 替换很可能是您的最佳选择。

    编辑:默认情况下,不存在的段将作为可读和可写发出(就像__DATA),因此这不适用于可执行代码。

    如果您想探索这里记录的内联汇编路径:https://developer.apple.com/library/content/documentation/DeveloperTools/Reference/Assembler/040-Assembler_Directives/asm_directives.html

    【讨论】:

    • 唯一的问题是我想将每个变量从这些部分移动到一个单独的段中,而不必像这样注释每个变量。否则,我将有数千个地方需要注释。
    • 可以重命名为__RODATA部分吗?
    • 约定是大写的表示段(根据约定,它可能由小写的部分组成),所以我假设您的意思是__RODATA 段。是的,您可以将一些可执行代码移动到另一个段(可能来自__TEXT),但您需要为您的__RODATA 调整段保护(在这种情况下为rx)。默认情况下,链接器会给它rw 权限。
    【解决方案2】:

    ld-rename_section 标志可以完成这项工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-21
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多