app签名原理

解析:xcode怎么运行到手机上的?(苹果主要保证app安装时它认证的,并且是他有安装到指定的设备上,在app线上是没有这些描述文件)

第一步: mac电脑上要生成一对公钥M和私钥M (公钥是从私钥生成),CSR文件(包含公钥M,可以直接cat CSR文件看下面)(CSR文件包含信息看下面)中(也就是 钥匙串访问/证书助理/从证书颁发机构请求证书.. (CertificateSigningRequest.certSigningRequest))发给苹果服务器申请证书

通过 命令获得

CSR信息如下

第二步: 苹果用私钥S加密公钥M去生成证书一个证书和一个Provision profile文件,下载到本地,然后mac上会把私钥M和证书关联到一起(验证是否公私钥对应)也就是钥匙串中情况看图

比如如果别的mac也要编译app安装,要把私钥打成p12给他。其中证书包含mac上的公钥M和公钥M的hash值(防止篡改)

另外还有个Provision profile文件是注册的devices和cers等看图  ,可以通过这个路径找到(包含多个系统会进行匹配获取)

可以通过命令得到描述文件的信息(是xml文件可以在xcode的plist查看,也就是下面图的内容):

第三步: 通过私钥M进行app加密签名和第2步的证书和Provision profile文件打包到app中

问题:怎么验证Provision profile文件加入到app中?

解压app后得到其中有个embedded.mobileprovision就是第2步下载的描述文件,可以对比看下

第四步:  取出第3步的证书通过公钥A(苹果内置)进行解密得到公钥M(验证Hash值是否合法),然后通过公钥M解密app签名判断app是否被修改过,在手机上2次签名认证

问题:怎么签名证书在app中?

看上面解压app后的图 其中有个_CodeSignature/CodeResources这个就是,不止是app包中有,在macho可执行文件中也包含看图(通过machoView查看)

快速重签名app安装到手机上

手动重签名 (重签app安装到手机上)(验证通过✅)

注意这里ipa是已经砸壳后的ipa

查看本电脑所以证书 (也就是~/Library/MobileDevice/Provisioning Profiles 路径下的证书)

查看app是否签名?

Authority=(unavailable) 没有签名信息 越狱应用,被砸过壳。如果有签名信息:

  • Authority=Apple iPhone OS Application Signing
  • Authority=Apple iPhone Certification Authority

查看app是否加密?

cryptid 0 没有加密的(这个是越狱应用),非越狱cryptid 1


真正步骤开始

  1. 解压app后其中这些Plugins插件个人账户没办法重签名,可以直接删除这个Plugins文件夹
  2. 其中有Watch也没办法重签名 直接删除
  3. 对Framework要重签名

4. 给可执行文件执行权限  (chmod +x WeChat)

5.把xcode中的Demo编译的app包的embedded.mobileprovision描述文件到Wechat的app包中

6.把xcode中Demo的BundleID赋值到Wechat的info.plist文件的名字中(可以使用通配符com.shengshui.* (后面名字随便起))

7.查看下WeChat中的描述文件(刚才copy的那个)

找到权限文件Entitlements把<dict> </dict>copy生成entitlements.plist(可以用xcode生成)

8.把7步生成的entitlements.plist放在WeChat.app同级目录下

9.签名整个app

10.把app搞到一个单独文件夹中打包成ipa

11.在Xcode中Widow/Devicesa and Simulators/Installed apps 点击+ 把ipa安装上就ok了 (注意中间细节如果出错一步可能就不行了)


Xcode重签名(更方便调试)(重签app安装到手机上)(验证通过✅)

  1. 进入Xcode编译的Demo.app,找到越狱wechat.app 替换Demo.app (名字要一样 用Demo.app)
  2. Demo.app(上面被wechat替换的)显示包内容 找到info.plist文件把bundleID改为Demo的bundleID
  3. 对Framework/所以framework要重签名
  4. 给可执行文件执行权限  (chmod +x WeChat)
  5. 删除Plugins文件夹
  6. Watch也没办法重签名 直接删除
  7. 然后执行运行Demo到手机上就行了

