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..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 @@ -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,25 @@ 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(); + baseDir = baseDir.getCanonicalFile(); + } + catch(IOException e) { + return false; + } + return isInSubDirectoryInternal(baseDir, file); } // checks that entry name contains no any traversals @@ -30,7 +42,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/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..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; @@ -46,6 +47,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); } @@ -59,12 +61,29 @@ 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); + } + + private void saveToFile(ResContainer rc, File outFile) { CodeWriter cw = rc.getContent(); if (cw != null) { cw.save(outFile);