iOS安全和逆向系列教程 第10篇:实战项目:逆向分析流行社交应用

iOS逆向工程专栏 第10篇:实战项目:逆向分析流行社交应用

作者:自学不成才

在前几篇文章中,我们深入探讨了iOS应用的静态分析、动态分析和保护技术。现在,是时候将这些知识付诸实践,通过一个实战项目来展示iOS逆向工程的完整流程。本文将以一个假设的流行社交应用"SocialShare"为例,演示如何分析和修改其核心功能。

注意:本文中的"SocialShare"是一个虚构的应用,所有分析和修改过程仅用于教育目的。在实际操作中,请确保你的逆向工程活动符合法律法规和伦理准则。

项目概述

目标应用介绍

"SocialShare"是一款假设的社交分享应用,具有以下特点:

  • 用户可以发布短文和图片
  • 内置高级滤镜功能(部分需要付费)
  • 具有好友关系和私密消息系统
  • 实现了多种安全保护措施

逆向工程目标

我们的逆向工程目标包括:

  1. 分析应用的整体架构和通信机制
  2. 研究用户认证和会话管理实现
  3. 了解付费功能验证流程
  4. 分析隐私保护和加密机制
  5. 修改应用行为(仅作演示,不鼓励实际应用)

准备工作

工具准备
  • 越狱设备(iPhone 8, iOS 14.3)
  • Mac开发机(macOS Monterey)
  • Frida(v15.1.17)
  • IDA Pro/Ghidra
  • Hopper Disassembler
  • LLDB调试器
  • Charles Proxy
  • 辅助工具:class-dump, otool, MachOView
环境设置
# 在Mac上安装Frida
pip install frida-tools

# 在越狱设备上安装Frida服务器
scp frida-server-15.1.17-ios-arm64 [email protected]:/usr/sbin/frida-server
ssh [email protected] "chmod +x /usr/sbin/frida-server"
ssh [email protected] "nohup /usr/sbin/frida-server &"

# 验证连接
frida-ps -U | grep SocialShare

初步分析

应用基本信息收集

首先,我们提取并分析应用的基本信息:

# 获取应用二进制
ssh [email protected] "cd /var/containers/Bundle/Application/*/SocialShare.app/ && tar -cf /tmp/SocialShare.tar *"
scp [email protected]:/tmp/SocialShare.tar ./
mkdir SocialShare && tar -xf SocialShare.tar -C SocialShare

# 使用file命令检查二进制类型
file SocialShare/SocialShare

# 检查加密状态
otool -l SocialShare/SocialShare | grep -A4 LC_ENCRYPTION_INFO

# 如果应用已加密,使用frida-ios-dump工具提取解密后的二进制
python3 dump.py "SocialShare"

应用权限和沙盒分析

# 分析Info.plist查看权限
plutil -p SocialShare/Info.plist

# 查看沙盒目录
ssh [email protected] "find /var/mobile/Containers/Data/Application/*/Library/Preferences/*SocialShare* -type f"
ssh [email protected] "find /var/mobile/Containers/Data/Application/*/Documents -type f | grep -v '.DS_Store'"

提取头文件和分析类结构

# 提取Objective-C类信息
class-dump -H SocialShare.decrypted -o SocialShare_headers

# 搜索关键类
grep -r "Controller" SocialShare_headers/
grep -r "Manager" SocialShare_headers/
grep -r "Service" SocialShare_headers/

通过分析头文件,我们找到了一些关键类:

// 用户管理相关
@interface SSUserManager : NSObject
+ (instancetype)sharedManager;
- (BOOL)isUserLoggedIn;
- (void)loginWithUsername:(NSString *)username password:(NSString *)password completion:(void (^)(SSUser *, NSError *))completion;
- (void)storeAuthToken:(NSString *)token;
- (NSString *)currentAuthToken;
@end

