写点什么

【iOS 逆向】小陈手牵手带你看懂 iOS 伪代码

作者:小陈
  • 2022-11-10
    四川
  • 本文字数:12347 字

    阅读完需:约 41 分钟

前言

上一篇文章带大家简单的入门了 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;}@endint 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



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


1.main 函数

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



源码如下:

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 调试等



源码如下:

- (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



用户头像

小陈

关注

和昨天不一样 2019-03-12 加入

公众号:移动端Android和iOS开发技术分享

评论

发布
暂无评论
【iOS逆向】小陈手牵手带你看懂iOS伪代码_移动安全_小陈_InfoQ写作社区