iOS逆向编程第九篇:重签名处理

为什么我们自己开发的App安装包不能随便安装到任意的手机呢?App安装包是自己的、手机是自己的,结果就是安装失败,有没有想过这个问题?下面我们来讲讲苹果公司设计的对App安装包的签名机制,并重点的讲解下怎么进行重签名以及反重签名的做法。

一、代码签名原理

想要重签名我们的APP安装包,我们先来了解下APP原始包的签名得到APP安装包过程。先上整体的流程图,然后再来解释每一步操作的过程:

①:通过Mac电脑创建的CSR文件苹果服务器申请证书CSR文件其实本质是Mac电脑创建的一对RSA公私钥中的公钥M,我们把CSR文件传给苹果服务器苹果服务器使用私钥ACSR文件进行加密和hash签名处理,生成一个证书文件。

②:我们从苹果服务器下载证书描述文件并安装到当前的Mac电脑中,Mac电脑会将对应的私钥M证书绑定存放在一起。(在手动管理证书的年代,为什么不能从苹果服务器直接下载了证书使用,而是一定要从证书创建者的Mac电脑中导出证书呢?就是因为私钥M的存在,现在是不是就能理解了)

③:打包的过程中,Mac电脑会使用证书下的私钥M对我们的原始APP包进行签名处理;并把证书以及描述文件都打包到APP的安装包中。

④:当我们的设备安装APP时,会先通过设备内嵌的公钥A证书描述文件做解密等处理,获取其中的内容,然后验证证书中的HASH值,来判断证书是否合法;验证APP的签名数据,判断APP是否被篡改过;判断当前设备是否存在可安装的设备列表中,判断描述文件info.plist中的BundleID是否一致等等。

⑤:最后完成APP的安装

Tips:提供一些查看或查找CSR文件证书描述文件内容使用到的命令

//查看CSR文件中的公钥内容
$cat CertificateSigningRequest.certSigningRequest

//查看CSR文件的其他信息(邮箱、加密方式、hash值算法)
$openssl asn1parse -i -in CertificateSigningRequest.certSigningRequest

//查看本机所有证书
$security find-identity -v -p codesigning

//查看描述文件的内容
$security cms -D -i 描述文件路径

二、通过终端命令手动重签名

我们在重签名之前,需要提前准备一些重签名必要的东西。

  • 砸过壳的IPA :可以去PP助手中下载越狱应用,自己砸壳的文章之后再进行分享;
  • 可正常使用证书 :重签名IPA包,意思是指替换掉旧的签名证书,使其能正常安装;

有了以上准备,我们就具体来试试手动重签名的操作。

第1步:解压砸过壳的IPA包,删除部分无法重签名的文件

A:删除`Payload` → `XXX.app` → `PlugIns`文件夹
B:删除`Payload` → `XXX.app` → `Watch`文件夹

第2步:PayloadXXX.appFramework文件夹下的XXX.framework进行签名。注意:如果IPA包中没有Framework文件夹,则可以跳过这步

//进入`XXX.app`目录下,执行如下命令(有很多`.framework`时需要多次执行)
$codesign -fs "证书" 需要签名的文件

第3步:App的可执行文件读写权限。

//进入`XXX.app`目录下,执行如下命令
$chmod +x 可执行文件名称

第4步:拷贝embedded.mobileprovision文件到Payload中,修改info.plist中的Bundle identifier

a. 将新证书的`embedded.mobileprovision`文件拷贝到`Payload`中
b. 将`info.plist`中的`Bundle identifier`值改为新证书对应的`Bundle identifier`值

第5步:生成.plist的权限文件

a. 进入`XXX.app`目录下,使用命令查看描述文件:$security cms -D -i 描述文件路径
b. 拷贝`Entitlements`键下的字典内容,将字典内容存储在新建的`XX.plist`文件
c. 把新建的`XX.plist`文件拷贝到`Playload`文件夹中

第6步:签名整个APP

