著名的apktool是android逆向界用的最普遍的一个工具,这个项目的原始地址在这里http://code.google.com/p/android-apktool/,但是你们都懂的在天朝谷歌是无法访问的,所以直接上github的 https://github.com/brutall/brut.apktool。

在brut.apktool路径是主要代码所在,当然还有brut.apktool.smali是反编译smali的目录,目测还有brut.j.common,brut.j.dir,brut.j.utils是用到java的一些类。

brut.apktool路径下的apktool-cli还不知道是干嘛的,总之下面的apktool-lib正是我们最需要了解的。

android目录是利用XmlPullParser实现的专门用于android当中xml的解码工具包。

brut/androlib目录正是我们研究的主题。

com/mindprod/ledatastream目录是le数据支持库。

org/xmlpull/mxp1_serializer目录是XmlPullParser的Xml解析库。

androlib目录一览。

先看一下ApkDecoder这个类。

    public ApkDecoder(File apkFile, Androlib androlib) {
mAndrolib = androlib;
setApkFile(apkFile);
} public void setApkFile(File apkFile) {
mApkFile = new ExtFile(apkFile);
mResTable = null;
}
mResTable这个一直很迷惑,很多地方用到了它,但是目前还不住到具体是干嘛的,先不研究这个,继续往下看。
   public void setOutDir(File outDir) throws AndrolibException {
mOutDir = outDir;
} public void setApi(int api) {
mApi = api;
}

这两个方法一看名字就不言而喻,这里就不啰嗦了。多看了几行代码发现,这代码质量相当高,简直不要太优质,比起什么AxmlPrinter2的代码好看多了,呵呵!

