0

Image Description

荆文征

Zhidu Inc.


你好,再见

IOS 防御战

  • 小酒馆老板
  • /
  • 2019/1/8 16:38:0

在ios上,因为客户端运行在各种形形色色的人手中,我们就要对自己交付出去的软件,进行一些列的守护。今天我这里就来看看,怎么进行一些守护。

既然谈到,防御,就得明白这些人的进攻方式,才可以进行守护。

以下我会从两个方面来看看如何攻击和如何防御

  1. 越狱hook
  2. 网络抓包 篡改

H1

软件自防护

在最开始,越狱的主要目的就是为了解决主题,字体…

但是殊不知,在系统的权限彻底开放之后,我们做的事更多。而且,由于近几年的ios逆向快速进步,很多开源作者的贡献,例如monkeyDev
这已经为一个小白去逆向,解决掉了很多很多绕绕绕的配置。
以前的微信自动抢红包,都变成了入门级项目,github上面抢红包的高级插件更是五花八门。而微信多开,已经是自动抢红包的第一步了。

在这种时候,我们有必要搞清楚,他们是如何进行攻击的,而保护我们的软件,尤其是我们的软件是特别需要安全的时候。

有兴趣了解越狱的原理,可以参考 全方位解析越狱原理


H2

越狱机检测

在越狱之后,就可以对软件进行hook,我们可以对设备进行检测其是否已经被越狱,检测方法有很多中,如

使用 stat 系列函数检测常用越狱工具。

struct stat stat_info;
BOOL jailCheck1 = 0 == stat("/Applications/Cydia.app", &stat_info);

使用NSFileManager,判断设备上是否安装了常用越狱工具。

//判断工具安装路径  本期先做成BOOL开关方法
 - (BOOL)checkPath
{
    BOOL jailBroken = NO;
    NSString * cydiaPath = @"/Applications/Cydia.app";
    NSString * aptPath = @"/private/var/lib/apt";
    if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
        jailBroken = YES;
    }
    if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
        jailBroken = YES;
    }
    return jailBroken;
}
·
上述路径也可替换为以下常见越狱工具路径:
 /Library/MobileSubstrate/MobileSubstrate.dylib
/Applications/Cydia.app   /var/lib/cydia/
/var/cache/apt   /var/lib/apt    /etc/apt
/bin/bash /bin/sh
/usr/sbin/sshd   /usr/libexec/ssh-keysign   /etc/ssh/sshd_config

检测stat是否出自系统库

int ret;
Dl_info dylib_info;
 int (*func_stat)(const char *,struct stat *) = stat;
 if ((ret = dladdr(func_stat, &dylib_info))) {
       if (strcmp(dylib_info.dli_fname,"/usr/lib/system/libsystem_kernel.dylib") != 0) {
           jailbroken = YES;
       }
}

检测链接动态库,检测是否被链接了异常动态库,但动态库相关Api属于私有Api,调用的话appStore审核会不通过,所以不列举。

其实越狱是开启了设备的文件访问权限,其实检测文件的权限,如果你可以读取的文件的根目录,那么这个项目一定是被越狱了

或者通过URLScheme来访问Cydia,但是目前有很多软件注册了该 URLScheme,所以不要使用该方法

BOOL jailCheck2 = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://"]];

但是一旦使用了objective-c代码,其实就增加了被hook的可能。所以我们尽量的使用 c 函数来进行检测,也就是使用第一个方法进行检测。

!!!但是这里,我必须澄清一下,c语言也不是就安全了,因为c语言也不是不可以hook,只能说,我们增加了hook的难度。 具体的hook方法,可以参考 fishhook 开源框架。


H2

非越狱机器

事实上,现在很多软件都开始不进行在越狱设备上开发,他们会把软件直接作为动态库加载到自己的项目中,这也是目前的多开微信的做法。

如果想了解这个问题,可以参考,这里不在展开解释了。黑科技:把第三方 iOS 应用转成动态库

在这里我们了解一下,敲壳吧,因为任何软件想要被做成动态库,都需要进行敲壳


H3

敲壳

App Store上的应用都使用了FairPlay DRM数字版权加密保护技术
FairPlay保护的文件是具有加密容器文件。使用AES 算法进行加密。解密所需的主密钥也以加密形式存储在容器文件中。解密主密钥所需的密钥称为“用户密钥”。当用户使用iTunes、App Store登陆新设备时,该设备向Apple服务器请求授权,从而获得用户密钥。在试图使用容器文件时,存储在文件中的主密钥随后与用户密钥匹配,并且如果成功则允许使用。

