]> git.saurik.com Git - backport.git/blobdiff - src/com/saurik/backport/Hook.java
Implement a complete fix for Android bug #9695860.
[backport.git] / src / com / saurik / backport / Hook.java
index 6d0e1341d52c3a0fd6b7337f47cecfa9b8f72a43..2ddd07ae649895cb28249e74387503b1e4177588 100644 (file)
 
 package com.saurik.backport;
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
-import java.util.LinkedHashMap;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
 
-import java.util.jar.JarFile;
+import java.util.LinkedHashMap;
 
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
@@ -45,53 +49,138 @@ public class Hook {
         }
     }
 
-    public static void initialize() {
-        MS.hookClassLoad("java.util.zip.ZipFile", new MS.ClassLoadHook() {
-            public void classLoaded(Class<?> ZipFile$) {
-                Field entries = null; {
-                    if (entries == null) try {
-                        entries = ZipFile$.getDeclaredField("entries");
-                    } catch (NoSuchFieldException e) {}
-
-                    if (entries == null) try {
-                        entries = ZipFile$.getDeclaredField("mEntries");
-                    } catch (NoSuchFieldException e) {}
+    private static Field scanField(Class clazz, String... names) {
+        for (String name : names) try {
+            return clazz.getDeclaredField(name);
+        } catch (NoSuchFieldException e) {}
+        return null;
+    }
+
+    private static Method findMethod(Class<?> clazz, String name, Class... args) {
+        try {
+            return clazz.getDeclaredMethod(name, args);
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+    }
+
+    private static Constructor findConstructor(Class<?> clazz, Class... args) {
+        try {
+            return clazz.getDeclaredConstructor(args);
+        } catch (NoSuchMethodException e) {
+            return null;
+        }
+    }
+
+    private static void fixZipEntry$init$() {
+        final Constructor ZipEntry$init$ = findConstructor(ZipEntry.class, byte[].class, InputStream.class);
+        if (ZipEntry$init$ == null)
+            return;
+
+        MS.hookMethod(ZipEntry.class, ZipEntry$init$,
+            new MS.MethodAlteration<ZipEntry, Void>() {
+                public Void invoked(ZipEntry thiz, Object... args)
+                    throws Throwable
+                {
+                    byte[] header = (byte[]) args[0];
+
+                    invoke(thiz, args);
+
+                    DataInputStream in = new DataInputStream(new ByteArrayInputStream(header));
+
+                    in.skip(8);
+                    for (int i = 0; i != 2; ++i)
+                        if ((in.readShort() & 0x0080) != 0)
+                            throw new ZipException("bug #99695860 [" + thiz.getName() + "]");
+
+                    in.skip(16);
+                    for (int i = 0; i != 3; ++i)
+                        if ((in.readShort() & 0x0080) != 0)
+                            throw new ZipException("bug #99695860 [" + thiz.getName() + "]");
+
+                    return null;
                 }
+            }
+        );
+    }
+
+    private static void fixZipFile$getInputStream() {
+        final Field ZipFile$mRaf = scanField(ZipFile.class, "mRaf", "raf");
+        if (ZipFile$mRaf == null)
+            return;
+        ZipFile$mRaf.setAccessible(true);
+
+        final Field ZipEntry$mLocalHeaderRelOffset = scanField(ZipEntry.class, "mLocalHeaderRelOffset", "localHeaderRelOffset");
+        if (ZipEntry$mLocalHeaderRelOffset == null)
+            return;
+        ZipEntry$mLocalHeaderRelOffset.setAccessible(true);
+
+        final Method ZipFile$getInputStream = findMethod(ZipFile.class, "getInputStream", ZipEntry.class);
+        if (ZipFile$getInputStream == null)
+            return;
+
+        MS.hookMethod(ZipFile.class, ZipFile$getInputStream,
+            new MS.MethodAlteration<ZipFile, InputStream>() {
+                public InputStream invoked(ZipFile thiz, Object... args)
+                    throws Throwable
+                {
+                    ZipEntry entry = (ZipEntry) args[0];
 
-                if (entries == null)
-                    return;
-                final Field ZipFile$entries = entries;
-                ZipFile$entries.setAccessible(true);
+                    RandomAccessFile raf = (RandomAccessFile) ZipFile$mRaf.get(thiz);
+                    synchronized (raf) {
+                        raf.seek(ZipEntry$mLocalHeaderRelOffset.getLong(entry));
 
-                final Method ZipFile$readCentralDir; try {
-                    ZipFile$readCentralDir = ZipFile$.getDeclaredMethod("readCentralDir");
-                } catch (NoSuchMethodException e) {
-                    Log.e("Backport", "ZipFile$readCentralDir", e);
-                    return;
+                        raf.skipBytes(6);
+                        if ((raf.readShort() & 0x0080) != 0)
+                            throw new ZipException("bug #99695860 [" + thiz.getName() + "]");
+
+                        raf.skipBytes(20);
+                        if ((raf.readShort() & 0x0080) != 0)
+                            throw new ZipException("bug #99695860 [" + thiz.getName() + "]");
+                    }
+
+                    return invoke(thiz, args);
                 }
+            }
+        );
+    }
+
+    private static void fixZipFile$readCentralDir() {
+        final Field ZipFile$entries = scanField(ZipFile.class, "mEntries", "entries");
+        if (ZipFile$entries == null)
+            return;
+        ZipFile$entries.setAccessible(true);
 
-                MS.hookMethod(ZipFile$, ZipFile$readCentralDir,
-                    new MS.MethodAlteration<ZipFile, Void>() {
-                        public Void invoked(ZipFile thiz, Object... args)
-                            throws Throwable
-                        {
-                            ZipFile$entries.set(thiz, new LinkedHashMap<String, ZipEntry>() {
-                                public ZipEntry put(String key, ZipEntry value) {
-                                    if (super.put(key, value) != null)
-                                        throw new WrongException(new ZipException("Duplicate entry name: " + key));
-                                    return null;
-                                }
-                            });
-
-                            try {
-                                return invoke(thiz, args);
-                            } catch (WrongException wrong) {
-                                throw wrong.getCause();
-                            }
+        final Method ZipFile$readCentralDir = findMethod(ZipFile.class, "readCentralDir");
+        if (ZipFile$readCentralDir == null)
+            return;
+
+        MS.hookMethod(ZipFile.class, ZipFile$readCentralDir,
+            new MS.MethodAlteration<ZipFile, Void>() {
+                public Void invoked(ZipFile thiz, Object... args)
+                    throws Throwable
+                {
+                    ZipFile$entries.set(thiz, new LinkedHashMap<String, ZipEntry>() {
+                        public ZipEntry put(String key, ZipEntry value) {
+                            if (super.put(key, value) != null)
+                                throw new WrongException(new ZipException("bug #8219321 [" + key + "]"));
+                            return null;
                         }
+                    });
+
+                    try {
+                        return invoke(thiz, args);
+                    } catch (WrongException wrong) {
+                        throw wrong.getCause();
                     }
-                );
+                }
             }
-        });
+        );
+    }
+
+    public static void initialize() {
+        fixZipEntry$init$();
+        fixZipFile$getInputStream();
+        fixZipFile$readCentralDir();
     }
 }