浅谈IOS如何对app进行安全加固

防止 tweak 依附

通常来说,我们要分析一个 app,最开始一般是砸壳,

$ DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/XXX.app/XXX

然后将解密之后的二进制文件扔给类似 hopper 这样的反编译器处理。直接将没有砸壳的二进制文件扔个 hopper 反编译出来的内容是无法阅读的(被苹果加密了)。所以说砸壳是破解分析 app 的第一步。对于这一步的防范,有两种方式。

1.限制二进制文件头内的段

通过在 Xcode 里面工程配置 build setting 选项中将

-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null

添加到 "Other Linker Flags"(注意这里我在项目中碰到了一个 问题,在 iPod touch iOS 9.3 的设备上,使用了 swift 的项目会导致莫名奇妙的 swift 标准库无法找到,而在 iOS 10 的设备上没有这个问题。之前并没有以为是因为添加了这个的原因,直到网上搜了所有解决方案,比如这个 SO Post 都没有效果的时候,我才发现是这个设置的原因)

2.setuid 和 setgid

Apple 不接受调用这两个函数的 app,因为它可以通过查看符号表来判断您的二进制运行文件是否包含这两个函数

检测越狱设备上是否有针对性 tweak

一般来说在越狱手机上,我们会使用 TheOS 创建 tweak 类型的工程。然后针对我们要分析的类,使用提供的 logify.pl 命令生成的 mk 文件来打印该类所有方法的入参和出参。这对分析 app 的运行方式有很大的帮助。当然,我们也可以自己创建某个类的 mk,来 hook 某个函数,让它以我们想要的方式运行,比如说对于一些做了证书绑定的 app,如果它用的框架是 AFNetWorking 的话,那么我们可以创建一个 mk 文件,hook AFSecurityPolicy 类的下列方法:

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain

让这个方法永远返回 YES,那么大多数的应用所做的证书绑定也就失效了。用过 TheOS 的 tweak 模版的话,你会发现这种方式相当简单快速。

对于这一步的防范,可以在工程的 main 函数里面加入一层判断,首先读取 /Library/MobileSubstrate/DynamicLibraries 下所有的 plist 文件的内容,查看是否某个 plist 含有你的 app 的 bundle id,是的话,可以判定有人想利用 tweak 攻击你的 app,这时候你可以采取比如说将 app 给 crash 掉,或者限制某些功能等方式来应对。

具体原理可以查看参考资料4,简单来说,就是 MobileSubstrate 在 app 加载到内存的时候会先去检查 /Library/MobileSubstrate/DynamicLibraries 下面是否有需要加载的 tweak,有的话就加载,怎么判断有没有?就是根据 plist 里面的 bundle ID 判断的。

代码参考如下

static __inline__ __attribute__((always_inline)) int anti_tweak()
{
    uint8_t lmb[] = {'S', 'u', 'b', 's', 't', 'r', 'a', 't', 'e', '/', 'D', 'y', 'n', 'a', 'm', 'i', 'c', 0, };
    NSString *dir = [NSString stringWithFormat:@"/%@/%@%s%@", @"Library", @"Mobile", lmb, @"Libraries"];
    NSArray *dirFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:nil];
    NSArray *plistFiles = [dirFiles filteredArrayUsingPredicate:
                           [NSPredicate predicateWithFormat:
                            [NSString stringWithFormat:@"%@ %@%@ '.%@%@'",@"self", @"EN", @"DSWITH", @"pli", @"st"]]];
    int cnt = 0;
    for (NSString *file in plistFiles) {
        NSString *filePath = [dir stringByAppendingPathComponent:file];
        NSString *fileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
        if (fileContent && [fileContent rangeOfString:[[NSBundle mainBundle] bundleIdentifier]].location != NSNotFound) {
            cnt ++;
        }
    }
    // 返回有针对本 app 的 tweak 数量,为 0 说明没有
    return cnt;
}

防 http 抓包

