首页
社区
课程
招聘
[原创]小陈手牵手带你看懂iOS伪代码
2022-11-10 21:13 22014

[原创]小陈手牵手带你看懂iOS伪代码

2022-11-10 21:13
22014

前言

上一篇文章带大家简单的入门了iOS开发,本文以上篇文章的二进制文件为例,带大家如何在IDA Pro里看懂iOS的伪代码。


一、学前知识

java创建一个对象,并调用该对象的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Person {
    String getResult(String a, String b, String c) {
        String result = a + b + c;
        return result;
    }
}
 
public static void main(String[] args) {
      Person p = new Person();
      String str1 = "i";
      String str2 = "am";
          String str3 = "wit";
      String result = p.getResult(str1, str2, str3);
}

oc创建一个对象,并调用该对象的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@interface Person : NSObject
 
- (NSString *)getResult:(NSString *)a b:(NSString *)b c:(NSString *)c;
 
@end
 
@implementation Person
 
- (NSString *)getResult:(NSString *)a b:(NSString *)b c:(NSString *)c{
    NSString *result = [a stringByAppendingString:b];
    result = [result stringByAppendingString:c];
    return result;
}
 
@end
 
int main(int argc, char * argv[]) {
    Person *p = [[Person alloc] init];
    NSString *str1 = @"i";
    NSString *str2 = @"am";
    NSString *str3 = @"wit";
    NSString *result = [p getResult:str1 b:str2 c:str3];
}

在java语言中的Person类中有一个方法,该方法的方法名是getResult,返回值为字符串,有三个形参。而在oc语言中的Person类中也有一个方法,该方法的方法名是getResult:b:c:,返回值同为字符串,也有三个形参,看懂了吗?也就是在oc的方法,有参数的情况下,把方法的返回值去掉,形参及对应的类型去掉,剩下的,拼一块,才是方法名,聪明的你也许发现了,只要有一个形参,方法名有一定有一个:符号。

二、工具

  • mac系统

  • IDA Pro:静态分析

三、步骤

使用IDA Pro 加载制作好的二进制文件,下载链接: https://pan.baidu.com/s/1I9kLns3fkEd8jXf5T4F91g?pwd=pem9 提取码: pem9

 

image-20221110183827046

 

注意:文章中针对每一行伪代码都进行了注释,中间有重复类似的部分。当你没有耐心时,一定要看最后一个网络请求的伪代码。

1.main函数

默认情况IDA Pro加载后,会打开start函数,这也就是App对应的main函数,如上图。如果你不在这位置,可通过左侧的搜索。或Exports选项,去找到start函数:

 

image-20221110184500927

 

源码如下:

1
2
3
4
5
6
7
8
int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

F5后的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
__int64 __fastcall start(__int64 a1, __int64 a2)
{
  // 定义变量,忽略就行了
  __int64 v2; // x19
  __int64 v3; // x20
  __int64 v4; // x21
  void *v5; // x0
  __int64 v6; // x0
  __int64 v7; // x22
  __int64 v8; // x19
 
    // 形参赋值
  v2 = a2;    // 形参赋值
  v3 = a1;    // 形参赋值
 
  // @autoreleasepool {}函数会被编译成objc_autoreleasePoolPush 和 objc_autoreleasePoolPop,忽略就行了
  v4 = objc_autoreleasePoolPush();
 
  // 等价于 [AppDelegate class]
  v5 = objc_msgSend(&OBJC_CLASS___AppDelegate, "class");
 
  // 这和源码一样
  v6 = NSStringFromClass(v5);
 
  // 就理解为 v7 = v6即可
  v7 = objc_retainAutoreleasedReturnValue(v6);
 
  // 这就是autoreleasepool函数的结束标志
  objc_autoreleasePoolPop(v4);
 
  // 这和源码一样
  v8 = UIApplicationMain(v3, v2, 0LL, v7);
 
  // 忽略
  objc_release(v7);
  return v8;
}

2.应用初始化成功后回调函数