下面就是反编译的核心方法了,客观请往下看。

 public void decode() throws AndrolibException, IOException,DirectoryException {
File outDir = getOutDir(); if (!mForceDelete && outDir.exists()) {//如果输出目录不是因为删除而不存在就抛出异常
throw new OutDirExistsException();
} if (!mApkFile.isFile() || !mApkFile.canRead()) {//如果apk文件不是文件类型或者不能读也抛出异常
throw new InFileNotFoundException();
} try {
OS.rmdir(outDir);//暂不明
} catch (BrutException ex) {
throw new AndrolibException(ex);
}
outDir.mkdirs(); LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + mApkFile.getName()); if (hasResources()) {//判断依据mApkFile.getDir().contraincontainsFile("resources.arsc")
setTargetSdkVersion();
setAnalysisMode(mAnalysisMode, true);//如果后面的参数为true,将会影响mResTable的取值
setCompressionMode();//mCompressResources赋值,res.arsc是个zip获取它的压缩模式是否是ZipEntry.DEFLATED默认 switch (mDecodeResources) {//这里默认是FULL
case DECODE_RESOURCES_NONE://不解码直接解压到指定res目录
mAndrolib.decodeResourcesRaw(mApkFile, outDir);
break;
case DECODE_RESOURCES_FULL://调用androilib.decodearesources方法,其实本质还是调AndrolibResources.decode()方法
mAndrolib.decodeResourcesFull(mApkFile, outDir, getResTable());
break;
}
} else {//没有资源文件
// if there's no resources.asrc, decode the manifest without looking
// up attribute references
if (hasManifest()) {//如果没有res.asrc就不需要查找manifest中的引用属性了
switch (mDecodeResources) {
case DECODE_RESOURCES_NONE:
mAndrolib.decodeManifestRaw(mApkFile, outDir);
break;
case DECODE_RESOURCES_FULL://调mAndRes.decodeManifest(resTable, apkFile, outDir)
mAndrolib.decodeManifestFull(mApkFile, outDir,
getResTable());
break;
}
}
} if (hasSources()) {//如果有源文件
switch (mDecodeSources) {
case DECODE_SOURCES_NONE://直接复制classes.dex
mAndrolib.decodeSourcesRaw(mApkFile, outDir, "classes.dex");
break;
case DECODE_SOURCES_SMALI://反编译成smali,SmaliDecoder.decode()
mAndrolib.decodeSourcesSmali(mApkFile, outDir, "classes.dex", mDebug, mDebugLinePrefix, mBakDeb, mApi);
break;
case DECODE_SOURCES_JAVA://反编译jarnew AndrolibJava().decode()
mAndrolib.decodeSourcesJava(mApkFile, outDir, mDebug);
break;
}
} if (hasMultipleSources()) {//如果有多个dex
// foreach unknown dex file in root, lets disassemble it
Set<String> files = mApkFile.getDirectory().getFiles(true);
for (String file : files) {//反编译多个dex
if (file.endsWith(".dex")) {
if (! file.equalsIgnoreCase("classes.dex")) {
switch(mDecodeSources) {
case DECODE_SOURCES_NONE:
mAndrolib.decodeSourcesRaw(mApkFile, outDir, file);
break;
case DECODE_SOURCES_SMALI:
mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mDebug, mDebugLinePrefix, mBakDeb, mApi);
break;
case DECODE_SOURCES_JAVA:
mAndrolib.decodeSourcesJava(mApkFile, outDir, mDebug);
break;
}
}
}
}
} mAndrolib.decodeRawFiles(mApkFile, outDir);//复制libs和assets
mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable);//发现一个问题,brutall的代码没有更新,新的在这里https://github.com/iBotPeaches/Apktool
mAndrolib.writeOriginalFiles(mApkFile, outDir);//输出原始文件,包括AndroidManifest.xml和签名证书
writeMetaFile();//写如描述文件apktool.yml
}
下面几个方法不解释咯
   public void setAnalysisMode(boolean mode, boolean pass) throws AndrolibException{
mAnalysisMode = mode; // only set mResTable, once it exists
if (pass) {
if (mResTable == null) {
mResTable = getResTable();
}
mResTable.setAnalysisMode(mode);
}
} public void setCompressionMode() throws AndrolibException, IOException {
// read the resources.arsc checking for STORED vs DEFLATE
// this will determine whether we compress on rebuild or not.
ZipExtFile zef = new ZipExtFile(mApkFile.getAbsolutePath());
ZipArchiveEntry ze = zef.getEntry("resources.arsc");
if (ze != null) {
int compression = ze.getMethod();
mCompressResources = (compression == ZipEntry.DEFLATED);
}
zef.close();
} public void setTargetSdkVersion() throws AndrolibException, IOException {
if (mResTable == null) {
mResTable = mAndrolib.getResTable(mApkFile);
} Map<String, String> sdkInfo = mResTable.getSdkInfo();
if (sdkInfo.get("targetSdkVersion") != null) {
mApi = Integer.parseInt(sdkInfo.get("targetSdkVersion"));
}
}
public ResTable getResTable() throws AndrolibException {
if (mResTable == null) {
boolean hasResources = hasResources();
boolean hasManifest = hasManifest();
if (! (hasManifest || hasResources)) {//一个apk文件不能没有AndroidManifest.xml和resource.arsc,否则就不是合法的apk文件
throw new AndrolibException(
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
}
AndrolibResources.sKeepBroken = mKeepBrokenResources;
mResTable = mAndrolib.getResTable(mApkFile, hasResources);
}
return mResTable;
}
End!
 补充:
在decode()中有个writeMetaFile()方法没讲到,这里再看看。
   private void writeMetaFile() throws AndrolibException {
Map<String, Object> meta = new LinkedHashMap<String, Object>();
meta.put("version", Androlib.getVersion());//静态方法?
meta.put("apkFileName", mApkFile.getName());//apk名称 if (mDecodeResources != DECODE_RESOURCES_NONE && (hasManifest() || hasResources())) {//如果要反编译资源并且有资源文件或者manifest文件
meta.put("isFrameworkApk", mAndrolib.isFrameworkApk(getResTable()));
putUsesFramework(meta);
putSdkInfo(meta);
putPackageInfo(meta);
putVersionInfo(meta);
putCompressionInfo(meta);
}
putUnknownInfo(meta);//加入Unknown文件目录说明
     mAndrolib.writeMetaFile(mOutDir, meta); //将meta数据写入apktool.yml写入到输出目录
  }
  private void putUsesFramework(Map<String, Object> meta) throws AndrolibException {
Set<ResPackage> pkgs = getResTable().listFramePackages();
if (pkgs.isEmpty()) {
return;
} Integer[] ids = new Integer[pkgs.size()];
int i = 0;
for (ResPackage pkg : pkgs) {
ids[i++] = pkg.getId();
}
Arrays.sort(ids); Map<String, Object> uses = new LinkedHashMap<String, Object>();
uses.put("ids", ids);//ids if (mAndrolib.apkOptions.frameworkTag != null) {//tag
uses.put("tag", mAndrolib.apkOptions.frameworkTag);
} meta.put("usesFramework", uses);
} private void putSdkInfo(Map<String, Object> meta) throws AndrolibException {
Map<String, String> info = getResTable().getSdkInfo();//ResTable可以获取sdk信息?
if (info.size() > 0) {
meta.put("sdkInfo", info);
}
} private void putPackageInfo(Map<String, Object> meta) throws AndrolibException {
String renamed = getResTable().getPackageRenamed();//还可以获取package信息?
String original = getResTable().getPackageOriginal();
int id = getResTable().getPackageId(); HashMap<String, String> packages = new HashMap<String, String>(); // only put rename-manifest-package into apktool.yml, if the change will be required
if (!renamed.equalsIgnoreCase(original)) {
packages.put("rename-manifest-package", renamed);
}
packages.put("forced-package-id", String.valueOf(id));
meta.put("packageInfo", packages);
} private void putVersionInfo(Map<String, Object> meta) throws AndrolibException {
Map<String, String> info = getResTable().getVersionInfo();//获取版本信息
if (info.size() > 0) {
meta.put("versionInfo", info);
}
} private void putUnknownInfo(Map<String, Object> meta) throws AndrolibException {
Map<String,String> info = mAndrolib.mResUnknownFiles.getUnknownFiles();//Androlib会收集Unknwn文件
if (info.size() > 0) {
meta.put("unknownFiles", info);
}
} private void putCompressionInfo(Map<String, Object> meta) throws AndrolibException {
meta.put("compressionType", getCompressionType());//压缩方式
}
 

