浅谈iOS性能优化之APP崩溃与hook方案

iOS(越狱) 应用脱壳反编译hook教程 (系统ios11.3.1) 为什么会有这边博文? 因为公司原因,领导又让我捡起荒废了一年多的ios,了解对ios应用脱壳以及反编译hook相关知识.相比于安卓的hook来说(想了解安卓hook的可以参考我的另外一篇文章),ios的hook要麻烦的多,前人栽树后人乘凉,希望我的这边文章能给大家对ios的hook有个清晰的认识和思路. 一. 项目需求 本文以很久以前上架的一个练手app为例(app有点烂,将就一下吧,点击传送门)... 阅读详情

本篇文章将为大家讲解下crash监控及防崩溃处理。

  • 如何收集crash

  • 利用bugly、友盟等第三方收集

  • 监控crash原理

  • 防崩溃处理

  • 常见崩溃类型

  • 防崩溃处理方案

  • hook方案

  • 安全接口

如何收集crash

在平常开发过程中,由于代码的不严谨比如不对入参做校验,使用C++野指针等会造成程序crash。crash应该算是最严重的bug了,尤其是线上crash,如果App用户量大的话可能造成很大的影响,所以需要有一套机制来收集项目中的crash并及时解决。

利用bugly、友盟等第三方收集

大部分公司都是采用第三方平台来收集crash。业内用的比较多有bugly、友盟、talkingdata。笔者比较推荐bugly,腾讯研发,比较轻量,用来监控crash和卡顿还是很方便的。

监控crash原理

一线大厂,大部分都会自研crash捕获框架。这个时候了解crash捕获原理就很有必要了,大家可以阅读开源库kscrash或者plcrashreporter其实捕获crash原理很简单。主要需要处理两种情况:

1、OC类异常。NSException异常是OC代码导致的crash。我们可以先通过NSGetUncaughtExceptionHandler保存先前注册的异常处理器,然后通过NSSetUncaughtExceptionHandler设置我们自己的异常处理器,我们不监控了,需要再设置回原理的异常处理器,在我们自己的uncaughtHandleException处理器里面,需要手动调用下原来的处理器。

static NSUncaughtExceptionHandler* g_previousUncaughtExceptionHandler;
void installUncaughtExceptionHandler(void){
    g_previousUncaughtExceptionHandler = NSGetUncaughtExceptionHandler();
    NSSetUncaughtExceptionHandler(&uncaughtHandleException);
}
void uninstallUncaughtExceptionHandler(void){
    if(g_previousUncaughtExceptionHandler){
        NSSetUncaughtExceptionHandler(g_previousUncaughtExceptionHandler);
    }
}
void uncaughtHandleException(NSException *exception)
{
    // 异常的堆栈信息
    NSArray *stackArray = [exception callStackSymbols];
    // 出现异常的原因
    NSString *reason = [exception reason];
    // 异常名称
    NSString *name = [exception name];
    NSString *exceptionInfo = [NSString stringWithFormat:@"Exception reason:%@\nException name:%@\nException stack:%@",name, reason, stackArray];
    NSLog(exceptionInfo);
    if (g_previousUncaughtExceptionHandler != NULL)
    {
        g_previousUncaughtExceptionHandler(exception);
    }
}

2、Signal信号捕获。Signal信号是由iOS底层mach信号异常转换后以signal信号抛出的异常。既然是兼容posix标准的异常,我们同样可以通过sigaction函数注册对应的信号。