//进入`Payload`文件夹下,执行如下命令
$codesign -fs "证书名称"  --no-strict --entitlements=XX.plist XXX.app

//查看APP的签名信息
$codesign -vv -d APP路径

//查看可执行文件的加密信息
$otool -l 可执行文件名称 | grep crypt

第7步:将已签名的APP包打包成IPA文件

//进入`Payload`的上级文件夹下,执行如下命令
$zip -ry XXX.ipa Payload

注意:手动重签名会出现很多安装异常的问题,因为可能有很多小细节没有处理或出现问题,所以一般都使用Xcode进行重签名处理。

三、通过Xcode进行重签名

苹果签名的所有细节处理都已经封装在Xcode中,所以我们可以使用Xcode来替我们做签名处理,只要替换Xcode签名的目标原文件达到欺骗Xcode的目的,使其对我们想要的原文件进行签名处理。

1、新建一个名为`AAA`的空工程,编译、运行使其安装到真机中。
2、解压砸过壳的`IPA`包,拷贝`Payload` → `XXX.app`到工程的`Products`下,重命名并替换`AAA.app`。
3、给`App`的可执行文件读写权限,进入`AAA.app`目录下执行命令:`$chmod +x 可执行文件名称`
4、删除部分无法重签名的文件;`①、删除Payload→AAA.app→PlugIns文件夹;②、删除Payload→AAA.app→Watch文件夹`
5、对`Payload`→`AAA.app`→`Framework`文件夹下的`XXX.framework`进行签名,进入`AAA.app`目录下执行命令:`$codesign -fs "证书" 需要签名的文件`
6、修改`AAA.app`→`info.plist`中的`Bundle identifier`值与当前工程的`Bundle identifier`值一致。
7、使用快捷键`command+R`运行当前的工程,此时Xcode已经完成了重签名处理。

最后注意:如果`IPA`包中没有`Framework`文件夹,则直接跳过第5步。

相比第一种手动重签名的方式,Xcode重签名就相对简单多了!

四、通过Run Script脚本进行重签名

相对手动重签名,Xcode重签名已经简单很多了,但是还不是最简单的

第1步:新建一个空工程,在工程目录下新建APP文件夹,将IPA包拷贝到APP目录下。
第2步:选择空工程Build Phases+New Run Script Phase添加一个脚本的入口
第3步:将如下的脚本内容,拷贝到Run Script

# ${SRCROOT} 它是工程文件所在的目录
TEMP_PATH="${SRCROOT}/Temp"
#资源文件夹
ASSETS_PATH="${SRCROOT}/APP"
#ipa包路径
TARGET_IPA_PATH="${ASSETS_PATH}/*.ipa"

#新建Temp文件夹
rm -rf "${SRCROOT}/Temp"
mkdir -p "${SRCROOT}/Temp"

#----------------------------------------
# 1. 解压IPA到Temp下
unzip -oqq "$TARGET_IPA_PATH" -d "$TEMP_PATH"
# 拿到解压的临时的APP的路径
TEMP_APP_PATH=$(set -- "$TEMP_PATH/Payload/"*.app;echo "$1")
# echo "路径是:$TEMP_APP_PATH"

#----------------------------------------
# 2. 将解压出来的.app拷贝进入工程下
# BUILT_PRODUCTS_DIR 工程生成的APP包的路径
# TARGET_NAME target名称
TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app"
echo "app路径:$TARGET_APP_PATH"

rm -rf "$TARGET_APP_PATH"
mkdir -p "$TARGET_APP_PATH"
cp -rf "$TEMP_APP_PATH/" "$TARGET_APP_PATH"

#----------------------------------------
# 3. 删除extension和WatchAPP.个人证书没法签名Extention
rm -rf "$TARGET_APP_PATH/PlugIns"
rm -rf "$TARGET_APP_PATH/Watch"

#----------------------------------------
# 4. 更新info.plist文件 CFBundleIdentifier
#  设置:"Set : KEY Value" "目标文件路径"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"

