浅谈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进行安全加固的资料请关注我们其它相关文章!

(0)

相关推荐

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

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

  • 详解IOS WebRTC的实现原理

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

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

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

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

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

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

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

  • 如何在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

  • 如何在IOS中使用IBeacon

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

  • 详解IOS如何防止抓包

    目录 抓包原理 防止抓包 一.发起请求之前判断是否存在代理,存在代理就直接返回,请求失败. 二.我们可以在请求配置中清空代理,让请求不走代理 SSL Pinning(AFN+SSL Pinning)推荐 扩展 抓包原理 其实原理很是简单:一般抓包都是通过代理服务来冒充你的服务器,客户端真正交互的是这个假冒的代理服务,这个假冒的服务再和我们真正的服务交互,这个代理就是一个中间者 ,我们所有的数据都会通过这个中间者,所以我们的数据就会被抓取.HTTPS 也同样会被这个中间者伪造的证书来获取我们加密的

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

    防止 tweak 依附 通常来说,我们要分析一个 app,最开始一般是砸壳, $ DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /path/to/XXX.app/XXX 然后将解密之后的二进制文件扔给类似 hopper 这样的反编译器处理.直接将没有砸壳的二进制文件扔个 hopper 反编译出来的内容是无法阅读的(被苹果加密了).所以说砸壳是破解分析 app 的第一步.对于这一步的防范,有两种方式. 1.限制二进制文件头内的段 通过在 Xcode 里面工程配

  • 浅谈iOS中几个常用协议 NSCopying/NSMutableCopying

    1.几点说明 说到NSCopying和NSMutableCopying协议,不得不说的就是copy和mutableCopy. 如果类想要支持copy操作,则必须实现NSCopying协议,也就是说实现copyWithZone方法; 如果类想要支持mutableCopy操作,则必须实现NSMutableCopying协议,也就是说实现mutableCopyWithZone方法; iOS系统中的一些类已经实现了NSCopying或者NSMutableCopying协议的方法,如果向未实现相应方法的系

  • 浅谈iOS开发中static变量的三大作用

    (1)先来介绍它的第一条也是最重要的一条:隐藏 当我们同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性.为理解这句话,我举例来说明.我们要同时编译两个源文件,一个是a.c,另一个是main.c. 下面是a.c的内容 char a = 'A'; // global variable void msg() { printf("Hello\n"); } 下面是main.c的内容 int main(void) { extern char a; // extern v

  • 浅谈iOS应用中的相关正则及验证

    1.手机号码的验证正则 正则表达式: ^((13[0-9])|(15[^4,\\D])|(18[0,0-9]))\\d{8}$ 详细解释 解释: •^...$: ^:开始 $:结束 中间为要处理的字串 •(13[0-9]): 以13开头接下来一位为0-9之间的数 13 : 以13开头 [0-9]:分割语法,13后面是0-9之间的数 •| : 或(or), 将前后两个匹配条件进行or运算 • (15[^4\\D]) : 以15开头接下来一位是除4之外的0-9数字 15 : 以15开头 [^4\\D

  • 浅谈IOS屏幕刷新ADisplayLink

    什么是CADisplayLink 我们在应用中创建一个新的CADisplayLink对象,把它添加到一个runloop中,并给它提供一个target和selector在屏幕刷新的时候调用. 一但CADisplayLink以特定的模式注册到runloop之后,每当屏幕需要刷新的时候,runloop就会调用CADisplayLink绑定的target上的selector,这时target可以读到CADisplayLink的每次调用的时间戳,用来准备下一帧显示需要的数据.例如一个视频应用使用时间戳来计

  • 浅谈iOS解析HTMl标签以及开发中的一些坑

    开篇 看了看更新日期好久没写简书了,经常还有小伙伴在文章下面评论,看到自己写的东西还是有点用的,鼓励自己接着坚持下去吧,哈哈.今天主要就写写iOS中怎么解析HTML标签,我们常用的后台返回数据一般是json格式的但是有些时候如果我们收到的是带HTMl标签的我们该怎么处理他呢,今天就来说一说吧. 正文 前两天获取后台数据的时候,得到这么一条返回信息 "恭喜您获得<font color='red'>8.1元</font>现金奖励 " 本来简简单单的把返回数据展示到l

  • 浅谈iOS UIWebView对H5的缓存功能

    这两天在搞与H5交互的事,之前做的都是加载的静态的web页面,交互调试起来很快,这次搞的是js写的前端页面,跳转什么的都是动态的,然后就不响应了,搞了半天原来是缓存的问题,这里简单介绍一下,一般请求会使用下面的方法: + (instancetype)requestWithURL:(NSURL *)URL; 该方法的描述如下: Creates and returns a URL request for a specified URL with default cache policy and ti

  • 浅谈iOS中三种生成随机数方法

    ios 有如下三种随机数方法: //第一种 srand((unsigned)time(0)); //不加这句每次产生的随机数不变 int i = rand() % 5; //第二种 srandom(time(0)); int i = random() % 5; //第三种 int i = arc4random() % 5 ; 注: ① rand()和random()实际并不是一个真正的伪随机数发生器,在使用之前需要先初始化随机种子,否则每次生成的随机数一样. ② arc4random() 是一个

  • 浅谈IOS中AFNetworking网络请求的get和post步骤

    1.首先通过第三方:CocoaPods下载AFNetworking 1.1.先找到要查找的三方库:pod search + AFNetworking 1.2.出来一堆列表页面,选择三方库最新版本命令,例如: pod 'MBProgressHUD','~>0.8'  (:q 返回) 1.3.创建工程,进入工程: cd + 工程路径 1.4.编辑工程的Podfile文件: vim Podfile 1.5.(platform :iOS, '8.0'
target "工程名" do
po

  • 浅谈iOS中的锁的介绍及使用

    在平时的开发中经常使用到多线程,在使用多线程的过程中,难免会遇到资源竞争的问题,那我们怎么来避免出现这种问题那? 线程安全是什么? 当一个线程访问数据的时候,其他的线程不能对其进行访问,直到该线程访问完毕.简单来讲就是在同一时刻,对同一个数据操作的线程只有一个.只有确保了这样,才能使数据不会被其他线程影响.而线程不安全,则是在同一时刻可以有多个线程对该数据进行访问,从而得不到预期的结果. 比如写文件和读文件,当一个线程在写文件的时候,理论上来说,如果这个时候另一个线程来直接读取的话,那么得到的结

随机推荐