从Appstore发布的应用,同时被开发者和Apple进行签名。 二进制文件是加密的,需要用密钥将文件解密成可读的版本。当iOS运行应用时, 密钥将二进制文件解密成一个可读的状态,然后加载到内存中执行, 而敲壳指的就是在这一段过程中,将内存中的内容dump下来,以输出一个完整的破壳后的二进制文件。iOS在 load command 中的LC_ENCRYPTION_INFO 结构来标记加密的状态,非0的值表示该二进制文件被加密了。

而敲壳其实就是去除数字验证的过程,而敲壳有两种方式,分为静态动态,

静态就是在已经掌握和了解到了壳应用的加密算法和逻辑后在不运行壳应用程序的前提下将壳应用程序进行解密处理。静态脱壳的方法难度大,而且加密方发现应用被破解后就可能会改用更加高级和复杂的加密技术;而动态就是从运行在进程内存空间中的可执行程序映像(image)入手,来将内存中的内容进行转储(dump)处理来实现脱壳处理。

一般的都是使用动态进行解析,其中解密处理都使用系统就好了。

目前的使用的敲壳开源项目 基本为

  1. dumpdecrypted
  2. frida-ios-dump
  3. Clutch

自行可以进行深入了解

而因为所有敲壳的软件都是使用的appStore下载的ipa包,它们都是不包含 arm64 架构的,所以所有的敲壳软件都只能在真机上运行

关于这里,我忽然想起来以前开发一个框架给第三方使用的时候,用到了这里。

- set -o pipefail && xcodebuild build -project Pods/Pods.xcodeproj -target OddityOcUI | xcpretty -c
- set -o pipefail && xcodebuild build -project Pods/Pods.xcodeproj -target OddityOcUI -sdk iphonesimulator10.3 | xcpretty -c
- lipo -create build/Release-iphoneos/OddityOcUI/libOddityOcUI.a build/Release-iphonesimulator/OddityOcUI/libOddityOcUI.a  -output libOddityOcUI.a

在这里如果想让框架可以被模拟器使用,就必须针对模拟器的框架进行打包。

目前我所了解的只是来看,你把软件安装到真机上是,需要证书,也就是 mobileprovision。这其中的原理非常复杂可以参考 iOS App 签名的原理

其实上面说了这些只是为了说明,你把软件作为动态库的时候,虽然你可以把她当作一个软件运行起来,但是你必须修改 bundle id。另外,你想多开的话也是需要修改 bundle id。


H3

检测 bundle id 修改

事实上,这个问题,很好检测的。我们只要获取

NSBundle.mainBundle.bundleIdentifier;

上传到服务器,或者与本地比对,发现bundle被修改,进行下一步操作就可以了。但是事实上,通过hook可以进行修改,让我们误认为自己的bundle是正确的。

目前已知的四中获取bundle方法