static struct sigaction* g_previousSignalHandlers = NULL; //旧的信号处理函数结构体数组
static int g_fatalSignals[] = {
    SIGHUP,
    SIGINT,
    SIGQUIT,
    SIGABRT,
    SIGILL,
    SIGSEGV,
    SIGFPE,
    SIGBUS,
    SIGPIPE
};
static int g_fatalSignalsCount = (sizeof(g_fatalSignals) / sizeof(g_fatalSignals[0]));
const int* kssignal_fatalSignals(void){
    return g_fatalSignals;
}
int kssignal_numFatalSignals(void){
    return g_fatalSignalsCount;
}
void signalExceptionHandler(int signo, siginfo_t *info, void *uapVoid){
    void *frames[128];
    int i, len = backtrace(frames, 128);
    //堆栈信息
    char **symbols = backtrace_symbols(frames, len);
    NSMutableString *exceptionContent = [[NSMutableString alloc] init];
    [exceptionContent appendFormat:@"signal name:%d \n signal stack:\n",signo];
    for (i = 0; i < len; ++i)
    {
        [exceptionContent appendFormat:@"%s\r\n", symbols[i]];
    }
    //释放缓存
    free(symbols);
    raise(signo);
}
void installSignalHandler(void){
    const int* fatalSignals = kssignal_fatalSignals();
    int fatalSignalsCount = kssignal_numFatalSignals();
    if(g_previousSignalHandlers == NULL){
        g_previousSignalHandlers = (struct sigaction *)malloc(sizeof(*g_previousSignalHandlers)
                                                              * (unsigned)fatalSignalsCount);
    }
    //初始化处理函数结构体
    struct sigaction action = {{0}};
    action.sa_flags = SA_SIGINFO | SA_ONSTACK;
    sigemptyset(&action.sa_mask);
    action.sa_sigaction = &signalExceptionHandler;
    for(int i = 0; i < fatalSignalsCount; i++)
    {
        if(sigaction(fatalSignals[i], &action, &g_previousSignalHandlers[i]) != 0)
        {
            // 取消已监听的handler
            for(i--;i >= 0; i--)
            {
                sigaction(fatalSignals[i], &g_previousSignalHandlers[i], NULL);
            }
            break;
        }
    }
}
void uninstallSignalHandler(void){
    const int* fatalSignals = kssignal_fatalSignals();
    int fatalSignalsCount = kssignal_numFatalSignals();
    for(int i = 0; i < fatalSignalsCount; i++)
    {
        sigaction(fatalSignals[i], &g_previousSignalHandlers[i], NULL);
    }
}

防崩溃处理

常见崩溃类型

根据笔者经验来看,oc中大部分崩溃都是源于没有对调用方法进行入参判断,比如数组添加object没有判空,访问数组元素越界等;还有一些C++崩溃,比如使用野指针。

防崩溃处理方案

由于oc中大部分崩溃都是来源于未对入参进行判断,所以调用方法对入参进行判断就能解决崩溃。如何统一地解决这类崩溃,有两种方案:hook方案和安全接口

hook方案

该方案对系统常见类的方法进行hook,进行入参判断。比如对hook NSMutableArray的addObject方法,进行判空操作。