通常破解一个 app,我们会抓包。这样的话,我们的 app 所有接口,接口数据都会暴露在逆向人员的眼皮底下。这时候,我们可以限制 http 抓包。方式很简单,就是将 NSURLSessionConfiguration 的 connectionProxyDictionary 设置成空的字典,因为这个属性就是用来控制会话的可用代理的。可用参见官方文档,也就是参考资料5。下面是对于 AFNetWorking 的使用方法:

// 继承 AFHTTPSessionManager,重写下列方法
- (instancetype)initWithServerHost:(PDLServerHost*)serverHost {
#ifdef DEBUG
    // debug 版本的包仍然能够正常抓包
    self = [super initWithBaseURL:serverHost.baseURL];
#else
// 由于使用 ephemeralSessionConfiguration session 发起的请求不带 cookie 和使用缓存等
    NSURLSessionConfiguration *conf = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    conf.connectionProxyDictionary = @{};
    self = [super initWithBaseURL:serverHost.baseURL sessionConfiguration:conf];
#endif
    return self;
}

但是由于 OC 方法很容易被 hook,避免抓包是不可能的,所以,个人认为最好的方式是对请求参数进行加密(最好是非对称加密,比如 RSA)

混淆(或者加密)硬编码的明文字符串

对于被砸壳的二进制文件,逆向分析人员分析代码有一条重要线索,也就是被硬编码的明文字符串。比如说,你的 app 被人抓包了,某些数据请求接口也被人发现了,那么很简单,逆向人员可以直接拷贝特征比较明显的字符串到 hopper 中搜索,通过查看该字符串被引用的地方,可以很快的找到相应的逻辑代码。

对于这一步的防范,需要做的就是对硬编码的明文进行加密或混淆。 有个开源代码可以用,UAObfuscatedString,但是这个开源混淆代码写出来的字符串是相当长的(也就是麻烦),同时不支持加密。最近我写了一个工具,可以在编译期间加密所有代码中的明文字符串,在 app 运行的时候解密字符串。这个工具的特点如下:

1.简单,开发人员可以硬编码明文字符串,所有的加密会在编译开始时自动处理

2.可以自定义加密或者混淆方式,(为了不影响 app 运行效率,需要提供一个简单快速的加密或混淆方式)提高解密难度

使用 Swift 开发

Swift 是目前比较新的开发 iOS 语言,由于 Swift 目前还不是很稳定,越狱开源社区对这个的支持也不是很即时,比如说 class-dump 工具目前就不支持含有 Swift 的二进制文件。 TheOS 也是最近才开始支持 Swift,但是还没有加到主分支上(可以参见Features)。所以目前来看,至少 Swift 可能比纯 OC 的工程要安全一点点。当然,等 Swift 日趋稳定,以及越狱开源社区的逐渐支持,这一点优势可能就不明显了。

使用静态内连 C 函数

由于 OC 语言的动态性,导致 OC 的代码是最容易被破解分析的。在安全性上,更推荐使用 C 语言写成的函数。但是 C 语言的函数也是可以被 hook 的,主要有3种方式:

1.使用 Facebook 开源的fishhook

2.使用 MobileSubstrate 提供的 hook C 语言函数的方法

void MSHookFunction(void* function, void* replacement, void** p_original);

3.使用 mach_override,关于mach_override 和 fishhook的区别请看 mach_override 和 fishhook 区别

由于上面这三种方式可以 hook C 函数。要想不被 hook 解决方法是使用静态内联函数,这样的话需要被 hook 的函数没有统一的入口,逆向人员想要破解只能去理解该函数的逻辑。

使用 block

严格来说使用 block 并不能很大程度提高安全性,因为逆向人员只要找到使用该 block 的方法,一般来说在其附近就会有 block 内代码的逻辑。

