【问题标题】:How can I get SEL (@selector()) from object file (Mach-o)? how SEL stored in Mach-o?如何从目标文件 (Mach-o) 中获取 SEL (@selector())? SEL 如何存储在 Mach-o 中?
【发布时间】:2013-03-27 12:54:46
【问题描述】:

从 objc 源我们可以看到 SEL 被定义为 typedef struct objc_selector *SEL;

我用idaq 反汇编了我的dylib,我确实找到了_MSHookMessageEx 函数的调用, 从 libsubstrate.dylib 链接

_MSHookMessageEx 有以下签名

void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP *result);

所以我们可以假设在源代码中有类似 @selector(someMethod:) 的东西 第二个参数

在目标文件的数据部分,我可以看到源代码中使用的所有 CFStrings

但是这里没有任何选择器字符串,所以我们可以看到@selector()没有转换成静态的CFString

我非常有兴趣找到传递给_MSHookMessageEx 函数的选择器和类的字符串表示形式。

如何从目标文件 (Mach-o) 中获取 SEL (@selector())? SEL 是如何存储在 Mach-o 中的?

谢谢!

更新:

在调用之前我确实发现 ida 方法表示中有一些字符串 方法

我猜有些选择器会传入函数。我说的对吗?

【问题讨论】:

  • 但是,class-dump 只能显示objective-c 类的方法和接口,不是吗?它可以显示传递给 C 函数的选择器(来自 C 函数)吗?
  • 如果我们谈论的是你的反汇编,选择器就在那里:postNotificationName:object:userInfo:。这不是你要的吗?
  • 是的,我猜。但是@selector() 如何存储在 Mach-o 文件中?我在数据部分中找不到它们作为字符串。

标签: iphone objective-c reverse-engineering ida cydia-substrate


【解决方案1】:

选择器名称存储在__TEXT 段的__objc_methname 部分中:

:; otool -v -s __TEXT __objc_methname /System/Library/Frameworks/AppKit.framework/AppKit | head
/System/Library/Frameworks/AppKit.framework/AppKit:
Contents of (__TEXT,__objc_methname) section
0x000000000097cbd8  count
0x000000000097cbde  countByEnumeratingWithState:objects:count:
0x000000000097cc09  alloc
0x000000000097cc0f  initWithObjects:count:
0x000000000097cc26  release
0x000000000097cc2e  autorelease
0x000000000097cc3a  copy
0x000000000097cc3f  timeIntervalSinceNow

指向选择器的指针存储在__DATA 段的__objc_selrefs 部分:

:; otool -v -s __DATA __objc_selrefs /System/Library/Frameworks/AppKit.framework/AppKit | head
/System/Library/Frameworks/AppKit.framework/AppKit:
Contents of (__DATA,__objc_selrefs) section
0x0000000000d77d80  __TEXT:__objc_methname:initWithObjects:count:
0x0000000000d77d88  __TEXT:__objc_methname:copy
0x0000000000d77d90  __TEXT:__objc_methname:timeIntervalSinceNow
0x0000000000d77d98  __TEXT:__objc_methname:sharedAppleEventManager
0x0000000000d77da0  __TEXT:__objc_methname:_prepareForDispatch
0x0000000000d77da8  __TEXT:__objc_methname:_setLaunchTaskMaskBits:
0x0000000000d77db0  __TEXT:__objc_methname:_disableSuddenTermination
0x0000000000d77db8  __TEXT:__objc_methname:_appleEventActivationInProgress

源代码中的SEL 实际上(当前)是指向选择器的 C 字符串名称的指针。所以如果你写这个:

SEL s = @selector(initWithObjects:count:);

那么s实际上是一个char const *,它指向字符串initWithObjects:count:。直到最近,您还可以通过以下方式打印选择器名称:

NSLog(@"selector is %s", (char *)s);

但是,Apple 更改了编译器(我相信从 Xcode 4.6 开始)以禁止将 SEL 转换为 char *,因此他们将来可能会更改选择器实现。

无论如何,棘手的部分是机器代码使用 PC 相对寻址从 __objc_selrefs 部分加载指针。 PC 是“程序计数器”,即当前执行指令的地址。在 x86 架构上,它通常称为 IP(指令指针)或 EIP(扩展 IP)。

这就是你的反汇编相关说明中发生的事情:

1444    LDR R1, =(off_2038 - 0x145C)
        ...
1454    LDR R1, (PC,R1)

指向选择器的指针从地址 0x2038 处的字加载。但是常量 0x2038 实际上并没有出现在机器代码中。通过分析程序的数据流,您的反汇编程序帮助您计算了它。存储在第一条LDR 指令中的常量实际上是 0xBDC,因为 0xBDC + 0x145C = 0x2038。

您可能想知道为什么当第二条LDR 指令位于地址 0x1454 时它使用 0x145C。当 ARM 处理器使用 PC 相对寻址计算地址时,PC 的值实际上是当前执行指令的地址加 4 或加 8(取决于处理器模式)。 This is documented here(可能还有其他地方)。

【讨论】:

    猜你喜欢
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多