// 帖子管理相关
@interface SSPostManager : NSObject
+ (instancetype)sharedManager;
- (void)fetchTimelinePosts:(void (^)(NSArray<SSPost *> *, NSError *))completion;
- (void)createPostWithText:(NSString *)text image:(UIImage *)image filter:(SSFilterType)filter completion:(void (^)(SSPost *, NSError *))completion;
@end

// 滤镜相关
@interface SSFilterManager : NSObject
+ (instancetype)sharedManager;
- (NSArray<SSFilter *> *)availableFilters;
- (BOOL)isFilterPremium:(SSFilterType)filterType;
- (BOOL)userHasAccessToFilter:(SSFilterType)filterType;
- (UIImage *)applyFilter:(SSFilterType)filterType toImage:(UIImage *)image;
@end

// 网络相关
@interface SSNetworkService : NSObject
+ (instancetype)sharedInstance;
- (NSURLRequest *)requestWithPath:(NSString *)path method:(NSString *)method parameters:(NSDictionary *)parameters;
- (void)sendRequest:(NSURLRequest *)request completion:(void (^)(id, NSError *))completion;
@end

// 安全相关
@interface SSSecurityManager : NSObject
+ (instancetype)sharedInstance;
- (NSString *)encryptString:(NSString *)string;
- (NSString *)decryptString:(NSString *)string;
- (BOOL)verifyAppIntegrity;
@end

动态库分析

# 查看应用依赖的动态库
otool -L SocialShare.decrypted

输出显示应用使用了以下关键框架:

/System/Library/Frameworks/Security.framework/Security
/System/Library/Frameworks/CoreImage.framework/CoreImage
/System/Library/Frameworks/AVFoundation.framework/AVFoundation
/usr/lib/libz.dylib
/usr/lib/libsqlite3.dylib

网络请求初步分析

使用Charles Proxy设置代理,并安装证书以捕获HTTPS流量:

  1. 在iOS设备上设置Charles代理
  2. 安装Charles根证书
  3. 启动应用并监控网络流量

初步观察发现以下API端点:

POST /api/v1/auth/login
GET /api/v1/user/profile
GET /api/v1/posts/timeline
POST /api/v1/posts/create
GET /api/v1/filters/list

请求头中包含以下字段:

Authorization: Bearer 
X-Device-ID: 
X-Client-Version: 2.5.0
X-Signature: 

深入分析

认证机制分析

使用Frida分析登录过程:

// auth-analysis.js
Java.perform(function() {
    var UserManager = ObjC.classes.SSUserManager;
    
    // 监控登录方法
    Interceptor.attach(UserManager["- loginWithUsername:password:completion:"].implementation, {
        onEnter: function(args) {
            var username = ObjC.Object(args[2]).toString();
            var password = ObjC.Object(args[3]).toString();
            
            console.log("[+] Login attempt:");
            console.log("    Username: " + username);
            console.log("    Password: " + password);
            
            // 保存callback以便后续使用
            this.completionBlock = args[4];
        }
    });
    
    // 监控令牌存储
    Interceptor.attach(UserManager["- storeAuthToken:"].implementation, {
        onEnter: function(args) {
            var token = ObjC.Object(args[2]).toString();
            console.log("[+] Auth token stored:");
            console.log("    Token: " + token);
        }
    });
    
    // 监控网络服务
    var NetworkService = ObjC.classes.SSNetworkService;
    Interceptor.attach(NetworkService["- requestWithPath:method:parameters:"].implementation, {
        onEnter: function(args) {
            var path = ObjC.Object(args[2]).toString();
            var method = ObjC.Object(args[3]).toString();
            var parameters = ObjC.Object(args[4]);
            
            if (path.indexOf("/auth") !== -1) {
                console.log("[+] Auth-related network request:");
                console.log("    Path: " + path);
                console.log("    Method: " + method);
                console.log("    Parameters: " + parameters);
            }
        }
    });
});

运行Frida脚本并尝试登录:

frida -U -l auth-analysis.js SocialShare

通过分析,我们了解到:

  1. 登录请求使用JSON格式发送用户名和密码
  2. 身份验证使用基于JWT的令牌系统
  3. 令牌存储在Keychain中
  4. 请求签名使用HMAC-SHA256算法,结合设备ID、时间戳和请求路径