但是个人认为使用 block 的安全性是比直接使用 oc 方法是要高的。在我的逆向分析 app 的经验中,对于使用了 block 的方法,目前我还不知道到怎么 hook (有知道的话,可以在 blog 上提个 issue 告诉我,先谢过)同时对于含有嵌套的 block 或者是作为参数传递的 block,处理起来就更加复杂了。所以,如果能将内敛 C 函数,嵌套 block , block 类型参数组合起来的话,安全性应该是会有一定提升。

代码混淆

代码混淆的方式有几种:

添加无用又不影响逻辑的代码片段,迷糊逆向人员

对关键的类、方法,命名成与真实意图无关的名称

个人认为最好的一个加密混淆工具是ios-class-guard,不过目前这个项目已经停止维护了。但是这种方式的混淆我觉得才是最终极的方案。

其他方法

比如 ptrace 反调试等(不过据说已经可以很容易被绕过)

// see http://iphonedevwiki.net/index.php/Crack_prevention for detail
static force_inline void disable_gdb() {
#ifndef DEBUG
    typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);
#ifndef PT_DENY_ATTACH
#define PT_DENY_ATTACH 31
#endif
    // this trick can be worked around,
    // see http://stackoverflow.com/questions/7034321/implementing-the-pt-deny-attach-anti-piracy-code
    void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
    ptrace_ptr_t ptrace_ptr = dlsym(handle, [@"".p.t.r.a.c.e UTF8String]);
    ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
    dlclose(handle);
#endif
}

注意事项

通过了解 OC 的运行时特性和 mach-o 二进制文件的结构,借助现有的工具,你会发现 hook 方法 是很简单就能完成的。虽然上面我提到了一些提高安全性的几个方案,但是,所有这些方式只是增加了逆向人员的逆向难度,并不能让 app 变的坚不可摧。不过采取一定的措施肯定比什么措施都不采取来的安全。

以上就是浅谈IOS如何对app进行安全加固的详细内容,更多关于IOS如何对app进行安全加固的资料请关注我们其它相关文章!

时间: 2021-06-05

IOS内存泄漏检查方法及重写MLeakFinder

对于iOS开发来讲,内存泄漏的问题,已经是老生常谈的话题.在日常的面试中经常会提到这些问题.我们日常的开发过程中进行内存泄漏的检测,一般是使用instrument工具中的Leaks/Allocation来进行排查,网络上也有比较高效又好用的内存泄漏检测工具,MLeakFinder. MLeakFinder-原理 首先看UIViewController,当一个UIViewController被pop或dismiss的时候,这个VC包括在这个VC上的View,或者子View都会很快的被释放.所以我们

IOS利用CocoaHttpServer搭建手机本地服务器

缘起 今天用暴风影音看视频,然后发现它有个功能,wifi传片,感觉挺有意思,然后就上网查了下相关内容. 原理 使用CocoaHTTPServer框架,在iOS端建立一个本地服务器,只要电脑和手机连入同一热点或者说网络,就可以实现通过电脑浏览器访问iOS服务器的页面,利用POST实现文件的上传. 实现 1.下载CocoaHTTPServer 2.导入CocoaHTTPServer-master目录下的Core文件夹 3.导入Samples/SimpleFileUploadServer目录下的MyH

详解IOS WebRTC的实现原理

概述 它在2011年5月开放了工程的源代码,在行业内得到了广泛的支持和应用,成为下一代视频通话的标准. WebRTC的音视频通信是基于P2P,那么什么是P2P呢? 它是点对点连接的英文缩写. P2P连接模式 一般我们传统的连接方式,都是以服务器为中介的模式: 类似http协议:客户端?服务端(当然这里服务端返回的箭头仅仅代表返回请求数据). 我们在进行即时通讯时,进行文字.图片.录音等传输的时候:客户端A?服务器?客户端B. 而点对点的连接恰恰数据通道一旦形成,中间是不经过服务端的,数据直接从一

怎样优化今日头条IOS安装包