应用创建成功后,会回调到main函数里的AppDelegate类的application:didFinishLaunchingWithOptions:方法,一般在这方法里创建第一个界面,并对程序里的代码进行初始化操作,比如一些SDK,越狱检测,lldb调试等

 

image-20221110190233447

 

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 
    // 第一个页面
    ViewController *viewController = [[ViewController alloc] init];
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
 
    // 初始化并显示第一个页面
    self.window = [[UIWindow  alloc] init];
    self.window.backgroundColor = [UIColor whiteColor];
    self.window.frame = [[UIScreen mainScreen] bounds];
    self.window.rootViewController = navigationController;
    [self.window makeKeyAndVisible];
    return YES;
}

F5后的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
bool __cdecl -[AppDelegate application:didFinishLaunchingWithOptions:](AppDelegate *self, SEL a2, id a3, id a4)
{
  // 定义变量,忽略就行了
  AppDelegate *v4; // x20
  void *v5; // x0
  void *v6; // x19
  __int64 v7; // x1
  __int64 v8; // x2
  __int64 v9; // x3
  void *v10; // x0
  void *v11; // x21
  __int64 v12; // x1
  __int64 v13; // x2
  __int64 v14; // x3
  void *v15; // x0
  void *v16; // x22
  void *v17; // x0
  __int64 v18; // x23
  UIWindow *v19; // x0
  void *v20; // x24
  void *v21; // x0
  void *v22; // x23
  double v23; // d0
  double v24; // d8
  double v25; // d1
  double v26; // d9
  double v27; // d2
  double v28; // d10
  double v29; // d3
  double v30; // d11
  UIWindow *v31; // x0
  void *v32; // x24
  UIWindow *v33; // x0
  void *v34; // x23
  UIWindow *v35; // x0
  void *v36; // x20
 
    // 当前对象,相当于java的this
  v4 = self;
 
  //  [[ViewController alloc] init] 也可以分开写 ViewController *vc = [ViewController alloc];       // vc = [vc init]; iOS的初始化一般不会分开写。后边也有类似代码
 
  // 等价于 [[ViewController alloc] init]相当于java的new, 后边的a2 a3 a4 忽略就行了,IDA Pro造成的,汇编是没有这三参数的,
  v5 = (void *)objc_alloc(&OBJC_CLASS___ViewController, a2, a3, a4);
  v6 = objc_msgSend(v5, "init");
 
  // 等价于  UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
  v10 = (void *)objc_alloc(&OBJC_CLASS___UINavigationController, v7, v8, v9);
  v11 = objc_msgSend(v10, "initWithRootViewController:", v6);    // 这儿的V6就是上边的ViewController对象
 
  // 等价于 [[UIWindow  alloc] init]
  v15 = (void *)objc_alloc(&OBJC_CLASS___UIWindow, v12, v13, v14);
  v16 = objc_msgSend(v15, "init");
 
  // self.window 代表当前对象有一个window变量(默认带有setWindow:(赋值)方法和window(获取)方法,这两方法由编译器自动生成)。当调用self.window = V16时,实际就是调用了setWindow:方法给变量赋值
  -[AppDelegate setWindow:](v4, "setWindow:", v16);
 
  // 忽略
  objc_release(v16);
 
  // self.window.backgroundColor = [UIColor whiteColor]; 分成右边的创建和左边的赋值两部分
 
  // 右边的创建对象
  v17 = objc_msgSend(&OBJC_CLASS___UIColor, "whiteColor");
  v18 = objc_retainAutoreleasedReturnValue(v17);
 
  // v4就是self对象, 这行代码相当于v19 = self.window
  v19 = ((UIWindow *(__cdecl *)(AppDelegate *, SEL))objc_msgSend)(v4, "window");
  // V20 = v19
  v20 = (void *)objc_retainAutoreleasedReturnValue(v19);
 
  // v20.setBackgroundColor = v18
  objc_msgSend(v20, "setBackgroundColor:", v18);
 
  // 忽略
  objc_release(v20);
  objc_release(v18);
 
  // 等价于 v21 = [UIScreen mainScreen]
  v21 = objc_msgSend(&OBJC_CLASS___UIScreen, "mainScreen");
 
  // v22 = v21;
  v22 = (void *)objc_retainAutoreleasedReturnValue(v21);
 
  // 等价于 [v22 bounds]
  objc_msgSend(v22, "bounds");
 
  // 这就是获取到的x,y,width,height
  v24 = v23;
  v26 = v25;
  v28 = v27;
  v30 = v29;
 
  // v31 = self.window 或 v31 = [self window]两者一个意思
  v31 = ((UIWindow *(__cdecl *)(AppDelegate *, SEL))objc_msgSend)(v4, "window");
 
  // v32 = v31
  v32 = (void *)objc_retainAutoreleasedReturnValue(v31);
 
  // v31.frame = CGRect(x, y, width, height)
  objc_msgSend(v32, "setFrame:", v24, v26, v28, v30);
 
  // 释放内存,忽略
  objc_release(v32);
  objc_release(v22);
 
  // v33 = [self window]
  v33 = ((UIWindow *(__cdecl *)(AppDelegate *, SEL))objc_msgSend)(v4, "window");
 
  // v34 = v33
  v34 = (void *)objc_retainAutoreleasedReturnValue(v33);
 
  // [v34 setRootViewController:v11]
  objc_msgSend(v34, "setRootViewController:", v11);
 
  // 忽略
  objc_release(v34);
 
  // v35 = self.window
  v35 = ((UIWindow *(__cdecl *)(AppDelegate *, SEL))objc_msgSend)(v4, "window");
 
  // v36 = v35
  v36 = (void *)objc_retainAutoreleasedReturnValue(v35);
 
  // [v36 makeKeyAndVisible] 显示当前window
  objc_msgSend(v36, "makeKeyAndVisible");
 
  // 忽略
  objc_release(v36);
  objc_release(v11);
  objc_release(v6);
  return 1;
}