@implementation NSMutableArray (akSafe)
+ (void)load {
    [self swizzMethodOriginalSelector:@selector(addObject:)
                     swizzledSelector:@selector(akSafe_addObject:)];
}
+ (void)swizzMethodOriginalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
    Method originalMethod = class_getInstanceMethod(self.class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(self.class, swizzledSelector);
    BOOL didAddMethod = class_addMethod(self.class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(self.class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
- (void)aksafe_AddObject:(id)anObject {
    if (anObject) {
        [self aksafe_AddObject:anObject];
    }
}
@end

安全接口

该方案对系统常见类的方法进行一层封装,进行入参判断。大家统一调用安全接口,比如封装NSMutableArray的addObject方法为aksafe_AddObject,大家统一调用aksafe_AddObject添加对象。

@implementation NSMutableArray (aksafe)
- (void)aksafe_AddObject:(id)anObject {
    if (anObject) {
        [self addObject:anObject];
    }
}
@end

两种方案各有优缺点,hook方案优点是业务方直接调用系统方法就行,缺点是由于要进行hook,有损性能;安全接口方案是业务方要统一调用安全接口,优点则是轻量。笔者推荐方案二,轻量并且可以作为编码规范。

iOS NSException与NSSetUncaughtExceptionHandler处理异常 前言 hihi,勇敢的小伙伴儿们大家好, 了解这个是因为我在项目里集成了Bugly,即使不在开发过程,用户使用项目产生崩溃的时候也能将崩溃的原因上传到服务器上,尤其是试运营的版本,能够为后期优化App和减少Bug数提供不少方便,记得以前看安卓代码有try/catch的捕捉异常和处理异常的操作(此处存疑,记不太清了),想着iOS异常是怎么捕捉到的呢?于是有了这篇博客。 接下来跟大家一起学习一下N... 阅读详情

相关推荐

xposed 框架学习

xposed 框架学习 xposed 框架学习 一xposed 启动过程 app_main 虚拟机 二hook流程分析 findAndHookMethod findMethodExact hookMethod 1hookMethodNative hookedMethodCallback handleHookedMethod invokeOriginalMethodNative 三注册流程分析一、xp...

djhsws的专栏 4532

Frida hook/invoke iOS以及内存搜刮和黑盒调用

终于学到了Frida的部分,在本篇中我们将从objection这款自动化hook框架的源码出发,学习使用Frida内置的ApiResolver搜刮器来枚举内存中的所有符号,包括所有类/所有方法/所有重载,再对其进行hook后输出参数调用栈返回值,并且对参数与返回值进行修改,以实现修改函数逻辑的目的。

大数据安全技术学习 4万+

iOS逆向之hook框架frida的安装和使用

一、Frida Frida 是一款基于 Python + javascript 的 hook 框架,通杀 android\iOS\linux\win\osx 各平台。Frida 原理是手机端安装一个 server 程序把手机端的端口转到 PC 端写的 python 脚本进行通信,而 Python 脚本中采用 javascript 语言编写 hook 代码。 ① install frida on device Start Cydia and add Frida’s repository by navig

╰つ栺尖篴夢ゞ 7万+

带你打造一套 APM 监控系统(四)

七、 Crash 监控 1. 异常相关知识回顾 1.1 Mach 层对异常的处理 Mach 在消息传递基础上实现了一套独特的异常处理方法。Mach 异常处理在设计时考虑到: 带有一致的语义的单一异常处理设施:Mach 只提供一个异常处理机制用于处理所有类型的异常(包括用户定义的异常、平台无关的异常以及平台特定的异常)。根据异常类型进行分组,具体的平台可以定义具体的子类型。 清晰和简洁:异常处理的接口依赖于 Mach 已有的具有良好定义的消息和端口架构,因此非常优雅(不会影响效率)。这就允许调试器和外部处

GSNICE 6270

非越狱环境下iOS逆向工程技术实战:dylib注入、重签名与App Hook

dylib注入技术利用了iOS系统的动态链接库(dynamic library,dylib)特性。动态链接库是包含可由多个程序共享的代码和数据的文件。当一个程序执行时,这些库的代码和资源被链接到程序中。在非越狱的iOS设备上,所有的应用程序都运行在沙盒环境中,为了确保系统的安全性和稳定性,Apple对沙盒环境做了严格的限制,应用程序不能直接操作其他应用程序的数据和代码。然而,通过dylib注入技术,我们可以动态地将自定义的代码注入到目标应用程序中,以此来修改应用程序的行为,或者为其添加新的功能。

weixin_31961675的博客 1960

WPF插件架构-如何动态加载封装好的第三方DLL的界面

插件架构中如何自动加载第三方DLL中的UI界面

lg24k的博客 1882

KSCrash源码阅读(Monitors)

前言 版本:1.15.18 这一篇主要介绍如何捕获异常的,由于KSCrash做了反调试,阅读起来有点麻烦,只能一步一步的阅读源码来探寻原理 Monitors 这个目录下面对crash的类型进行了分类处理,挑几个重点的来看 KSCrashMonitor_NSException #import "KSCrash.h" #import "KSCrashMonitor_NSException...

Nate的博客 2652

1.1.4 运用防火墙实现入侵防御

摘要:本文详细介绍了某公司网络拓扑中防火墙FW1的配置过程。主要内容包括:1)通过web界面登录防火墙;2)配置三个接口的IP地址及所属安全区域;3)创建两个入侵防御配置文件(anti_untrust和anti_trust);4)配置安全策略untrust2dmz和trust2dmz,分别允许公网/内网访问WWW服务器;5)保存配置。操作步骤配有详细截图说明,涉及接口配置、安全区域划分、入侵防御策略设定等关键环节,最终实现内外网对服务器Server1的安全访问控制。(149字)

