diff --git a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java index cc9024a28..07999919a 100644 --- a/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java +++ b/jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java @@ -227,6 +227,12 @@ public class JadxCLIArgs { ) protected UseKotlinMethodsForVarNames useKotlinMethodsForVarNames = UseKotlinMethodsForVarNames.APPLY; + @Parameter( + names = { "--use-headers-for-detect-resource-extensions" }, + description = "Use headers for detect resource extensions if resource obfuscated" + ) + protected boolean useHeadersForDetectResourceExtensions = false; + @Parameter( names = { "--rename-flags" }, description = "fix options (comma-separated list of):" @@ -354,6 +360,7 @@ public class JadxCLIArgs { args.setDeobfuscationMaxLength(deobfuscationMaxLength); args.setDeobfuscationWhitelist(Arrays.asList(deobfuscationWhitelistStr.split(" "))); args.setUseSourceNameAsClassNameAlias(getUseSourceNameAsClassNameAlias()); + args.setUseHeadersForDetectResourceExtensions(useHeadersForDetectResourceExtensions); args.setSourceNameRepeatLimit(sourceNameRepeatLimit); args.setUseKotlinMethodsForVarNames(useKotlinMethodsForVarNames); args.setResourceNameSource(resourceNameSource); @@ -586,6 +593,10 @@ public class JadxCLIArgs { return fsCaseSensitive; } + public boolean isUseHeadersForDetectResourceExtensions() { + return useHeadersForDetectResourceExtensions; + } + public CommentsLevel getCommentsLevel() { return commentsLevel; } diff --git a/jadx-core/src/main/java/jadx/api/JadxArgs.java b/jadx-core/src/main/java/jadx/api/JadxArgs.java index d8a87300d..b0c547f3a 100644 --- a/jadx-core/src/main/java/jadx/api/JadxArgs.java +++ b/jadx-core/src/main/java/jadx/api/JadxArgs.java @@ -91,6 +91,7 @@ public class JadxArgs implements Closeable { private boolean skipResources = false; private boolean skipSources = false; + private boolean useHeadersForDetectResourceExtensions; /** * Predicate that allows to filter the classes to be process based on their full name @@ -817,6 +818,14 @@ public class JadxArgs implements Closeable { this.loadJadxClsSetFile = loadJadxClsSetFile; } + public void setUseHeadersForDetectResourceExtensions(boolean useHeadersForDetectResourceExtensions) { + this.useHeadersForDetectResourceExtensions = useHeadersForDetectResourceExtensions; + } + + public boolean isUseHeadersForDetectResourceExtensions() { + return useHeadersForDetectResourceExtensions; + } + /** * Hash of all options that can change result code */ @@ -825,7 +834,7 @@ public class JadxArgs implements Closeable { + inlineAnonymousClasses + inlineMethods + moveInnerClasses + allowInlineKotlinLambda + deobfuscationOn + deobfuscationMinLength + deobfuscationMaxLength + deobfuscationWhitelist + useSourceNameAsClassNameAlias + sourceNameRepeatLimit - + resourceNameSource + + resourceNameSource + useHeadersForDetectResourceExtensions + useKotlinMethodsForVarNames + insertDebugLines + extractFinally + debugInfo + escapeUnicode + replaceConsts + restoreSwitchOverString @@ -888,6 +897,7 @@ public class JadxArgs implements Closeable { + ", pluginOptions=" + pluginOptions + ", cfgOutput=" + cfgOutput + ", rawCFGOutput=" + rawCFGOutput + + ", useHeadersForDetectResourceExtensions=" + useHeadersForDetectResourceExtensions + '}'; } } diff --git a/jadx-core/src/main/java/jadx/api/ResourceFile.java b/jadx-core/src/main/java/jadx/api/ResourceFile.java index 00038f64e..e98e92675 100644 --- a/jadx-core/src/main/java/jadx/api/ResourceFile.java +++ b/jadx-core/src/main/java/jadx/api/ResourceFile.java @@ -4,6 +4,9 @@ import java.io.File; import org.jetbrains.annotations.Nullable; +import jadx.core.deobf.FileTypeDetector; +import jadx.core.utils.StringUtils; +import jadx.core.utils.exceptions.JadxException; import jadx.core.xmlgen.ResContainer; import jadx.core.xmlgen.entry.ResourceEntry; import jadx.zip.IZipEntry; @@ -11,7 +14,7 @@ import jadx.zip.IZipEntry; public class ResourceFile { private final JadxDecompiler decompiler; private final String name; - private final ResourceType type; + private ResourceType type; private @Nullable IZipEntry zipEntry; private String deobfName; @@ -53,22 +56,63 @@ public class ResourceFile { return ResourcesLoader.loadContent(decompiler, this); } - public boolean setAlias(ResourceEntry ri) { + public boolean setAlias(ResourceEntry entry, boolean useHeders) { StringBuilder sb = new StringBuilder(); - sb.append("res/").append(ri.getTypeName()).append(ri.getConfig()); - sb.append("/").append(ri.getKeyName()); - int lastDot = name.lastIndexOf('.'); - if (lastDot != -1) { - sb.append(name.substring(lastDot)); + sb.append("res/").append(entry.getTypeName()).append(entry.getConfig()); + sb.append("/").append(entry.getKeyName()); + + if (useHeders) { + try { + int maxBytesToReadLimit = 4096; + byte[] bytes = ResourcesLoader.decodeStream(this, (size, is) -> { + int bytesToRead; + if (size > 0) { + bytesToRead = (int) Math.min(size, maxBytesToReadLimit); + } else if (size == 0) { + bytesToRead = 0; + } else { + bytesToRead = maxBytesToReadLimit; + } + if (bytesToRead == 0) { + return new byte[0]; + } + return is.readNBytes(bytesToRead); + }); + + String fileExtension = FileTypeDetector.detectFileExtension(bytes); + if (!StringUtils.isEmpty(fileExtension)) { + sb.append(fileExtension); + } else { + sb.append(getExtFromName(name)); + } + } catch (JadxException ignored) { + } + } else { + sb.append(getExtFromName(name)); } String alias = sb.toString(); if (!alias.equals(name)) { setDeobfName(alias); + type = ResourceType.getFileType(alias); return true; } return false; } + private String getExtFromName(String name) { + // the image .9.png extension always saved, when resource shrinking by aapt2 + if (name.contains(".9.png")) { + return ".9.png"; + } + + int lastDot = name.lastIndexOf('.'); + if (lastDot != -1) { + return name.substring(lastDot); + } + + return ""; + } + public @Nullable IZipEntry getZipEntry() { return zipEntry; } diff --git a/jadx-core/src/main/java/jadx/api/ResourcesLoader.java b/jadx-core/src/main/java/jadx/api/ResourcesLoader.java index a98b30e77..6a76aa119 100644 --- a/jadx-core/src/main/java/jadx/api/ResourcesLoader.java +++ b/jadx-core/src/main/java/jadx/api/ResourcesLoader.java @@ -165,7 +165,7 @@ public final class ResourcesLoader implements IResourcesLoader { } private static ResContainer decodeImage(ResourceFile rf, InputStream inputStream) { - String name = rf.getOriginalName(); + String name = rf.getDeobfName(); if (name.endsWith(".9.png")) { try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { Res9patchStreamDecoder decoder = new Res9patchStreamDecoder(); diff --git a/jadx-core/src/main/java/jadx/core/deobf/FileTypeDetector.java b/jadx-core/src/main/java/jadx/core/deobf/FileTypeDetector.java new file mode 100644 index 000000000..8bd5bb4ee --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/deobf/FileTypeDetector.java @@ -0,0 +1,129 @@ +package jadx.core.deobf; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; + +import jadx.core.utils.FileSignature; +import jadx.core.utils.StringUtils; + +public class FileTypeDetector { + private static final Pattern DOCTYPE_PATTERN = Pattern.compile("\\s*]", Pattern.CASE_INSENSITIVE); + private static final List FILE_SIGNATURES = new ArrayList<>(); + + static { + register("png", "89 50 4E 47"); + register("jpg", "FF D8 FF"); + register("gif", "47 49 46 38"); + register("webp", "52 49 46 46 ?? ?? ?? ?? 57 45 42 50 56 50 38"); + register("bmp", "42 4D"); + register("bmp", "42 41"); + register("bmp", "43 49"); + register("bmp", "43 50"); + register("bmp", "49 43"); + register("bmp", "50 54"); + register("mp4", "00 00 00 ?? 66 74 79 70 69 73 6F 36"); + register("mp4", "00 00 00 ?? 66 74 79 70 6D 70 34 32"); + register("m4a", "00 00 00 ?? 66 74 79 70 4D 34 41 20"); + register("mp3", "49 44 33"); + register("ogg", "4F 67 67 53"); + register("wav", "52 49 46 46 ?? ?? ?? ?? 57 41 56 45"); + register("ttf", "00 01 00 00"); + register("ttc", "74 74 63 66"); + register("otf", "4F 54 54 4F"); + register("xml", "03 00 08 00"); + } + + public static void register(String fileType, String signature) { + FILE_SIGNATURES.add(new FileSignature(fileType, signature)); + } + + private static String detectByHeaders(byte[] data) { + for (FileSignature sig : FILE_SIGNATURES) { + if (FileSignature.matches(sig, data)) { + if (sig.getFileType().equals("png") && isNinePatch(data)) { + return ".9.png"; + } + return "." + sig.getFileType(); + } + } + return null; + } + + public static String detectFileExtension(byte[] data) { + // detect ext by headers + String extByHeaders = detectByHeaders(data); + if (!StringUtils.isEmpty(extByHeaders)) { + return extByHeaders; + } + + // detect ext by readable text + String text = new String(data, StandardCharsets.UTF_8); + if (text.startsWith("-----BEGIN CERTIFICATE-----")) { + return ".cer"; + } + if (text.startsWith("-----BEGIN PRIVATE KEY-----")) { + return ".key"; + } + if (text.contains("")) { + return ".html"; + } + Matcher m = DOCTYPE_PATTERN.matcher(text); + if (m.lookingAt()) { + return "." + m.group(1).toLowerCase(); + } + + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(new java.io.ByteArrayInputStream(data)); + String rootTag = doc.getDocumentElement().getNodeName(); + + if ("svg".equalsIgnoreCase(rootTag)) { + return ".svg"; + } + if ("plist".equalsIgnoreCase(rootTag)) { + return ".plist"; + } + if ("kml".equalsIgnoreCase(rootTag)) { + return ".kml"; + } + return ".xml"; + } catch (Exception ignored) { + } + + return null; + } + + private static int readInt(byte[] data, int offset) { + return (data[offset] & 0xFF) << 24 + | (data[offset + 1] & 0xFF) << 16 + | (data[offset + 2] & 0xFF) << 8 + | (data[offset + 3] & 0xFF); + } + + private static boolean isNinePatch(byte[] data) { + int offset = 8; + while (offset + 8 < data.length) { + int chunkLength = readInt(data, offset); + int chunkType = readInt(data, offset + 4); + if (chunkType == 0x6e705463) { // 'npTc' + return true; + } + offset += 8 + chunkLength + 4; // chunk + data + CRC + } + return false; + } +} diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java index 1239e2970..bb78e5d75 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java @@ -271,6 +271,7 @@ public class RootNode { if (args.isSkipResources()) { return; } + boolean useHeaders = args.isUseHeadersForDetectResourceExtensions(); long start = System.currentTimeMillis(); int renamedCount = 0; ResourceStorage resStorage = parser.getResStorage(); @@ -285,7 +286,7 @@ public class RootNode { for (ResourceFile resource : resources) { ResourceEntry resEntry = entryNames.get(resource.getOriginalName()); if (resEntry != null) { - if (resource.setAlias(resEntry)) { + if (resource.setAlias(resEntry, useHeaders)) { renamedCount++; } } diff --git a/jadx-core/src/main/java/jadx/core/utils/FileSignature.java b/jadx-core/src/main/java/jadx/core/utils/FileSignature.java new file mode 100644 index 000000000..e2beb2b0d --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/utils/FileSignature.java @@ -0,0 +1,37 @@ +package jadx.core.utils; + +public class FileSignature { + private final byte[] signatureBytes; + private final String fileType; + + public FileSignature(String fileType, String signatureHex) { + this.fileType = fileType; + String[] parts = signatureHex.split(" "); + this.signatureBytes = new byte[parts.length]; + for (int i = 0; i < parts.length; i++) { + if (parts[i].length() != 2) { + throw new RuntimeException(signatureHex); + } + if (!parts[i].equals("??")) { + this.signatureBytes[i] = (byte) Integer.parseInt(parts[i], 16); + } + } + } + + public static boolean matches(FileSignature sig, byte[] data) { + if (data.length < sig.signatureBytes.length) { + return false; + } + for (int i = 0; i < sig.signatureBytes.length; i++) { + byte b = sig.signatureBytes[i]; + if (b != data[i]) { + return false; + } + } + return true; + } + + public String getFileType() { + return fileType; + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java index 4861edc7d..29c2869b1 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/JadxSettings.java @@ -446,6 +446,10 @@ public class JadxSettings extends JadxCLIArgs { this.resourceNameSource = source; } + public void setUseHeadersForDetectResourceExtension(boolean enable) { + this.useHeadersForDetectResourceExtensions = enable; + } + public void updateRenameFlag(JadxArgs.RenameEnum flag, boolean enabled) { if (enabled) { renameFlags.add(flag); diff --git a/jadx-gui/src/main/java/jadx/gui/settings/ui/JadxSettingsWindow.java b/jadx-gui/src/main/java/jadx/gui/settings/ui/JadxSettingsWindow.java index 9faf3f608..49d05e78c 100644 --- a/jadx-gui/src/main/java/jadx/gui/settings/ui/JadxSettingsWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/settings/ui/JadxSettingsWindow.java @@ -234,6 +234,13 @@ public class JadxSettingsWindow extends JDialog { needReload(); }); + JCheckBox useHeaders = new JCheckBox(); + useHeaders.setSelected(settings.isUseHeadersForDetectResourceExtensions()); + useHeaders.addItemListener(e -> { + settings.setUseHeadersForDetectResourceExtension(e.getStateChange() == ItemEvent.SELECTED); + needReload(); + }); + JComboBox generatedRenamesMappingFileModeCB = new JComboBox<>(GeneratedRenamesMappingFileMode.values()); generatedRenamesMappingFileModeCB.setSelectedItem(settings.getGeneratedRenamesMappingFileMode()); @@ -265,6 +272,7 @@ public class JadxSettingsWindow extends JDialog { deobfGroup.addRow(NLS.str("preferences.deobfuscation_min_len"), minLenSpinner); deobfGroup.addRow(NLS.str("preferences.deobfuscation_max_len"), maxLenSpinner); deobfGroup.addRow(NLS.str("preferences.deobfuscation_res_name_source"), resNamesSource); + deobfGroup.addRow(NLS.str("preferences.deobfuscation_res_use_headers"), useHeaders); deobfGroup.addRow(NLS.str("preferences.generated_renames_mapping_file_mode"), generatedRenamesMappingFileModeCB); deobfGroup.addRow(NLS.str("preferences.deobfuscation_whitelist"), NLS.str("preferences.deobfuscation_whitelist.tooltip"), editWhitelistedEntities); diff --git a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties index 8147567ec..9d8febcc3 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties @@ -277,6 +277,7 @@ preferences.generated_renames_mapping_file_mode=Umgang mit Map-Dateien preferences.deobfuscation_min_len=Minimale Namenlänge preferences.deobfuscation_max_len=Maximale Namenlänge preferences.deobfuscation_res_name_source=Bessere Ressourcennamenquelle +#preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions preferences.deobfuscation_whitelist=Pakete und Klassen von Deobfuskierung ausschließen preferences.deobfuscation_whitelist.editDialog=Weiße Liste für Deobfuskierung preferences.deobfuscation_whitelist.tooltip=Liste der durch ':' getrennten Pakete (Suffix '.*') und Klassenamen, die nicht deobfuskiert werden sollen diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index 426fa15a4..b18b33843 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -277,6 +277,7 @@ preferences.generated_renames_mapping_file_mode=Map file handle mode preferences.deobfuscation_min_len=Minimum name length preferences.deobfuscation_max_len=Maximum name length preferences.deobfuscation_res_name_source=Better resources name source +preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions preferences.deobfuscation_whitelist=Exclude packages and classes from deobfuscation preferences.deobfuscation_whitelist.editDialog=Whitelist for deobfuscation preferences.deobfuscation_whitelist.tooltip=List of ':' separated packages (suffix '.*') and class names that will not be deobfuscated diff --git a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties index 6cc6641b7..1a4eb3118 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -277,6 +277,7 @@ preferences.deobfuscation_on=Activar desobfuscación preferences.deobfuscation_min_len=Longitud mínima del nombre preferences.deobfuscation_max_len=Longitud máxima del nombre #preferences.deobfuscation_res_name_source=Better resources name source +#preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions #preferences.deobfuscation_whitelist=Exclude packages and classes from deobfuscation #preferences.deobfuscation_whitelist.editDialog=Whitelist for deobfuscation #preferences.deobfuscation_whitelist.tooltip=List of ':' separated packages (suffix '.*') and class names that will not be deobfuscated diff --git a/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties b/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties index d18f7b73e..0949a2cb6 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties @@ -277,6 +277,7 @@ preferences.generated_renames_mapping_file_mode=Mode penanganan file pemetaan preferences.deobfuscation_min_len=Panjang nama minimum preferences.deobfuscation_max_len=Panjang nama maksimum preferences.deobfuscation_res_name_source=Sumber nama sumber daya yang lebih baik +#preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions #preferences.deobfuscation_whitelist=Exclude packages and classes from deobfuscation #preferences.deobfuscation_whitelist.editDialog=Whitelist for deobfuscation #preferences.deobfuscation_whitelist.tooltip=List of ':' separated packages (suffix '.*') and class names that will not be deobfuscated diff --git a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties index 593f3a284..38199d9c2 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties @@ -277,6 +277,7 @@ preferences.generated_renames_mapping_file_mode=맵 파일 처리 모드 preferences.deobfuscation_min_len=최소 이름 길이 preferences.deobfuscation_max_len=최대 이름 길이 preferences.deobfuscation_res_name_source=더 나은 리소스 이름 소스 +#preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions #preferences.deobfuscation_whitelist=Exclude packages and classes from deobfuscation #preferences.deobfuscation_whitelist.editDialog=Whitelist for deobfuscation #preferences.deobfuscation_whitelist.tooltip=List of ':' separated packages (suffix '.*') and class names that will not be deobfuscated diff --git a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties index 7a5d116fd..20a8bcdd8 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties @@ -277,6 +277,7 @@ preferences.deobfuscation_on=Ativar desofuscação preferences.deobfuscation_min_len=Tamanho mínimo do nome preferences.deobfuscation_max_len=Tamanho máximo do nome preferences.deobfuscation_res_name_source=Melhora nome da fonte dos recursos +#preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions #preferences.deobfuscation_whitelist=Exclude packages and classes from deobfuscation #preferences.deobfuscation_whitelist.editDialog=Whitelist for deobfuscation #preferences.deobfuscation_whitelist.tooltip=List of ':' separated packages (suffix '.*') and class names that will not be deobfuscated diff --git a/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties b/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties index f98474637..f346c7478 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties @@ -277,6 +277,7 @@ preferences.generated_renames_mapping_file_mode=Режим обработки м preferences.deobfuscation_min_len=Минимальная длина имени preferences.deobfuscation_max_len=Максимальная длина имени preferences.deobfuscation_res_name_source=Расшифровка имен ресурсов +#preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions preferences.deobfuscation_whitelist=Исключить пакеты и классы из деобфускации preferences.deobfuscation_whitelist.editDialog=Белый список деобфускации preferences.deobfuscation_whitelist.tooltip=Разделяйте пакеты через ':' (суффикс '.*') и имя класса которое не будет деобфусцировано diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties index 8a5204309..1428ec24d 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -277,6 +277,7 @@ preferences.generated_renames_mapping_file_mode=映射文件句柄模式 preferences.deobfuscation_min_len=最小命名长度 preferences.deobfuscation_max_len=最大命名长度 preferences.deobfuscation_res_name_source=更好的资源名称来源 +#preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions preferences.deobfuscation_whitelist=从反混淆中排除包和类 preferences.deobfuscation_whitelist.editDialog=反混淆白名单 preferences.deobfuscation_whitelist.tooltip=以‘:’分隔的包(后缀‘.*’)和类名列表,它们不会被反混淆。 diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties index a5bdffa5a..3b6c89eae 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties @@ -277,6 +277,7 @@ preferences.generated_renames_mapping_file_mode=Map 檔案處理模式 preferences.deobfuscation_min_len=最小名稱長度 preferences.deobfuscation_max_len=最大名稱長度 preferences.deobfuscation_res_name_source=較佳的資源名稱來源 +#preferences.deobfuscation_res_use_headers=Use headers for detect resource extensions preferences.deobfuscation_whitelist=去模糊化時排除套件和類別 preferences.deobfuscation_whitelist.editDialog=去模糊化白名單 preferences.deobfuscation_whitelist.tooltip=將不會被去模糊化的套件(後綴 '.*')和類別名稱清單,以 ':' 分隔