NSBundle.mainBundle.bundleIdentifier;
[NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleIdentifier"];
NSBundle.mainBundle.infoDictionary[@"CFBundleIdentifier"];
[NSDictioanry dictionaryWithContentsOfFile:@"Info.plist"][@"CFBundleIdentifier"]

以下hook修改方法来自 iOS 多开检测,反多开检测,反反多开检测

/*
 * 假设当前分身的 Bundle Identifier 值为 com.unique.xin
 */

#import 

#define CFBundleIdentifier @"CFBundleIdentifier"
#define ORIG_VALUE            @"com.tencent.xin"
#define REAL_VALUE            @"com.unique.xin"

/*
 * 这里干掉了 -[NSBundle bundleIdentifier] 方法
 */
MUHInstanceImplementation(NSBundle, bundleIdentifier, NSString *) {
    NSString *orig = MUHOrig(NSBundle, bundleIdentifier);
    if ([orig isEqualToString:REAL_VALUE]) {
        orig = ORIG_VALUE;
    }
    return orig;
}

/*
 * 这里干掉了 -[NSBundle objectForInfoDictionaryKey:] 方法
 *
 * MUHInstanceImplementation 注释:定义一个 Hook 的实现体
 *        第一个参数是要 Hook 的类
 *         第二个参数是自己取的方法名,会在下面的 MUHMain 和 MUHOrig 用到,与实际方法名可以不一致,但是要保证唯一性
 *          第三个参数是返回值类型
 *           第四个参数以及之后的参数是 Hook 方法的实际参数表。
 *
 * 如果你要 Hook 一个 Class Method 比如 +[UIImage imageNamed]
 * 请使用 MUHClassImplementation,具体用法同上
 */
MUHInstanceImplementation(NSBundle, objForInfoKey, id, NSString *key) {
    /*
     * MUHOrig 注释:调用原方法
     *         第一个参数是原方法的类
     *          第二个参数是自己取的方法名
     *           第三个参数以及之后的参数是传入的实际参数
     */
    NSString *orig = MUHOrig(NSBundle, objForInfoKey, key);
    if ([key isKindOfClass:[NSString class]]) {
        if ([key isEqualToString:CFBundleIdentifier]) {
            if ([orig isEqualToString:REAL_VALUE]) {
                orig = ORIG_VALUE;
            }
        }
    }
    return orig;
}

MUHInstanceImplementation(NSBundle, infoDictionary, NSDictionary *) {
    NSMutableDictionary *info = [MUHOrig(NSBundle, infoDictionary) mutableCopy];
    if (self == NSBundle.mainBundle) {
        info[CFBundleIdentifier] = REAL_VALUE;
    }
    return [info copy];
}

MUHInstanceImplementation(NSDictionary, objectForKey, id, NSString *key) {
    id orig = MUHOrig(NSDictionary, objectForKey, key);
    if ([key isKindOfClass:[NSString class]]) {
        if ([key isEqualToString:CFBundleIdentifier]) {
            if ([orig isEqualToString:REAL_VALUE]) {
                id = ORIG_VALUE;
            }
        }
    }
    return orig
}

MUHInstanceImplementation(NSDictionary, valueForKey, id, NSString *key) {
    id orig = MUHOrig(NSDictionary, valueForKey, key);
    if ([key isKindOfClass:[NSString class]]) {
        if ([key isEqualToString:CFBundleIdentifier]) {
            if ([orig isEqualToString:REAL_VALUE]) {
                id = ORIG_VALUE;
            }
        }
    }
    return orig
}

MUHInstanceImplementation(NSDictionary, objectForKeyedSubscript, id, NSString *key) {
    id orig = MUHOrig(NSDictionary, objectForKeyedSubscript, key);
    if ([key isKindOfClass:[NSString class]]) {
        if ([key isEqualToString:CFBundleIdentifier]) {
            if ([orig isEqualToString:REAL_VALUE]) {
                id = ORIG_VALUE;
            }
        }
    }
    return orig
}


/*
 *    MUHMain 注释:定义一个拥有 constructor 属性的函数。
 *    当 dyld 加载此二进制文件到内存中的时候会自动调用此函数,完成运行前的 hook 工作
 */
void MUHMain() {
    /*
     *    MUHHookInstanceMessage 注释:让上面定义的某个 Instance Hook 实现体生效
     *         第一个参数是上面实现体的类
     *          第二个参数是上面实现体自己取的方法名
     *           第三个参数是对应的 SEL
     *
     *    如果要让一个 Class Hook 生效,可以使用
     *         MUHHookClassMessage()
     *          使用方式同上
     */
    MUHHookInstanceMessage(NSBundle, bundleIdentifier, bundleIdentifier);
    MUHHookInstanceMessage(NSBundle, infoDictionary, infoDictionary);
    MUHHookInstanceMessage(NSBundle, objectForInfoDictionaryKey, objectForInfoDictionaryKey:);
    MUHHookInstanceMessage(NSDictionary, objectForKey, objectForKey:);
    MUHHookInstanceMessage(NSDictionary, valueForKey, valueForKey:);
    MUHHookInstanceMessage(NSDictionary, objectForKeyedSubscript, objectForKeyedSubscript:);
}

而事实上,很多地方都可以进行检测,这些地方成为监测点,每一个检测点都需要进行hook,比如,我们完全可以使用,判断同一个设备是否使用了同样的软件。 idfa - deviceName.

即使如此,我们也可以hook,idfa以及devicename获取的方法。返回一个可以通过的假数据

因为他们是hook的检测点,我们完全可以写检测点。例如

import CommonCrypto

guard let path = Bundle.main.path(forResource: "Info", ofType: "plist")  else { return }

let url = URL(fileURLWithPath: path)

let data = try! Data(contentsOf: url)

print(String(data: data, encoding: String.Encoding.ascii))

var digest = Data(count: Int(CC_MD5_DIGEST_LENGTH))

_ = digest.withUnsafeMutableBytes { (digestBytes: UnsafeMutablePointer<UInt8>) -> UnsafeMutablePointer<UInt8> in
    data.withUnsafeBytes({ (messageBytes: UnsafePointer<UInt8>) -> UnsafeMutablePointer<UInt8> in
//                CC_MD5(messageBytes, CC_LONG(data.count), digestBytes)
        CC_SHA256(messageBytes, CC_LONG(data.count), digestBytes)
    })
}

print(digest.map{ String.init(format: "%02hhx", $0) }.joined())

他们除非找到所有的检测点,否则是不可能攻破这个守护的,我们也可以增加多个方法。

事实上,方法解耦会增加被hook的几率,很多加密解密方法,我们可以使用比较笨的ctrl c+v 来处理。


H3

strip symbols

在Xcode上设置 strip ,编译时去除一些符号:


Image Description

一般在Release版本设置Strip.


H3

减少OC函数的使用

尽量少用Objective-C代码,直接使用Objective-C代码,会将OC代码的函数名,类名等信息记录在二进制文件中,极易被通过函数类名来进行分析逆向。

解决方法就是尽量把代码写成C或者C++的代码,且使用static声明 ,这种代码编译后会是这样 :


Image Description

字符串加密
动态生成字符串,字符串加密保存,而不是明文保存。攻击者通过全局搜索字符串,而找到指定的需要的内容,然后进行修改。

使用Build Phases来在编译之前修改所有原文件,将进行标记的字符串,进行加密.加密在编译之前,解密在运行期间,而静态分析将无法得到明文字符串,提高破解难度。加密算法使用O(n)的算法,因为定义字符串在系统中是很多,很常用的,所以尽量不要影响到系统性能。

于是自行实现了OCSM ,一个简单的编译前进行字符串加密的工具, 开源放在Github上,点这里


H3

阻止Cycript的注入。

阻止Cycript的注入,我们知道其动态库是 libcycript.dylib ,所以,我们通过以下代码来检测程序中是否加载了该动态库 :

uint32_t count = _dyld_image_count();
BOOL hasInjected = NO;
for (uint32_t i = 0; i < count; i++) {
    if (strstr( _dyld_get_image_name(i),"libcycript.dylib")) {
        hasInjected = YES;
        break;
    }
}

但是这里只能检测到初始化的时候的注入,即以cycript启动应用,而在运行期间的阻止,我们通过_dyld_register_func_for_add_image来实现 :

void func(const struct mach_header* mh, intptr_t vmaddr_slide){
    Dl_info info;
    if (dladdr(mh, &info) == 0) {
        return;
    }
    if (strstr(info.dli_fname,"libcycript.dylib")) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            exit(1);
        });
    }
}
_dyld_register_func_for_add_image(func);

我们在检测到程序中有动态库cycript注入时,关闭应用。


H3

加密状态

提交到AppStore加密后的文件,会带上一个LC_ENCRYPTION_INFO 的macho load command,

在ARM64中,是LC_ENCRYPTION_INFO_64, 所以,我们可以通过检测这个值,来判断当前APP是否被破壳.


H3

地址检测

上面提到了一系列的检测函数,这些函数我们要保证其安全性,所以检测函数要是一个inline函数,确保攻击者不能简单地替换该函数来跳过检测。 使用 __attribute__((always_inline)) ,表示强制编译器进行inline编译,因为单纯的声明inline,可能编译器并不一定会内联,所以需要强制声明。

由于我们的检测一般会调用系统函数,而攻击者会动态替换函数,以使跳过检测,或者返回错误的返回结果。所以我们有时候要检测函数的地址,以避免函数被hook :

#import <dlfcn.h>        
Dl_info info2;
IMP imp2 = class_getMethodImplementation([MeViewController class], @selector(tableView:didSelectRowAtIndexPath:));
if (dladdr(imp2, &info2)) {
    printf("dli_fname: %s\n", info2.dli_fname);
    printf("dli_sname: %s\n", info2.dli_sname);
    printf("dli_fbase: %p\n", info2.dli_fbase);
    printf("dli_saddr: %p\n", info2.dli_saddr);
} else {
    printf("error: can't find that symbol.\n");
}

通过校验dli_fname来保证函数没有被篡改。我们对上述所有的检测中的系统函数,进行地址校验,同时对检测函数进行内联,并结合多种检测,保证了APP的安全性。 所以做到这一步时, 简单的hook函数已经无法处理我们的APP了,攻击者必须通过修改汇编代码的形式以达成自己的目的。