付费功能验证分析

接下来,分析应用如何验证付费滤镜功能:

// premium-filter-analysis.js
Java.perform(function() {
    var FilterManager = ObjC.classes.SSFilterManager;
    
    // 监控滤镜访问检查方法
    Interceptor.attach(FilterManager["- userHasAccessToFilter:"].implementation, {
        onEnter: function(args) {
            var filterType = args[2].toInt32();
            console.log("[+] Checking access to filter type: " + filterType);
            this.filterType = filterType;
        },
        onLeave: function(retval) {
            console.log("[+] Access check result for filter " + this.filterType + ": " + retval);
            
            // 强制允许访问所有滤镜(仅用于演示)
            // retval.replace(1);
        }
    });
    
    // 监控滤镜高级状态检查
    Interceptor.attach(FilterManager["- isFilterPremium:"].implementation, {
        onEnter: function(args) {
            var filterType = args[2].toInt32();
            this.filterType = filterType;
        },
        onLeave: function(retval) {
            console.log("[+] Filter " + this.filterType + " is premium: " + retval);
        }
    });
});

运行脚本并测试滤镜功能:

frida -U -l premium-filter-analysis.js SocialShare

通过分析,我们发现:

  1. 滤镜类型由整数ID表示(1-10为基本滤镜,11-20为高级滤镜)
  2. 高级滤镜状态存储在用户配置文件中
  3. 验证流程包括:
    • 检查滤镜ID是否在高级列表中
    • 查询用户的购买记录
    • 验证购买收据的有效性

安全机制分析

分析应用的安全保护措施:

// security-analysis.js
Java.perform(function() {
    // 反调试保护
    var ptrace = Module.findExportByName(null, "ptrace");
    if (ptrace) {
        Interceptor.attach(ptrace, {
            onEnter: function(args) {
                if (args[0].toInt32() === 31) { // PT_DENY_ATTACH
                    console.log("[!] Anti-debugging detected: ptrace PT_DENY_ATTACH");
                }
            }
        });
    }
    
    // 越狱检测
    var NSFileManager = ObjC.classes.NSFileManager;
    Interceptor.attach(NSFileManager["- fileExistsAtPath:"].implementation, {
        onEnter: function(args) {
            var path = ObjC.Object(args[2]).toString();
            
            // 越狱相关路径
            var jailbreakPaths = [
                "/Applications/Cydia.app",
                "/Library/MobileSubstrate/MobileSubstrate.dylib",
                "/bin/bash",
                "/usr/sbin/sshd",
                "/etc/apt"
            ];
            
            for (var i = 0; i < jailbreakPaths.length; i++) {
                if (path.indexOf(jailbreakPaths[i]) !== -1) {
                    console.log("[!] Jailbreak detection checking path: " + path);
                    break;
                }
            }
        }
    });
    
    // 数据加密
    var SecurityManager = ObjC.classes.SSSecurityManager;
    
    // 监控加密方法
    Interceptor.attach(SecurityManager["- encryptString:"].implementation, {
        onEnter: function(args) {
            var string = ObjC.Object(args[2]).toString();
            console.log("[+] Encrypting string: " + string);
            this.original = string;
        },
        onLeave: function(retval) {
            var encrypted = ObjC.Object(retval).toString();
            console.log("[+] Encryption result: " + encrypted);
            console.log("[+] Original -> Encrypted: " + this.original + " -> " + encrypted);
        }
    });
    
    // 监控解密方法
    Interceptor.attach(SecurityManager["- decryptString:"].implementation, {
        onEnter: function(args) {
            var string = ObjC.Object(args[2]).toString();
            console.log("[+] Decrypting string: " + string);
            this.encrypted = string;
        },
        onLeave: function(retval) {
            var decrypted = ObjC.Object(retval).toString();
            console.log("[+] Decryption result: " + decrypted);
            console.log("[+] Encrypted -> Original: " + this.encrypted + " -> " + decrypted);
        }
    });
    
    // 完整性验证
    Interceptor.attach(SecurityManager["- verifyAppIntegrity"].implementation, {
        onLeave: function(retval) {
            console.log("[+] App integrity check result: " + retval);
        }
    });
});

