
简介面向 Android 应用开发者定位为 APK 签名与安全加固的实用工具可替代繁琐的原生签名流程用于增强应用防逆向、防篡改及防盗版能力尤其适合在应用市场上架前完成安全校验。包内文件共 28 个涵盖 9 个 dll、6 个 exe、5 个 jar 等核心组件并配有 cfg 配置文件与 docx、txt 操作说明便于在 Windows 等环境下直接运行整体 8.3MB轻量易部署。当前已有 949 人浏览学习。使用该工具可导入开发者 keystore/jks 签名文件完成签名后进一步执行代码混淆与资源加密加固最终输出高安全性 APK整个过程被封装为可视化操作降低了命令行使用门槛。资源适合对应用安全有要求的初中级开发者用于发布前构建加固与签名流程也可作为团队自动化打包环节的备选方案。 做Android开发的多少都经历过这种糟心事辛辛苦苦写了大半年的应用编译出APK丢到应用商店没过多久市场上就出现一个和你长得一模一样、但包体里塞满广告SDK的“孪生兄弟”。你的登录逻辑、支付回调、核心算法被反编译之后看得一干二净人家改个图标就能重新打包上架。想防住这种局面最直接的办法就是给你的APK做加固。360加固应该是我接触比较早的一套商业加固方案配套的签名工具链倒腾下来我对整个“加固—签名—上架”的流程也算摸出了一点门道。这篇东西就是来把这件事讲透的加固到底干了什么、为什么加固完必须重新签名、以及从下载加固包到最终签名验证的全过程连带我踩过的几个坑一起写出来。如果你正准备给自己辛苦开发的应用加一道保险或者第一次接触加固签名这套流程照着做基本不会跑偏。顺便多说一句网上经常有人搜“360加固去壳软件”这种词我自己的态度是做加固的目的应该放在“保护自己的应用”上而不是去拆别人的壳后者既涉及法律风险也不是一个开发者该花精力研究的方向。ipa签名工具那个是iOS生态里的另一套玩法别和Android的加固签名搞混了。1. 加固到底在防谁APK被逆向有多轻松1.1 APK本质就是一个zip包很多新手对APK的安全性有一种莫名的信任觉得应用打包之后就等于“加密”了。其实APK就是个zip压缩包你把后缀改成.zip解压出来就能看到AndroidManifest.xml、classes.dex、resources.arsc这些关键文件。其中classes.dex是Java层代码编译后的字节码而这种字节码格式带极强的“可还原性”。我用jadx或者dex2jar这类工具实际操作几分钟就能把一个没加固的APK还原成接近源码的Java工程。一个几百K的dex文件几乎能把你应用里的所有逻辑看个遍包名结构、网络请求地址、加密密钥、业务判断条件全部暴露无遗。这种“裸奔”状态对于一个投入了真金白银做开发的产品来说等于把底牌先亮给了对手。1.2 加固的本质给应用套一层壳360加固这类方案的核心思路通俗来说就是“加壳”。它会把你原本APK里的核心代码主要是classes.dex做一层加密或抽离处理然后在外面包裹一个新的壳程序。应用在安装运行的时候壳程序先启动在内存中把真正的代码解密出来再加载执行。最终用户拿到的APK直接用反编译工具看只能看到壳程序的代码核心业务逻辑被藏在加密层后面反编译工具根本读不出原来的内容。这就是加固最基础的一道防线。1.3 除了防读还要防篡改经常有人问加固到底是不是彻底安全说句大实话没有绝对无法绕过的加固方案任何加固都存在被攻破的可能性只是成本高低的问题。但我们平时遇到的大部分风险根本不是顶级的逆向高手而是批量抓包、反编译、改图标、重新打包上架的“搬运工”。加固能把这类低成本的篡改直接挡在门外。因为你把加密后的APK做任何手脚壳程序的自校验逻辑就会触发应用轻则闪退重则直接拒绝运行。对大多数人来说有这一层保护就已经把绝大多数风险挡掉了。我自己的感受是做商业应用特别是涉及登录、支付、用户数据这些敏感模块的加固不是可选项而是上线前的必选项。它解决的就是两个问题一是不让人轻易“看光”你的代码二是不让人轻易“改包”后拿去搞二次分发。2. 加固一分钟签名半小时为什么绕不过签名这道坎2.1 加固后的APK为什么必须重新签名先说签名的作用。Android系统要求所有安装的应用必须携带数字签名这个签名相当于应用的“身份证”。系统安装应用时会校验签名是否合法应用升级时校验新旧包的签名是否一致如果签名对不上系统直接拒绝安装或升级。但是加固服务在修改APK结构之后原本APK里META-INF目录下的签名文件CERT.RSA、CERT.SF、MANIFEST.MF已经和新的APK文件内容不匹配了。也就是说加固后的APK如果直接拿去安装系统校验签名时会发现文件摘要对不上报“应用未安装”或“签名不一致”的错误。所以加固产物拿到手之后第一件事就是重新用你的正式keystore给这个新包签名。这一步看似简单但恰恰是很多人翻车的重灾区。我见过有同事在加固平台下载完加固包之后直接拿Android Studio又编译了一次结果把加固壳整体破坏了应用一启动就闪退。后面会细讲这个坑怎么躲。2.2 签名方案怎么选v1、v2、v3的关系Android签名方案演进到现在主流接触到的有三个版本v1JAR签名、v2APK签名方案、v3支持密钥轮换的签名方案。v1签名其实早在Android诞生初期就有了它校验的是APK包内每一个具体文件的摘要信息。v2签名则是Android 7.0API 24引入的它校验的是整个APK的摘要这种方式签名验证速度更快安全性也更高。v3在v2的基础上增加了密钥轮换机制一般个人开发者用不上。这里最关键的坑在于v2签名只覆盖Android 7.0及以上系统。如果你只做v2签名包发到Android 7.0以下的设备上系统会直接提示签名校验失败无法安装。所以稳妥的做法是同时开启v1和v2双签让新老系统都能正常识别。实际用360加固那个流程时平台端的签名方案默认值不一定合你的意签名工具的手动操作在v1和v2的选择上也经常让新手迷糊。我的结论是别折腾统一走“v1v2双签”这条最稳的路。2.3 加固服务里的签名参数填哪些走加固平台的在线加固流程时一般会让你填签名相关信息包括keystore文件、别名alias、storepass和keypass。这些参数必须和最终签名输出保持一致否则后续自己签名时会出现数据对不上的诡异问题。一个容易忽略的细节是上传到加固平台的那个原始APK最好已经用最终的正式keystore签过一遍。这样做的好处是最终加固签名后的包在市场上的表现和你预期一致避免某些渠道后台在签名匹配校验上出幺蛾子。3. 实操签名jarsigner、apksigner、zipalign一个都不许错3.1 工具链准备签名工具主要依赖两块一是JDK自带的keytool和jarsigner二是Android SDK build-tools里的apksigner和zipalign。如果你电脑上装过Android Studiobuild-tools目录下大概率已经有这些工具了。我的习惯是手动维护一个SDK环境变量方便在命令行里直接调用export ANDROID_HOME/你的SDK路径 export PATH$ANDROID_HOME/build-tools/你的版本号:$PATH用之前先检查一下apksigner是否可用运行apksigner --version能打印版本号就说明OK。3.2 从加固包到可上架APK的完整命令流程拿到360加固平台下载下来的加固APK后我一般按下面这套步骤走第一步zipalign对齐zipalign -v 4 input_jiagu.apk aligned.apkzipalign的作用是把APK内的资源文件按4字节对齐这样系统在读取资源时能减少内存映射的次数运行效率更高内存占用也更低。为什么要放在签名前因为对齐操作会修改APK内部的压缩条目如果放在签名之后做v2签名校验的APK整体摘要就失效了。第二步apksigner签名apksigner sign \ --ks your.keystore \ --ks-key-alias your_alias \ --ks-pass pass:你的storepass \ --key-pass pass:你的keypass \ --v1-signing-enabled true \ --v2-signing-enabled true \ --out signed.apk aligned.apk这段命令就是把之前对齐好的APK用你的keystore做v1v2双签输出签名后的正式包。如果你不习惯命令行传密码也可以去掉--ks-pass和--key-pass工具会提示你交互式输入这样也能避免密码出现在shell历史记录里。顺便说下老牌的jarsigner。如果你的项目还在用纯v1签名命令长这样jarsigner -verbose \ -sigalg SHA1withRSA \ -digestalg SHA1 \ -keystore your.keystore \ -storepass 你的storepass \ aligned.apk your_alias但jarsigner只支持v1签名Android 7.0之后出来的apksigner才是首选。我现在的项目已经彻底转向apksigner了。第三步验证签名结果apksigner verify -v signed.apk apksigner verify --print-certs signed.apk第一条命令会列出这个APK使用的签名方案第二条会打印出证书的SHA256指纹和DN信息。这个步骤千万别省很多“签名成功”实际上只走了v1或者签名用的keystore根本不是你要发布的那把一旦上架之后换不了签名后悔都来不及。3.3 两种签名方式怎么选对比项jarsignerapksigner签名方案仅v1v1/v2/v3均可Android 7.0验证方式逐个校验文件摘要整体校验APK支持的minSdk所有版本所有版本v1v2双签时推荐程度老项目兼容用新项目首选一句话总结只要你的编译环境里能拿到apksigner就直接用它别再回头碰jarsigner了。v1v2双签这个配置既兼容Android 7.0以下的老设备也不损失新系统上的安全性和安装效率。4. 我踩过的签名坑从密钥丢失到兼容性翻车4.1 大坑之一keystore丢了应用升级全线崩溃这个坑几乎每个做过Android开发的人都听说过但总有前赴后继的人往里跳。keystore就是应用的身份证明一旦丢失意味着你永远无法对现有应用做签名升级。用户已经安装的版本无法覆盖安装唯一的出路是换包名重新上架或者引导用户卸载重装——这个代价基本等于从零开始攒用户。所以我一向来强调keystore至少备份到三个不同的安全位置本地磁盘、加密U盘、私有云盘同时把storepass和alias写进一个单独的密码管理工具里不要和代码仓库放一起。另外创建keystore时尽量把有效期拉长比如30年keytool -genkeypair -v \ -keystore your.keystore \ -alias your_alias \ -keyalg RSA \ -keysize 2048 \ -validity 10950有些应用商店对签名证书的有效期很敏感太短的时间可能导致审核不通过10950天30年是行业内比较常见的做法。4.2 大坑之二签名方案与设备版本不匹配有次我给一个老项目做加固当时图省事只签了v2自己手上测试机全是Android 8.0以上怎么跑都没问题。结果灰度测试阶段有用户反馈手机是Android 6.0安装时报“解析包时出现问题”。查了一下才发现v2签名在Android 7.0以下根本不识别系统只认v1签名。那次的教训很深刻。现在我做签名配置永远默认v1v2双开。只有在很特殊的情况比如明确所有用户设备都在Android 7.0以上或者某些极端的包体大小需求我才会考虑只做v2签名。为了省那几毫秒的验证时间而丢掉一整批存量用户这笔账怎么算都不划算。4.3 大坑之三二次构建把加固壳搞炸了这个坑发生在一个外包项目上。当时从加固平台下载完加固包同事觉得包里的图标要换一下直接拉到Android Studio里改了个资源文件然后点了Build APK。结果上线后大量用户反馈“应用闪退”“启动黑屏”。事后排查发现Android Studio的构建流程会对APK做重新打包和签名这个过程把原来的加固壳和加密的dex数据全部破坏了应用运行起来后自校验不过直接崩溃。这也是我反复强调的一点已加固的APK是“最终产物”任何二次构建、二次打包的行为都会破坏它的完整性。要改资源、改逻辑回到源码层面重新编译、重新加固、重新签名流程重走一遍而不是在加固包上“打个补丁”。4.4 大坑之四模拟器上闪退不是包的锅加固后的APK在模拟器上运行的兼容性普遍比真机差因为很多加固方案的壳程序会检测运行环境如果发现是模拟器会直接拒绝运行防止攻击者在模拟器里做动态分析。遇到这种情况不要急着怀疑自己的签名有问题先拿到真机上实测。特别是那些带x86_64架构的模拟器更容易触发这类问题。我的习惯是签名验证通过之后先在一台主流品牌真机上安装测试再考虑上架。如果真机没问题模拟器上闪退大概率是加固壳的“脾气”跟你无关。5. 批量签名与自动化把加固签名做成流水线5.1 一个能直接用的批量签名脚本如果你的项目是多渠道打包比如要同时出华为、小米、应用宝、官网等多个渠道包一个包一个包手动签名既低效又容易漏。我写了一个简单的bash脚本专门用来批量签名一批加固包#!/bin/bash KEYSTORE/path/to/your.keystore ALIASyour_alias STOREPASS${STORE_PASS} KEYPASS${KEY_PASS} INPUT_DIR./jiagu_output OUTPUT_DIR./signed_apks mkdir -p $OUTPUT_DIR for apk in $INPUT_DIR/*.apk; do name$(basename $apk) echo 正在对齐: $name zipalign -v 4 $apk $OUTPUT_DIR/aligned_$name echo 正在签名: $name apksigner sign \ --ks $KEYSTORE \ --ks-key-alias $ALIAS \ --ks-pass pass:$STOREPASS \ --key-pass pass:$KEYPASS \ --v1-signing-enabled true \ --v2-signing-enabled true \ --out $OUTPUT_DIR/signed_$name \ $OUTPUT_DIR/aligned_$name echo 正在验证: $name apksigner verify -v $OUTPUT_DIR/signed_$name rm -f $OUTPUT_DIR/aligned_$name done echo 全部完成脚本里的STOREPASS和KEYPASS我特意没有写死而是从环境变量读取避免密钥信息被提交到代码仓库里。如果你在团队里协作建议把签名相关的脚本单独放一个私有仓库和业务代码隔离。5.2 自动化流水线里的安全习惯现在不少团队已经用CI/CD流水线做自动打包加固和签名其实也可以集成进去。大体的流水线顺序是源码编译出release签名包上传到加固平台调用加固服务任务完成后下载加固包执行zipalign apksigner重新签名运行apksigner verify验证输出最终包并归档这里有个安全细节特别想强调不要在CI流水线的配置文件里硬编码keystore路径和密码。正确的做法是把这些敏感信息放到CI平台的Secret/变量管理里构建时动态注入环境变量。我见过不止一个团队因为图省事把签名密码写进Jenkinsfile里结果代码仓库被扫描到整个密钥库直接泄露。另外自动化脚本里建议在签名完成后立刻打印证书指纹方便人工确认这批次签名用的确实是正式密钥而不是某台构建机上残留的测试keystore。我个人的习惯是每次上架前的最终包都要跑一遍apksigner verify --print-certs核对证书指纹和上一个正式版本完全一致确认无误才提交到商店后台。这一步花不了多少时间但能拦住绝大多数因为签名问题导致的应用市场驳回。反正被“签名不一致”折磨过一次之后我是再也不敢跳过验证步骤了。本文还有配套的精品资源点击获取