脚本自动重签名app(重签app安装到手机上)(验证通过✅)

  1. xcode demo能运行手机上
  2. 把下面脚本copy到 TRAGETS/Bunild Phases 点击+新建一个Shell script ,然后copy里面
  3. 先编译下,把ipa放工程下的App文件夹中就行
  4. 直接运行到手机上了

逆向签名(八)

签名原理:

解析:xcode怎么运行到手机上的?(苹果主要保证app安装时它认证的,并且是他有安装到指定的设备上,在app线上是没有这些描述文件)

第一步: mac电脑上要生成一对公钥M和私钥M (公钥是从私钥生成),CSR文件(包含公钥M,可以直接cat CSR文件看下面)(CSR文件包含信息看下面)中(也就是 钥匙串访问/证书助理/从证书颁发机构请求证书.. (CertificateSigningRequest.certSigningRequest))发给苹果服务器申请证书

通过 命令获得

CSR信息如下

第二步: 苹果用私钥S加密公钥M去生成证书一个证书和一个Provision profile文件,下载到本地,然后mac上会把私钥M和证书关联到一起(验证是否公私钥对应)也就是钥匙串中情况看图

比如如果别的mac也要编译app安装,要把私钥打成p12给他。其中证书包含mac上的公钥M和公钥M的hash值(防止篡改)

另外还有个Provision profile文件是注册的devices和cers等看图  ,可以通过这个路径找到(包含多个系统会进行匹配获取)

可以通过命令得到描述文件的信息(是xml文件可以在xcode的plist查看,也就是下面图的内容):

第三步: 通过私钥M进行app加密签名和第2步的证书和Provision profile文件打包到app中

问题:怎么验证Provision profile文件加入到app中?

解压app后得到其中有个embedded.mobileprovision就是第2步下载的描述文件,可以对比看下

第四步 取出第3步的证书通过公钥A(苹果内置)进行解密得到公钥M(验证Hash值是否合法),然后通过公钥M解密app签名判断app是否被修改过,在手机上2次签名认证

问题:怎么签名证书在app中?

看上面解压app后的图 其中有个_CodeSignature/CodeResources这个就是,不止是app包中有,在macho可执行文件中也包含看图(通过machoView查看)


手动重签名 (重签app安装到手机上)

查看本电脑所以证书 (也就是~/Library/MobileDevice/Provisioning Profiles 路径下的证书)

查看app是否签名?

Authority=(unavailable) 没有签名信息 越狱应用,被砸过壳。如果有签名信息:

  • Authority=Apple iPhone OS Application Signing
  • Authority=Apple iPhone Certification Authority

查看app是否加密?

cryptid 0 没有加密的(这个是越狱应用),非越狱cryptid 1


  1. 解压app后其中这些Plugins插件个人账户没办法重签名,可以直接删除这个Plugins文件夹
  2. 其中有Watch也没办法重签名 直接删除
  3. 对Framework/所以framework要重签名

4. 给可执行文件执行权限  (chmod +x WeChat)

5.把xcode中的Demo编译的app包的embedded.mobileprovision描述文件到Wechat的app包中

6.把xcode中Demo的BundleID赋值到Wechat的info.plist文件的名字中(可以使用通配符com.shengshui.* (后面名字随便起))

7.查看下WeChat中的描述文件(刚才copy的那个)

找到权限文件Entitlements把<dict> </dict>copy生成entitlements.plist(可以用xcode生成)

8.把7步生成的entitlements.plist放在WeChat.app同级目录下

9.签名整个app

10.把app搞到一个单独文件夹中打包成ipa

11.在Xcode中Widow/Devicesa and Simulators/Installed apps 点击+ 把ipa安装上就ok了


