android打包apk apk打包容易被破解吗

> 转[Android]APK打包历程详解(一)
转[Android]APK打包历程详解(一)
renji220 & &
发布时间: & &
浏览:127 & &
回复:0 & &
悬赏:0.0希赛币
转[Android]APK打包过程详解(一)
原文地址:如作者要求,请留言,博主可删除此博文。这篇文章对android打包过程的每个步骤做了详细的解释,这里我给一个Maven简单版本作为概括第一步, aapt,如果pom依赖中有apklib,将会先解压,与原文件一起产生aidl r等文件。第二步, aidl,javac,编译, 和传统maven编译一样, 需要解决依赖, 包冲突等还有scope。第三步, proguard,混淆,发布包需要,会把所有依赖的jar包放一起处理, 形成混淆后的单一jar包第四步, Dex, 混淆后的jar包, 处理成delvik认识的classes.dex。第五步, apkbuilder,打APK,将把所有资源文件, 和dex, 打包成为apk。 第六步, 有maven插件支持,将替换相应的资源文件和配置项, 最后再次调用aapt打包。最后& , jarsigner,ziplign就是类似签名,对齐等操作不表 渠道包的关键是在第六步, 注意是一次编译class,一次混淆。便可打出n多个渠道包。 每一步都是过程明确,产出目标明确,可以使用maven。如下引用原文:1.Android程序编译、打包、签名、发布的三种方式: 方式一:命令行手动编译打包 方式二:使用ant自动编译打包 方式三:使用eclipse+ADT编译打包 2.Android编译、打包的步骤: 2.1第一步 生成R.java类文件: Eclipse中会自动生成R.java,ant和命令行使用android SDK提供的aapt.ext程序生成R.java。 2.2第二步 将.aidl文件生成.java类文件: Eclipse中自动生成,ant和命令行使用android SDK提供的aidl.exe生成.java文件。 2.3第三步 编译.java类文件生成class文件: Eclipse中自动生成,ant和命令行使用jdk的javac编译java类文件生成class文件。 2.4第四步 将class文件打包生成classes.dex文件: Eclipse中自动生成,ant和命令行使用android SDK提供的dx.bat命令行脚本生成classes.dex文件。 2.5第五步 打包资源文件(包括res、assets、androidmanifest.xml等): Eclipse中自动生成,ant和命令行使用Android SDK提供的aapt.exe生成资源包文件。 2.6第六步 生成未签名的apk安装文件: Eclipse中自动生成debug签名文件存放在bin目录中,ant和命令行使用android SDK提供的apkbuilder.bat命令脚本生成未签名的apk安装文件。 2.7第七步 对未签名的apk进行签名生成签名后的android文件: Eclipse中使用Android Tools进行签名,ant和命令行使用jdk的jarsigner对未签名的包进行apk签名。3.命令行手动编译打包详解 详见:4.ant自动打包android程序详解 4.1生成R.java类文件: &&   &!-- Generate the R.java file for this project's resources. --&
&target name="resource-src" depends="copy"&
&echo&Generating R.java / Manifest.java from the resources...&/echo&
&exec executable="${aapt}" failonerror="true"&
&arg value="package" /&
&arg value="-m" /&
&arg value="-J" /&
&arg value="${outdir-gen}" /&
&arg value="-M" /&
&arg value="AndroidManifest.xml" /&
&arg value="-S" /&
&arg value="${resource-dir}" /&
&arg value="-I" /&
&arg value="${android-jar}" /&
&/target& 4.2将.aidl文件生成.java类文件: &   &!-- Generate java classes from .aidl files. --&
&target name="aidl" depends="copy"&
&echo&Compiling aidl files into Java classes...&/echo&
&apply executable="${aidl}" failonerror="true"&
&arg value="-p${android-framework}" /&
&arg value="-I${srcdir}" /&
&fileset dir="${srcdir}"&
&include name="**/*.aidl"/&
&/fileset&
&/target& 4.3编译.java类文件生成class文件: &&   &!-- Compile this project's .java files into .class files. --&
&target name="compile" depends="copy, resource-src, aidl"&
&javac encoding="GB18030" target="1.5" debug="true" extdirs=""
srcdir="."
destdir="${outdir-classes}"
bootclasspath="${android-jar}"&
&classpath&
&fileset dir="${external-libs}" includes="*.jar"/&
&/classpath&
&/target& && 4.4第四步 将class文件打包生成classes.dex文件: &&   &!-- Convert this project's .class files into .dex files. --&
&target name="dex" depends="compile"&
&echo&Converting compiled files and external libraries into ${outdir}/${dex-file}...&/echo&
&apply executable="${dx}" failonerror="true" parallel="true"&
&arg value="--dex" /&
&arg value="--output=${intermediate-dex-ospath}" /&
&arg path="${outdir-obfuscate-classes-ospath}" /&
&fileset dir="${external-libs}" includes="*.jar"/&
&/target& 4.5第五步 打包资源文件(包括res、assets、androidmanifest.xml等): &   &!-- Put the project's resources into the output package file. --&
&target name="package-res-and-assets"&
&echo&Packaging resources and assets...&/echo&
&exec executable="${aapt}" failonerror="true"&
&arg value="package" /&
&arg value="-f" /&
&arg value="-M" /&
&arg value="AndroidManifest.xml" /&
&arg value="-S" /&
&arg value="${resource-dir}" /&
&arg value="-A" /&
&arg value="${asset-dir}" /&
&arg value="-I" /&
&arg value="${android-jar}" /&
&arg value="-F" /&
&arg value="${resources-package}" /&
&/target& 4.6第六步 生成未签名的apk安装文件:
  &target name="package" depends="dex, package-res"&