3.第一个页面(ViewController)

ViewDidLoad方法的源码如下:

1
2
3
4
5
6
- (void)viewDidLoad {
    [super viewDidLoad];
 
    self.title = @"首页列表";
    [self.view addSubview:self.tableView];
}

F5后的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void __cdecl -[ViewController viewDidLoad](ViewController *self, SEL a2)
{
    // 变量定义
  ViewController *v2; // x19
  void *v3; // x0
  void *v4; // x20
  UITableView *v5; // x0
  __int64 v6; // x19
  ViewController *v7; // [xsp+0h] [xbp-20h]
  __objc2_class *v8; // [xsp+8h] [xbp-18h]
 
  v2 = self;
  v7 = self;
 
  // 忽略,F5造成的
  v8 = &OBJC_CLASS___ViewController;
 
  // 注意objc_msgSendSuper2是调用父类的方法,
  // 等价于 [super viewDidLoad]。super就类似于java的super
  objc_msgSendSuper2(&v7, "viewDidLoad", self, &OBJC_CLASS___ViewController);
 
  // objc_msgSend是调用当前类的方法,下边代码等价于 self.title = @"首页列表" or [self setTitle:@"首页列表"]
  objc_msgSend(v2, "setTitle:", CFSTR("首页列表"));
 
  // v3 = self.view;
  v3 = objc_msgSend(v2, "view");
 
  // v4 = v3;
  v4 = (void *)objc_retainAutoreleasedReturnValue(v3);
 
  // v5 = self.tableView or v5 = [self tableView]
  v5 = -[ViewController tableView](v2, "tableView");
 
  // v6 = v5
  v6 = objc_retainAutoreleasedReturnValue(v5);
 
  // [v4 addSubview:v6];
  objc_msgSend(v4, "addSubview:", v6);
 
  // 释放内存,忽略
  objc_release(v6);
  objc_release(v4);
}

tableView:didSelectRowAtIndexPath:方法的源码如下:

1
2
3
4
5
6
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // 点击列表时,跳转到详情页
    DetailViewController *detailViewController = [[DetailViewController alloc] init];
    detailViewController.row = indexPath.row;   // 传一个参数过去
    [self.navigationController pushViewController:detailViewController animated:YES];
}

F5后的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
void __cdecl -[ViewController tableView:didSelectRowAtIndexPath:](ViewController *self, SEL a2, id a3, id a4)
{
 
// 定义变量
  ViewController *v4; // x19
  void *v5; // x21
  __int64 v6; // x1
  __int64 v7; // x2
  __int64 v8; // x3
  void *v9; // x0
  void *v10; // x20
  void *v11; // x22
  void *v12; // x0
  void *v13; // x19
 
  v4 = self;
 
  // v5 = a4
  v5 = (void *)objc_retain(a4, a2, a3);
 
  // v9 = [DetailViewController alloc];
  v9 = (void *)objc_alloc(&OBJC_CLASS___DetailViewController, v6, v7, v8);
 
  // v10 = [v9 init];
  v10 = objc_msgSend(v9, "init");
 
  // v11 = [v5 row];
  v11 = objc_msgSend(v5, "row");
 
  // 释放内存
  objc_release(v5);
 
  // [v10 setRow:v11];
  objc_msgSend(v10, "setRow:", v11);
 
  // v12 = self.navigationController;
  v12 = objc_msgSend(v4, "navigationController");
 
  // v13 = v12;
  v13 = (void *)objc_retainAutoreleasedReturnValue(v12);
 
  // [v13 pushViewController:v10 animated:YES];
  objc_msgSend(v13, "pushViewController:animated:", v10, 1LL);
 
  // 内存释放
  objc_release(v13);
  objc_release(v10);
}

4.详情页(DetailViewController)

在ViewController类的tableView:didSelectRowAtIndexPath:方法里,创建完DetailViewController对象后,有调用setRow:方法,我们这就先看该方法。

 

源码如下:

1
@property (assign, nonatomic) NSInteger row;

这就类似于java的变量,但在编译时,会自动生成setRow:row方法。自动生成的代码大概如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
@interface DetailViewController : UIViewController {
    NSInteger _row;    // 这就类似于java的变量,但在iOS里,其他对象是无法直接读写该对象,所以就生成了对应的get和set方法
}
 
// get方法
- (NSInteger)row {
    return _row;
}
 
// set方法
- (void)setRow:(NSInteger)row {
    _row = row;
}

row方法F5后的伪代码如下:

1
2
3
4
5
signed __int64 __cdecl -[DetailViewController row](DetailViewController *self, SEL a2)
{
// 是不是感觉有点熟悉,对滴。oc类,编译后,就是一个c的结构体
  return self->_row;
}

setRow:方法F5后的伪代码如下:

1
2
3
4
5
6
// 注意:括号里有三个参数。第一个形参是当前对象,第二个形参是当前方法名,第三个形参就是我们传过来的参数(后边以此类推)
void __cdecl -[DetailViewController setRow:](DetailViewController *self, SEL a2, signed __int64 a3)
{
// 不解释
  self->_row = a3;
}