Xcode重签名

  1. 进入Xcode编译的Demo.app,找到越狱wechat.app 替换Demo.app (名字要一样 用Demo.app)
  2. Demo.app(上面被wechat替换的)显示包内容 找到info.plist文件把bundleID改为Demo的bundleID
  3. 对Framework/所以framework要重签名
  4. 给可执行文件执行权限  (chmod +x WeChat)
  5. 删除Plugins文件夹
  6. Watch也没办法重签名 直接删除
  7. 然后执行运行Demo到手机上就行了

脚本自动化重签名

  1. xcode demo能运行手机上
  2. 把下面脚本copy到 TRAGETS/Bunild Phases 点击+新建一个Shell script ,然后copy里面
  3. 先编译下,把ipa放工程下的App文件夹中就行
  4. 直接运行到手机上了

逆向密码(七)

比如签名的CertificateSigningRequest.certSigningRequest文件就是base64对二进制编码

ValueCharValueCharValueCharValueChar
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/
source ASCII (if <128)Man
source octets77 (0x4d)97 (0x61)110 (0x6e)
Bit pattern010011010110000101101110
Index1922546
Base64-encodedTWFu
encoded octets84 (0x54)87 (0x57)70 (0x46)117 (0x75)
Text contentM
ASCII77 (0x4d)0 (0x00)0 (0x00)
Bit pattern010011010000000000000000
Index191600
Base64-encodedTQ==
Text contentMa
ASCII77 (0x4d)97 (0x61)0 (0x00)
Bit pattern010011010110000100000000
Index192240
Base64-encodedTWE=

把要编码的字母到对应assci二进制码 每6个二进制取一个值那对应的符号(其他的=补全)

base64大多是对加密后的数据进行编码

base64编码:

base64解码:

密码:

  • 非对称 (RSA,公私钥..)(由于简单的数据运算,效率比较低,主要用于加密核心的小数据)
  • 对称
  • HASH 哈希(散列)函数(不可逆,不能用加密解密)

对称密码:

  • 分组密码 (Feistel,DES,AES)
  • 序列密码 (线性反馈寄存器,内容扰乱系统,A5/1算法,RC5算法)
  • 密码模式 (电子密码本ECB,密码块链接CBC,填充密码块链接PCBC,密文反馈CFB,计数器模式CTR)

哈希密码:

  • 用途:文件校验,数字签名
  • 算法:MD4,MD5,SHA1

Openssl(公开加密算法库):

生成私钥:

从上面private.pem私钥中生成公钥 (公钥是根据私钥算出)

查看明文的private内容


MD5

一个二进制只有一个Hash值(可用于判断一个数据有没有被修改过)

 

 

–未完.待更新

静态语言、动态语言区别?

静态语言:

比如c语言,值声明了方法不实现是报错的,如果现实了比如下面简单代码,在编译时期就已经确定了run代码段的内存地址。比如int age=27;至于在要age名字有必要吗?

动态语言:

OC只声明不现实不报错,它是根据运行时macho上查找 IMP在Symbok Table 符号表查找(sel > IMP(地址)‘对应查看)

逆向ASLR(六)

程序是先装载的macho文件然后在装载依赖库

macho装载内存后,是一个虚拟内存(相对macho来说)

内存中不存在header ,load commands

__DATA段的VM Address是__PAGEZERO的VM Address+__TEXT段的VM Size(真实大小)(每次编译都会改变)


ASLR(Address space layout randomization)地址空间配置随机加载 

是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。据研究表明ASLR可以有效的降低缓冲区溢出攻击的成功率,如今Linux、FreeBSD、Windows等主流操作系统都已采用了该技术。

作用: 降低缓冲区溢出攻击的成功率

问题:0x1000063B8 是否[Began:withEvent:]地址?

比如要手动下方法断点,这时找不到真正的地址是无光动态调试,0x1000063B8其实并不是内存条上的真实地址,

通过image list 拿到macho文件在内存条的地址(比如0x0000000102598000 应该拿0x2598000)+0x1000063B8就是真实的地址了

问题:怎么拿到全局的变量?