&echo&Packaging ${out-unsigned-package} for release...&/echo&
&exec executable="${apk-builder}" failonerror="true"&
&arg value="${out-unsigned-package-ospath}" /&
&arg value="-u" /&
&arg value="-z" /&
&arg value="${resources-package-ospath}" /&
&arg value="-f" /&
&arg value="${intermediate-dex-ospath}" /&
&arg value="-rf" /&
&arg value="${srcdir-ospath}" /&
&arg value="-rj" /&
&arg value="${external-libs-ospath}" /&
&echo&It will need to be signed with jarsigner before being published.&/echo&
&/target& &&& 4.7第七步 对未签名的apk进行签名生成签名后的android文件: &target name="jarsigner" depends="package"&   &echo&Packaging ${out-unsigned-package} for release...&/echo&
&exec executable="${jarsigner}" failonerror="true"&
&arg value="-verbose" /&
&arg value="-storepass" /&
&arg value="byread002" /&
&arg value="-keypass" /&
&arg value="byread002" /&
&arg value="-keystore" /&
&arg value="bbyread.keystore" /&
&arg value="-signedjar" /&
&arg value="${out-signed-package-ospath}" /&
&arg value="${out-unsigned-package-ospath}" /&
&arg value="byread" /&
Ant配置文件:  & xml version="1.0"
&project name="Byread" default="debug"&
&!-- SDK Locations --&
&property name="sdk2.2-folder" value="F:\explorer\android-sdk-windows2.2" /&
&property name="sdk-folder" value="${sdk2.2-folder}/platforms/android-3" /&
&property name="sdk-tools" value="${sdk-folder}/tools" /&
&property name="android-tools" value="${sdk2.2-folder}/tools" /&
&property name="proguardpath" location="${wtkhome}/lib/proguard" /&
&!-- step 1.generate pile java to class by javac。exe 3.generate classes.dex by dx.bat
&!-- 4.package resources by aapt 5. package resource and classes.dex by apkbuilder.bat 6.sign apk by jarsinger --&
&!-- Tools --&
&property name="aapt" value="${sdk-tools}/aapt.exe" /&
&property name="dx" value="${sdk-tools}/dx.bat" /&
&property name="apk-builder" value="${android-tools}/apkbuilder.bat" /&
&property name="aidl" value="${android-tools}/aidl.exe" /&
&property name="adb" value="${android-tools}/adb.exe" /&
&property name="android-jar" value="${sdk-folder}/android.jar" /&
&property name="jarsigner" value="C:\Program Files\Java\jdk1.6.0_07\bin\jarsigner.exe" /&
&!-- Application Package Name --&
&property name="application-package" value="com.byread.reader" /&
&property name="useragent" value="byAndroidWeb" /&
&property name="version" value="1.02" /&
&!-- The intermediates directory --&
&!-- Eclipse uses "bin" for its own output, so we do the same. --&
&property name="outdir-bin" value="bin" /&
&property name="outdir-gen" value="gen" /&
&!-- source directories --&
&property name="resource-dir" value="res" /&
&property name="asset-dir" value="assets" /&
&property name="srcdir" value="src" /&
&property name="srcdir-ospath" value="${basedir}/${srcdir}" /&
&property name="external-libs" value="libs" /&
&property name="external-libs-ospath" value="${basedir}/${external-libs}" /&
&!-- dest directories --&
&property name="des-resource-dir" value="${outdir-bin}/res" /&
&property name="des-asset-dir" value="${outdir-bin}/assets" /&
&property name="des-srcdir" value="${outdir-bin}/src" /&
&property name="des-srcdir-ospath" value="${basedir}/${outdir-bin}/${srcdir}" /&
&property name="des-external-libs" value="${outdir-bin}/libs" /&
&property name="des-external-libs-ospath" value="${basedir}/${outdir-bin}/${external-libs}" /&
&!-- Output directories --&
&property name="outdir-classes" value="${outdir-bin}/src" /&
&property name="outdir-obfuscate-classes" value="${outdir-bin}/classes" /&
&property name="outdir-obfuscate-classes-ospath" value="${basedir}/${outdir-obfuscate-classes}" /&
&!-- Intermediate files --&
&property name="dex-file" value="classes.dex" /&
&property name="intermediate-dex" value="${outdir-bin}/${dex-file}" /&
&property name="intermediate-dex-ospath" value="${basedir}/${intermediate-dex}" /&
&!-- The final package file to generate --&
&property name="resources-package" value="${outdir-bin}/${ant.project.name}" /&
&property name="resources-package-ospath" value="${basedir}/${resources-package}" /&
&property name="out-debug-package" value="${outdir-bin}/${ant.project.name}-debug.apk" /&
&property name="out-debug-package-ospath" value="${basedir}/${out-debug-package}" /&
&property name="out-unsigned-package" value="${outdir-bin}/${ant.project.name}-unsigned.apk" /&
&property name="out-unsigned-package-ospath" value="${basedir}/${out-unsigned-package}" /&
&property name="out-signed-package" value="${useragent}\${ant.project.name}.apk" /&
&property name="out-signed-package-ospath" value="${basedir}\${out-signed-package}" /&
&!-- init --&
&target name="init"&
&echo&Creating all output directories &/echo&
&delete dir="${outdir-bin}" /&
&delete dir="${useragent}" /&
&mkdir dir="${outdir-bin}" /&
&mkdir dir="${outdir-classes}" /&
&mkdir dir="${useragent}" /&
&!-- copy original strings and modify useragent --&
&target name="copy" depends="init"&
&echo&copy files to output folder&/echo&
&delete file="${resource-dir}\values\strings.xml"/&
&copy file="strings.xml" todir="${resource-dir}\values" /&
&replace file="${resource-dir}\values\strings.xml" token="@USERAGENT@" value="${useragent}" encoding="utf-8"/&
&!-- Generate the R.java file for this project's resources. --&
&target name="resource-src" depends="copy"&
&echo&Generating R.java / Manifest.java from the resources...&/echo&
&exec executable="${aapt}" failonerror="true"&
&arg value="package" /&
&arg value="-m" /&
&arg value="-J" /&
&arg value="${outdir-gen}" /&
&arg value="-M" /&
&arg value="AndroidManifest.xml" /&
&arg value="-S" /&
&arg value="${resource-dir}" /&
&arg value="-I" /&
&arg value="${android-jar}" /&
&!-- Generate java classes from .aidl files. --&
&target name="aidl" depends="copy"&
&echo&Compiling aidl files into Java classes...&/echo&
&apply executable="${aidl}" failonerror="true"&
&arg value="-p${android-framework}" /&
&arg value="-I${srcdir}" /&
&fileset dir="${srcdir}"&
&include name="**/*.aidl"/&
&/fileset&
&!-- Compile this project's .java files into .class files. --&
&target name="compile" depends="copy, resource-src, aidl"&
&javac encoding="GB18030" target="1.5" debug="true" extdirs=""
srcdir="."
destdir="${outdir-classes}"
bootclasspath="${android-jar}"&
&classpath&
&fileset dir="${external-libs}" includes="*.jar"/&
&/classpath&
&!-- Convert this project's .class files into .dex files. --&
&target name="dex" depends="compile"&
&echo&Converting compiled files and external libraries into ${outdir}/${dex-file}...&/echo&
&apply executable="${dx}" failonerror="true" parallel="true"&
&arg value="--dex" /&
&arg value="--output=${intermediate-dex-ospath}" /&
&arg path="${outdir-obfuscate-classes-ospath}" /&
&fileset dir="${external-libs}" includes="*.jar"/&
&!-- Put the project's resources into the output package file. --&
&target name="package-res-and-assets"&
&echo&Packaging resources and assets...&/echo&
&exec executable="${aapt}" failonerror="true"&
&arg value="package" /&
&arg value="-f" /&
&arg value="-M" /&
&arg value="AndroidManifest.xml" /&
&arg value="-S" /&
&arg value="${resource-dir}" /&
&arg value="-A" /&
&arg value="${asset-dir}" /&
&arg value="-I" /&
&arg value="${android-jar}" /&
&arg value="-F" /&
&arg value="${resources-package}" /&
&!-- Same as package-res-and-assets, but without "-A ${asset-dir}" --&
&target name="package-res-no-assets"&
&echo&Packaging resources...&/echo&
&exec executable="${aapt}" failonerror="true"&
&arg value="package" /&
&arg value="-f" /&
&arg value="-M" /&
&arg value="AndroidManifest.xml" /&
&arg value="-S" /&
&arg value="${resource-dir}" /&
&!-- No assets directory --&
&arg value="-I" /&
&arg value="${android-jar}" /&
&arg value="-F" /&
&arg value="${resources-package}" /&
&!-- Invoke the proper target depending on whether or not
an assets directory is present. --&
&!-- TODO: find a nicer way to include the "-A ${asset-dir}" argument
only when the assets dir exists. --&
&target name="package-res"&
&available file="${asset-dir}" type="dir"
property="res-target" value="and-assets" /&
&property name="res-target" value="no-assets" /&
&antcall target="package-res-${res-target}" /&
&!-- Package the application and sign it with a debug key.
This is the default target when building. It is used for debug. --&
&target name="debug" depends="dex, package-res"&
&echo&Packaging ${out-debug-package}, and signing it with a debug key...&/echo&
&exec executable="${apk-builder}" failonerror="true"&
&arg value="${out-debug-package-ospath}" /&
&arg value="-z" /&
&arg value="${resources-package-ospath}" /&
&arg value="-f" /&
&arg value="${intermediate-dex-ospath}" /&
&arg value="-rf" /&
&arg value="${srcdir-ospath}" /&
&arg value="-rj" /&
&arg value="${external-libs-ospath}" /&
&!-- Package the application without signing it.
This allows for the application to be signed later with an official publishing key. --&
&target name="package" depends="dex, package-res"&
&echo&Packaging ${out-unsigned-package} for release...&/echo&
&exec executable="${apk-builder}" failonerror="true"&
&arg value="${out-unsigned-package-ospath}" /&
&arg value="-u" /&
&arg value="-z" /&
&arg value="${resources-package-ospath}" /&
&arg value="-f" /&
&arg value="${intermediate-dex-ospath}" /&
&arg value="-rf" /&
&arg value="${srcdir-ospath}" /&
&arg value="-rj" /&
&arg value="${external-libs-ospath}" /&
&echo&It will need to be signed with jarsigner before being published.&/echo&
&target name="jarsigner" depends="package"&
&echo&Packaging ${out-unsigned-package} for release...&/echo&
&exec executable="${jarsigner}" failonerror="true"&
&arg value="-verbose" /&
&arg value="-storepass" /&
&arg value="byread002" /&
&arg value="-keypass" /&
&arg value="byread002" /&
&arg value="-keystore" /&
&arg value="bbyread.keystore" /&
&arg value="-signedjar" /&
&arg value="${out-signed-package-ospath}" /&
&arg value="${out-unsigned-package-ospath}" /&
&arg value="byread" /&
&target name="release" depends="jarsigner"&
&echo&release for release...&/echo&
&!-- Install the package on the default emulator --&
&target name="install" depends="debug"&
&echo&Installing ${out-debug-package} onto default emulator...&/echo&
&exec executable="${adb}" failonerror="true"&
&arg value="install" /&
&arg value="${out-debug-package}" /&
&target name="reinstall" depends="debug"&
&echo&Installing ${out-debug-package} onto default emulator...&/echo&
&exec executable="${adb}" failonerror="true"&
&arg value="install" /&
&arg value="-r" /&
&arg value="${out-debug-package}" /&
&!-- Uinstall the package from the default emulator --&
&target name="uninstall"&
&echo&Uninstalling ${application-package} from the default emulator...&/echo&
&exec executable="${adb}" failonerror="true"&
&arg value="uninstall" /&
&arg value="${application-package}" /&
&/project&
5.eclipse打包签名 详见:
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&sunzeduo 的BLOG
用户名:sunzeduo
文章数:199
评论数:60
访问量:89611
注册日期:
阅读量:5863
阅读量:12276
阅读量:309518
阅读量:1025545
51CTO推荐博文
以下内容从
这个博客转载过来,由于原理很简单,不用说什么东西,但是为了服务各位看官,自己写了一个例子供大家参考,有源码例子工程理解起来更方便...客户端软件发布后,可能会被他人破解使用。破解的目的可能是汉化、去广告、加入便捷功能,但也有可能是植入恶意模块。Androd 也存在这个问题。Android 应用程序在发布前,都必须被签名。假设用于签名的密钥不被泄露或共享,我们可以认为,当被破解的Android软件重新打包后,其 “签名”必然与官方版本不同。这个“签名”到底是什么东西?如果你手头方便的话,可以随便解压一个APK。打开解压目录,“META-INF”里面就是签名内容保存的地方。 签名过程的源码在,核心代码从()。首先,签名程序将遍历APK里的所有文件,并用得出每个文件的“摘要信息” 。这些摘要信息就通通记录在“META-INF”目录的“MANIFEST.MF”文件中。所以得出解决方案一:可以比对MANIFEST.MF里各个摘要信息是否相同,来获知APK是否被修改。(比对样本是“官方”APK,下同)真正的“签名”却还没开始,因为还没有用到公/私钥。MANIFEST.MF的生成,提供了用密钥进行签名的清单。接下来,会对MANIFEST.MF里所有文件的“摘要信息”用私钥进行二次加密,采用的加密算法是“”非对称加密算法。生成的信息记录在目录下".SF"结尾的文件里。(,)和解决方案一相同,我们同样可以比对此文件,获知APK是否被篡改。姑且不占用“解决方案二”这个名头,继续往下分析。最后,将公钥用
算法加密保存在 “.RSA” 结尾的文件中(准确说是将包含了公钥等其它相关信息的数字证书加密保存。关于公/私钥、数字证书我搜了)。这个文件如果直接用文本阅读器打开,会看到乱码。(,)解决方案二:通过判断公钥是否一致,来获知软件是否被重新“打包”。解决方案二看起来更简单一些:1. 方案一,需要逐一比对apk里所有文件的摘要信息。2. 软件正常升级后,apk里面的内容必然改变。因此方案一的比对只能在同版本之间进行。OK。方案一的具体实现抛却不谈,因为有这个思路后,再没有任何技术困难。方案二,需要突破的地方是:如何才能解码 “.RSA” 文件,从而从中提取出公钥呢?这里需要引入另一个源码文件:。 核心代码是 方法,能清楚看到通过数字证书解析公钥的过程。但是这个类被加上了“hide”注解,所以并不能直接调用,但可以用反射去使用这些隐藏的API。最后得出方法:[java]publicstatic String getApkSignatureMD5(String apkPath) throws Exception {
Class clazz = Class.forName("android.content.pm.PackageParser");
Method parsePackageMethod = clazz.getMethod("parsePackage", File.class, String.class, DisplayMetrics.class, int.class);
Object packageParser = clazz.getConstructor(String.class).newInstance("");
Object packag = parsePackageMethod.invoke(packageParser, new File(apkPath), null, getContext().getResources().getDisplayMetrics(), 0x0004);
Method collectCertificatesMethod = clazz.getMethod("collectCertificates", Class.forName("android.content.pm.PackageParser$Package"), int.class);
collectCertificatesMethod.invoke(packageParser, packag, PackageManager.GET_SIGNATURES);
Signature mSignatures[] = (Signature[]) packag.getClass().getField("mSignatures").get(packag);
Signature apkSignature = mSignatures.length & 0 ? mSignatures[0] : null; if(apkSignature != null) { return StringUtils.md5(apkSignature.toCharsString());
} returnnull; } // 得到任意apk公钥信息的md5字符串
public static String getApkSignatureMD5(String apkPath) throws Exception {
Class clazz = Class.forName("android.content.pm.PackageParser");
Method parsePackageMethod = clazz.getMethod("parsePackage", File.class, String.class, DisplayMetrics.class, int.class);
Object packageParser = clazz.getConstructor(String.class).newInstance("");
Object packag = parsePackageMethod.invoke(packageParser, new File(apkPath), null, getContext().getResources().getDisplayMetrics(), 0x0004);
Method collectCertificatesMethod = clazz.getMethod("collectCertificates", Class.forName("android.content.pm.PackageParser$Package"), int.class);
collectCertificatesMethod.invoke(packageParser, packag, PackageManager.GET_SIGNATURES);
Signature mSignatures[] = (Signature[]) packag.getClass().getField("mSignatures").get(packag);
Signature apkSignature = mSignatures.length & 0 ? mSignatures[0] :
if(apkSignature != null) {
// 说明:没有提供md5的具体实现
return StringUtils.md5(apkSignature.toCharsString());
}如果当前运行的软件要得到自身的公钥信息,只需要得到apk位置就可以了(每个软件(非内置)安装后,都会在/data/system里保存一份apk文件):[java]String path = context.getApplicationInfo()
.publicSourceDir String path = context.getApplicationInfo()
.publicSourceDir接下来的事情就是找到比对时机。什么时候,采取什么形式来比对。建议可以在一些关键步骤(如程序第一次启动、安装成功、登陆/注册等)启动比对。若是b/s结构的程序,建议将比对放在服务器进行。也可以选择放在Native代码里进行比对(但是也更容易在破解后通过修改代码绕过)。本文若有不周详之处,欢迎读者指正。
了这篇文章
附件下载:  
类别:┆阅读(0)┆评论(0)
请输入验证码:}

我要回帖

更多关于 android命令行打包apk 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信