6

从 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 方法表示中有一些字符串

在此处输入图像描述

我猜有些选择器会传递给函数。我对吗?

4

1 回答 1

11

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

:; 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

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

:; 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

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

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

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

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

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

无论如何,棘手的部分是机器代码__objc_selrefs使用 PC 相对寻址从该部分加载指针。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(取决于处理器模式)。 这记录在这里(可能还有其他地方)。

于 2013-04-05T08:18:11.667 回答