ShannonChenCHN / iOSDevLevelingUp

A journey of leveling up iOS development skills and knowledge.
365 stars 105 forks source link

安全、逆向 #28

Open ShannonChenCHN opened 7 years ago

ShannonChenCHN commented 7 years ago
ShannonChenCHN commented 7 years ago

延伸阅读:

ShannonChenCHN commented 7 years ago

如何查看 App Store 中下载的 APP 中的图片资源?

  1. 下载 cartool 源码

  2. 打开 project,Command+B 编译一下;

  3. 找到工程目录 products 下的 cartool 文件,右击,show in finder;

  1. 打开终端,输入 :
    $ cd <cartool文件所在目录>
$ ./cartool  /xxx/Assets.car /xxx/outputDirectory

参考资料:

ShannonChenCHN commented 7 years ago

class dump

  1. 下载 class-dump
  2. 获取 /usr/bin 目录的访问权限:重启电脑按住 cmd+R,打开终端,输入 csrutil disable
  3. 拷贝 class-dump 可执行文件到 /usr/bin 目录下
  4. class-dump 操作权限:执行 sudo chmod 777 /usr/bin/class-dump 命令
  5. 获取头文件信息:先获取 ipa 包中的可执行文件,然后执行终端命令 class-dump -H 要破解的可执行文件路径 -o 破解后的头文件存放路径

参考资料:

ShannonChenCHN commented 7 years ago

代码混淆

示例脚本:

#!/usr/bin/env bash

TABLENAME=symbols
SYMBOL_DB_FILE="symbols"
STRING_SYMBOL_FILE="func.list"
HEAD_FILE="$PROJECT_DIR/$PROJECT_NAME/codeObfuscation.h"
export LC_CTYPE=C

#维护数据库方便日后作排重
createTable()
{
echo "create table $TABLENAME(src text, des text);" | sqlite3 $SYMBOL_DB_FILE
}

insertValue()
{
echo "insert into $TABLENAME values('$1' ,'$2');" | sqlite3 $SYMBOL_DB_FILE
}

query()
{
echo "select * from $TABLENAME where src='$1';" | sqlite3 $SYMBOL_DB_FILE
}

ramdomString()
{
openssl rand -base64 64 | tr -cd 'a-zA-Z' |head -c 16
}

rm -f $SYMBOL_DB_FILE
rm -f $HEAD_FILE
createTable

touch $HEAD_FILE
echo '#ifndef Demo_codeObfuscation_h
#define Demo_codeObfuscation_h' >> $HEAD_FILE
echo "//confuse string at `date`" >> $HEAD_FILE
cat "$STRING_SYMBOL_FILE" | while read -ra line; do
if [[ ! -z "$line" ]]; then
ramdom=`ramdomString`
echo $line $ramdom
insertValue $line $ramdom
echo "#define $line $ramdom" >> $HEAD_FILE
echo "#define _$line _$ramdom" >> $HEAD_FILE
fi
done
echo "#endif" >> $HEAD_FILE

sqlite3 $SYMBOL_DB_FILE .dump

参考资料

ShannonChenCHN commented 7 years ago

接口加密

参考

ShannonChenCHN commented 6 years ago

《代码签名探析》学习笔记

只有在越狱之后,iOS 才能运行没有签名的代码。 越狱使应用可以绕过代码签名和沙盒安全机制的全部限制,这会是一个非常危险的行为。

一、证书和密匙

作为一个 iOS 开发者,在你开发使用的机器上应该已经有一个证书,一个公钥,以及一个私钥。这些是代码签名机制的核心。

有两种方式可以查看你的系统中能用来对代码进行签名的证书:

$ csapp security find-identity -v -p codesigning
  1) A853191D0F53EBEEAADD9EE99932CA596F5A1F9F "Mac Developer: 273879688@qq.com (C6KU79QV5A)"
  2) 8120BD6A4536DCF46DBBF7D88EFF9EAB241F1870 "iPhone Developer: 273879688@qq.com (C6KU79QV5A)"
     2 valid identities found

一个证书是一个公钥加上许多附加信息,这些附加信息都是被某个认证机构(Certificate Authority 简称 CA)进行签名认证过的,认证这个证书中的信息是准确无误的。

命令行工具 CodeSign

签名过程本身是由命令行工具 codesign 来完成的。如果你在 Xcode 中编译一个应用,这个应用构建完成之后会自动调用 codesign 命令进行签名。

二、一个已签名应用的组成

可执行文件

一个已签名的可执行文件的签名包含在 Mach-O 二进制文件格式中。

在 macOS 和 iOS 上的任何可执行二进制文件都可以被设置签名:不论是动态库,命令行工具,还是 .app 后缀的程序包。

