From 6e50ddf5c847cff8f6f8a4467caae1de4df410a9 Mon Sep 17 00:00:00 2001 From: Sergey Toshin Date: Tue, 26 Jun 2018 20:07:30 +0300 Subject: [PATCH 1/3] Generates and saves public.xml in apktool style --- .../java/jadx/core/xmlgen/ResTableParser.java | 19 ++++++++++++++++++- .../java/jadx/core/xmlgen/ResourcesSaver.java | 5 +++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java index e3f94c0a5..89f630f20 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResTableParser.java @@ -65,7 +65,7 @@ public class ResTableParser extends CommonBinaryParser { ResXmlGen resGen = new ResXmlGen(resStorage, vp); ResContainer res = ResContainer.multiFile("res"); - res.setContent(makeDump()); + res.setContent(makeXmlDump()); res.getSubFiles().addAll(resGen.makeResourcesXml()); return res; } @@ -82,6 +82,23 @@ public class ResTableParser extends CommonBinaryParser { writer.finish(); return writer; } + + public CodeWriter makeXmlDump() { + CodeWriter writer = new CodeWriter(); + writer.startLine(""); + writer.startLine(""); + writer.incIndent(); + + for (ResourceEntry ri : resStorage.getResources()) { + String format = String.format("", + ri.getTypeName(), ri.getKeyName(), ri.getId()); + writer.startLine(format); + } + writer.decIndent(); + writer.startLine(""); + writer.finish(); + return writer; + } public ResourceStorage getResStorage() { return resStorage; diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java index 2675caf74..874e824cd 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java @@ -46,6 +46,7 @@ public class ResourcesSaver implements Runnable { if (subFiles.isEmpty()) { save(rc, outDir); } else { + saveToFile(rc, new File(outDir, "res/values/public.xml")); for (ResContainer subFile : subFiles) { saveResources(subFile); } @@ -65,6 +66,10 @@ public class ResourcesSaver implements Runnable { } return; } + saveToFile(rc, outFile); + } + + private void saveToFile(ResContainer rc, File outFile) { CodeWriter cw = rc.getContent(); if (cw != null) { cw.save(outFile); From ddbcf8bb194d57a69ec390ca0ba86f85eca4b839 Mon Sep 17 00:00:00 2001 From: Sergey Toshin Date: Tue, 26 Jun 2018 20:26:31 +0300 Subject: [PATCH 2/3] Prevents path traversal attacks thru rc names --- .../jadx/core/utils/files/ZipSecurity.java | 21 ++++++++++++++----- .../java/jadx/core/xmlgen/ResourcesSaver.java | 14 +++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java b/jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java index b1edeeea3..1c9246c83 100644 --- a/jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java +++ b/jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java @@ -1,6 +1,7 @@ package jadx.core.utils.files; import java.io.File; +import java.io.IOException; import java.util.zip.ZipEntry; import org.slf4j.Logger; @@ -14,14 +15,24 @@ public class ZipSecurity { private ZipSecurity() {} - private static boolean isInSubDirectory(File base, File file) { - if (file == null) { + private static boolean isInSubDirectoryInternal(File baseDir, File canonFile) { + if (canonFile == null) { return false; } - if (file.equals(base)) { + if (canonFile.equals(baseDir)) { return true; } - return isInSubDirectory(base, file.getParentFile()); + return isInSubDirectoryInternal(baseDir, canonFile.getParentFile()); + } + + public static boolean isInSubDirectory(File baseDir, File file) { + try { + file = file.getCanonicalFile(); + } + catch(IOException e) { + return false; + } + return isInSubDirectoryInternal(baseDir, file); } // checks that entry name contains no any traversals @@ -30,7 +41,7 @@ public class ZipSecurity { try { File currentPath = new File(".").getCanonicalFile(); File canonical = new File(currentPath, entryName).getCanonicalFile(); - if (isInSubDirectory(currentPath, canonical)) { + if (isInSubDirectoryInternal(currentPath, canonical)) { return true; } LOG.error("Path traversal attack detected, invalid name: {}", entryName); diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java b/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java index 874e824cd..2eb608760 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/ResourcesSaver.java @@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory; import jadx.api.ResourceFile; import jadx.api.ResourceType; import jadx.core.codegen.CodeWriter; +import jadx.core.utils.files.ZipSecurity; import static jadx.core.utils.files.FileUtils.prepareFile; @@ -60,12 +61,25 @@ public class ResourcesSaver implements Runnable { String ext = FilenameUtils.getExtension(outFile.getName()); try { outFile = prepareFile(outFile); + + if(!ZipSecurity.isInSubDirectory(outDir, outFile)) { + LOG.error("Path traversal attack detected, invalid resource name: {}", + outFile.getPath()); + return; + } + ImageIO.write(image, ext, outFile); } catch (IOException e) { LOG.error("Failed to save image: {}", rc.getName(), e); } return; } + + if(!ZipSecurity.isInSubDirectory(outDir, outFile)) { + LOG.error("Path traversal attack detected, invalid resource name: {}", + rc.getFileName()); + return; + } saveToFile(rc, outFile); } From 53fa8205f27db2993aafe75c7b0a49329ec51adc Mon Sep 17 00:00:00 2001 From: Sergey Toshin Date: Tue, 26 Jun 2018 22:37:16 +0300 Subject: [PATCH 3/3] Receives canonical path in ZipSecurity.isInSubDirectory(...) --- jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java b/jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java index 1c9246c83..baee1ac27 100644 --- a/jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java +++ b/jadx-core/src/main/java/jadx/core/utils/files/ZipSecurity.java @@ -28,6 +28,7 @@ public class ZipSecurity { public static boolean isInSubDirectory(File baseDir, File file) { try { file = file.getCanonicalFile(); + baseDir = baseDir.getCanonicalFile(); } catch(IOException e) { return false;