【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; // x21void *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; // x20void *v5; // x0void *v6; // x19__int64 v7; // x1__int64 v8; // x2__int64 v9; // x3void *v10; // x0void *v11; // x21__int64 v12; // x1__int64 v13; // x2__int64 v14; // x3void *v15; // x0void *v16; // x22void *v17; // x0__int64 v18; // x23UIWindow *v19; // x0void *v20; // x24void *v21; // x0void *v22; // x23double v23; // d0double v24; // d8double v25; // d1double v26; // d9double v27; // d2double v28; // d10double v29; // d3double v30; // d11UIWindow *v31; // x0void *v32; // x24UIWindow *v33; // x0void *v34; // x23UIWindow *v35; // x0void *v36; // x20// 当前对象,相当于java的thisv4 = 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.windowv19 = ((UIWindow *(__cdecl *)(AppDelegate *, SEL))objc_msgSend)(v4, "window");// V20 = v19v20 = (void *)objc_retainAutoreleasedReturnValue(v19);// v20.setBackgroundColor = v18objc_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,heightv24 = v23;v26 = v25;v28 = v27;v30 = v29;// v31 = self.window 或 v31 = [self window]两者一个意思v31 = ((UIWindow *(__cdecl *)(AppDelegate *, SEL))objc_msgSend)(v4, "window");// v32 = v31v32 = (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 = v33v34 = (void *)objc_retainAutoreleasedReturnValue(v33);// [v34 setRootViewController:v11]objc_msgSend(v34, "setRootViewController:", v11);// 忽略objc_release(v34);// v35 = self.windowv35 = ((UIWindow *(__cdecl *)(AppDelegate *, SEL))objc_msgSend)(v4, "window");// v36 = v35v36 = (void *)objc_retainAutoreleasedReturnValue(v35);// [v36 makeKeyAndVisible] 显示当前windowobjc_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; // x19void *v3; // x0void *v4; // x20UITableView *v5; // x0__int64 v6; // x19ViewController *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的superobjc_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 = v5v6 = 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; // x19void *v5; // x21__int64 v6; // x1__int64 v7; // x2__int64 v8; // x3void *v9; // x0void *v10; // x20void *v11; // x22void *v12; // x0void *v13; // x19v4 = self;// v5 = a4v5 = (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; // x19void *v3; // x0__int64 v4; // x21void *v5; // x0void *v6; // x22__int64 v7; // x1__int64 v8; // x2__int64 v9; // x3void *v10; // x0void *v11; // x21void *v12; // x0__int64 v13; // x22void *v14; // x0void *v15; // x24void *v16; // x0void *v17; // x24void *v18; // x0__int64 v19; // x23void *v20; // x0void *v21; // x19DetailViewController *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"]; // 设置headerrequest.HTTPBody = body; // 注意,HTTPBody是一个16进制数据,一般直接16进制输出,再转换成文本查看NSURLSession *session = [NSURLSession sharedSession]; // 获取网络对象NSURLSessionTask *task = [session dataTaskWithRequest:requestcompletionHandler:^(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; // x20void *v4; // x0void *v5; // x19void *v6; // x0__int64 v7; // x21void *v8; // x0__int64 v9; // x0__int64 v10; // x22void *v11; // x0void *v12; // x23void *v13; // x0void *v14; // x0void *v15; // x24void *v16; // x0void *v17; // x20void **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 = v9v10 = 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 = v14v15 = v14;// 匿名的c函数,以sub_开头。也就是当你看到block,sub_等关键字。就把这理解为一个c函数即可,函数名为sub_100004CE8v18 = _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_8void *v6; // x0void *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; // selfv4 = a3; // responsev5 = a4; // error// a1就是DetailViewController对象v23 = a1;v22 = 0LL;// v22 = a2objc_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 = selfv15 = 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开发技术分享









评论