设置签名的过程实际上会改动可执行文件的文件内容,将签名数据写入二进制文件中。

如果你拥有一个证书和它的私钥,那么用 codesign 来设置签名非常简单:

$ codesign -s "iPhone Developer: 273879688@qq.com (C6KU79QV5A)" ~/Desktop/AwesomeProject.app
/Users/ShannonChen/Desktop/AwesomeProject.app: is already signed

为一个已经签过名的文件重新签名:

$ codesign -f -s "iPhone Developer: 273879688@qq.com (C6KU79QV5A)" ~/Desktop/AwesomeProject.app
/Users/ShannonChen/Desktop/AwesomeProject.app: replacing existing signature

查看文件签名状态的信息:

$ codesign -vv -d ~/Desktop/AwesomeProject.app

得到的结果:

Executable=/Users/ShannonChen/Desktop/AwesomeProject.app/AwesomeProject
Identifier=org.reactjs.native.example.AwesomeProject
Format=app bundle with Mach-O thin (x86_64)
CodeDirectory v=20400 size=55629 flags=0x0(none) hashes=1731+3 location=embedded
Signature size=4799
Authority=iPhone Developer: 273879688@qq.com (C6KU79QV5A)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=2019年2月15日 下午4:19:35
Info.plist entries=29
TeamIdentifier=L32PN8QKLZ
Sealed Resources version=2 rules=13 files=12
Internal requirements count=1 size=208

检查一下封印是否完好,没有任何输出说明签名是完好的:

$ codesign --verify ~/Desktop/AwesomeProject.app

程序包和其他资源文件

为一个程序包设置签名时,这个包中的所有资源文件也都会被设置签名,包括图片、XIB/NIB 文件、存档文件(archives),甚至是证书文件。

为了达到为所有文件设置签名的目的,签名的过程中会在程序包中新建一个叫做 _CodeSignatue/CodeResources 的文件,这个文件实际上是一个 xml 文件,其中定义了被签名的程序包中所有文件的签名。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>files</key>
  <dict>
  ...
  </dict>
  <key>files2</key>
  <dict>
    <key>Base.lproj/LaunchScreen.nib</key>
    <dict>
      <key>hash</key>
      <data>
      hTT3EydgxVsF1sYscxcv10yz+kw=
      </data>
      <key>hash2</key>
      <data>
      u2MAOaedOTTaTtvI7WSWhH5swfkntlTSa1izuXC50Jk=
      </data>
    </dict>
    ...
  </dict>
  <key>rules</key>
  <dict>
  ...
  </dict>
  <key>rules2</key>
  <dict>
  ...
  </dict>
</dict>

三、授权机制 (Entitlements) 和配置文件 (Provisioning)

代码签名保证了这个应用里所包含的内容没有被修改过,而沙盒则是限制了应用访问系统的资源。

授权机制

授权机制决定了哪些系统资源在什么情况下允许被一个应用使用。简单的说它就是一个沙盒的配置列表,上面列出了哪些行为被允许,哪些会被拒绝。

在 Xcode 的 Capabilities 选项卡下选择一些选项之后,Xcode 会自动生成一个 .entitlements 文件,然后在需要的时候往里面添加条目。当构建整个应用时,这个文件也会提交给 codesign 作为应用所需要拥有哪些授权的参考。这些授权信息必须都在开发者中心的 App ID 中启用,并且包含在配置文件中。

授权信息会被包含在应用的签名信息中,你可以尝试查看签名信息中具体包含了什么授权信息:

$ codesign -d --entitlements - AwesomeProject.app

描述文件(Provisioning Profile)

一个描述文件是一组信息的集合,这组信息决定了某一个应用是否能够在某一个特定的设备上运行。

一个证书可以对应多个不同的描述文件。

如果你要在自己的机器上找到描述文件,在这个目录下 ~/Library/MobileDevice/Provisioning Profiles,Xcode 将从开发者中心下载的全部描述文件都放在了这里。

描述文件是一个根据密码讯息语法 (Cryptographic Message Syntax) 加密的文件,在 Mac 上不能直接打开查看,不过我们可以用 security 工具查看描述文件中的信息:

$ security cms -D -i ~/Library/MobileDevice/Provisioning\ Profiles/c1f2bcb3-6e73-4db8-abc7-260eef7f904c.mobileprovision
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>AppIDName</key>
  <string>onlyu</string>
  <key>ApplicationIdentifierPrefix</key>
  <array>
  <string>38K2TJBGY2</string>
  </array>
  <key>CreationDate</key>
  <date>2016-11-24T04:34:48Z</date>
  <key>Platform</key>
  <array>
    <string>iOS</string>
  </array>
  <key>DeveloperCertificates</key>
  <array>
    <data>MIIFjDCCBHSgAwIBAgIIedRPpOc4HBIwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTYxMTI0MDQyMTQ4WhcNMTkxMTI0MDQyMTQ4WjCBjTEaMBgGCgmSJomT8ixkAQEMCjM4SzJUSkJHWTIxMDAuBgNVBAMMJ2lQaG9uZSBEaXN0cmlidXRpb246IFlIT1VTRSBDb3Jwb3JhdGlvbjETMBEGA1UECwwKMzhLMlRKQkdZMjEbMBkGA1UECgwSWUhPVVNFIENvcnBvcmF0aW9uMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALmEtQvnT7HgEPrNctaIZkE5UVpHby+BwkcdcYUJpOEa4hgYjEKGQEm6kCCjaITygndAMLl9aa+uj7YXRZoTkIZI1GihaqfWfw0lpMrAWnRc2R6BEEQTpnu0+iEvIoqyXG49WW6jSpFok2Lk3kCFOCvKRauvm7QyvIM13t++wcujtATn4pVUGJ7sIIFDM3QPTwLrwA89n6EQb/14KWdk0I0U72gKeNXGYj2TNiT+qOpD94GCTyPSRCgN8xUL8FZQZQ/8cw9ZAwrHhO8h7tSpjEQr1VhdYrIYu4cBwpekANzDjZ+jDwld+WIra8wiETfoFvGgktQIkqx7glNeilITUCUCAwEAAaOCAeMwggHfMD8GCCsGAQUFBwEBBDMwMTAvBggrBgEFBQcwAYYjaHR0cDovL29jc3AuYXBwbGUuY29tL29jc3AwMi13d2RyMDEwHQYDVR0OBBYEFL7srqri6AwTjTOt0lKhQFNFKWYxMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZxVJUo7cwggEPBgNVHSAEggEGMIIBAjCB/wYJKoZIhvdjZAUBMIHxMIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3LmFwcGxlLmNvbS9hcHBsZWNhLzAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwMwEwYKKoZIhvdjZAYBBAEB/wQCBQAwDQYJKoZIhvcNAQEFBQADggEBACCsQ85W+jGC9Cl7LuNq3aW00UVJJcjIWEF0cXborTL9nP6oDlKv4cmSSrEVwSYm94pDoslFpPErwwGySvILxJ7yo7D3YA3myN06w67iFSioZlh28xMcCTdB3UnMKr2A8hw0mwMRY91PzhU6zKGgCCQ3IhzTtxZAZMVXGyjHFQMcQMR6tOGSHzdBNfaJ/aKfZ2OKuQk4IJlF01JF42mmNHMC/G6bfZzWVFPzDZ4O7Mq6jKzb9tb6yLEnIZwugqLfGt9fKWX9fq380IdgrNEuQf4iBb07kgBoADQjYNDXkzOVV3/ml/TuD68xetE7UG5zfNtd490G9WMgI6Mk7ffWhs8=</data>
  </array>
  <key>Entitlements</key>
  <dict>
    <key>keychain-access-groups</key>
    <array>
      <string>38K2TJBGY2.*</string>
    </array>
    <key>get-task-allow</key>
    <false/>
    <key>application-identifier</key>
    <string>38K2TJBGY2.com.yhouse.onlyu</string>
    <key>com.apple.developer.team-identifier</key>
    <string>38K2TJBGY2</string>
    <key>aps-environment</key>
    <string>production</string>
  </dict>
  <key>ExpirationDate</key>
  <date>2017-11-24T04:34:48Z</date>
  <key>Name</key>
  <string>onlyu_inHouse_distribution</string>
  <key>ProvisionsAllDevices</key>
  <true/>
  <key>TeamIdentifier</key>
  <array>
    <string>38K2TJBGY2</string>
  </array>
  <key>TeamName</key>
  <string>YHOUSE Corporation</string>
  <key>TimeToLive</key>
  <integer>365</integer>
  <key>UUID</key>
  <string>c1f2bcb3-6e73-4db8-abc7-260eef7f904c</string>
  <key>Version</key>
  <integer>1</integer>
</dict>
</plist>%

参考

ShannonChenCHN commented 5 years ago

iOS Code Signing Tutorials(Part 1 Getting Started)学习笔记

1. Code Signing

跟我们平时签合同一样,代码签名主要保证两点:

2. iOS Code Signing

3. 为什么需要学习 iOS Code Signing 相关的知识

4. 准备条件

5. 代码签名的好处和局限

好处:

局限:

参考

