mirror of
https://github.com/revanced/Apktool.git
synced 2024-12-05 02:22:55 +01:00
support for decoding unknown files, @todo add support for building unknown files
This commit is contained in:
parent
2e44e3a856
commit
0ca74eca67
@ -33,23 +33,12 @@ import java.util.logging.Logger;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import org.apache.commons.io.FileUtils.*;
|
||||
|
||||
/**
|
||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
*/
|
||||
@ -152,10 +141,11 @@ public class Androlib {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void decodeUnknownFiles(ExtFile apkFile, File outDir)
|
||||
public void decodeUnknownFiles(ExtFile apkFile, File outDir, ResTable resTable)
|
||||
throws AndrolibException {
|
||||
LOGGER.info("Copying unknown files/dir...");
|
||||
File unknownOut = new File(outDir, UNK_DIRNAME);
|
||||
ZipEntry invZipFile;
|
||||
|
||||
// have to use container of ZipFile to help identify compression type
|
||||
// with regular looping of apkFile for easy copy
|
||||
@ -163,23 +153,27 @@ public class Androlib {
|
||||
Directory unk = apkFile.getDirectory();
|
||||
ZipFile apkZipFile = new ZipFile(apkFile.getAbsolutePath());
|
||||
|
||||
// loop all items in container, ignoring any that are pre-defined by aapt
|
||||
Set<String> files = unk.getFiles();
|
||||
// loop all items in container recursively, ignoring any that are pre-defined by aapt
|
||||
Set<String> files = unk.getFiles(true);
|
||||
for (String file : files) {
|
||||
if (!isAPKFileNames(file)) {
|
||||
|
||||
// copy file out of archive into special "unknown" folder
|
||||
// to be re-included on build
|
||||
unk.copyToDir(unknownOut,file);
|
||||
System.out.println(apkZipFile.getEntry(file).getMethod());
|
||||
try {
|
||||
invZipFile = apkZipFile.getEntry(file.toString());
|
||||
|
||||
// lets record the name of the file, and its compression type
|
||||
// so that we may re-include it the same way
|
||||
if (invZipFile != null) {
|
||||
resTable.addUnknownFileInfo(invZipFile.getName(), String.valueOf(invZipFile.getMethod()));
|
||||
}
|
||||
} catch (NullPointerException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
// for folders now.
|
||||
Map<String, Directory> dirs = unk.getDirs();
|
||||
for (String dir : dirs.keySet()) {
|
||||
if (!isAPKFileNames(dir)) {
|
||||
unk.copyToDir(unknownOut,dir);
|
||||
System.out.println(apkZipFile.getEntry(dir).getMethod());
|
||||
}
|
||||
// @todo add ability to loop through dir and pull those methods
|
||||
}
|
||||
}
|
||||
catch (DirectoryException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
@ -187,8 +181,6 @@ public class Androlib {
|
||||
catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void writeOriginalFiles(ExtFile apkFile, File outDir)
|
||||
@ -287,6 +279,10 @@ public class Androlib {
|
||||
buildLib(appDir, flags);
|
||||
buildCopyOriginalFiles(appDir, flags);
|
||||
buildApk(appDir, outFile, flags);
|
||||
|
||||
// we must go after the Apk is built, and copy the files in via Zip
|
||||
// this is because Aapt won't add files it doesn't know (ex unknown files)
|
||||
buildUnknownFiles(appDir,outFile,meta);
|
||||
}
|
||||
|
||||
public void buildSources(File appDir, HashMap<String, Boolean> flags)
|
||||
@ -533,53 +529,31 @@ public class Androlib {
|
||||
}
|
||||
}
|
||||
|
||||
public void remove_manifest_versions(String filePath)
|
||||
throws AndrolibException {
|
||||
public void buildUnknownFiles(File appDir, File outFile, Map<String, Object> meta)
|
||||
throws AndrolibException {
|
||||
|
||||
File f = new File(filePath);
|
||||
|
||||
if (f.exists()) {
|
||||
// remove versionCode and versionName
|
||||
try {
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
Document doc = docBuilder.parse(filePath.toString());
|
||||
// confirm we have unknown files to inject
|
||||
if (meta.containsKey("unknownFiles")) {
|
||||
LOGGER.info("Copying unknown files/dir...");
|
||||
|
||||
Node manifest = doc.getFirstChild();
|
||||
Map<String, String> files = (Map<String, String>)meta.get("unknownFiles");
|
||||
|
||||
// load attr
|
||||
NamedNodeMap attr = manifest.getAttributes();
|
||||
Node vCode = attr.getNamedItem("android:versionCode");
|
||||
Node vName = attr.getNamedItem("android:versionName");
|
||||
try {
|
||||
ZipFile apkZipFile = new ZipFile(outFile.getAbsolutePath());
|
||||
|
||||
// remove versionCode
|
||||
if (vCode != null) {
|
||||
attr.removeNamedItem("android:versionCode");
|
||||
// loop through files inside
|
||||
for (Map.Entry<String,String> entry : files.entrySet()) {
|
||||
|
||||
// check if file exists
|
||||
if (new File(appDir,entry.getKey()).isFile()) {
|
||||
// apkZipFile.
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
if (vName != null) {
|
||||
attr.removeNamedItem("android:versionName");
|
||||
}
|
||||
|
||||
// save manifest
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
DOMSource source = new DOMSource(doc);
|
||||
StreamResult result = new StreamResult(new File(filePath));
|
||||
transformer.transform(source, result);
|
||||
|
||||
} catch (ParserConfigurationException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (SAXException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (TransformerConfigurationException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (TransformerException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void buildApk(File appDir, File outApk,
|
||||
HashMap<String, Boolean> flags) throws AndrolibException {
|
||||
|
@ -133,11 +133,8 @@ public class ApkDecoder {
|
||||
}
|
||||
|
||||
mAndrolib.decodeRawFiles(mApkFile, outDir);
|
||||
mAndrolib.decodeUnknownFiles(mApkFile, outDir);
|
||||
mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable);
|
||||
mAndrolib.writeOriginalFiles(mApkFile, outDir);
|
||||
|
||||
// remove version names in favour of aapt injection
|
||||
mAndrolib.remove_manifest_versions(outDir.getAbsolutePath() + "/AndroidManifest.xml");
|
||||
writeMetaFile();
|
||||
}
|
||||
|
||||
@ -251,6 +248,7 @@ public class ApkDecoder {
|
||||
putPackageInfo(meta);
|
||||
putVersionInfo(meta);
|
||||
putCompressionInfo(meta);
|
||||
putUnknownInfo(meta);
|
||||
//meta.put("packageId", getResTable().getPackageInfo().get("cur_package_id"));
|
||||
}
|
||||
|
||||
@ -281,32 +279,42 @@ public class ApkDecoder {
|
||||
meta.put("usesFramework", uses);
|
||||
}
|
||||
|
||||
private void putSdkInfo(Map<String, Object> meta) throws AndrolibException {
|
||||
Map<String, String> info = getResTable().getSdkInfo();
|
||||
if (info.size() > 0) {
|
||||
meta.put("sdkInfo", info);
|
||||
}
|
||||
}
|
||||
|
||||
private void putPackageInfo(Map<String, Object> meta)
|
||||
throws AndrolibException {
|
||||
Map<String, String> info = getResTable().getPackageInfo();
|
||||
if (info.size() > 0) {
|
||||
meta.put("packageInfo", info);
|
||||
}
|
||||
}
|
||||
|
||||
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 putSdkInfo(Map<String, Object> meta)
|
||||
throws AndrolibException {
|
||||
Map<String, String> info = getResTable().getSdkInfo();
|
||||
if (info.size() > 0) {
|
||||
meta.put("sdkInfo", info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void putCompressionInfo(Map<String, Object> meta)
|
||||
throws AndrolibException {
|
||||
meta.put("compressionType", getCompressionType());
|
||||
}
|
||||
private void putPackageInfo(Map<String, Object> meta)
|
||||
throws AndrolibException {
|
||||
Map<String, String> info = getResTable().getPackageInfo();
|
||||
if (info.size() > 0) {
|
||||
meta.put("packageInfo", info);
|
||||
}
|
||||
}
|
||||
|
||||
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 = getResTable().getUnknownFiles();
|
||||
if (info.size() > 0) {
|
||||
meta.put("unknownFiles", info);
|
||||
}
|
||||
}
|
||||
|
||||
private void putCompressionInfo(Map<String, Object> meta)
|
||||
throws AndrolibException {
|
||||
meta.put("compressionType", getCompressionType());
|
||||
}
|
||||
|
||||
private boolean getCompressionType() {
|
||||
return mCompressResources;
|
||||
|
@ -47,7 +47,6 @@ import javax.xml.transform.stream.StreamResult;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.xml.sax.SAXException;
|
||||
@ -244,6 +243,54 @@ final public class AndrolibResources {
|
||||
}
|
||||
}
|
||||
|
||||
public void remove_manifest_versions(String filePath)
|
||||
throws AndrolibException {
|
||||
|
||||
File f = new File(filePath);
|
||||
|
||||
if (f.exists()) {
|
||||
// remove versionCode and versionName
|
||||
try {
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
|
||||
Document doc = docBuilder.parse(filePath.toString());
|
||||
|
||||
Node manifest = doc.getFirstChild();
|
||||
|
||||
// load attr
|
||||
NamedNodeMap attr = manifest.getAttributes();
|
||||
Node vCode = attr.getNamedItem("android:versionCode");
|
||||
Node vName = attr.getNamedItem("android:versionName");
|
||||
|
||||
// remove versionCode
|
||||
if (vCode != null) {
|
||||
attr.removeNamedItem("android:versionCode");
|
||||
}
|
||||
if (vName != null) {
|
||||
attr.removeNamedItem("android:versionName");
|
||||
}
|
||||
|
||||
// save manifest
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
DOMSource source = new DOMSource(doc);
|
||||
StreamResult result = new StreamResult(new File(filePath));
|
||||
transformer.transform(source, result);
|
||||
|
||||
} catch (ParserConfigurationException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (SAXException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (IOException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (TransformerConfigurationException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
} catch (TransformerException ex) {
|
||||
throw new AndrolibException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void decode(ResTable resTable, ExtFile apkFile, File outDir)
|
||||
throws AndrolibException {
|
||||
Duo<ResFileDecoder, AXmlResourceParser> duo = getResFileDecoder();
|
||||
@ -263,9 +310,13 @@ final public class AndrolibResources {
|
||||
fileDecoder.decodeManifest(inApk, "AndroidManifest.xml", out,
|
||||
"AndroidManifest.xml");
|
||||
|
||||
// fix package if needed
|
||||
// fix package (Android 4.2)
|
||||
adjust_package_manifest(resTable, outDir.getAbsolutePath()
|
||||
+ "/AndroidManifest.xml");
|
||||
+ File.separator + "AndroidManifest.xml");
|
||||
|
||||
// Remove versionName / versionCode (aapt API 16)
|
||||
remove_manifest_versions(outDir.getAbsolutePath()
|
||||
+ File.separator + "/AndroidManifest.xml");
|
||||
|
||||
if (inApk.containsDir("res")) {
|
||||
in = inApk.getDir("res");
|
||||
|
@ -38,6 +38,7 @@ public class ResTable {
|
||||
private Map<String, String> mSdkInfo = new LinkedHashMap<String, String>();
|
||||
private Map<String, String> mPackageInfo = new LinkedHashMap<String, String>();
|
||||
private Map<String, String> mVersionInfo = new LinkedHashMap<String, String>();
|
||||
private Map<String, String> mUnknownFiles = new LinkedHashMap<String, String>();
|
||||
|
||||
public ResTable() {
|
||||
mAndRes = null;
|
||||
@ -137,6 +138,10 @@ public class ResTable {
|
||||
mPackageInfo.put(key, value);
|
||||
}
|
||||
|
||||
public void addUnknownFileInfo(String file, String value) {
|
||||
mUnknownFiles.put(file,value);
|
||||
}
|
||||
|
||||
public Map<String, String> getPackageInfo() {
|
||||
return mPackageInfo;
|
||||
}
|
||||
@ -149,6 +154,10 @@ public class ResTable {
|
||||
return mSdkInfo;
|
||||
}
|
||||
|
||||
public Map<String, String> getUnknownFiles() {
|
||||
return mUnknownFiles;
|
||||
}
|
||||
|
||||
public boolean isPackageInfoValueSet(String key) {
|
||||
return (mPackageInfo.containsKey(key));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user