H1

网络防护

至此,在完成了软件防护的时候,我们来看看和服务器数据交换的时候,ios进行的防护手段吧。


H2

App Transport Security

WWDC 15 提出的 ATS (App Transport Security) 是 Apple 在推进网络通讯安全的一个重要方式。在 iOS 9 和 OS X 10.11 中,默认情况下非 HTTPS 的网络访问是被禁止的。

ATS 要求:

证书基本要求

  1. 经Apple ATS信任的CA机构签发的SSL数字,详情查看:iOS 中可用的受信任根证书列表
  2. 签发证书的通用名称证书与域名匹配,非常重要;
  3. 证书时间有效,使用在线工具检查;
  4. 证书公钥算法使用RSA 2048位及以上,或使用更高的算法ECC 256加密算法;
  5. 使用SHA2级别的证书签名算法,例如SHA-256, SHA-512等;

服务器配置项

  1. 开启服务器SSL/TLS要求的端口例如443,8443等并助部署支持https协议
  2. 支持TLS1.0, TLS1.1, TLS1.2,禁用SSL3.0和SSL2.0
  3. 支持前向安全性
  4. iOS 密码套件支持
    RSA算法要求使用以下加密套件:
    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
    DSA算法要求使用以下加密套件:
    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA

Apache配置项

SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDH:AESGCM:HIGH:!RC4:!DH:!MD5:!aNULL:!eNULL;

Nginx配置项

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDH:AESGCM:HIGH:!RC4:!DH:!MD5:!aNULL:!eNULL;

Tomcat要求环境 tomcat7+和JDK1.7+,配置参考如下:

<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="keystore/domain.jks" keystorePass="证书密码"
clientAuth="false" sslProtocol="TLS"
ciphers="TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
SSL_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA" />

当然,因为这样的推进影响面非常广,作为缓冲,我们可以在 Info.plist 中添加 NSAppTransportSecurity 字典并且将 NSAllowsArbitraryLoads 设置为 YES 来禁用 ATS。

您需要添加 NSAllowsArbitraryLoads 以确保您的广告在 iOS 9 设备上不受 ATS 影响.

同时需要添加 NSAllowsArbitraryLoadsForMediaNSAllowsArbitraryLoadsInWebContent,以确保您的广告在 iOS 10 设备上不受 ATS 影响。


H2

中间人攻击

中间人攻击(英语:Man-in-the-middle attack,缩写:MITM)在密码学和计算机安全领域中,是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。在中间人攻击中,攻击者可以拦截通讯双方的通话并插入新的内容。在许多情况下这是很简单的(例如,在一个未加密的Wi-Fi 无线接入点的接受范围内的中间人攻击者,可以将自己作为一个中间人插入这个网络)。

一个中间人攻击能成功的前提条件是攻击者能将自己伪装成每一个参与会话的终端,并且不被其他终端识破。中间人攻击是一个(缺乏)相互认证的攻击。大多数的加密协议都专门加入了一些特殊的认证方法以阻止中间人攻击。例如,SSL协议可以验证参与通讯的一方或双方使用的证书是否是由权威的受信任的数字证书认证机构颁发,并且能执行双向身份认证。
—- 引自

通讯内容加密

也就是请求无论是 request,还是 response 都进行一次本身的加密,无论是 aes 或者 等其他加密,都可以。这种方式的好处就是和服务器可控,即使网络最终被劫持,第三者解密了请求以及返回,但是本身数据就是加密的,他也很难分析其原始数据。 <有钱花> 就是使用该方法。 坏处,就是因为毕竟解密就在本地,所以只要是有心,花费大时间逆向了,百度的有钱花软件就可以解密了。

SSL Pinning

在客户端进行代码层面的证书校验,校验方式也有两种,一是证书本身校验,二是公钥校验。

证书校验是文件级别的校验,客户端只信任若干个证书文件,这些证书文件是和客户端一起打包发布的,这种处理方式要面对的一个问题证书过期问题,为了避免证书过期导致的校验失败,客户端和服务器之间需要额外存在一个证书更新机制,其实做起来也比较简单,只需要服务器下发一个特定的错误码,触发一个客户端的新证书下载流程即可。
公钥校验模式可以免去上述的麻烦,公钥模式只校验证书中所包含的公钥是否匹配,即使证书过期了,只要服务器更新证书,保证公钥不变,依然能完成校验过程,但这个大前提是,服务器的公钥私钥对不能更换。

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{}