ShannonChenCHN commented 5 years ago

iOS Code Signing Tutorials(Part 2 Certificate Signing Requests)学习笔记

创建 iOS 开发/发布证书的第一步就是 Certificate Signing Requests。

1. 什么是 CSR

CSR 请求指的是申请者为了申请一个数字身份证书(digital identity certificate)而向权威认证机构发送一条信息。

创建 CSR 请求的过程是 PKI(Public Key Infrastructure)中的一个标准,在这个过程中,申请者要在本地的机器上生成一对公钥和私钥。申请者会将公钥、邮箱地址、国家等信息附加到 CSR 中,私钥会由申请者自己保留起来。

创建一个 CSR 请求通常需要以下这些信息:

2. 向苹果发送 CSR 请求

向苹果发送 CSR 请求时,苹果会验证请求信息,如果验证通过,就会分发证书。

CSR 请求的发起必须是在 macOS 机器上,发送 CSR 请求有两种方式:

在我们创建 CSR 文件时,发生了这几件事:

参考

ShannonChenCHN commented 5 years ago

iOS Code Signing Tutorials(Part 3 Certificates)学习笔记

1. 创建证书

根据官方文档,苹果总共有 10 种不同类型的证书。

创建证书的步骤:

双击下载下来的 .cer 证书,系统就会自动将它添加到 KeyChain 中。Keychain 会自动把它和之前创建 CSR 时自动生成的私钥归为一组,无论是在「我的证书」中查看证书还是在「密钥」中查看私钥,都能看到与之匹配的另一半。

2. 证书中有哪些信息

3. PKCS#12(p12)

当我们想要在另一台机器上上进行代码签名时,据需要将公钥证书和对应的私钥导出成一个 .p12 文件。

.p12 文件是根据 PKCS#12 标准生成的,PKCS#12 是一种公钥密码学标准(Public Key Cryptography Standard,PKCS)。这个标准用来将私钥和公钥证书保存成一个文件,并用密码保护起来。

.p12 文件中包含我们的公钥证书和对应的私钥,我们可以用下面的命令查看 .p12 文件中的信息:

$ openssl pkcs12 -info -in mycert.p12

参考

ShannonChenCHN commented 5 years ago

iOS Code Signing Tutorials(Part 4 Provisioning Profiles)学习笔记

1. 几个概念

Provisioning Profile 实际上是证书、app ID、device ID 和 entitlements 的组合。

2. 创建 Provisioning Profiles

注:从 Xcode 8 开始,苹果推出了 automatic code signing 机制,可以自动创建和管理 Provisioning Profiles。

手动创建 Provisioning Profile 的步骤:

双击下载好的 Provisioning Profile 后,系统会自动将其添加到 ~/Library/MobileDevice/Provisioning\ Profiles 目录下。

3. Provisioning Profiles 中有什么内容

iOS 代码签名概览

4. Xcode and Provisioning Profile

在 Xcode 的 General tab 中可以选择是否开启 Automatically manage sigining,在未开启 Automatically manage sigining 的模式下,可以在 Build Settings tab 中手动指定 Provisioning Profile。

参考

ShannonChenCHN commented 5 years ago

iOS Code Signing Tutorials(Part 5 Signing iOS App)学习笔记

1. Code Signing

Xcode 的自动签名只适合在本地机器上使用,如果需要在 CI 服务器上签名就需要自己去执行脚本调用相关工具进行手动签名了。

苹果提供了一个叫做 codesign 的命令行工具来进行手动签名,Xcode 的自动签名机制其实本质上也是在调用这个命令行工具。

2. Code Signing Stages

对 iOS App 签名时,会经历这三个步骤:

2.1 Seal

2.2 Digital Signature

代码签名软件用签名者的身份信息生成数字签名来对 seal 进行编码,以保证密封的完整性。

2.3 Code Requirement

Code Requirement 是验证代码签名时的规则。

3. Automatic Code Signing VS. Manual Code Signing

4. Re-Signing iOS Apps

准备条件:

重签名步骤:

参考

ShannonChenCHN commented 5 years ago

iOS 代码签名的原理总结

1. 为什么要代码签名

2. 什么是代码签名

image (图片来源:http://xelz.info/blog/2019/01/11/ios-code-signature/

3. 安装 iOS App 的几种方式

4. 几个概念

5. 代码签名的流程(以在真机上直接运行 app 为例)

image (图片来源:http://blog.cnbang.net/tech/3386/

6. 几个问题

参考

ShannonChenCHN commented 5 years ago

HTTPS、TLS 和 SSL

image TLS/SSL 握手过程(单向认证)

image 完整的 HTTPS 连接的建立过程

延伸阅读: