Refactor JarMap
This commit is contained in:
parent
e7d668502c
commit
6f7c13b814
@ -118,7 +118,7 @@ object PatchAPK {
|
|||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun patch(apk: String, out: String, pkg: String, label: String = "Manager"): Boolean {
|
fun patch(apk: String, out: String, pkg: String, label: String = "Manager"): Boolean {
|
||||||
try {
|
try {
|
||||||
val jar = JarMap(apk)
|
val jar = JarMap.open(apk)
|
||||||
val je = jar.getJarEntry(Const.ANDROID_MANIFEST)
|
val je = jar.getJarEntry(Const.ANDROID_MANIFEST)
|
||||||
val xml = jar.getRawData(je)
|
val xml = jar.getRawData(je)
|
||||||
|
|
||||||
|
@ -15,117 +15,149 @@ import java.util.jar.Manifest;
|
|||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
/*
|
public abstract class JarMap implements Closeable {
|
||||||
* A universal random access interface for both JarFile and JarInputStream
|
|
||||||
*
|
|
||||||
* In the case when JarInputStream is provided to constructor, the whole stream
|
|
||||||
* will be loaded into memory for random access purposes.
|
|
||||||
* On the other hand, when a JarFile is provided, it simply works as a wrapper.
|
|
||||||
* */
|
|
||||||
|
|
||||||
public class JarMap implements Closeable {
|
LinkedHashMap<String, JarEntry> entryMap;
|
||||||
|
|
||||||
private JarFile jarFile;
|
public static JarMap open(String file) throws IOException {
|
||||||
private JarInputStream jis;
|
return new FileMap(new File(file), true, ZipFile.OPEN_READ);
|
||||||
private LinkedHashMap<String, JarEntry> bufMap;
|
|
||||||
private Manifest manifest;
|
|
||||||
|
|
||||||
public JarMap(File file) throws IOException {
|
|
||||||
this(file, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JarMap(File file, boolean verify) throws IOException {
|
public static JarMap open(File file, boolean verify) throws IOException {
|
||||||
this(file, verify, ZipFile.OPEN_READ);
|
return new FileMap(file, verify, ZipFile.OPEN_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JarMap(File file, boolean verify, int mode) throws IOException {
|
public static JarMap open(String file, boolean verify) throws IOException {
|
||||||
jarFile = new JarFile(file, verify, mode);
|
return new FileMap(new File(file), verify, ZipFile.OPEN_READ);
|
||||||
manifest = jarFile.getManifest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JarMap(String name) throws IOException {
|
public static JarMap open(InputStream is, boolean verify) throws IOException {
|
||||||
this(new File(name));
|
return new StreamMap(is, verify);
|
||||||
}
|
|
||||||
|
|
||||||
public JarMap(String name, boolean verify) throws IOException {
|
|
||||||
this(new File(name), verify);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JarMap(InputStream is) throws IOException {
|
|
||||||
this(is, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public JarMap(InputStream is, boolean verify) throws IOException {
|
|
||||||
jis = new JarInputStream(is, verify);
|
|
||||||
bufMap = new LinkedHashMap<>();
|
|
||||||
JarEntry entry;
|
|
||||||
while ((entry = jis.getNextJarEntry()) != null) {
|
|
||||||
bufMap.put(entry.getName(), new JarMapEntry(entry, jis));
|
|
||||||
}
|
|
||||||
manifest = jis.getManifest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public File getFile() {
|
public File getFile() {
|
||||||
return jarFile == null ? null : new File(jarFile.getName());
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Manifest getManifest() {
|
public abstract Manifest getManifest() throws IOException;
|
||||||
return manifest;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getInputStream(ZipEntry ze) throws IOException {
|
public InputStream getInputStream(ZipEntry ze) throws IOException {
|
||||||
if (bufMap != null) {
|
JarMapEntry e = getMapEntry(ze.getName());
|
||||||
JarMapEntry e = (JarMapEntry) bufMap.get(ze.getName());
|
return e != null ? e.data.getInputStream() : null;
|
||||||
if (e != null)
|
|
||||||
return e.data.getInputStream();
|
|
||||||
}
|
|
||||||
return jarFile.getInputStream(ze);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputStream getOutputStream(ZipEntry ze) {
|
public OutputStream getOutputStream(ZipEntry ze) {
|
||||||
manifest = null; /* Invalidate the manifest */
|
if (entryMap == null)
|
||||||
if (bufMap == null)
|
entryMap = new LinkedHashMap<>();
|
||||||
bufMap = new LinkedHashMap<>();
|
|
||||||
JarMapEntry e = new JarMapEntry(ze.getName());
|
JarMapEntry e = new JarMapEntry(ze.getName());
|
||||||
bufMap.put(ze.getName(), e);
|
entryMap.put(ze.getName(), e);
|
||||||
return e.data;
|
return e.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getRawData(ZipEntry ze) throws IOException {
|
public byte[] getRawData(ZipEntry ze) throws IOException {
|
||||||
if (bufMap != null) {
|
JarMapEntry e = getMapEntry(ze.getName());
|
||||||
JarMapEntry e = (JarMapEntry) bufMap.get(ze.getName());
|
return e != null ? e.data.toByteArray() : null;
|
||||||
if (e != null)
|
|
||||||
return e.data.toByteArray();
|
|
||||||
}
|
|
||||||
ByteArrayStream bytes = new ByteArrayStream();
|
|
||||||
bytes.readFrom(jarFile.getInputStream(ze));
|
|
||||||
return bytes.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Enumeration<JarEntry> entries() {
|
public abstract Enumeration<JarEntry> entries();
|
||||||
return jarFile == null ? Collections.enumeration(bufMap.values()) : jarFile.entries();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZipEntry getEntry(String name) {
|
public final ZipEntry getEntry(String name) {
|
||||||
return getJarEntry(name);
|
return getJarEntry(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JarEntry getJarEntry(String name) {
|
public JarEntry getJarEntry(String name) {
|
||||||
JarEntry e = jarFile == null ? bufMap.get(name) : jarFile.getJarEntry(name);
|
return getMapEntry(name);
|
||||||
if (e == null && bufMap != null)
|
}
|
||||||
return bufMap.get(name);
|
|
||||||
|
JarMapEntry getMapEntry(String name) {
|
||||||
|
JarMapEntry e = null;
|
||||||
|
if (entryMap != null)
|
||||||
|
e = (JarMapEntry) entryMap.get(name);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static class FileMap extends JarMap {
|
||||||
public void close() throws IOException {
|
|
||||||
if (jarFile != null)
|
private JarFile jarFile;
|
||||||
|
|
||||||
|
FileMap(File file, boolean verify, int mode) throws IOException {
|
||||||
|
jarFile = new JarFile(file, verify, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getFile() {
|
||||||
|
return new File(jarFile.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Manifest getManifest() throws IOException {
|
||||||
|
return jarFile.getManifest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream(ZipEntry ze) throws IOException {
|
||||||
|
InputStream is = super.getInputStream(ze);
|
||||||
|
return is != null ? is : jarFile.getInputStream(ze);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] getRawData(ZipEntry ze) throws IOException {
|
||||||
|
byte[] b = super.getRawData(ze);
|
||||||
|
if (b != null)
|
||||||
|
return b;
|
||||||
|
ByteArrayStream bytes = new ByteArrayStream();
|
||||||
|
bytes.readFrom(jarFile.getInputStream(ze));
|
||||||
|
return bytes.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<JarEntry> entries() {
|
||||||
|
return jarFile.entries();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JarEntry getJarEntry(String name) {
|
||||||
|
JarEntry e = getMapEntry(name);
|
||||||
|
return e != null ? e : jarFile.getJarEntry(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
jarFile.close();
|
jarFile.close();
|
||||||
else
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StreamMap extends JarMap {
|
||||||
|
|
||||||
|
private JarInputStream jis;
|
||||||
|
|
||||||
|
StreamMap(InputStream is, boolean verify) throws IOException {
|
||||||
|
jis = new JarInputStream(is, verify);
|
||||||
|
entryMap = new LinkedHashMap<>();
|
||||||
|
JarEntry entry;
|
||||||
|
while ((entry = jis.getNextJarEntry()) != null) {
|
||||||
|
entryMap.put(entry.getName(), new JarMapEntry(entry, jis));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Manifest getManifest() {
|
||||||
|
return jis.getManifest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<JarEntry> entries() {
|
||||||
|
return Collections.enumeration(entryMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
jis.close();
|
jis.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class JarMapEntry extends JarEntry {
|
private static class JarMapEntry extends JarEntry {
|
||||||
|
|
||||||
ByteArrayStream data;
|
ByteArrayStream data;
|
||||||
|
|
||||||
JarMapEntry(JarEntry je, InputStream is) {
|
JarMapEntry(JarEntry je, InputStream is) {
|
||||||
|
@ -72,7 +72,7 @@ public class SignAPK {
|
|||||||
|
|
||||||
ZipAdjust.adjust(temp1, temp2);
|
ZipAdjust.adjust(temp1, temp2);
|
||||||
|
|
||||||
try (JarMap map = new JarMap(temp2, false)) {
|
try (JarMap map = JarMap.open(temp2, false)) {
|
||||||
sign(cert, key, map, output, true);
|
sign(cert, key, map, output, true);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -65,7 +65,7 @@ public class ZipSigner {
|
|||||||
|
|
||||||
Security.insertProviderAt(new BouncyCastleProvider(), 1);
|
Security.insertProviderAt(new BouncyCastleProvider(), 1);
|
||||||
|
|
||||||
try (JarMap in = new JarMap(args[args.length - 2], false);
|
try (JarMap in = JarMap.open(args[args.length - 2], false);
|
||||||
OutputStream out = new FileOutputStream(args[args.length - 1])) {
|
OutputStream out = new FileOutputStream(args[args.length - 1])) {
|
||||||
if (args.length == 2) {
|
if (args.length == 2) {
|
||||||
sign(in, out);
|
sign(in, out);
|
||||||
|
Loading…
Reference in New Issue
Block a user