美文网首页iOS精选
iOS逆向编程第九篇:重签名处理

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

作者: 大雄記 | 来源:发表于2019-09-26 08:54 被阅读0次

    为什么我们自己开发的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防护混淆关键代码隐藏敏感方法调用等。此篇文章记录到此,其他的安全防护处理,在之后的文章另做的技术记录。

    相关文章

      网友评论

        本文标题:iOS逆向编程第九篇:重签名处理

        本文链接:https://www.haomeiwen.com/subject/riuaectx.html