Alamofire SSL Pinning

/// 获取 加密规则
let trustPolicy = ServerTrustPolicy.pinCertificates(
            certificates: ServerTrustPolicy.certificates(in: Bundle.main),
            validateCertificateChain: true,
            validateHost: true)

/// 配置 百度的 加密 规则
let trustPolicies = [ "www.baidu.com": trustPolicy ]

let policyManager =  ServerTrustPolicyManager(policies: trustPolicies)

/// 配置 请求管理
self.sessionManager = SessionManager(
    configuration: URLSessionConfiguration.default,
    serverTrustPolicyManager: policyManager
)

sessionManager.request("https://www.baidu.com").response { (res) in

    guard let data = res.data else { return }

    print(String(data: data, encoding: String.Encoding.utf8))
}

在如此情况下, 正常的证书会正常请求,但是如果是错误的中间人证书,就会canceled 请求。

还是我们上面说的,检测的方法有几种。

/// - performDefaultEvaluation: Uses the default server trust evaluation while allowing you to control whether to
///                             validate the host provided by the challenge. Applications are encouraged to always
///                             validate the host in production environments to guarantee the validity of the server's
///                             certificate chain.
///
/// - performRevokedEvaluation: Uses the default and revoked server trust evaluations allowing you to control whether to
///                             validate the host provided by the challenge as well as specify the revocation flags for
///                             testing for revoked certificates. Apple platforms did not start testing for revoked
///                             certificates automatically until iOS 10.1, macOS 10.12 and tvOS 10.1 which is
///                             demonstrated in our TLS tests. Applications are encouraged to always validate the host
///                             in production environments to guarantee the validity of the server's certificate chain.
///
/// - pinCertificates:          Uses the pinned certificates to validate the server trust. The server trust is
///                             considered valid if one of the pinned certificates match one of the server certificates.
///                             By validating both the certificate chain and host, certificate pinning provides a very
///                             secure form of server trust validation mitigating most, if not all, MITM attacks.
///                             Applications are encouraged to always validate the host and require a valid certificate
///                             chain in production environments.
///
/// - pinPublicKeys:            Uses the pinned public keys to validate the server trust. The server trust is considered
///                             valid if one of the pinned public keys match one of the server certificate public keys.
///                             By validating both the certificate chain and host, public key pinning provides a very
///                             secure form of server trust validation mitigating most, if not all, MITM attacks.
///                             Applications are encouraged to always validate the host and require a valid certificate
///                             chain in production environments.
///
/// - disableEvaluation:        Disables all evaluation which in turn will always consider any server trust as valid.
///
/// - customEvaluation:         Uses the associated closure to evaluate the validity of the server trust.

主要是用 PublicKeys 以及 Certificats。


H1

小结

至此,我们已经说明了几种防守的手段。但是无论我们做到任何程度都是无法保证我们的软件是绝对安全的。正所谓?“道高一尺,魔高一丈二”。 我们只能让我们的软件现对安全,最次也要筛选下去一批中低端的攻击者,

没有学习过汇编,但是在学习的时候,发现很多大佬,可以使用逆向命令,来达到一些目的。例如,比如我们发现了自己的软件想要退出自己的软件

当然我看的文章所说的exit()方法,我觉得完全没有必要,因为我直接 让一个nil对象调用方法,软件自己就退出了啊?何必这么麻烦呢?

不过她提到的,使用汇编代码确实让我大开眼界

static __attribute__((always_inline)) void sysexit()
{
#ifdef __arm64__
    __asm__("mov X0, #1 \t\n"
            "mov w16, #1 \t\n" // ip1 指针。
            "svc #0x80"
            );
#elif __arm__
    __asm__(
            "mov r0, #1 \t\n"
            "mov ip, #1 \t\n"
            "svc #0x80"
            );
#endif
    return;
}

好吧,就到这里吧。学习果然是无止境的。

在这里给大家拜个早年啦啦啦啦啦


自从hexo-wordcount 不知道怎么的出现了问题

我自己使用了自己的计数方法之后,文章计数就显的蠢蠢的。。。。今天因为文章内因为直接使用 base64字符串设置图片,更是达到了惊人的蠢。。。。

修修吧………

专栏: IOS
标签: IOS Hook Cycript MonkeyDev