#----------------------------------------
# 5. 给MachO文件上执行权限
# 拿到MachO文件的路径
APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<`
#上可执行权限
chmod +x "$TARGET_APP_PATH/$APP_BINARY"

#----------------------------------------
# 6. 重签名第三方 FrameWorks
TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks"
if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ];
    then
for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"*
do

#签名
/usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK"
done
fi

五、重签名APP的用处

描述了这么多的重签名方法,有什么用处呢?当然不只是简单的在一个设备上安装多个相同应用这么简单。比如苹果商店有很多需要付费下载的应用,通过重签名后,就能免费进行安装和使用了;类似国内中的同步推91助手等平台提供很多免费应用,而这些应用在App Store中可能就需要付费下载了。所以大概总结了以下几点重签名的用途:
1、破解需付费下载的应用,比如:同步推91助手等平台。
2、通过注入FrameworkHook重签名APP中的方法,修改代码的执行顺序,比如:制作微信抢红包的外挂。
3、动态调试重签名的APP,查看界面布局等,比如:探究竞争对象发布的APP的新功能。

六、防止重签名的处理

在逆向编程中,重签名是一个很常用的的动态调试基本操作,所以做重签名的防护是很必要的一个步骤,下面来讲下防止别人重签名你的APP需要怎么处理。

我们先查看下Xcode使用的证书APP描述文件的对应关系:
第1步:进入Mac电脑中的钥匙串中,选择证书,双击签名使用的证书,查看并拷贝组织单位编号
第2步:进入XXX.app路径下,使用命令security cms -D -i embedded.mobileprovision查看embedded.mobileprovision内容,找到key = application-identifier对应的value值。

结合文章开篇所述的重签名步骤来思考,在任何必要的时候(例如:APP启动等),是否可以通过检测APP签名证书中的组织单位ID是否与Xcdoe工程中的内容一致来判断当前APP是否已经被重签名过。

void checkAppCodesignReplaced(NSString *bundleId)
{
    //描述文件路径
    NSString *embeddedPath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];
    //读取application-identifier注意描述文件的编码要使用:NSASCIIStringEncoding
    NSString *embeddedProvisioning = [NSString stringWithContentsOfFile:embeddedPath encoding:NSASCIIStringEncoding error:nil];
    NSArray *embeddedProvisioningLines = [embeddedProvisioning componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
    for (int i = 0; i < embeddedProvisioningLines.count; i ++) {
        if ([embeddedProvisioningLines[i] rangeOfString:@"application-identifier"].location != NSNotFound) {
            NSInteger fromPosition = [embeddedProvisioningLines[i+1] rangeOfString:@"<string>"].location+8;
            NSInteger toPosition = [embeddedProvisioningLines[i+1] rangeOfString:@"</string>"].location;
            NSRange range = NSMakeRange(fromPosition, (toPosition - fromPosition));
            NSString *fullIdentifier = [embeddedProvisioningLines[i+1] substringWithRange:range];
            NSArray *identifierComponents = [fullIdentifier componentsSeparatedByString:@"."];
            NSString *appIdentifier = [identifierComponents firstObject];
       
            //对比签名ID
            if (![appIdentifier isEqual:bundleId])  {
                asm( //exit
                    "mov X0,  #0\n"
                    "mov w16, #1\n"
                    "svc #0x80"
                    );
            }
            break;
        }
    }
}

注意:使用内联汇编代码(asm)是防止逆向工程师通过符号断点来定位exit的调用位置。

七、后续

在APP中仅仅加入防止重签名是远远不够的,对于逆向开发工程师来说,这种操作很容易就破解了。比如说使用HOOK,替换判断组织单位编号是否一致的方法,亦或是修改汇编代码,使用b指令直接跳过验证方法等等。所以我们还需要做很多其他的处理,才能达到APP安全防护的目的,比如说:反HOOK防护ptrace防护混淆关键代码隐藏敏感方法调用等。此篇文章记录到此,其他的安全防护处理,在之后的文章另做的技术记录。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容