From acd57930cc6772e9dde61b64ef1b3736c28a1276 Mon Sep 17 00:00:00 2001 From: Yaroslav <43380144+MrIkso@users.noreply.github.com> Date: Wed, 14 May 2025 21:35:24 +0300 Subject: [PATCH] fix(gui): improve apk signature loading speed (PR #2481) fix(gui): improve spk signature loading speed (fix #1827) --- .../java/jadx/gui/treemodel/ApkSignature.java | 250 -------------- .../jadx/gui/treemodel/ApkSignatureNode.java | 320 ++++++++++++++++++ .../src/main/java/jadx/gui/ui/MainWindow.java | 4 +- .../java/jadx/gui/ui/panel/HtmlPanel.java | 8 +- .../resources/i18n/Messages_de_DE.properties | 1 + .../resources/i18n/Messages_en_US.properties | 1 + .../resources/i18n/Messages_es_ES.properties | 1 + .../resources/i18n/Messages_id_ID.properties | 1 + .../resources/i18n/Messages_ko_KR.properties | 1 + .../resources/i18n/Messages_pt_BR.properties | 1 + .../resources/i18n/Messages_ru_RU.properties | 1 + .../resources/i18n/Messages_zh_CN.properties | 1 + .../resources/i18n/Messages_zh_TW.properties | 1 + 13 files changed, 337 insertions(+), 254 deletions(-) delete mode 100644 jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java create mode 100644 jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignatureNode.java diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java b/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java deleted file mode 100644 index 6a0f96c6b..000000000 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignature.java +++ /dev/null @@ -1,250 +0,0 @@ -package jadx.gui.treemodel; - -import java.io.File; -import java.security.cert.Certificate; -import java.util.List; -import java.util.stream.Collectors; - -import javax.swing.Icon; -import javax.swing.ImageIcon; - -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.commons.text.StringEscapeUtils; -import org.jetbrains.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.android.apksig.ApkVerifier; - -import jadx.api.ICodeInfo; -import jadx.api.ResourceFile; -import jadx.api.ResourceType; -import jadx.api.impl.SimpleCodeInfo; -import jadx.gui.JadxWrapper; -import jadx.gui.ui.panel.ContentPanel; -import jadx.gui.ui.panel.HtmlPanel; -import jadx.gui.ui.tab.TabbedPane; -import jadx.gui.utils.CertificateManager; -import jadx.gui.utils.NLS; -import jadx.gui.utils.UiUtils; -import jadx.zip.IZipEntry; - -public class ApkSignature extends JNode { - private static final long serialVersionUID = -9121321926113143407L; - - private static final Logger LOG = LoggerFactory.getLogger(ApkSignature.class); - - private static final ImageIcon CERTIFICATE_ICON = UiUtils.openSvgIcon("nodes/styleKeyPack"); - - private final transient File openFile; - private ICodeInfo content; - - @Nullable - public static ApkSignature getApkSignature(JadxWrapper wrapper) { - // Only show the ApkSignature node if an AndroidManifest.xml is present. - // Without a manifest the Google ApkVerifier refuses to work. - File apkFile = null; - for (ResourceFile resFile : wrapper.getResources()) { - if (resFile.getType() == ResourceType.MANIFEST) { - IZipEntry zipEntry = resFile.getZipEntry(); - if (zipEntry != null) { - apkFile = zipEntry.getZipFile(); - break; - } - } - } - if (apkFile == null) { - return null; - } - return new ApkSignature(apkFile); - } - - public ApkSignature(File openFile) { - this.openFile = openFile; - } - - @Override - public JClass getJParent() { - return null; - } - - @Override - public Icon getIcon() { - return CERTIFICATE_ICON; - } - - @Override - public String makeString() { - return "APK signature"; - } - - @Override - public ContentPanel getContentPanel(TabbedPane tabbedPane) { - return new HtmlPanel(tabbedPane, this); - } - - @Override - public ICodeInfo getCodeInfo() { - if (content != null) { - return this.content; - } - ApkVerifier verifier = new ApkVerifier.Builder(openFile).build(); - try { - ApkVerifier.Result result = verifier.verify(); - StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4); - builder.append("

APK signature verification result:

"); - - builder.append("

"); - if (result.isVerified()) { - builder.escape(NLS.str("apkSignature.verificationSuccess")); - } else { - builder.escape(NLS.str("apkSignature.verificationFailed")); - } - builder.append("

"); - - final String err = NLS.str("apkSignature.errors"); - final String warn = NLS.str("apkSignature.warnings"); - final String sigSuccKey = "apkSignature.signatureSuccess"; - final String sigFailKey = "apkSignature.signatureFailed"; - - writeIssues(builder, err, result.getErrors()); - - if (!result.getV1SchemeSigners().isEmpty()) { - builder.append("

"); - builder.escape(NLS.str(result.isVerifiedUsingV1Scheme() ? sigSuccKey : sigFailKey, 1)); - builder.append("

\n"); - - builder.append("
"); - for (ApkVerifier.Result.V1SchemeSignerInfo signer : result.getV1SchemeSigners()) { - builder.append("

"); - builder.escape(NLS.str("apkSignature.signer")); - builder.append(" "); - builder.escape(signer.getName()); - builder.append(" ("); - builder.escape(signer.getSignatureFileName()); - builder.append(")"); - builder.append("

"); - writeCertificate(builder, signer.getCertificate()); - writeIssues(builder, err, signer.getErrors()); - writeIssues(builder, warn, signer.getWarnings()); - } - builder.append("
"); - } - if (!result.getV2SchemeSigners().isEmpty()) { - builder.append("

"); - builder.escape(NLS.str(result.isVerifiedUsingV2Scheme() ? sigSuccKey : sigFailKey, 2)); - builder.append("

\n"); - - builder.append("
"); - for (ApkVerifier.Result.V2SchemeSignerInfo signer : result.getV2SchemeSigners()) { - builder.append("

"); - builder.escape(NLS.str("apkSignature.signer")); - builder.append(" "); - builder.append(Integer.toString(signer.getIndex() + 1)); - builder.append("

"); - writeCertificate(builder, signer.getCertificate()); - writeIssues(builder, err, signer.getErrors()); - writeIssues(builder, warn, signer.getWarnings()); - } - builder.append("
"); - } - if (!result.getV3SchemeSigners().isEmpty()) { - builder.append("

"); - builder.escape(NLS.str(result.isVerifiedUsingV3Scheme() ? sigSuccKey : sigFailKey, 3)); - builder.append("

\n"); - - builder.append("
"); - for (ApkVerifier.Result.V3SchemeSignerInfo signer : result.getV3SchemeSigners()) { - builder.append("

"); - builder.escape(NLS.str("apkSignature.signer")); - builder.append(" "); - builder.append(Integer.toString(signer.getIndex() + 1)); - builder.append("

"); - writeCertificate(builder, signer.getCertificate()); - writeIssues(builder, err, signer.getErrors()); - writeIssues(builder, warn, signer.getWarnings()); - } - builder.append("
"); - } - if (!result.getV31SchemeSigners().isEmpty()) { - builder.append("

"); - builder.escape(NLS.str(result.isVerifiedUsingV31Scheme() ? sigSuccKey : sigFailKey, 31)); - builder.append("

\n"); - - builder.append("
"); - for (ApkVerifier.Result.V3SchemeSignerInfo signer : result.getV31SchemeSigners()) { - builder.append("

"); - builder.escape(NLS.str("apkSignature.signer")); - builder.append(" "); - builder.append(Integer.toString(signer.getIndex() + 1)); - builder.append("

"); - writeCertificate(builder, signer.getCertificate()); - writeIssues(builder, err, signer.getErrors()); - writeIssues(builder, warn, signer.getWarnings()); - } - builder.append("
"); - } - writeIssues(builder, warn, result.getWarnings()); - - this.content = new SimpleCodeInfo(builder.toString()); - } catch (Exception e) { - LOG.error(e.getMessage(), e); - StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4); - builder.append("

"); - builder.escape(NLS.str("apkSignature.exception")); - builder.append("

");
-			builder.escape(ExceptionUtils.getStackTrace(e));
-			builder.append("
"); - return new SimpleCodeInfo(builder.toString()); - } - return this.content; - } - - private void writeCertificate(StringEscapeUtils.Builder builder, Certificate cert) { - CertificateManager certMgr = new CertificateManager(cert); - builder.append("
");
-		builder.escape(certMgr.generateHeader());
-		builder.append("
");
-		builder.escape(certMgr.generatePublicKey());
-		builder.append("
");
-		builder.escape(certMgr.generateSignature());
-		builder.append("
");
-		builder.append(certMgr.generateFingerprint());
-		builder.append("
"); - } - - private void writeIssues(StringEscapeUtils.Builder builder, String issueType, List issueList) { - if (!issueList.isEmpty()) { - builder.append("

"); - builder.escape(issueType); - builder.append("

"); - builder.append("
"); - // Unprotected Zip entry issues are very common, handle them separately - List unprotIssues = issueList.stream() - .filter(i -> i.getIssue() == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY) - .collect(Collectors.toList()); - if (!unprotIssues.isEmpty()) { - builder.append("

"); - builder.escape(NLS.str("apkSignature.unprotectedEntry")); - builder.append("

"); - for (ApkVerifier.IssueWithParams issue : unprotIssues) { - builder.escape((String) issue.getParams()[0]); - builder.append("
"); - } - builder.append("
"); - } - List remainingIssues = issueList.stream() - .filter(i -> i.getIssue() != ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY) - .collect(Collectors.toList()); - if (!remainingIssues.isEmpty()) { - builder.append("
\n");
-				for (ApkVerifier.IssueWithParams issue : remainingIssues) {
-					builder.escape(issue.toString());
-					builder.append("\n");
-				}
-				builder.append("
\n"); - } - builder.append("
"); - } - } -} diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignatureNode.java b/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignatureNode.java new file mode 100644 index 000000000..42fb4c76a --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/ApkSignatureNode.java @@ -0,0 +1,320 @@ +package jadx.gui.treemodel; + +import java.io.File; +import java.security.cert.Certificate; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.android.apksig.ApkVerifier; + +import jadx.api.ICodeInfo; +import jadx.api.ResourceFile; +import jadx.api.ResourceType; +import jadx.api.impl.SimpleCodeInfo; +import jadx.gui.JadxWrapper; +import jadx.gui.ui.panel.ContentPanel; +import jadx.gui.ui.panel.HtmlPanel; +import jadx.gui.ui.tab.TabbedPane; +import jadx.gui.utils.CertificateManager; +import jadx.gui.utils.NLS; +import jadx.gui.utils.UiUtils; +import jadx.zip.IZipEntry; + +public class ApkSignatureNode extends JNode { + private static final long serialVersionUID = -9121321926113143407L; + + private static final Logger LOG = LoggerFactory.getLogger(ApkSignatureNode.class); + + private static final ImageIcon CERTIFICATE_ICON = UiUtils.openSvgIcon("nodes/styleKeyPack"); + + private final transient File openFile; + private ICodeInfo content; + private volatile boolean loadingStarted = false; + private static TabbedPane tabbedPane; + + @Nullable + public static ApkSignatureNode getApkSignature(JadxWrapper wrapper) { + // Only show the ApkSignature node if an AndroidManifest.xml is present. + // Without a manifest the Google ApkVerifier refuses to work. + File apkFile = null; + for (ResourceFile resFile : wrapper.getResources()) { + if (resFile.getType() == ResourceType.MANIFEST) { + IZipEntry zipEntry = resFile.getZipEntry(); + if (zipEntry != null) { + apkFile = zipEntry.getZipFile(); + break; + } + } + } + if (apkFile == null) { + return null; + } + return new ApkSignatureNode(apkFile); + } + + public ApkSignatureNode(File openFile) { + this.openFile = openFile; + } + + @Override + public JClass getJParent() { + return null; + } + + @Override + public Icon getIcon() { + return CERTIFICATE_ICON; + } + + @Override + public String makeString() { + return "APK signature"; + } + + @Override + public ContentPanel getContentPanel(TabbedPane tabbedPane) { + ApkSignatureNode.tabbedPane = tabbedPane; + return new HtmlPanel(tabbedPane, this); + } + + @Override + public ICodeInfo getCodeInfo() { + if (content != null) { + return content; + } + + // If loading hasn't started yet, start it. + if (!loadingStarted) { + loadingStarted = true; + SwingUtilities.invokeLater(() -> { + new ApkSignatureWorker(this).execute(); + }); + + return new SimpleCodeInfo(StringEscapeUtils.escapeHtml4(NLS.str("apkSignature.loading"))); + } + + return new SimpleCodeInfo(StringEscapeUtils.escapeHtml4(NLS.str("apkSignature.loading"))); + } + + private void writeCertificate(StringEscapeUtils.Builder builder, Certificate cert) { + CertificateManager certMgr = new CertificateManager(cert); + builder.append("
");
+		builder.escape(certMgr.generateHeader());
+		builder.append("
");
+		builder.escape(certMgr.generatePublicKey());
+		builder.append("
");
+		builder.escape(certMgr.generateSignature());
+		builder.append("
");
+		builder.append(certMgr.generateFingerprint());
+		builder.append("
"); + } + + private static void writeIssues(StringEscapeUtils.Builder builder, String issueType, List issueList) { + if (!issueList.isEmpty()) { + builder.append("

"); + builder.escape(issueType); + builder.append("

"); + builder.append("
"); + // Unprotected Zip entry issues are very common, handle them separately + List unprotIssues = issueList.stream() + .filter(i -> i.getIssue() == ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY) + .collect(Collectors.toList()); + if (!unprotIssues.isEmpty()) { + builder.append("

"); + builder.escape(NLS.str("apkSignature.unprotectedEntry")); + builder.append("

"); + for (ApkVerifier.IssueWithParams issue : unprotIssues) { + builder.escape((String) issue.getParams()[0]); + builder.append("
"); + } + builder.append("
"); + } + List remainingIssues = issueList.stream() + .filter(i -> i.getIssue() != ApkVerifier.Issue.JAR_SIG_UNPROTECTED_ZIP_ENTRY) + .collect(Collectors.toList()); + if (!remainingIssues.isEmpty()) { + builder.append("
\n");
+				for (ApkVerifier.IssueWithParams issue : remainingIssues) {
+					builder.escape(issue.toString());
+					builder.append("\n");
+				}
+				builder.append("
\n"); + } + builder.append("
"); + } + } + + private static class ApkSignatureWorker extends SwingWorker { + private final ApkSignatureNode node; + + public ApkSignatureWorker(ApkSignatureNode node) { + this.node = node; + } + + @Override + protected ICodeInfo doInBackground() { + LOG.debug("Starting APK signature verification for {}", node.openFile); + ApkVerifier verifier = new ApkVerifier.Builder(node.openFile).build(); + try { + ApkVerifier.Result result = verifier.verify(); + + // Build HTML content + StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4); + builder.append("

APK signature verification result:

"); + + builder.append("

"); + if (result.isVerified()) { + builder.escape(NLS.str("apkSignature.verificationSuccess")); + } else { + builder.escape(NLS.str("apkSignature.verificationFailed")); + } + builder.append("

"); + + final String err = NLS.str("apkSignature.errors"); + final String warn = NLS.str("apkSignature.warnings"); + final String sigSuccKey = "apkSignature.signatureSuccess"; + final String sigFailKey = "apkSignature.signatureFailed"; + + ApkSignatureNode parentNode = node; + + writeIssues(builder, err, result.getErrors()); + + if (!result.getV1SchemeSigners().isEmpty()) { + builder.append("

"); + builder.escape(NLS.str(result.isVerifiedUsingV1Scheme() ? sigSuccKey : sigFailKey, 1)); + builder.append("

\n"); + + builder.append("
"); + for (ApkVerifier.Result.V1SchemeSignerInfo signer : result.getV1SchemeSigners()) { + builder.append("

"); + builder.escape(NLS.str("apkSignature.signer")); + builder.append(" "); + builder.escape(signer.getName()); + builder.append(" ("); + builder.escape(signer.getSignatureFileName()); + builder.append(")"); + builder.append("

"); + parentNode.writeCertificate(builder, signer.getCertificate()); + writeIssues(builder, err, signer.getErrors()); + writeIssues(builder, warn, signer.getWarnings()); + } + builder.append("
"); + } + if (!result.getV2SchemeSigners().isEmpty()) { + builder.append("

"); + builder.escape(NLS.str(result.isVerifiedUsingV2Scheme() ? sigSuccKey : sigFailKey, 2)); + builder.append("

\n"); + + builder.append("
"); + for (ApkVerifier.Result.V2SchemeSignerInfo signer : result.getV2SchemeSigners()) { + builder.append("

"); + builder.escape(NLS.str("apkSignature.signer")); + builder.append(" "); + builder.append(Integer.toString(signer.getIndex() + 1)); + builder.append("

"); + parentNode.writeCertificate(builder, signer.getCertificate()); + writeIssues(builder, err, signer.getErrors()); + writeIssues(builder, warn, signer.getWarnings()); + } + builder.append("
"); + } + if (!result.getV3SchemeSigners().isEmpty()) { + builder.append("

"); + builder.escape(NLS.str(result.isVerifiedUsingV3Scheme() ? sigSuccKey : sigFailKey, 3)); + builder.append("

\n"); + + builder.append("
"); + for (ApkVerifier.Result.V3SchemeSignerInfo signer : result.getV3SchemeSigners()) { + builder.append("

"); + builder.escape(NLS.str("apkSignature.signer")); + builder.append(" "); + builder.append(Integer.toString(signer.getIndex() + 1)); + builder.append("

"); + parentNode.writeCertificate(builder, signer.getCertificate()); + writeIssues(builder, err, signer.getErrors()); + writeIssues(builder, warn, signer.getWarnings()); + } + builder.append("
"); + } + if (!result.getV31SchemeSigners().isEmpty()) { + builder.append("

"); + builder.escape(NLS.str(result.isVerifiedUsingV31Scheme() ? sigSuccKey : sigFailKey, 31)); + builder.append("

\n"); + + builder.append("
"); + for (ApkVerifier.Result.V3SchemeSignerInfo signer : result.getV31SchemeSigners()) { + builder.append("

"); + builder.escape(NLS.str("apkSignature.signer")); + builder.append(" "); + builder.append(Integer.toString(signer.getIndex() + 1)); + builder.append("

"); + parentNode.writeCertificate(builder, signer.getCertificate()); + writeIssues(builder, err, signer.getErrors()); + writeIssues(builder, warn, signer.getWarnings()); + } + builder.append("
"); + } + writeIssues(builder, warn, result.getWarnings()); + + return new SimpleCodeInfo(builder.toString()); + + } catch (Exception e) { + LOG.error("Failed to verify APK signature for {}", node.openFile, e); + StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4); + builder.append("

"); + builder.escape(NLS.str("apkSignature.exception")); + builder.append("

");
+				builder.escape(ExceptionUtils.getStackTrace(e));
+				builder.append("
"); + return new SimpleCodeInfo(builder.toString()); + } + } + + @Override + protected void done() { + try { + node.content = get(); + if (tabbedPane != null) { + ContentPanel panel = tabbedPane.getTabByNode(node); + if (panel instanceof HtmlPanel) { + ((HtmlPanel) panel).loadContent(node); + } + } else { + LOG.warn("Could not find TabbedPane to refresh ApkSignatureNode panel."); + } + + } catch (InterruptedException | ExecutionException e) { + LOG.error("Error during APK signature verification SwingWorker", e); + StringEscapeUtils.Builder builder = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_HTML4); + builder.append("

"); + builder.escape(NLS.str("apkSignature.exception")); + builder.append("

");
+				Throwable cause = (e instanceof ExecutionException) ? e.getCause() : e;
+				builder.escape(ExceptionUtils.getStackTrace(cause));
+				builder.append("
"); + node.content = new SimpleCodeInfo(builder.toString()); + + if (tabbedPane != null) { + ContentPanel panel = tabbedPane.getTabByNode(node); + if (panel instanceof HtmlPanel) { + ((HtmlPanel) panel).loadContent(node); + } + } + } finally { + node.loadingStarted = false; + } + } + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 9bcf4d83f..041d49ac9 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -116,7 +116,7 @@ import jadx.gui.settings.JadxSettings; import jadx.gui.settings.ui.JadxSettingsWindow; import jadx.gui.settings.ui.plugins.PluginSettings; import jadx.gui.tree.TreeExpansionService; -import jadx.gui.treemodel.ApkSignature; +import jadx.gui.treemodel.ApkSignatureNode; import jadx.gui.treemodel.JInputFiles; import jadx.gui.treemodel.JInputScripts; import jadx.gui.treemodel.JInputs; @@ -682,7 +682,7 @@ public class MainWindow extends JFrame { } private void addTreeCustomNodes() { - treeRoot.replaceCustomNode(ApkSignature.getApkSignature(wrapper)); + treeRoot.replaceCustomNode(ApkSignatureNode.getApkSignature(wrapper)); treeRoot.replaceCustomNode(new SummaryNode(this)); } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/panel/HtmlPanel.java b/jadx-gui/src/main/java/jadx/gui/ui/panel/HtmlPanel.java index d9117b7a1..ae3a49eeb 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/panel/HtmlPanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/panel/HtmlPanel.java @@ -23,8 +23,7 @@ public final class HtmlPanel extends ContentPanel { setLayout(new BorderLayout()); textArea = new JHtmlPane(); loadSettings(); - textArea.setText(jnode.getCodeInfo().getCodeStr()); - textArea.setCaretPosition(0); // otherwise the start view will be the last line + loadContent(jnode); textArea.setEditable(false); JScrollPane sp = new JScrollPane(textArea); add(sp); @@ -38,6 +37,11 @@ public final class HtmlPanel extends ContentPanel { textArea.setFont(settings.getFont()); } + public void loadContent(JNode jnode) { + textArea.setText(jnode.getCodeInfo().getCodeStr()); + textArea.setCaretPosition(0); // otherwise the start view will be the last line + } + public JEditorPane getHtmlArea() { return textArea; } 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 5c07389e3..dae064370 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256-Fingerabdruck certificate.serialPubKeyY=Y apkSignature.signer=Signierer +#apkSignature.loading=Loading signature... apkSignature.verificationSuccess=Signaturprüfung erfolgreich abgeschlossen apkSignature.verificationFailed=Signaturprüfung fehlgeschlagen apkSignature.signatureSuccess=Gültige APK-Signatur v%d gefunden 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 90b12db29..6006d0980 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 Fingerprint certificate.serialPubKeyY=Y apkSignature.signer=Signer +apkSignature.loading=Loading signature... apkSignature.verificationSuccess=Signature verification succeeded apkSignature.verificationFailed=Signature verification failed apkSignature.signatureSuccess=Valid APK signature v%d found 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 61867a8ec..38dfdf8ae 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=Huella SHA-256 certificate.serialPubKeyY=Y #apkSignature.signer=Signer +#apkSignature.loading=Loading signature... #apkSignature.verificationSuccess=Signature verification succeeded #apkSignature.verificationFailed=Signature verification failed #apkSignature.signatureSuccess=Valid APK signature v%d found 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 9e3b3a3e0..e13886915 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_id_ID.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=Sidik Jari SHA-256 certificate.serialPubKeyY=Y apkSignature.signer=Penandatangan +#apkSignature.loading=Loading signature... apkSignature.verificationSuccess=Verifikasi tanda tangan berhasil apkSignature.verificationFailed=Verifikasi tanda tangan gagal apkSignature.signatureSuccess=Tanda tangan APK yang valid v%d ditemukan 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 1b4adbe12..90c2ce004 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 지문 certificate.serialPubKeyY=Y apkSignature.signer=서명자 +#apkSignature.loading=Loading signature... apkSignature.verificationSuccess=서명 검증 성공 apkSignature.verificationFailed=서명 검증 실패 apkSignature.signatureSuccess=유효한 APK 서명 v%d을(를) 찾았습니다. 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 c3495d189..09a6b4698 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_pt_BR.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=Assinatura digital SHA-256 certificate.serialPubKeyY=Y apkSignature.signer=Assinador +#apkSignature.loading=Loading signature... apkSignature.verificationSuccess=Verificação de assinatura bem-sucedida apkSignature.verificationFailed=Verificação de assinatura falhou apkSignature.signatureSuccess=Assinatura válida de apk v%d encontrada 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 19e15ba18..820e8ecd3 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ru_RU.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 Fingerprint certificate.serialPubKeyY=Y apkSignature.signer=Signer +#apkSignature.loading=Loading signature... apkSignature.verificationSuccess=Signature verification succeeded apkSignature.verificationFailed=Signature verification failed apkSignature.signatureSuccess=Valid APK signature v%d found 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 497fe6ca1..8e361ccb6 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 签名 certificate.serialPubKeyY=Y apkSignature.signer=签名者 +#apkSignature.loading=Loading signature... apkSignature.verificationSuccess=签名验证成功 apkSignature.verificationFailed=签名验证失败 apkSignature.signatureSuccess=找到有效的 APK 签名 v%d 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 2b447eefb..877f2757d 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_TW.properties @@ -398,6 +398,7 @@ certificate.serialSHA256=SHA-256 指紋 certificate.serialPubKeyY=Y apkSignature.signer=簽署者 +#apkSignature.loading=Loading signature... apkSignature.verificationSuccess=簽名驗證成功 apkSignature.verificationFailed=簽名驗證失敗 apkSignature.signatureSuccess=找到可用的 APK 簽名 v%d