]> git.saurik.com Git - backport.git/blame - src/com/saurik/backport/Hook.java
Add support for protecting against bug #10227498.
[backport.git] / src / com / saurik / backport / Hook.java
CommitLineData
6e682be6
JF
1/* Backport - Bring New Fixes to old Androids
2 * Copyright (C) 2013 Jay Freeman (saurik)
3*/
4
5/* GNU Lesser General Public License, Version 3 {{{ */
6/*
7 * Substrate is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * Substrate is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Substrate. If not, see <http://www.gnu.org/licenses/>.
19**/
20/* }}} */
21
22package com.saurik.backport;
23
2202c245 24import java.lang.reflect.Constructor;
6e682be6
JF
25import java.lang.reflect.Field;
26import java.lang.reflect.Method;
27
2202c245
JF
28import java.io.ByteArrayInputStream;
29import java.io.DataInputStream;
30import java.io.InputStream;
31import java.io.RandomAccessFile;
6e682be6 32
2202c245 33import java.util.LinkedHashMap;
6e682be6
JF
34
35import java.util.zip.ZipEntry;
36import java.util.zip.ZipException;
37import java.util.zip.ZipFile;
38
39import android.util.Log;
40
41import com.saurik.substrate.MS;
42
43public class Hook {
79cf0362
JF
44 private static class WrongException
45 extends RuntimeException
46 {
47 public WrongException(Throwable cause) {
48 super(cause);
49 }
50 }
51
2202c245
JF
52 private static Field scanField(Class clazz, String... names) {
53 for (String name : names) try {
54 return clazz.getDeclaredField(name);
55 } catch (NoSuchFieldException e) {}
56 return null;
57 }
58
59 private static Method findMethod(Class<?> clazz, String name, Class... args) {
60 try {
61 return clazz.getDeclaredMethod(name, args);
62 } catch (NoSuchMethodException e) {
63 return null;
64 }
65 }
66
67 private static Constructor findConstructor(Class<?> clazz, Class... args) {
68 try {
69 return clazz.getDeclaredConstructor(args);
70 } catch (NoSuchMethodException e) {
71 return null;
72 }
73 }
74
75 private static void fixZipEntry$init$() {
76 final Constructor ZipEntry$init$ = findConstructor(ZipEntry.class, byte[].class, InputStream.class);
77 if (ZipEntry$init$ == null)
78 return;
79
80 MS.hookMethod(ZipEntry.class, ZipEntry$init$,
81 new MS.MethodAlteration<ZipEntry, Void>() {
82 public Void invoked(ZipEntry thiz, Object... args)
83 throws Throwable
84 {
85 byte[] header = (byte[]) args[0];
86
87 invoke(thiz, args);
88
04b93b54
JF
89 if (thiz.getName().indexOf(0) != -1)
90 throw new ZipException("bug #10148349 [" + thiz.getName() + "]");
91
2202c245
JF
92 DataInputStream in = new DataInputStream(new ByteArrayInputStream(header));
93
94 in.skip(8);
95 for (int i = 0; i != 2; ++i)
96 if ((in.readShort() & 0x0080) != 0)
68e68412 97 throw new ZipException("bug #9695860 [" + thiz.getName() + "]");
2202c245
JF
98
99 in.skip(16);
100 for (int i = 0; i != 3; ++i)
101 if ((in.readShort() & 0x0080) != 0)
68e68412 102 throw new ZipException("bug #9695860 [" + thiz.getName() + "]");
2202c245
JF
103
104 return null;
6e682be6 105 }
2202c245
JF
106 }
107 );
108 }
109
110 private static void fixZipFile$getInputStream() {
eee29e9e
JF
111 final Field ZipEntry$compressedSize = scanField(ZipEntry.class, "compressedSize");
112 if (ZipEntry$compressedSize == null)
113 return;
114 ZipEntry$compressedSize.setAccessible(true);
115
116 final Field ZipEntry$compressionMethod = scanField(ZipEntry.class, "compressionMethod");
117 if (ZipEntry$compressionMethod == null)
118 return;
119 ZipEntry$compressionMethod.setAccessible(true);
120
121 final Field ZipEntry$size = scanField(ZipEntry.class, "size");
122 if (ZipEntry$size == null)
123 return;
124 ZipEntry$size.setAccessible(true);
125
d6bb9203
JF
126 final Field ZipEntry$nameLen = scanField(ZipEntry.class, "nameLen", "nameLength");
127 if (ZipEntry$nameLen == null)
128 return;
129 ZipEntry$nameLen.setAccessible(true);
130
2202c245
JF
131 final Field ZipFile$mRaf = scanField(ZipFile.class, "mRaf", "raf");
132 if (ZipFile$mRaf == null)
133 return;
134 ZipFile$mRaf.setAccessible(true);
135
136 final Field ZipEntry$mLocalHeaderRelOffset = scanField(ZipEntry.class, "mLocalHeaderRelOffset", "localHeaderRelOffset");
137 if (ZipEntry$mLocalHeaderRelOffset == null)
138 return;
139 ZipEntry$mLocalHeaderRelOffset.setAccessible(true);
140
141 final Method ZipFile$getInputStream = findMethod(ZipFile.class, "getInputStream", ZipEntry.class);
142 if (ZipFile$getInputStream == null)
143 return;
144
145 MS.hookMethod(ZipFile.class, ZipFile$getInputStream,
146 new MS.MethodAlteration<ZipFile, InputStream>() {
147 public InputStream invoked(ZipFile thiz, Object... args)
148 throws Throwable
149 {
150 ZipEntry entry = (ZipEntry) args[0];
6e682be6 151
2202c245
JF
152 RandomAccessFile raf = (RandomAccessFile) ZipFile$mRaf.get(thiz);
153 synchronized (raf) {
154 raf.seek(ZipEntry$mLocalHeaderRelOffset.getLong(entry));
6e682be6 155
2202c245
JF
156 raf.skipBytes(6);
157 if ((raf.readShort() & 0x0080) != 0)
68e68412 158 throw new ZipException("bug #9695860 [" + thiz.getName() + "]");
2202c245 159
d6bb9203
JF
160 raf.skipBytes(18);
161
48bc4607 162 int length = Short.reverseBytes(raf.readShort()) & 0xffff;
d6bb9203 163 if (length != ZipEntry$nameLen.getInt(entry))
4d4eb512 164 throw new ZipException("bug #9950697 [" + thiz.getName() + "]");
d6bb9203 165
2202c245 166 if ((raf.readShort() & 0x0080) != 0)
68e68412 167 throw new ZipException("bug #9695860 [" + thiz.getName() + "]");
2202c245
JF
168 }
169
eee29e9e
JF
170 if (ZipEntry$compressionMethod.getInt(entry) == ZipEntry.STORED)
171 if (ZipEntry$compressedSize.getLong(entry) != ZipEntry$size.getLong(entry))
172 throw new ZipException("bug #10227498 [" + thiz.getName() + "]");
173
2202c245 174 return invoke(thiz, args);
6e682be6 175 }
2202c245
JF
176 }
177 );
178 }
179
180 private static void fixZipFile$readCentralDir() {
181 final Field ZipFile$entries = scanField(ZipFile.class, "mEntries", "entries");
182 if (ZipFile$entries == null)
183 return;
184 ZipFile$entries.setAccessible(true);
6e682be6 185
2202c245
JF
186 final Method ZipFile$readCentralDir = findMethod(ZipFile.class, "readCentralDir");
187 if (ZipFile$readCentralDir == null)
188 return;
189
190 MS.hookMethod(ZipFile.class, ZipFile$readCentralDir,
191 new MS.MethodAlteration<ZipFile, Void>() {
192 public Void invoked(ZipFile thiz, Object... args)
193 throws Throwable
194 {
195 ZipFile$entries.set(thiz, new LinkedHashMap<String, ZipEntry>() {
196 public ZipEntry put(String key, ZipEntry value) {
197 if (super.put(key, value) != null)
198 throw new WrongException(new ZipException("bug #8219321 [" + key + "]"));
199 return null;
6e682be6 200 }
2202c245
JF
201 });
202
203 try {
204 return invoke(thiz, args);
205 } catch (WrongException wrong) {
206 throw wrong.getCause();
6e682be6 207 }
2202c245 208 }
6e682be6 209 }
2202c245
JF
210 );
211 }
212
213 public static void initialize() {
214 fixZipEntry$init$();
215 fixZipFile$getInputStream();
216 fixZipFile$readCentralDir();
6e682be6
JF
217 }
218}