Ljs040411的博客 2130

一文读懂iOS线程调用栈原理

高级程序员都深入到汇编、寄存器、内核排查bug,你还在看日志嘛?本文带你窥探汇编、函数调用过程及寄存器的使用,并深入到内核,掌握KSCrash崩溃收集框架最重要的:线程调用栈原理。其实原理很简单,走起~ 简介 使用场景 说到线程调用栈大家肯定都不陌生,比如我们经常debug调试时断点查看调用栈,如下图所示: 还有应用排除bug的崩溃日志报告或者使用崩溃日志收集工具来收集整个线程的调用栈,如下图: 还要一个重要的用途就是应用性能优化中的“卡顿检测”,需要获取主线程的调用栈,来检测具体的函数调用过程分析.

henry_lei的博客 943

从零搭建:基于Matlab/Simulink与FlightGear的飞行器实时可视化仿真平台

本文详细介绍了如何从零搭建基于Matlab/Simulink与FlightGear的飞行器实时可视化仿真平台。通过环境准备、模型部署、接口配置及联合仿真等步骤,帮助用户快速掌握飞行器仿真的核心技术,实现高效的三维可视化与实时数据交互。

weixin_29100399的博客 517

Voicebox本地部署:模型下载与离线模式实战指南

在本地语音处理场景中,模型下载失败和离线运行需求是开发者最常遇到的两大难题。理解语音工具的本地推理原理,关键在于掌握模型文件与程序逻辑的分离管理:模型独立下载,程序负责推理,输出留在本机。这种架构带来显著的技术价值——数据不出本地、不依赖公网、批量任务不中断。无论是语音识别转写、语音合成,还是集成到自动化脚本中,本地离线模式都能在隐私敏感或网络不稳定环境下稳定运行。对开发者而言,先解决模型文件的完整获取,再验证离线启动流程,就能绕过“无法下载模型”的常见坑。本文从环境准备、模型放置、服务启动到接口调用,提供

weixin_29048309的博客 306

iOS中几种hook代码的方法