运行安全分析脚本:

frida -U -l security-analysis.js SocialShare

分析结果显示:

  1. 应用实现了以下安全措施:

    • 反调试保护(ptrace)
    • 越狱检测(文件系统检查)
    • 敏感数据AES加密
    • 代码签名验证
    • 网络请求签名
  2. 加密分析:

    • 使用AES-256-CBC加密
    • 密钥由设备ID和应用ID派生
    • 初始化向量(IV)固定存储在应用中

修改应用行为

注意:以下修改仅用于教育目的,展示逆向工程的可能性。不鼓励在实际应用中使用这些技术。

创建全面的绕过脚本

基于分析结果,我们创建一个综合脚本,绕过应用的保护措施:

// comprehensive-bypass.js
Java.perform(function() {
    console.log("[+] SocialShare Bypass Script Loaded");
    
    // 1. 绕过安全检查
    
    // 绕过反调试
    var ptrace = Module.findExportByName(null, "ptrace");
    if (ptrace) {
        Interceptor.attach(ptrace, {
            onEnter: function(args) {
                if (args[0].toInt32() === 31) {
                    console.log("[*] Bypassing ptrace anti-debugging");
                    args[0] = ptr(0); // 替换为PT_NULL
                }
            }
        });
    }
    
    // 绕过越狱检测
    var NSFileManager = ObjC.classes.NSFileManager;
    Interceptor.attach(NSFileManager["- fileExistsAtPath:"].implementation, {
        onEnter: function(args) {
            var path = ObjC.Object(args[2]).toString();
            
            // 越狱相关路径
            var jailbreakPaths = [
                "/Applications/Cydia.app",
                "/Library/MobileSubstrate/MobileSubstrate.dylib",
                "/bin/bash",
                "/usr/sbin/sshd",
                "/etc/apt",
                "/private/var/lib/apt"
            ];
            
            for (var i = 0; i < jailbreakPaths.length; i++) {
                if (path.indexOf(jailbreakPaths[i]) !== -1) {
                    console.log("[*] Bypassing jailbreak detection for path: " + path);
                    this.jailbreakCheck = true;
                    break;
                }
            }
        },
        onLeave: function(retval) {
            if (this.jailbreakCheck) {
                retval.replace(0); // 返回NO/false
            }
        }
    });
    
    // 绕过完整性检查
    var SecurityManager = ObjC.classes.SSSecurityManager;
    Interceptor.attach(SecurityManager["- verifyAppIntegrity"].implementation, {
        onLeave: function(retval) {
            console.log("[*] Bypassing app integrity check");
            retval.replace(1); // 返回YES/true
        }
    });
    
    // 2. 启用高级功能
    
    // 允许访问所有滤镜
    var FilterManager = ObjC.classes.SSFilterManager;
    Interceptor.attach(FilterManager["- userHasAccessToFilter:"].implementation, {
        onEnter: function(args) {
            var filterType = args[2].toInt32();
            console.log("[*] Access requested for filter: " + filterType);
        },
        onLeave: function(retval) {
            console.log("[*] Granting access to all filters");
            retval.replace(1); // 返回YES/true
        }
    });
    
    // 3. 监控网络通信
    
    // 监控网络请求
    var NetworkService = ObjC.classes.SSNetworkService;
    Interceptor.attach(NetworkService["- sendRequest:completion:"].implementation, {
        onEnter: function(args) {
            var request = ObjC.Object(args[2]);
            console.log("[+] Network request:");
            console.log("    URL: " + request.URL().absoluteString());
            console.log("    Method: " + request.HTTPMethod());
            
            // 打印请求头
            var headers = request.allHTTPHeaderFields();
            var headerKeys = headers.allKeys();
            console.log("    Headers:");
            for (var i = 0; i < headerKeys.count(); i++) {
                var key = headerKeys.objectAtIndex_(i);
                var value = headers.objectForKey_(key);
                console.log("      " + key + ": " + value);
            }
            
            // 打印请求体
            var body = request.HTTPBody();
            if (body) {
                try {
                    var bodyStr = ObjC.classes.NSString.alloc().initWithData_encoding_(body, 4).toString();
                    console.log("    Body: " + bodyStr);
                } catch (e) {
                    console.log("    Body: ");
                }
            }
        }
    });
    
    console.log("[+] SocialShare Bypass Script Ready");
});