ViewDidLoad源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void)viewDidLoad {
    [super viewDidLoad];
 
    self.view.backgroundColor = [UIColor whiteColor];
 
    UILabel *tipsLabel = [[UILabel alloc] init];
    tipsLabel.frame = CGRectMake(0, 100, 100, 40);
    tipsLabel.text = @"这是详情页";
    tipsLabel.textColor = [UIColor redColor];
    [self.view addSubview:tipsLabel];
 
    UIButton *loginButton = [UIButton buttonWithType:UIButtonTypeCustom];
    loginButton.frame = CGRectMake(0, 150, 80, 40);
    [loginButton setTitle:@"登录" forState:UIControlStateNormal];
    [loginButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [loginButton addTarget:self action:@selector(loginButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
 
    [self.view addSubview:loginButton];
}

F5后的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
void __cdecl -[DetailViewController viewDidLoad](DetailViewController *self, SEL a2)
{
// 定义变量
  DetailViewController *v2; // x19
  void *v3; // x0
  __int64 v4; // x21
  void *v5; // x0
  void *v6; // x22
  __int64 v7; // x1
  __int64 v8; // x2
  __int64 v9; // x3
  void *v10; // x0
  void *v11; // x21
  void *v12; // x0
  __int64 v13; // x22
  void *v14; // x0
  void *v15; // x24
  void *v16; // x0
  void *v17; // x24
  void *v18; // x0
  __int64 v19; // x23
  void *v20; // x0
  void *v21; // x19
  DetailViewController *v22; // [xsp+0h] [xbp-60h]
  __objc2_class *v23; // [xsp+8h] [xbp-58h]
 
  v2 = self;
  v22 = self;
  v23 = &OBJC_CLASS___DetailViewController;
 
  // [super viewDidLoad];
  objc_msgSendSuper2(&v22, "viewDidLoad", self, &OBJC_CLASS___DetailViewController);
 
  // v3 = [UIColor whiteColor];
  v3 = objc_msgSend(&OBJC_CLASS___UIColor, "whiteColor");
 
  // v4 = v3;
  v4 = objc_retainAutoreleasedReturnValue(v3);
 
  // v5 = self.view; 或 v5 = [self view];
  v5 = objc_msgSend(v2, "view");
 
  // v6 = v5;
  v6 = (void *)objc_retainAutoreleasedReturnValue(v5);
 
  // [v6 setBackgroundColor:v4];
  objc_msgSend(v6, "setBackgroundColor:", v4);
 
  // 内存释放
  objc_release(v6);
  objc_release(v4);
 
  // 创建UILabel对象 v10 = [UILabel alloc];
  v10 = (void *)objc_alloc(&OBJC_CLASS___UILabel, v7, v8, v9);
 
  // 初始化 v11 = [v10 init];
  v11 = objc_msgSend(v10, "init");
  // 设置坐标 [v11 setFrame:CGRect(x, y ,width, height)]; 有些伪代码会造成误解,看不明白时,切到汇编看看
  objc_msgSend(v11, "setFrame:", 0.0);
 
  // [v11 setText:@"这是详情页"];
  objc_msgSend(v11, "setText:", CFSTR("这是详情页"));
 
  // v12 = [UIColor redColor];
  v12 = objc_msgSend(&OBJC_CLASS___UIColor, "redColor");
 
  // v13 = v12;
  v13 = objc_retainAutoreleasedReturnValue(v12);
 
  // 给label设置颜色 [v11 setTextColor:v13];
  objc_msgSend(v11, "setTextColor:", v13);
 
  // 以后遇到这种,直接忽略
  objc_release(v13);
 
  // v14 = [self view];
  v14 = objc_msgSend(v2, "view");
 
  // v15 = v14;
  v15 = (void *)objc_retainAutoreleasedReturnValue(v14);
 
  // [v15 addSubview:v11]; 将label添加到当前页面
  objc_msgSend(v15, "addSubview:", v11);
  objc_release(v15);
 
  // v16 = [UIButton buttonWithType:0];
  v16 = objc_msgSend(&OBJC_CLASS___UIButton, "buttonWithType:", 0LL);
 
  // v17 = v16;
  v17 = (void *)objc_retainAutoreleasedReturnValue(v16);
 
  // [v17 setFrame:CGRect(x, y, width, height)];
  objc_msgSend(v17, "setFrame:", 0.0, 150.0, 80.0, 40.0);
  // [v17 setTitle:@"登录" forState: 0]; 给按钮设置标题
  objc_msgSend(v17, "setTitle:forState:", CFSTR("登录"), 0LL);
 
  // v18 = [UIColor blackColor];
  v18 = objc_msgSend(&OBJC_CLASS___UIColor, "blackColor");
 
  // v19 = v18;
  v19 = objc_retainAutoreleasedReturnValue(v18);
 
  // [v17 setTitleColor:v19 forState:0]; 给按钮的标题设置颜色
  objc_msgSend(v17, "setTitleColor:forState:", v19, 0LL);
  objc_release(v19);
 
  // 给按钮添加一个方法,点击时会触发
  // [v17 addTarget: self action:@SEL(loginButtonDidClick:) forControlEvents: click];
  objc_msgSend(v17, "addTarget:action:forControlEvents:", v2, "loginButtonDidClick:", 64LL);
 
     // v20 = self.view     当前控制器的视图
 v20 = objc_msgSend(v2, "view");
 
     // v21 = v20;
  v21 = (void *)objc_retainAutoreleasedReturnValue(v20);
 
  // [v21 addSubview:v17];
  objc_msgSend(v21, "addSubview:", v17);
  objc_release(v21);
  objc_release(v17);
  objc_release(v11);
}

按钮点击触发的事件loginButtonDidClick:源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- (void)loginButtonDidClick:(UIButton *)sender {
 
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"微信公众号"] = @"移动端Android和iOS开发技术分享";
    params[@"QQ群"] = @"812546729";
 
    NSData *body = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];
 
    // 调用登录接口
    NSURL *loginURL = [NSURL URLWithString:@"https://127.0.0.1:9080/login"];    // 接口
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:loginURL]; // 请求对象
    request.HTTPMethod = @"POST";    // 请求方式
    [request setValue:@"d83kd9d323" forHTTPHeaderField:@"x-sign"];   // 设置header
    request.HTTPBody = body;    // 注意,HTTPBody是一个16进制数据,一般直接16进制输出,再转换成文本查看
 
    NSURLSession *session = [NSURLSession sharedSession];   // 获取网络对象
    NSURLSessionTask *task = [session dataTaskWithRequest:request
                                        completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // 请求结果会调到这
 
        if (error != nil) {
            NSLog(@"出错了");
            return;
        }
 
        NSLog(@"获取到的二进制文件为:%@", data);
 
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"tips" message:@"请求完成" preferredStyle:UIAlertControllerStyleAlert];
 
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self dismissViewControllerAnimated:YES completion:nil];
        }];
        [alertController addAction:okAction];
        [self presentViewController:alertController animated:YES completion:nil];
 
    }]; // 创建请求任务
    [task resume];  // 发起网络请求
}