前言 今日头条 iOS 端从 2016 年起就关注到了安装包大小的问题,并启动了包大小优化.2017 年,我们将当时的经验发表为技术文章 <干货|今日头条iOS端安装包大小优化-思路与实践>[1]. 如今三年过去了.今日头条在继续探索包大小优化时实践了更多思路,包括构建配置.图片压缩.__TEXT 段迁移.二进制段压缩等.这些优化项在业务入侵较少的前提下给今日头条带来了显著的包大小收益.同时,整个业界在包大小优化上也产出了更多方案.因此我们更新文章,期待与大家共同交流包大小优化这件事. 表格:

IOS小组件实现时钟按秒刷新功能

引言   上一节中我们了解了IOS小组件的刷新机制,发现根本没法实现按秒刷新,但是看别的App里面有做到,以为用了什么黑科技,原来是因为系统提供了一个额外的机制实现时间的动态更新,不用走小组件的刷新机制. Text控件支持显示日期时间,下面是来自官网的代码 计算时间差 let components = DateComponents(minute: 11, second: 14) let futureDate = Calendar.current.date(byAdding: components

如何在IOS中使用IBeacon

什么是iBeacon? iBeacon 是苹果公司2013年9月发布的移动设备用OS(iOS7)上配备的新功能.其工作方式是,配备有低功耗蓝牙(BLE)通信功能的设备使用BLE技术向周围发送自己特有的 ID,接收到该 ID 的应用软件会根据该 ID 采取一些行动. 从个人的角度看: iBeacon向四面八方不停地广播信号,就像是往平静的水面上扔了一块石子,泛起层层涟漪(俗称水波),波峰相当于 iBeacon 的RSSI(接受信号强度指示),越靠近中心点的地方波峰越高(RSSI 越大),这个波峰的

如何在IOS中使用Cordova插件

一.准备 插件功能:打开IOS相机 1:创建插件 plugman create --name [插件名称] --plugin_id [插件ID] --plugin_version [插件版本号] plugman create --name CameraDemo --plugin_id cordova-plugin-camerademo --plugin_version 1.0.0 2:添加IOS平台 plugman platform add --platform_name ios 3:创建pac

如何在AngularJs中调用第三方插件库

在AngularJs中我们会不可避免的使用第三方库,例如jquery插件库.我们不能散乱的在AngularJS中引入这些库,例如在controller中.那么应该怎么在Angular中使用第三方库呢? 如何使用? 很简单,给插件写一个directive. 在这里,我会使用一个简单的jquery插件Toolbar.js 的DEMO. 这是我们如何在jquery中创建一个tooltip的: <!-- Click this to see a toolbar --> <div id="

如何在Intellij中安装LeetCode刷题插件方便Java刷题

一.安装 在 IDEA(2019)的 setting 的 Plugins 的 Marketplace 中搜索 leetcode,即可以找到该插件,安装完成了,重启即可. 二.配置 1.重启完成后,第一次使用的时候,需要一些基本的配制,在 setting 中的 Tools 中可以找到该插件工具,为 leetcode plugin,在里面,可以选择访问的为国际的 LeetCode 还是国内的,以及何种语言,同时,输入自己账户名(LoginName)和密码(Password),则可以和自己帐号关联起来

IOS中使用UIWebView 加载网页、文件、 html的方法

UIWebView 是用来加载加载网页数据的一个框.UIWebView可以用来加载pdf word doc 等等文件 生成webview 有两种方法: 1.通过storyboard 拖拽 2.通过alloc init 来初始化 创建webview,下列文本中 _webView.dataDetectorTypes = UIDataDetectorTypeAll; 是识别webview中的类型,例如 当webview中有电话号码,点击号码就能直接打电话 - (UIWebView *)webView

iOS中关于模块化开发解决方案(纯干货)

关于iOS模块化开发解决方案网上也有一些介绍,但真正落实在在具体的实例却很少看到,计划编写系统文章来介绍关于我对模块化解决方案的理解,里面会有包含到一些关于解耦.路由.封装.私有Pod管理等内容:并编写的一个实例项目放在git进行开源[jiaModuleDemo],里面现在已经放着一些封装的功能模块:会不断的进行更新,假如你感兴趣可以Star一下,项目也不断的更新完善优化:如果你有更好的方案或者说好的建议可以lssues,我会在短时间进行更新并修改相应的问题: 一:项目中存在的问题 1:当公司里

iOS中的NSURLCache数据缓存类用法解析

在IOS应用程序开发中,为了减少与服务端的交互次数,加快用户的响应速度,一般都会在IOS设备中加一个缓存的机制.使用缓存的目的是为了使用的应用程序能更快速的响应用户输入,是程序高效的运行.有时候我们需要将远程web服务器获取的数据缓存起来,减少对同一个url多次请求.下面将介绍如何在IOS设备中进行缓存. 内存缓存我们可以使用sdk中的NSURLCache类.NSURLRequest需要一个缓存参数来说明它请求的url何如缓存数据的,我们先看下它的CachePolicy类型.    1.NSUR

Java中使用WebUploader插件上传大文件单文件和多文件的方法小结

一.使用webuploader插件的原因说明 被现在做的项目坑了. 先说一下我的项目架构spring+struts2+mybatis+MySQL 然后呢.之前说好的按照2G上传就可以了,于是乎,用了ajaxFileUpload插件,因为之前用图片上传也是用这个,所以上传附件的时候就直接拿来用了 各种码代码,测试也测过了,2G文件上传没问题,坑来了,项目上线后,客户又要求上传4G文件,甚至还有20G以上的..纳尼,你不早说哦... 在IE11下用ajaxFileUpload.js插件上传超过4G的

maven如何在tomcat8中实现自动部署

本文介绍了maven如何在tomcat8中实现自动部署,分享给大家,具体如下: 1.首先需要有tomcat,并且配置好用户. 配置的地方在tomcat的config文件中的tomcat-users.xml文件中 <role rolename="manager"/> <role rolename="manager-gui"/> <role rolename="admin"/> <role rolename=

iOS中sqlite数据库的原生用法

在iOS中,也同样支持sqlite.目前有很多第三方库,封装了sqlite操作,比如swift语言写的SQLite.swift.苹果官网也为我们封装了一个框架:CoreData. 它们都离不开Sqlite数据库的支持. 本文主要介绍下,如何在swift中使用原生的sqlite的API. 在Xcode中引入sqlite API 新建一个swift项目后,我们需要让项目引入sqlite的动态链接库: 1.项目配置界面,选择Build Phases 2.点开Link Binary With Libra

iOS中使用对象的弱引用示例代码

简介 我们都知道使用 UIImage imageNamed 创建的 UIImage 对象会被持有(强引用),如果图片太大会占用内存,损耗 APP 的性能,影响用户体验,如果能改造对其的强引用变为弱引用就可以解决问题. 我们可能会有类似上面的场景,有些对象暂时保存起来,可能后面会用到,也有可能不会使用,但是又不想去管理它们的生命周期,如果它们能够自己被销毁就很省事,不需要去关心这些对象到底耗费了多少内存. 今天跟大家聊聊如何在 iOS 开发中保持对对象的弱引用而不是强引用,希望看完之后,能帮助到大

详解如何在webpack中做预渲染降低首屏空白时间

一.浏览器渲染过程 1.用户打开页面,空白屏,等待html的返回 2.html下载完毕,开始解析html,初始渲染 3.下载css.js等资源,执行js渲染虚拟DOM 4.发起请求.获取数据,渲染内容 下面我们主要是讨论一下如何通过预渲染的方式降低空白屏的时间 缩小首屏载时间是一个重要的优化项,总结来主要有以下几种方式: 1.尽可能的缩小webpack或者其他打包工具生成的包的大小 2.使用服务端渲染的方式 3.使用预渲染的方式 4.使用gzip减小网络传输的流量大小 5.按照页面或者组件分块懒