持久化修改:创建Tweak

除了使用Frida进行动态分析和修改,我们还可以创建一个持久化的Tweak,使修改永久生效:

  1. 设置Theos环境:
# 安装Theos
git clone --recursive https://github.com/theos/theos.git $THEOS

# 创建新Tweak项目
$THEOS/bin/nic.pl
# 选择iphone/tweak模板
# 输入项目名称:SocialShareTweak
# 输入包标识符:com.example.socialsharetweak
# 输入要处理的bundle id:com.example.socialshare
  1. 编写Tweak.x文件:
// Tweak.x
#import <UIKit/UIKit.h>

// 声明需要hook的类和方法
@interface SSFilterManager : NSObject
- (BOOL)userHasAccessToFilter:(int)filterType;
- (BOOL)isFilterPremium:(int)filterType;
@end

@interface SSSecurityManager : NSObject
- (BOOL)verifyAppIntegrity;
@end

%hook SSFilterManager

// 允许访问所有滤镜
- (BOOL)userHasAccessToFilter:(int)filterType {
    NSLog(@"[SocialShareTweak] Access requested for filter: %d", filterType);
    return YES;
}

%end

%hook SSSecurityManager

// 绕过完整性检查
- (BOOL)verifyAppIntegrity {
    NSLog(@"[SocialShareTweak] Bypassing app integrity check");
    return YES;
}

%end

// 添加UI指示器,显示Tweak已激活
%hook UIApplicationDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    BOOL result = %orig;
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"SocialShareTweak"
                                                                       message:@"Tweak has been successfully loaded!"
                                                                preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
        [alert addAction:okAction];
        
        [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];
    });
    
    return result;
}

%end
  1. 编辑Makefile:
TARGET := iphone:clang:latest:14.0
ARCHS = arm64 arm64e

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = SocialShareTweak

SocialShareTweak_FILES = Tweak.x
SocialShareTweak_CFLAGS = -fobjc-arc

include $(THEOS_MAKE_PATH)/tweak.mk
  1. 编译和安装Tweak:
make
make package
make install THEOS_DEVICE_IP=192.168.1.100 THEOS_DEVICE_PORT=22

使用MonkeyDev制作修改版应用

MonkeyDev允许我们创建一个完整的修改版应用,可以重签名并安装在非越狱设备上:

  1. 设置MonkeyDev环境:
    1. 设置MonkeyDev环境(续):
# 安装MonkeyDev
git clone https://github.com/AloneMonkey/MonkeyDev.git
cd MonkeyDev
./install.sh
  1. 创建新项目:
# 创建修改版应用项目
monkeydev -N SocialShareMod -T App -p /path/to/SocialShare.ipa
  1. 编辑RootViewController.m添加修改代码:
// RootViewController.m
#import "RootViewController.h"
#import <objc/runtime.h>

@interface SSFilterManager : NSObject
- (BOOL)userHasAccessToFilter:(int)filterType;
- (BOOL)isFilterPremium:(int)filterType;
@end

@interface SSSecurityManager : NSObject
- (BOOL)verifyAppIntegrity;
@end

// 替换方法实现的函数
static BOOL new_userHasAccessToFilter(id self, SEL _cmd, int filterType) {
    NSLog(@"[SocialShareMod] Access requested for filter: %d", filterType);
    return YES;
}