F5后的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
void __cdecl -[DetailViewController loginButtonDidClick:](DetailViewController *self, SEL a2, id a3)
{
// 定义变量
  DetailViewController *v3; // x20
  void *v4; // x0
  void *v5; // x19
  void *v6; // x0
  __int64 v7; // x21
  void *v8; // x0
  __int64 v9; // x0
  __int64 v10; // x22
  void *v11; // x0
  void *v12; // x23
  void *v13; // x0
  void *v14; // x0
  void *v15; // x24
  void *v16; // x0
  void *v17; // x20
  void **v18; // [xsp+8h] [xbp-58h]
  __int64 v19; // [xsp+10h] [xbp-50h]
  __int64 (__fastcall *v20)(); // [xsp+18h] [xbp-48h]
  void *v21; // [xsp+20h] [xbp-40h]
  DetailViewController *v22; // [xsp+28h] [xbp-38h]
 
  v3 = self;
 
  // 创建一个字典 v4 = [NSMutableDictionary dictionary];
  v4 = objc_msgSend(&OBJC_CLASS___NSMutableDictionary, "dictionary", a3);
 
  // v5 = v4;
  v5 = (void *)objc_retainAutoreleasedReturnValue(v4);
 
  // 给字典添加一个键值对 v5[@"微信公众号"] = @"移动端Android和iOS开发技术分享";
  objc_msgSend(
    v5,
    "setObject:forKeyedSubscript:",
    CFSTR("移动端Android和iOS开发技术分享"),
    CFSTR("微信公众号"));
 
  // 给字典添加一个键值对 v5[@"QQ群"] = @"812546729";
  objc_msgSend(v5, "setObject:forKeyedSubscript:", CFSTR("812546729"), CFSTR("QQ群"));
 
  // 将字典转换成二进制流
  v6 = objc_msgSend(&OBJC_CLASS___NSJSONSerialization, "dataWithJSONObject:options:error:", v5, 1LL, 0LL);
 
  // v7 = v6;
  v7 = objc_retainAutoreleasedReturnValue(v6);
 
  // 创建URL对象,并传入接口地址 v8 = [NSURL URLWithString:@"https://127.0.0.1:9080/login"];
  v8 = objc_msgSend(&OBJC_CLASS___NSURL, "URLWithString:", CFSTR("https://127.0.0.1:9080/login"));
  // v9 = v8;
  v9 = objc_retainAutoreleasedReturnValue(v8);
 
  // v10 = v9
  v10 = v9;
 
  // 封装请求的地址及请求参数 v11 = [NSMutableURLRequest requestWithURL: v9];
  v11 = objc_msgSend(&OBJC_CLASS___NSMutableURLRequest, "requestWithURL:", v9);
 
  // v12 = v11;
  v12 = (void *)objc_retainAutoreleasedReturnValue(v11);
 
  // 设置请求方式为POST [v12 setHTTPMethod: @"POST"];
  objc_msgSend(v12, "setHTTPMethod:", CFSTR("POST"));
 
  // 设置请求的header [v12 setValue:@"d83kd9d323" forHTTPHeaderField:@"x-sign"];
  objc_msgSend(v12, "setValue:forHTTPHeaderField:", CFSTR("d83kd9d323"), CFSTR("x-sign"));
 
  // 设置请求参数 [v12 setHTTPBody: v7];
  objc_msgSend(v12, "setHTTPBody:", v7);
 
  // 获取系统的网络请求处理对象 v13 = [NSURLSession sharedSession];
  v13 = objc_msgSend(&OBJC_CLASS___NSURLSession, "sharedSession");
 
  // v14 = v13;
  v14 = (void *)objc_retainAutoreleasedReturnValue(v13);
 
  // v15 = v14
  v15 = v14;
 
  // 匿名的c函数,以sub_开头。也就是当你看到block,sub_等关键字。就把这理解为一个c函数即可,函数名为sub_100004CE8
  v18 = _NSConcreteStackBlock;
  v19 = 3254779904LL;
  v20 = sub_100004CE8;
  v21 = &unk_1000080A8;
 
  v22 = v3;
 
  // 创建网络请求的任务 v16 = [v14 dataTaskWithRequest:v12 completionHandler:sub_100004CE8],请求完成后,会调用sub_100004CE8函数
  v16 = objc_msgSend(v14, "dataTaskWithRequest:completionHandler:", v12, &v18);
 
  // v17 = v16;
  v17 = (void *)objc_retainAutoreleasedReturnValue(v16);
 
  // 任务开始执行 [v17 resume];
  objc_msgSend(v17, "resume");
 
  objc_release(v17);
  objc_release(v15);
  objc_release(v12);
  objc_release(v10);
  objc_release(v7);
  objc_release(v5);
}