最新文章

  1. sqlserver多文件组数据库的备份和还原实战
  2. Java多线程系列--“JUC线程池”04之 线程池原理(三)
  3. 网站上点击自定义按钮发起QQ聊天的解决方案
  4. ACM: 限时训练题解-Rock-Paper-Scissors-前缀和
  5. Java--&gt;Tomcat(免费的Java Web服务器)
  6. Vijos p1770 大内密探 树形DP+计数
  7. html转jsp乱码问题
  8. Android ActionBar详解(三):ActionBar实现切换Tabs标签
  9. java注解编程
  10. Java IO设计模式(装饰模式与适配器模式)
  11. python 异步协程
  12. Windows Server 2008 R2服务器系统安全设置参考指南
  13. KiB 、十进制单位转换 、二进制单位转换
  14. 四、K8S
  15. CITROEN C8 BSI HC12 Mileage Correction with Digiprog3
  16. ios 百度地图,火星坐标,地球坐标互转
  17. 【异常记录(八)】 This operation requires IIS integrated pipeline mode.
  18. php trim() 函数实例讲解
  19. Oracle EBS 采购 接收入库 接口开发
  20. 曲演杂坛--使用TRY CATCH应该注意的一个小细节

热门文章

  1. Android——网格视图 GridView
  2. java.lang.OutOfMemoryError: Java heap space 解决方法
  3. jquery树形表格实现方法
  4. Hibernate- 连接查询
  5. RRD.so文件 rrdruby
  6. java分布式集群
  7. 13 款最棒的 jQuery 图像 360&#176; 旋转插件
  8. 【转】MFC 字体LOGFONT
  9. CentOS下的一些基础问题解答
  10. LR中点鼠标做关联(winsock协议)