static BOOL new_verifyAppIntegrity(id self, SEL _cmd) {
    NSLog(@"[SocialShareMod] Bypassing app integrity check");
    return YES;
}

@implementation RootViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 应用启动时执行的修改
    [self installHooks];
    
    // 隐藏修改器视图(或者可以添加自定义控制面板)
    self.view.hidden = YES;
}

- (void)installHooks {
    NSLog(@"[SocialShareMod] Installing hooks...");
    
    // 替换滤镜访问检查方法
    Class filterManagerClass = objc_getClass("SSFilterManager");
    if (filterManagerClass) {
        Method originalMethod = class_getInstanceMethod(filterManagerClass, @selector(userHasAccessToFilter:));
        if (originalMethod) {
            method_setImplementation(originalMethod, (IMP)new_userHasAccessToFilter);
            NSLog(@"[SocialShareMod] Successfully hooked userHasAccessToFilter:");
        }
    }
    
    // 替换完整性检查方法
    Class securityManagerClass = objc_getClass("SSSecurityManager");
    if (securityManagerClass) {
        Method originalMethod = class_getInstanceMethod(securityManagerClass, @selector(verifyAppIntegrity));
        if (originalMethod) {
            method_setImplementation(originalMethod, (IMP)new_verifyAppIntegrity);
            NSLog(@"[SocialShareMod] Successfully hooked verifyAppIntegrity");
        }
    }
    
    NSLog(@"[SocialShareMod] Hooks installed successfully");
    
    // 显示成功信息
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"SocialShareMod"
                                                                      message:@"Modifications have been successfully applied!"
                                                               preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
        [alert addAction:okAction];
        
        UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
        [keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];
    });
}

@end
  1. 编译和安装应用:
# 编译项目
cd SocialShareMod
xcodebuild clean build CODE_SIGN_IDENTITY="iPhone Developer: Your Name (XXXXXXXX)" PROVISIONING_PROFILE="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"

# 安装到设备
ios-deploy --bundle ./build/Release-iphoneos/SocialShareMod.app -W -d

高级分析:通信协议和API

通过前面的分析,我们已经了解了SocialShare应用的主要功能和保护机制。接下来,让我们深入分析应用的通信协议和API结构。

API结构分析

基于之前的网络监控,我们构建了应用API的完整映射:

1. 认证接口:
   - POST /api/v1/auth/login
   - POST /api/v1/auth/register
   - POST /api/v1/auth/refresh-token
   - POST /api/v1/auth/logout

2. 用户相关:
   - GET /api/v1/user/profile
   - PUT /api/v1/user/profile
   - GET /api/v1/user/{userID}
   - GET /api/v1/user/{userID}/posts

3. 内容相关:
   - GET /api/v1/posts/timeline
   - GET /api/v1/posts/explore
   - POST /api/v1/posts/create
   - GET /api/v1/posts/{postID}
   - DELETE /api/v1/posts/{postID}
   - POST /api/v1/posts/{postID}/like
   - DELETE /api/v1/posts/{postID}/like

4. 滤镜相关:
   - GET /api/v1/filters/list
   - GET /api/v1/filters/{filterID}
   - POST /api/v1/filters/purchase
   - GET /api/v1/filters/purchased

5. 社交相关:
   - GET /api/v1/social/friends
   - POST /api/v1/social/friends/request
   - PUT /api/v1/social/friends/request/{requestID}
   - GET /api/v1/social/messages
   - POST /api/v1/social/messages/send

请求签名算法

通过进一步分析,我们理解了请求签名的生成过程:

// 请求签名分析
function analyzeRequestSigning() {
    var NetworkService = ObjC.classes.SSNetworkService;
    var SecurityManager = ObjC.classes.SSSecurityManager;
    
    // 找到生成签名的方法
    Interceptor.attach(NetworkService["- signRequest:"].implementation, {
        onEnter: function(args) {
            var request = ObjC.Object(args[2]);
            console.log("[+] Signing request: " + request.URL().absoluteString());
        },
        onLeave: function(retval) {
            var signedRequest = ObjC.Object(retval);
            var signature = signedRequest.valueForHTTPHeaderField_("X-Signature");
            console.log("[+] Generated signature: " + signature);
            
            // 可选:分析生成的签名
            // ...
        }
    });
    
    // 监控HMAC计算
    var CCHmac = Module.findExportByName(null, "CCHmac");
    if (CCHmac) {
        Interceptor.attach(CCHmac, {
            onEnter: function(args) {
                var algorithm = args[0].toInt32();
                var keyPtr = args[1];
                var keyLen = args[2].toInt32();
                var dataPtr = args[3];
                var dataLen = args[4].toInt32();
                
                if (algorithm === 2) { // kCCHmacAlgSHA256
                    console.log("[+] HMAC-SHA256 calculation detected");
                    
                    // 读取密钥
                    var keyData = Memory.readByteArray(keyPtr, keyLen);
                    console.log("[+] HMAC Key: " + hexdump(keyData));
                    
                    // 读取数据
                    var data = Memory.readByteArray(dataPtr, Math.min(dataLen, 256));
                    console.log("[+] HMAC Data (first 256 bytes): ");
                    console.log(hexdump(data));
                    
                    // 可选:尝试解析数据为字符串
                    try {
                        var dataStr = Memory.readUtf8String(dataPtr, Math.min(dataLen, 256));
                        if (dataStr && dataStr.length > 0) {
                            console.log("[+] HMAC Data as string: " + dataStr);
                        }
                    } catch (e) {}
                }
            }
        });
    }
}

通过分析,我们发现请求签名的生成过程如下:

  1. 组合字符串:HTTP方法 + URL路径 + 请求时间戳 + 请求体(如果存在)
  2. 使用HMAC-SHA256算法和应用密钥计算签名
  3. 将签名添加到请求头的"X-Signature"字段

数据加密分析

进一步分析应用的数据加密机制:

// 深入分析加密实现
function analyzeEncryption() {
    var SecurityManager = ObjC.classes.SSSecurityManager;
    
    // 寻找密钥生成或存储的方法
    Interceptor.attach(SecurityManager["- encryptionKey"].implementation, {
        onLeave: function(retval) {
            var key = ObjC.Object(retval);
            console.log("[+] Encryption key: " + key);
            
            if (key.isKindOfClass_(ObjC.classes.NSData)) {
                var keyBytes = Memory.readByteArray(key.bytes(), key.length());
                console.log(hexdump(keyBytes));
            }
        }
    });
    
    // 监控CommonCrypto操作
    var CCCrypt = Module.findExportByName(null, "CCCrypt");
    if (CCCrypt) {
        Interceptor.attach(CCCrypt, {
            onEnter: function(args) {
                var op = args[0].toInt32(); // 0 = kCCEncrypt, 1 = kCCDecrypt
                var alg = args[1].toInt32(); // 算法
                var options = args[2].toInt32(); // 选项
                var keyPtr = args[3];
                var keyLen = args[4].toInt32();
                var ivPtr = args[5];
                var dataInPtr = args[6];
                var dataInLen = args[7].toInt32();
                
                console.log("[+] CCCrypt called with operation: " + (op === 0 ? "Encrypt" : "Decrypt"));
                console.log("    Algorithm: " + alg); // 0 = AES
                console.log("    Options: " + options); // 1 = ECB, 2 = CBC
                
                // 读取密钥
                var keyData = Memory.readByteArray(keyPtr, keyLen);
                console.log("    Key: " + hexdump(keyData));
                
                // 读取IV(如果存在)
                if (!ivPtr.isNull()) {
                    // 大多数算法使用16字节IV
                    var ivData = Memory.readByteArray(ivPtr, 16);
                    console.log("    IV: " + hexdump(ivData));
                }
                
                // 保存上下文以便在onLeave中使用
                this.op = op;
                this.dataInPtr = dataInPtr;
                this.dataInLen = dataInLen;
            },
            onLeave: function(retval) {
                // 分析操作结果
                // ...
            }
        });
    }
}