接着再看网络请求完成后的回调函数sub_100004CE8的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
__int64 __fastcall sub_100004CE8(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
// 定义变量
  __int64 v4; // ST40_8
  __int64 v5; // ST48_8
  void *v6; // x0
  void *v7; // x0
  __int64 v9; // [xsp+50h] [xbp-70h]
  void **v10; // [xsp+58h] [xbp-68h]
  int v11; // [xsp+60h] [xbp-60h]
  int v12; // [xsp+64h] [xbp-5Ch]
  __int64 (__fastcall *v13)(); // [xsp+68h] [xbp-58h]
  void *v14; // [xsp+70h] [xbp-50h]
  __int64 v15; // [xsp+78h] [xbp-48h]
  __int64 v16; // [xsp+80h] [xbp-40h]
  void *v17; // [xsp+88h] [xbp-38h]
  int v18; // [xsp+94h] [xbp-2Ch]
  __int64 v19; // [xsp+98h] [xbp-28h]
  __int64 v20; // [xsp+A0h] [xbp-20h]
  __int64 v21; // [xsp+A8h] [xbp-18h]
  __int64 v22; // [xsp+B0h] [xbp-10h]
  __int64 v23; // [xsp+B8h] [xbp-8h]
 
  v9 = a1;    // self
  v4 = a3;    // response
  v5 = a4;  // error
 
  // a1就是DetailViewController对象
  v23 = a1;   
  v22 = 0LL;
  // v22 = a2
  objc_storeStrong(&v22, a2);
  v21 = 0LL;
  // v21 = v4;
  objc_storeStrong(&v21, v4);
  v20 = 0LL;
  // v20 = v5;
  objc_storeStrong(&v20, v5);
  v19 = v9;
 
  // 如果有错误信息
  if ( v20 )
  {
    NSLog(CFSTR("出错了"));
    v18 = 1;
  }
  else
  {
 
      // 这儿输出获取到的data数据,F5有问题,看汇编
    NSLog(CFSTR("获取到的二进制文件为:%@"));
 
    // 创建弹窗对象 v6 = [UIAlertController alertControllerWithTitle: @"tips" message:@"请求完成" preferredStyle: 1];
    v6 = objc_msgSend(
           &OBJC_CLASS___UIAlertController,
           "alertControllerWithTitle:message:preferredStyle:",
           CFSTR("tips"),
           CFSTR("请求完成"),
           1LL);
 
    // v17 = v6;
    v17 = (void *)objc_retainAutoreleasedReturnValue(v6);
 
    // block,匿名函数。一般这种匿名函数的位置,会在当前函数的后边。
    v10 = _NSConcreteStackBlock;
    v11 = -1040187392;
    v12 = 0;
    v13 = __44__DetailViewController_loginButtonDidClick___block_invoke_2;
    v14 = &__block_descriptor_40_e8_32s_e23_v16__0__UIAlertAction_8l;
 
    // v15 = self
    v15 = objc_retain(*(_QWORD *)(v9 + 32));
 
    // v7 = [UIAlertAction actionWithTitle:@"ok" style:0 handler:block];
    v7 = objc_msgSend(&OBJC_CLASS___UIAlertAction, "actionWithTitle:style:handler:", CFSTR("ok"), 0LL, &v10);
 
    // v16 = v7;
    v16 = objc_retainAutoreleasedReturnValue(v7);
 
    // [v17 addAction:v16]; 给弹窗添加一个ok按钮
    objc_msgSend(v17, "addAction:", v16);
 
    // [self presentViewController: v17 animated:YES completion:nil]; 显示弹窗
    objc_msgSend(*(void **)(v9 + 32), "presentViewController:animated:completion:", v17, 1LL);
 
    // 内存释放 和 objc_release一个意思
    objc_storeStrong(&v16, 0LL);
    objc_storeStrong(&v15, 0LL);
    objc_storeStrong(&v17, 0LL);
    v18 = 0;
  }
  // 内存释放
  objc_storeStrong(&v20, 0LL);
  objc_storeStrong(&v21, 0LL);
  return objc_storeStrong(&v22, 0LL);
}

总结

码字不易,如果对你有帮助,关注我吧。

提示:阅读此文档的过程中遇到任何问题,请关注公众号【移动端Android和iOS开发技术分享】或加QQ群【812546729

 

IMG_4048


[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞1
打赏
分享
最新回复 (3)
雪    币: 4089
活跃值: (8230)
能力值: ( LV9,RANK:181 )
在线值:
发帖
回帖
粉丝
nevinhappy 2 2022-11-11 08:23
2
0
iOS的deb文件修改了,怎么啥工具可以打包回去 ?
雪    币: 668
活跃值: (1205)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
witchan 2022-11-11 08:52
3
0
nevinhappy iOS的deb文件修改了,怎么啥工具可以打包回去 ?
dpkg-deb
游客
登录 | 注册 方可回帖
返回