比如定义了int age=27; 在macho中怎么找到(其中age这个变量名是个地址在编译时就已经有地址位置,要age名字没必要的) (静态语言就是根据把代码生成地址空间在编译时期就知道 比如c语言只声明不实现会报错。OC只声明不现实不报错,它是根据运行时macho上查找 IMP在Symbok Table查找)

  1. 获取&age地址 (0x00000001022fcfd8)
  2. &age-image list的macho的地址(0x00000001022f4000) =  0x8FD8
  3. 在2中相减得到的地址在macho(__DATA,__data)中查看


静态语言和动态语言区别?

静态语言就是根据把代码生成地址空间在编译时期就知道 比如c语言只声明不实现会报错。

OC只声明不现实不报错,它是根据运行时macho上查找 IMP在Symbok Table查找

逆向方法反汇编(五)

局部变量属于强引用。汇编代码:

#mark-1: 看汇编objc_msgSend 这里结构是

oc中调用: [Animal alloc]

objc_msgSend(Animal.class,@selector(alloc));

根据汇编也就是x0寄存器也类,x1寄存器是sel

#mark-3:

  • x0:animal对象
  • x1:nil  (也就是首页指针指向nil,释放原来的对象)

注意:objc_storeStrong

所有OC中使用Strong修饰的对象 实际调用的函数是objc_storeStrong,代码实现如下


上面的一些是动态分析,如果是在真实的项目中决定是非常的复杂,所有动态分析很麻烦,可以直接用ida工具来分析

查看ida分析和上面动态分析是一样结果,只是它的更加详细 函数名也一起展示了。

问题:看上图 地址都是text:000000010000….    中间都是一个1 (后面8个0),为什么?

0x100000000 是4个G的虚拟size  (也就是text是从0x100000000开始)

问题:ida是怎么知道 这个地址的函数名 类名等?

主要是通过mach0文件分析对应查找, 如图

逆向block(四)

  • globalblock (编译时期)
  • stackblock    (编译时期)
  • mallocblock    (运行时期)

汇编:

#mark-a:

x8是通过adrp add 算出地址是0x104b7c080,读内存地址 得到__NSGlobalBlock__,__NSGlobalBlock__是block的isa指针也就是在这附近有一个block的定义.


比如一些稍复杂的block定义:

汇编:

这时直接用动态调试非常麻烦(算地址再去macho查看),可以直接借助 ida工具来

逆向LLDB(三)

LLDB (Low Lever Debug)

常用指令

  • help breakpoint 产看breakpoint指令
  • breakpoint set -n funcRun   (-n是-name,  funcRun是方法名字) (简写 b funcRun)
  • breakpoint set -n “-[ViewController run]” -n “-[ViewController eat:]”   设置多个断点
  • breakpoint set –selector touchesBegan:withEvent:  断点所以得方法和类无光
  • breakpoint set –file ViewController.m  –selector touchesBegan:withEvent:   在指定文件中设置断点
  • breakpoint set -r Run:  遍历满足整个项目中符合Run:这个字符的所以方法
  • breakpoint list 断点的list
  • breakpoint disable 2.1  禁用2.1处断点(也就是funcRun处断点)
  • breakpoint enable 2.1  启用2.1处断点
  • breakpoint delete 2  删除一组断点 (删除一个是禁用,只有删除一组才可以删除)
  • breakpoint delete  全部删除
  • p 就是expression简写
  • poexpression -O
  • expression 断点修改…  (p (Animal *)self.cat    得到$2 然后再去设置$2.run 才能执行) (control+return 多行)
  • memory read 0x32…..  读内存地址 也可以用 x 0x32…
  • register read x1  读寄存器

  • up 查看堆栈上一个调用的函数
  • thread return  回滚堆栈上一个调用的函数 (再c执行就结束了 不会再往下走, 因为return)
  • frame select 5 查看bt后的#序号的函数,也就是直接断点到#序号的函数中
  • frame variable 查看整个方法中的参数

 

  • continue  简写c 继续执行
  • next 简写n  单步运行,一行一行代码走
  • step 简写s  单步运行,遇到子函数会进去


