目录
一、查看OC方法汇编
准备如下代码:
// Person.h
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
+ (instancetype)person;
@end
// Person.m
@implementation Person
+ (instancetype)person {
return [[Person alloc] init];
}
@end
// main.m
int main(int argc, char * argv[]) {
Person *p = [Person person];
return 0;
}
汇编如下:
OC-Method`main:
0x1021f1ed0 <+0>: sub sp, sp, #0x30 ; =0x30
0x1021f1ed4 <+4>: stp x29, x30, [sp, #0x20]
0x1021f1ed8 <+8>: add x29, sp, #0x20 ; =0x20
0x1021f1edc <+12>: stur wzr, [x29, #-0x4]
0x1021f1ee0 <+16>: stur w0, [x29, #-0x8]
0x1021f1ee4 <+20>: str x1, [sp, #0x10]
0x1021f1ee8 <+24>: adrp x8, 8
0x1021f1eec <+28>: add x8, x8, #0x3d0 ; =0x3d0
0x1021f1ef0 <+32>: ldr x0, [x8]
0x1021f1ef4 <+36>: adrp x8, 8
0x1021f1ef8 <+40>: add x8, x8, #0x3c0 ; =0x3c0
0x1021f1efc <+44>: ldr x1, [x8]
0x1021f1f00 <+48>: bl 0x1021f2250 ; symbol stub for: objc_msgSend
这里objc_msgSend方法有两个参数:id、SEL、汇编中通过x0和x1寄存器传递参数
0x1021f1f04 <+52>: mov x29, x29
0x1021f1f08 <+56>: bl 0x1021f2274 ; symbol stub for: objc_retainAutoreleasedReturnValue
0x1021f1f0c <+60>: add x8, sp, #0x8 ; =0x8
0x1021f1f10 <+64>: str x0, [sp, #0x8]
-> 0x1021f1f14 <+68>: stur wzr, [x29, #-0x4]
0x1021f1f18 <+72>: mov x0, x8
0x1021f1f1c <+76>: mov x8, #0x0
0x1021f1f20 <+80>: mov x1, x8
0x1021f1f24 <+84>: bl 0x1021f228c ; symbol stub for: objc_storeStrong
第一个参数为p(实例对象)的地址,第二参数为0x0(nil)
调用objc_storeStrong相当于将p(实例对象)释放了
0x1021f1f28 <+88>: ldur w0, [x29, #-0x4]
0x1021f1f2c <+92>: ldp x29, x30, [sp, #0x20]
0x1021f1f30 <+96>: add sp, sp, #0x30 ; =0x30
0x1021f1f34 <+100>: ret
查看x0和x1寄存器中的值:
objc_storeStrong:
void
objc_storeStrong(id *location, id obj)
{
id prev = *location;
if (obj == prev) {
return;
}
objc_retain(obj);
*location = obj;
objc_release(prev);
}
二、使用反汇编工具分析汇编
修改main
中的代码:
int main(int argc, char * argv[]) {
Person *p = [Person person];
p.name = @"differ";
p.age = 18;
return 0;
}
编译-->将编译后的可执行文件拖到Hopper
中:
三、Block反汇编
int main(int argc, char * argv[]) {
void (^block)(void) = ^() {
NSLog(@"block");
};
block();
return 0;
}
由于block中的实现代码保存到invoke中的,所以分析block汇编代码主要找到invoke
struct Block_ layout {
void *isa; // 8字节
volatile int32_t flags; // contains ref count 4字节
int32_t reserved; // 4字节
BlockInvokeFunction invoke; // 因此invoke变量地址就是block地址+16字节
struct Block_descriptor_1 *descriptor;
// imported variables
};
block地址为0x0000000104d0c028,因此invoke的保存在0x104d0c038指向的变量中(0x104d09ed4)
Hopper
中查看Block的invoke:
Hopper
中还能查看流程图、伪代码
Hopper
的伪代码可读性很差,一般使用IDA。IDA还能动态调试。
网友评论