分析后,我们了解到应用的加密实现:

  1. 使用AES-256-CBC进行敏感数据加密
  2. 加密密钥由设备UUID和应用特定字符串派生
  3. IV(初始化向量)是固定的16字节值
  4. 敏感存储(如auth token)使用Keychain,并添加额外加密层

安全评估与改进建议

基于我们对SocialShare应用的深入分析,我们可以提出以下安全评估和改进建议:

安全问题

  1. 身份验证:

    • JWT令牌有效期过长(30天)
    • 刷新令牌机制不够安全
    • 缺乏多因素认证选项
  2. 加密实现:

    • 使用固定IV降低了AES-CBC的安全性
    • 加密密钥派生过程较弱
    • 本地存储的敏感数据保护不足
  3. 通信安全:

    • 证书固定实现不完整
    • 请求签名机制可以被重放
    • API缺乏速率限制防护
  4. 代码保护:

    • 混淆程度不足
    • 反调试措施可以轻易绕过
    • 越狱检测实现过于简单

改进建议

  1. 身份验证增强:

    • 缩短令牌有效期(最多24小时)
    • 实现安全的令牌刷新机制
    • 提供双因素认证选项
    • 实现设备绑定
  2. 加密增强:

    • 使用随机IV并与密文一起存储
    • 改进密钥派生过程(使用PBKDF2或类似算法)
    • 对所有敏感数据使用Keychain安全存储
  3. 通信安全增强:

    • 完善证书固定实现
    • 在请求签名中加入nonce防止重放
    • 实现API速率限制和异常行为检测
  4. 代码保护增强:

    • 增加代码混淆程度
    • 实现更复杂的反调试措施
    • 使用多层次的完整性检查
    • 添加反篡改措施

总结

在本文中,我们对一个虚构的社交应用"SocialShare"进行了全面的逆向工程分析。通过静态分析、动态分析和行为修改,我们深入了解了应用的架构、安全机制和潜在漏洞。这个案例展示了iOS逆向工程的完整流程,涵盖了前几篇文章中介绍的各种技术。

关键要点回顾

  1. 初步分析:

    • 提取应用二进制和资源
    • 分析头文件和类结构
    • 了解应用权限和沙盒布局
  2. 深入分析:

    • 研究认证机制和令牌管理
    • 分析付费功能验证流程
    • 了解应用的保护措施
  3. 修改技术:

    • 使用Frida进行动态修改
    • 创建Cydia Substrate/Theos Tweak
    • 使用MonkeyDev制作修改版应用
  4. 安全评估:

    • 识别身份验证和加密问题
    • 分析通信安全漏洞
    • 评估代码保护有效性
    • 提出全面的改进建议

实际应用

本文所展示的技术和方法可以应用于多种合法场景:

  1. 应用安全评估:

    • 发现和修复潜在安全漏洞
    • 评估应用对攻击的抵抗能力
  2. 安全研究:

    • 了解最新的保护技术和趋势
    • 研究新型攻击和防御方法
  3. 兼容性开发:

    • 理解未公开API的行为
    • 开发兼容或增强功能
  4. 教育目的:

    • 学习移动应用安全原理
    • 培训安全专业人员

伦理与法律提醒

逆向工程虽然是一种强大的技术,但也带有重要的伦理和法律责任:

  1. 始终遵守相关法律法规,尊重知识产权
  2. 获得适当的授权再进行安全测试
  3. 负责任地披露发现的安全漏洞
  4. 不要将技术用于破解付费内容或侵犯隐私

在掌握这些技术的同时,请记住权力越大,责任越大。

在下一篇文章中,我们将探讨iOS应用混淆和加固技术,学习如何从应用开发者的角度保护iOS应用免受逆向工程。


作者:自学不成才
本文为iOS逆向工程专栏的第10篇文章,版权所有,未经许可请勿转载。

你可能感兴趣的:(iOS安全和逆向系列教程,ios,cocoa,macos)