内存断点:(和断点的一些设置一样 delete 、list等)

  • watchpoint set variable cat->name  对cat的name设置内存断点(也就是name改变就断点)
  • watchpoint set expression 0x00000003d…    给内存地址设置断点

断点添加指令:

  • break command add 1              添加指令
  • breakpoint command list 1     查看1处指令
  • breakpoint command delte 1   删除指令


stop-hook

pass和debugView 不会触发,只对breadpoint,watchpoint

  • target stop-hook add -o “p self.cat.name”
  • target stop-hook delete  删除
  • undisplay 1           删除一组
  • target stop-hook list    查看所有

image

  • image lookup -a 0x32323f2    通过地址查看指令
  • image lookup -t Animal  查看类的信息 (包含了头文件)
  • image list

例子:真机上崩溃信息

可以用image lookup -a 0x18564ed8c 这样方式来看崩溃的堆栈信息


总结:

lldb在断点启动的时候会走 $HOME/.lldbinit 文件 (如果没有自己新建),里面可以配置一些指令,一般是用作导入配置文件

逆向Mach-o(二)

Mach-o(Mach Ojbect缩写)文件有11种格式(并不是所有的可执行文件都有Mach-o),是Mac/iOS上用于存储程序,库的标准格式

Mach-o常见格式:

  • 可执行文件
  • object   (a. 其中包括.o 文件   b. .a静态库文件 其实就是N个.o文件集合)
  •   DYLIB:动态库 (a. dylib  b.framwork)
  • 动态连接器
  • DSYM

例子1:

把上面的代码文件.c编程.o执行命令

  • clang -c main.c   (会生成一个main.o) (也可以直接生成多个 clang -c main.c test.c)
  • file main.o  (main.o: Mach-O 64-bit object x86_64)(属于Mach-o 是一个object 不是可执行文件
  • clang main.o (或者生成cusmain clang -o cusmain main.0)(生成a.out 在file a.out (a.out: Mach-O 64-bit executable x86_64) (可执行文件))
  • ./a.out 直接执行 (Hello, World!)

上面那几步也可以直接生成可执行文件 :

例子2:多文件文件合并成一个可执行文件

这个文件类交Test.c  (不需要引入#include..),另一个文件还是上面的main.c (和.c顺序没关系)

执行下面命令合并(会有警告 没关系)

它会生成一个sks可执行文件,./sks 直接执行就行

*find找文件 find /cust/dsk -name “*.a”


动态库共享缓存:

为了提高性能,系统的动态库文件都存在动态库共享缓存里面(其中动态库只有一份)

比如上面的dyld_shared….x86_64h 多个app动态库都放在这,起到公用库的作用(类似单利) (通过动态连接器加载动态库)

动态加载器(动态连接器)(dyld) (用来加载动态库) (是dynamic linker可执行文件)

  • dynamic linker
  • dynamic loadel


二进制文件

其中xcode中默认是Executable可执行文件

  • Executable (默认)
  • Dynamic Library
  • Bundle
  • Static Library
  • Relocatable Object File

xcode,debug下生成app可执行文件是arm64, 在release中是多个架构,这个debug中YES是当前真机的架构

Architectures和有效架构是取交集,所有上面只生成arm64 armv7,在Architectures加一种就可以生成armv7s架构

在分析汇编代码的时候,大多时候值分析一个架构就可以(经常用于静态库):

拆分二进制文件:

合并:


MachO

MachO主要分为3大块:

  • MachO Header (包含整个架构的信息,load Commands数量等)
  • Load Commands (区域位置)
  • Data (代码 全局变量等)

MachO工具


附加: shell转成二进制可执行文件

http://www.datsi.fi.upm.es/~frosal/ 下载解压进入 然后执行make test

  • test.sh.x是加密后的可执行的二进制文件;用./test.sh.x即可运行,
  • test.sh.x.c是生成 test.sh.x的原文件(c语言)

-e:指定过期时间为2018年05月24日
-m:过期后打印出的信息;
-v: verbose
-r: 可在相同操作系统的不同主机上执行
-f: 指定源shell

另外的一种方式 gzexe test.sh