private JCertificate getCertificate(List<ResourceFile> resources) { if (resources.isEmpty()) { return null; } for (ResourceFile rf : resources) { if (rf.getZipRef() != null) { String rfName = rf.getName().toUpperCase(); if (rfName.endsWith(".DSA") || rfName.endsWith(".RSA")) { return new JCertificate(rf); } } } return null; }
@Override public String getSyntaxName() { if (resFile == null) { return null; } switch (resFile.getType()) { case CODE: return super.getSyntaxName(); case MANIFEST: case XML: return SyntaxConstants.SYNTAX_STYLE_XML; default: String syntax = getSyntaxByExtension(resFile.getName()); if (syntax != null) { return syntax; } return super.getSyntaxName(); } }
@Override public void run() { saveResources(resourceFile.loadContent()); }
private void addEntry(List<ResourceFile> list, File zipFile, ZipEntry entry) { if (entry.isDirectory()) { return; } String name = entry.getName(); ResourceType type = ResourceType.getFileType(name); ResourceFile rf = ResourceFile.createResourceFile(jadxRef, name, type); if (rf != null) { rf.setZipRef(new ZipRef(zipFile, name)); list.add(rf); } }
@Override public synchronized String getContent() { if (loaded) { return content; } if (resFile == null || type != JResType.FILE) { return null; } if (!isSupportedForView(resFile.getType())) { return null; } ResContainer rc = resFile.loadContent(); if (rc == null) { return null; } if (rc.getDataType() == ResContainer.DataType.RES_TABLE) { content = loadCurrentSingleRes(rc); for (ResContainer subFile : rc.getSubFiles()) { loadSubNodes(this, subFile, 1); } loaded = true; return content; } // single node return loadCurrentSingleRes(rc); }
@Override public Icon getIcon() { switch (type) { case ROOT: return ROOT_ICON; case DIR: return FOLDER_ICON; case FILE: ResourceType resType = resFile.getType(); if (resType == ResourceType.MANIFEST) { return MANIFEST_ICON; } if (resType == ResourceType.CODE) { return new OverlayIcon(FILE_ICON, ERROR_ICON, JAVA_ICON); } if (!isSupportedForView(resType)) { return new OverlayIcon(FILE_ICON, ERROR_ICON); } return FILE_ICON; } return FILE_ICON; }
public static ResContainer resourceFileLink(ResourceFile resFile) { return new ResContainer(resFile.getName(), Collections.emptyList(), resFile, DataType.RES_LINK); }
public static ResourceFile createResourceFile(JadxDecompiler decompiler, String name, ResourceType type) { if (!ZipSecurity.isValidZipEntryName(name)) { return null; } return new ResourceFile(decompiler, name, type); }
private void addResourceFile(List<ResourceFile> list, File file) { String name = file.getAbsolutePath(); ResourceType type = ResourceType.getFileType(name); ResourceFile rf = ResourceFile.createResourceFile(jadxRef, name, type); if (rf != null) { list.add(rf); } }
public void loadResources(List<ResourceFile> resources) { ResourceFile arsc = null; for (ResourceFile rf : resources) { if (rf.getType() == ResourceType.ARSC) { arsc = rf; break; } } if (arsc == null) { LOG.debug("'.arsc' file not found"); return; } try { ResourceStorage resStorage = ResourcesLoader.decodeStream(arsc, (size, is) -> { ResTableParser parser = new ResTableParser(); parser.decode(is); return parser.getResStorage(); }); processResources(resStorage); } catch (Exception e) { LOG.error("Failed to parse '.arsc' file", e); } }
private static ResContainer decodeImage(ResourceFile rf, InputStream inputStream) { String name = rf.getName(); if (name.endsWith(".9.png")) { Res9patchStreamDecoder decoder = new Res9patchStreamDecoder(); ByteArrayOutputStream os = new ByteArrayOutputStream(); try { decoder.decode(inputStream, os); return ResContainer.decodedData(rf.getName(), os.toByteArray()); } catch (Exception e) { LOG.error("Failed to decode 9-patch png image, path: {}", name, e); } } return ResContainer.resourceFileLink(rf); }
@Override public String getContent() { try { ResourceFile.ZipRef zipRef = rf.getZipRef(); if (zipRef == null) { File file = new File(rf.getName()); try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) { return CertificateManager.decode(inputStream); } } else { try (ZipFile zipFile = new ZipFile(zipRef.getZipFile())) { ZipEntry entry = zipFile.getEntry(zipRef.getEntryName()); if (entry == null) { throw new IOException("Zip entry not found: " + zipRef); } if (!ZipSecurity.isValidZipEntry(entry)) { return null; } try (InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(entry))) { return CertificateManager.decode(inputStream); } } } } catch (Exception e) { LOG.error("Certificate decode error: {}", rf.getName(), e); return "Decode error: " + e.getMessage(); } } }
static ResContainer loadContent(JadxDecompiler jadxRef, ResourceFile rf) { try { return decodeStream(rf, (size, is) -> loadContent(jadxRef, rf, is)); } catch (JadxException e) { LOG.error("Decode error", e); CodeWriter cw = new CodeWriter(); cw.add("Error decode ").add(rf.getType().toString().toLowerCase()); cw.startLine(Utils.getStackTrace(e.getCause())); return ResContainer.textResource(rf.getName(), cw); } }
@Nullable private ContentPanel makeContentPanel(JNode node) { if (node instanceof JResource) { JResource res = (JResource) node; ResourceFile resFile = res.getResFile(); if (resFile != null) { if (resFile.getType() == ResourceType.IMG) { return new ImagePanel(this, res); } } else { return null; } } if (node instanceof ApkSignature) { return new HtmlPanel(this, node); } if (node instanceof JCertificate) { return new CertificatePanel(this, node); } return new CodePanel(this, node); }
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. if (wrapper.getResources().stream().noneMatch(r -> "AndroidManifest.xml".equals(r.getName()))) { return null; } File openFile = wrapper.getOpenFile(); return new ApkSignature(openFile); }
private BufferedImage loadImage(JResource res) { ResourceFile resFile = res.getResFile(); ResContainer resContainer = resFile.loadContent(); ResContainer.DataType dataType = resContainer.getDataType(); if (dataType == ResContainer.DataType.DECODED_DATA) { try { return ImageIO.read(new ByteArrayInputStream(resContainer.getDecodedData())); } catch (Exception e) { throw new JadxRuntimeException("Failed to load image", e); } } else if (dataType == ResContainer.DataType.RES_LINK) { try { return ResourcesLoader.decodeStream(resFile, (size, is) -> ImageIO.read(is)); } catch (Exception e) { throw new JadxRuntimeException("Failed to load image", e); } } else { throw new JadxRuntimeException("Unsupported resource image data type: " + resFile); } }
public static <T> T decodeStream(ResourceFile rf, ResourceDecoder<T> decoder) throws JadxException { try { ZipRef zipRef = rf.getZipRef(); if (zipRef == null) { File file = new File(rf.getName()); try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) { return decoder.decode(file.length(), inputStream); } } else { try (ZipFile zipFile = new ZipFile(zipRef.getZipFile())) { ZipEntry entry = zipFile.getEntry(zipRef.getEntryName()); if (entry == null) { throw new IOException("Zip entry not found: " + zipRef); } if (!ZipSecurity.isValidZipEntry(entry)) { return null; } try (InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(entry))) { return decoder.decode(entry.getSize(), inputStream); } } } } catch (Exception e) { throw new JadxException("Error decode: " + rf.getName(), e); } }
private static ResContainer loadContent(JadxDecompiler jadxRef, ResourceFile rf, InputStream inputStream) throws IOException { switch (rf.getType()) { case MANIFEST: case XML: CodeWriter content = jadxRef.getXmlParser().parse(inputStream); return ResContainer.textResource(rf.getName(), content); case ARSC: return new ResTableParser().decodeFiles(inputStream); case IMG: return decodeImage(rf, inputStream); default: return ResContainer.resourceFileLink(rf); } }
public final void update() { if (files.isEmpty()) { if (type == JResType.DIR || type == JResType.ROOT || resFile.getType() == ResourceType.ARSC) { // fake leaf to force show expand button // real sub nodes will load on expand in loadNode() method add(new TextNode(NLS.str("tree.loading"))); } } else { removeAllChildren(); for (JResource res : files) { res.update(); add(res); } } }