扩展 Mach-O 文件中的部分
Extend section in Mach-O file
我正在尝试从 Dyld_shared_cache 中提取库,需要修复外部引用。
例如,__DATA.__objc_selrefs
部分中的指针通常指向 mach-o 文件之外的数据,为了修复我必须从 dyld 复制相应的 c 字符串并将其附加到__TEXT.__objc_methname
节。
虽然根据我对 Mach-O 文件格式的理解,__TEXT.__objc_methname
的这个扩展会移动它后面的所有部分,并会迫使我修复引用它们的所有偏移量和指针。有没有办法在不破坏很多东西的情况下向部分添加数据?
谢谢!
更新
在与 OP 澄清 __TEXT.__objc_methname
的扩展将在 Mach-O post 处理现有可执行文件的过程中发生后,我对这个问题有了新的认识。
另一种做法是创建一个新的加载命令 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
有趣的是只有 ld
到 High Sierra 10.14.6 生成 __TEXT.__objc_methname
,在 Catalina 上没有它的踪迹,它的做法不同。
UPDATE2.
玩弄它,我注意到 __objc_methname
工作不需要 __TEXT
段(和 __TEXT_EXEC
的执行权)。
不需要更好的特定段和部分名称:
我可以成功:
__DATA.__objc_methname
__DATA_CONST.__objc_methname
__ARBITRARY.__arbitrary
或者在我的情况下,最后 __DATA
部分
__DATA.__objc_classrefs
原始数据由选择器名称连接在一起。
只要有一个带有选择器名称的正确的空终止 C 字符串就可以了。如果我故意破坏十六进制编辑器或 MachOView 中的 "new[=54=]" 我会得到
"+[NSObject ne]: unrecognized selector sent to instance ..."
启动我的 POC 可执行文件后,肯定会使用该值。
所以总结 __TEXT.__objc_methname
部分本身可能是链接器发出的一些调试器提示。应用程序运行时似乎只需要在内存中的任何位置选择器名称为 char*
。
感谢@Kamil.S 关于添加新加载命令和部分的想法。
向节中添加更多数据的一种方法是创建一个重复的节和节,并将其插入到 __LINKEDIT 节之前。
- 滑动 __LINKEDIT 部分,以便我们 space 添加新部分。
- 定义滑动量,这个必须是页面对齐的,所以我选择0x4000。
- 在相关加载命令中添加滑动量,包括但不限于:
- __LINKEDIT 段(废话)
- dyld_info_command
- symtab_command
- dysymtab_command
- linkedit_data_commands
- 物理移动文件中的 __LINKEDIT。
- 复制该部分并更改以下内容1
- size,应该是你的新数据的长度。
- addr,应该在空闲的space.
- offset,应该在free space.
- 复制段并更改以下内容1
- fileoff,应该是free的开始space.
- vmaddr,应该是free的开始space.
- 文件大小,只要大于您的数据即可。
- vmsize,必须与文件大小相同。
- nsects,更改以反映您添加的部分数。
- cmdsize,更改以反映段命令及其部分命令的大小。
- 在 __LINKEDIT 段之前插入重复的段和节
- 更新 mach_header
- ncmd
- sizeofcmds
- 在文件中物理写入额外数据。
- 您可以选择更改 segname 和 sectname 字段,但这不是必需的。谢谢Kamil.S!
我正在尝试从 Dyld_shared_cache 中提取库,需要修复外部引用。
例如,__DATA.__objc_selrefs
部分中的指针通常指向 mach-o 文件之外的数据,为了修复我必须从 dyld 复制相应的 c 字符串并将其附加到__TEXT.__objc_methname
节。
虽然根据我对 Mach-O 文件格式的理解,__TEXT.__objc_methname
的这个扩展会移动它后面的所有部分,并会迫使我修复引用它们的所有偏移量和指针。有没有办法在不破坏很多东西的情况下向部分添加数据?
谢谢!
更新
在与 OP 澄清 __TEXT.__objc_methname
的扩展将在 Mach-O post 处理现有可执行文件的过程中发生后,我对这个问题有了新的认识。
另一种做法是创建一个新的加载命令 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
有趣的是只有 ld
到 High Sierra 10.14.6 生成 __TEXT.__objc_methname
,在 Catalina 上没有它的踪迹,它的做法不同。
UPDATE2.
玩弄它,我注意到 __objc_methname
工作不需要 __TEXT
段(和 __TEXT_EXEC
的执行权)。
不需要更好的特定段和部分名称:
我可以成功:
__DATA.__objc_methname
__DATA_CONST.__objc_methname
__ARBITRARY.__arbitrary
或者在我的情况下,最后 __DATA
部分
__DATA.__objc_classrefs
原始数据由选择器名称连接在一起。
只要有一个带有选择器名称的正确的空终止 C 字符串就可以了。如果我故意破坏十六进制编辑器或 MachOView 中的 "new[=54=]" 我会得到
"+[NSObject ne]: unrecognized selector sent to instance ..."
启动我的 POC 可执行文件后,肯定会使用该值。
所以总结 __TEXT.__objc_methname
部分本身可能是链接器发出的一些调试器提示。应用程序运行时似乎只需要在内存中的任何位置选择器名称为 char*
。
感谢@Kamil.S 关于添加新加载命令和部分的想法。
向节中添加更多数据的一种方法是创建一个重复的节和节,并将其插入到 __LINKEDIT 节之前。
- 滑动 __LINKEDIT 部分,以便我们 space 添加新部分。
- 定义滑动量,这个必须是页面对齐的,所以我选择0x4000。
- 在相关加载命令中添加滑动量,包括但不限于:
- __LINKEDIT 段(废话)
- dyld_info_command
- symtab_command
- dysymtab_command
- linkedit_data_commands
- 物理移动文件中的 __LINKEDIT。
- 复制该部分并更改以下内容1
- size,应该是你的新数据的长度。
- addr,应该在空闲的space.
- offset,应该在free space.
- 复制段并更改以下内容1
- fileoff,应该是free的开始space.
- vmaddr,应该是free的开始space.
- 文件大小,只要大于您的数据即可。
- vmsize,必须与文件大小相同。
- nsects,更改以反映您添加的部分数。
- cmdsize,更改以反映段命令及其部分命令的大小。
- 在 __LINKEDIT 段之前插入重复的段和节
- 更新 mach_header
- ncmd
- sizeofcmds
- 在文件中物理写入额外数据。
- 您可以选择更改 segname 和 sectname 字段,但这不是必需的。谢谢Kamil.S!