iOS中Object-C代码的主要hook方式。其原理是利用OC的Runtime特性,动态改变SEL(方法编号)和IMP(方法实现)的对应关系,达到OC方法调用流程改变的目的。比如, 我们可以通过hook字典NSMutableDictionary的 setObject:forKey和removeObjectForKey:方法,帮助其实现空安全。2.dobby是一个开源的第三方框架,主要用于C、C++等静态代码的hook。其原理是,直接修改目标函数的头部代码(修改的是内存中MachO的代码段。

老猿的自留地 3399

基于YOLO11的垃圾分类AI模型训练实战

通过这次实战,我们成功训练出了一个高性能的垃圾分类AI模型。项目展示了从数据准备、模型训练到结果分析的完整流程,为AI在环保领域的应用提供了有价值的参考。项目文件结构│ ├── best.pt # 最佳模型权重│ └── last.pt # 最新模型权重├── results.csv # 详细训练数据├── results.png # 训练曲线图├── confusion_matrix.png # 混淆矩阵└── args.yaml # 训练参数配置。

lydz1的博客 1657

iOS中常用的第三方框架

ios第三方框架

qq_43658148的博客 2724

Skill的嵌套

Skill的嵌套就很简单,直接引用其他的Skill就好了。在一个 Skill 的 SKILL.md 中,可以明确指示 Claude 去读取另一个 Skill 的文档。

Criss@陈磊 956

静态时序分析—伪路径(set_false_path)

set_false_path应用场景

m0_61544122的博客 2万+

iOS 崩溃捕获:使用 NSSetUncaughtExceptionHandler

在 iOS 开发中,应用崩溃是一个常见且严重的问题。为了提升用户体验,开发者需要了解如何捕获和处理崩溃信息,从而进行调试和改进。NSSetUncaughtExceptionHandler 是一种简单有效的方式来捕获未处理的异常并进行相应处理。

qq_43673244的博客 890

2. Android_逆向的历史与发展

学完本节,希望你能够:了解 Android 逆向工程的发展历程,从早期 APK 破解到现代应用保护;入门先把这几类「在干啥」搞清楚,后面学脱壳、反反调试会顺很多。(反编译 APK 得到的类汇编代码,相当于程序的「菜谱」)就能绕过验证,到后来混淆、加固、反调试一起上,逆向难度越来越高。(第三节 什么是 CPU 指令集),帮你搞清楚「反汇编看到的那些指令」是从哪来的、和 Android 逆向有啥关系。有必要——先搞清「没加固时怎么玩」,再学脱壳和对抗,思路才顺。读起来费劲,但逻辑还在,耐心一点还能跟。

长沙火山 1390

APP安全测试——HOOK技术

最近学习app的测试学会了客户端的测试方法。只知道怎么实现将其中存在的漏洞和不合规项找出来但是不知道其中的原理。一直再说HOOK技术,也就是所谓的钩子今天了解一下他到底是个啥东西。 HOOK Hook 英文翻译过来就是「钩子」的意思,那我们在什么时候使用这个「钩子」呢?在 Android 操作系统中系统维护着自己的一套事件分发机制。应用程序,包括应用触发事件和后台逻辑处理,也是根据事件流程一步步地向下执行。而「钩子」的意思,就是在事件传送到终点前截获并监控事件的传输,像个钩子钩上事件一样,并且能够在钩上事件

LiBai'S BLOG 2万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

iOS Hook 崩溃

被Hook写的Hook。

豪冷的博客 628

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

iOS - 关于对App跳转方法的hook

文章目录App的跳转方法hook App的跳转方法 实现app跳转有urlscheme以及universal Link(deep link) 跳转。 url scheme application:openURL:options:是最新的方法,其他两个都废弃了 - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id&gt

CaicaiNo.1 1475

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

iOS 稳定性问题治理:卡死崩溃监控原理及最佳实践

文章会持续更新的。绝对干货!!!Android进阶学习全套手册关于实战,我想每一个做开发的都有话要说,对于小白而言,缺乏实战经验是通病,那么除了在实际工作过程当中,我们如何去更了解实战方面的内容呢?实际上,我们很有必要去看一些实战相关的电子书。

2401_84024148的博客 1420

IOS 之FishHook原理及例子

一、HOOK概述 HOOK,中文为“钩子”或“挂钩”,在ios逆向中是指改变程序的运行流程的一种技术,通过hook可以让别人的程序执行自己的代码逻辑,在逆向中经常使用。所以就来看看HOOK的原理吧! 上图很常见的微信抢红包,hook原理就相当于程序本来收到红包消息用户应该点击红包之后点击“抢”,才能领红包,而通过HOOK既可以执行自己的代码,用户不需要点击自动执行抢红包代码,这就是...

qq_39153421的博客 2538

关于如何hook原生短信

最近在研究iPhone手机上的app短信HOOK,试着去修改原生短信的APP界面和程序,现在正在进行中,完成了,再告诉大家,请大家关注我的博客,谢谢。

miemie1320的专栏 1975

在 ReactNative 的 App 中,集成 Bugly 你会遇到的一些坑

一、前言最近开新项目,准备尝试一下 ReactNative,所以前期做了一些调研工作,ReactNative 的优点非常的明显,可以做到跨平台,除了少部分 UI 效果可能需要对不同的平台进行单独适配,其中的核心逻辑代码,都是可以重用的。所以如果最终用 ReactNative 的话,可以省出某一端的客户端开发人员。而我这里调研的主要方向,就是它对国内第三方 SDK 的支持。 在国内,开发 App,...

weixin_34380296的博客 399

《挑战不用macOS逆向iOS APP》之ObjC语法、iOS应用开发、及Objection自动化hook入门

本篇文章是《挑战不用macOS逆向iOS APP》系列的第二课iOS逆向基础知识主要为了了解在iOS APP逆向过程中一些常见知识

大数据安全技术学习 4万+
上一篇: springboot:YAML语言整体概述
下一篇: iOS跨线程与跨进程通讯
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值