【iOS逆向】小陈手牵手带你看懂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 加载制作好的二进制文件,下载链接: 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
】