小陈手牵手带你看懂iOS伪代码

前言

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


一、学前知识

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

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创建一个对象,并调用该对象的方法:

@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 加载制作好的二进制文件,下载链接: 百度网盘 请输入提取码 提取码: pem9

image-20221110183827046

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

1.main函数

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

image-20221110184500927

源码如下:

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后的伪代码如下:

__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

源码如下:

- (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后的伪代码如下:

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方法的源码如下:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"首页列表";
    [self.view addSubview:self.tableView];
}

F5后的伪代码如下:

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:方法的源码如下:

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

F5后的伪代码如下:

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:方法,我们这就先看该方法。

源码如下:

@property (assign, nonatomic) NSInteger row;

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

@interface DetailViewController : UIViewController {
    NSInteger _row;	// 这就类似于java的变量,但在iOS里,其他对象是无法直接读写该对象,所以就生成了对应的get和set方法
}

// get方法
- (NSInteger)row {
    return _row;
}

// set方法
- (void)setRow:(NSInteger)row {
    _row = row;
}

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

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

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

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

ViewDidLoad源码如下:

- (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后的伪代码如下:

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:源码如下:

- (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后的伪代码如下:

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的伪代码:

__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

2 个赞

就这????

1 个赞