元始天尊 发表于 2015-12-27 15:12:47

【Android】解决修改arsc同名文件导致apktool反编译失败

有些软件,会修改apk的resources.arsc文件,做成同名资源,导致apktool出现崩溃:
Exception in thread "main" brut.androlib.AndrolibException: Multiple res specs: drawable/
at brut.androlib.res.data.ResTypeSpec.addResSpec(ResTypeSpec.java:78)
at brut.androlib.res.decoder.ARSCDecoder.readEntry(ARSCDecoder.java:248)
at brut.androlib.res.decoder.ARSCDecoder.readTableType(ARSCDecoder.java:212)
at brut.androlib.res.decoder.ARSCDecoder.readTableTypeSpec(ARSCDecoder.java:154)
at brut.androlib.res.decoder.ARSCDecoder.readTablePackage(ARSCDecoder.java:116)
at brut.androlib.res.decoder.ARSCDecoder.readTableHeader(ARSCDecoder.java:78)
at brut.androlib.res.decoder.ARSCDecoder.decode(ARSCDecoder.java:47)
at brut.androlib.res.AndrolibResources.getResPackagesFromApk(AndrolibResources.java:544)
at brut.androlib.res.AndrolibResources.loadMainPkg(AndrolibResources.java:63)
at brut.androlib.res.AndrolibResources.getResTable(AndrolibResources.java:55)
at brut.androlib.Androlib.getResTable(Androlib.java:66)
at brut.androlib.ApkDecoder.setTargetSdkVersion(ApkDecoder.java:198)
at brut.androlib.ApkDecoder.decode(ApkDecoder.java:96)
at brut.apktool.Main.cmdDecode(Main.java:165)
at brut.apktool.Main.main(Main.java:81)

为了解决这个问题,就要修改apktool,编译过程如上一篇帖子所述http://www.0xaa55.com/thread-1659-1-1.html
发生异常后,程序断在:

    public void addResSpec(ResResSpec spec) throws AndrolibException {
      if (mResSpecs.put(spec.getName(), spec) != true) {
            throw new AndrolibException(String.format(
                  "Multiple res specs: %s/%s", getName(), spec.getName()));
      }
    }
//ResType.java
package brut.androlib.res.data;

import brut.androlib.AndrolibException;
import brut.androlib.err.UndefinedResObject;
import java.util.*;

/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public final class ResType {
    private final String mName;
    private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<String, ResResSpec>();

    private final ResTable mResTable;
    private final ResPackage mPackage;

    public ResType(String name, ResTable resTable, ResPackage package_) {
      this.mName = name;
      this.mResTable = resTable;
      this.mPackage = package_;
    }

    public String getName() {
      return mName;
    }

    public boolean isString() {
      return mName.equalsIgnoreCase("string");
    }

    public Set<ResResSpec> listResSpecs() {
      return new LinkedHashSet<ResResSpec>(mResSpecs.values());
    }

    public ResResSpec getResSpec(String name) throws AndrolibException {
      ResResSpec spec = mResSpecs.get(name);
      if (spec == null) {
            throw new UndefinedResObject(String.format("resource spec: %s/%s",
                  getName(), name));
      }
      return spec;
    }

    public void addResSpec(ResResSpec spec) throws AndrolibException {
      if (mResSpecs.put(spec.getName(), spec) != null) {
            throw new AndrolibException(String.format(
                  "Multiple res specs: %s/%s", getName(), spec.getName()));
      }
    }

    @Override
    public String toString() {
      return mName;
    }

可以发现mResSpecs是map结构的,键值一一对应,所以对方如果在arsc中放了2个同名资源的话,apktool不会继续处理
那么比较好的方法是将mResSpecs做成multimap结构,因此改动如下:

package brut.androlib.res.data;

import com.google.common.collect.HashMultimap;

import brut.androlib.AndrolibException;
import brut.androlib.err.UndefinedResObject;
import java.util.*;

/**
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/
public final class ResType {
    private final String mName;
    //private final Map<String, ResResSpec> mResSpecs = new LinkedHashMap<String, ResResSpec>();
    private static HashMultimap<String,ResResSpec> mResSpecs = null;
    private final ResTable mResTable;
    private final ResPackage mPackage;

    public ResType(String name, ResTable resTable, ResPackage package_) {
      this.mName = name;
      this.mResTable = resTable;
      this.mPackage = package_;
      mResSpecs = HashMultimap.create();
    }

    public String getName() {
      return mName;
    }

    public boolean isString() {
      return mName.equalsIgnoreCase("string");
    }

    public Set<ResResSpec> listResSpecs() {
      return new LinkedHashSet<ResResSpec>(mResSpecs.values());
    }

    public ResResSpec getResSpec(String name) throws AndrolibException {
      //ResResSpec spec = mResSpecs.get(name);
      Set<ResResSpec> spec = mResSpecs.get(name);
      if (spec.size() == 0) {
            throw new UndefinedResObject(String.format("resource spec: %s/%s",
                  getName(), name));
      }
      //return spec;
      return spec.iterator().next();
    }

    public void addResSpec(ResResSpec spec) throws AndrolibException {
      //if (mResSpecs.put(spec.getName(), spec) != null) {
      if (mResSpecs.put(spec.getName(), spec) != true) {
            throw new AndrolibException(String.format(
                  "Multiple res specs: %s/%s", getName(), spec.getName()));
      }
    }

    @Override
    public String toString() {
      return mName;
    }
}


在android studio中调试成功解密出文件
之后替换 安卓改之理 中的apktool,完美恢复!
页: [1]
查看完整版本: 【Android】解决修改arsc同名文件导致apktool反编译失败