-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPatchData.java
More file actions
228 lines (204 loc) · 12.3 KB
/
PatchData.java
File metadata and controls
228 lines (204 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
package com.kdeveloper.utils;
import com.kdeveloper.translation.KDevAPI;
import com.kdgdev.nxt.utils.FSUtils;
import com.kdgdev.nxt.utils.FileUtils;
import com.kdgdev.nxt.utils.IOUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by kirill on 29.08.14.
*/
public class PatchData {
private LinkedHashMap<String, String> replaceAllFiles = new LinkedHashMap<>();
private LinkedHashMap<String, String> copyFile = new LinkedHashMap<>();
private LinkedHashMap<String, LinkedHashMap<String, String>> replaceinfile = new LinkedHashMap<>();
private LinkedHashMap<String, LinkedHashMap<String, MethodData>> replacemethod = new LinkedHashMap<>();
private LinkedHashMap<String, LinkedList<ReplaceData>> replacestrings = new LinkedHashMap<>();
public String appfile = null;
public String apppackage = null;
public String mapping = null;
public PatchData(File in) throws IOException {
List<String> fileLines = IOUtils.readLines(new FileInputStream(in), Charset.forName("UTF-8"));
Pattern appfile_p = Pattern.compile("^\\s{0,}appfile\\s+\\<(.*)\\>\\s{0,}\\;");
Pattern apppackage_p = Pattern.compile("^\\s{0,}apppackage\\s+\\<(.*)\\>\\s{0,}\\;");
Pattern replaceall_p = Pattern.compile("^\\s{0,}replaceinall\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s{0,}\\;");
Pattern replacefile_p = Pattern.compile("^\\s{0,}replaceinfile\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s{0,}\\;");
Pattern copyfile_p = Pattern.compile("^\\s{0,}copyfile\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s{0,}\\;");
Pattern mapping_p = Pattern.compile("^\\s{0,}mapping\\s+\\\"(.*)\\\"\\s{0,}\\;");
Pattern replacemethod_p = Pattern.compile("^\\s{0,}methodreplace\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s{0,}\\;");
Pattern replacestrings_p = Pattern.compile("^\\s{0,}methodstrings\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s+\\\"(.*)\\\"\\s+\\\"(.*?)\\\"\\s+\\\"(.*?)\\\"\\s{0,}\\;");
for (String line : fileLines) {
Matcher appfile_m = appfile_p.matcher(line);
if (appfile_m.matches()) {
appfile = appfile_m.group(1);
continue;
}
Matcher apppackage_m = apppackage_p.matcher(line);
if (apppackage_m.matches()) {
apppackage = apppackage_m.group(1);
continue;
}
Matcher replaceall_m = replaceall_p.matcher(line);
if (replaceall_m.matches()) {
replaceAllFiles.put(replaceall_m.group(1), replaceall_m.group(2));
continue;
}
Matcher copyfile_m = copyfile_p.matcher(line);
if (copyfile_m.matches()) {
copyFile.put(FileUtils.fixSeparator(copyfile_m.group(1)), FileUtils.fixSeparator(copyfile_m.group(2)));
continue;
}
Matcher replacefile_m = replacefile_p.matcher(line);
if (replacefile_m.matches()) {
if (replaceinfile.containsKey(replacefile_m.group(1))) {
replaceinfile.get(replacefile_m.group(1)).put(replacefile_m.group(2), replacefile_m.group(3));
} else {
LinkedHashMap<String, String> replacer = new LinkedHashMap<>();
replacer.put(replacefile_m.group(2), replacefile_m.group(3));
replaceinfile.put(replacefile_m.group(1), replacer);
}
}
Matcher mapping_m = mapping_p.matcher(line);
if (mapping_m.matches()) {
mapping = mapping_m.group(1);
}
Matcher replacemethod_m = replacemethod_p.matcher(line);
if (replacemethod_m.matches()) {
MethodData methodData = new MethodData(replacemethod_m.group(3), replacemethod_m.group(4), replacemethod_m.group(5), replacemethod_m.group(6));
if (replacemethod.containsKey(replacemethod_m.group(1))) {
replacemethod.get(replacemethod_m.group(1)).put(replacemethod_m.group(2), methodData);
} else {
LinkedHashMap<String, MethodData> replacer = new LinkedHashMap<>();
replacer.put(replacemethod_m.group(2), methodData);
replacemethod.put(replacemethod_m.group(1), replacer);
}
}
Matcher replacestrings_m = replacestrings_p.matcher(line);
if (replacestrings_m.matches()) {
ReplaceData replacerData = new ReplaceData(replacestrings_m.group(3), replacestrings_m.group(4), replacestrings_m.group(2), replacestrings_m.group(5), replacestrings_m.group(6));
if(replacestrings.containsKey(replacestrings_m.group(1))) {
replacestrings.get(replacestrings_m.group(1)).add(replacerData);
} else {
LinkedList<ReplaceData> list = new LinkedList<>();
list.add(replacerData);
replacestrings.put(replacestrings_m.group(1), list);
}
}
}
}
@Override
public String toString() {
System.out.println(appfile);
System.out.println(apppackage);
System.out.println(mapping);
System.out.println(copyFile);
System.out.println(replaceAllFiles);
System.out.println(replaceinfile);
return super.toString();
}
private static final char[] hexChar = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
private static String unicodeEscape(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if ((c >> 7) > 0) {
sb.append("\\u");
sb.append(hexChar[(c >> 12) & 0xF]); // append the hex character for the left-most 4-bits
sb.append(hexChar[(c >> 8) & 0xF]); // hex for the second group of 4-bits from the left
sb.append(hexChar[(c >> 4) & 0xF]); // hex for the third group
sb.append(hexChar[c & 0xF]); // hex for the last group, e.g., the right most 4-bits
} else {
sb.append(c);
}
}
return sb.toString();
}
public void patch(File here, File smali, File apk) throws IOException {
if (appfile == null && apppackage == null) throw new RuntimeException("Where I can patch it?!");
for (String fileFrom : copyFile.keySet()) {
String fileTo = copyFile.get(fileFrom);
Path pFileFrom = Paths.get(fileFrom.replace("%here%", here.getCanonicalPath()).replace("%smali%", smali.getCanonicalPath()));
Path pFileTo = Paths.get(fileTo.replace("%here%", here.getCanonicalPath()).replace("%smali%", smali.getCanonicalPath()));
LOGGER.info("Copying file: " + pFileFrom + " to " + pFileTo);
Files.copy(pFileFrom, pFileTo, StandardCopyOption.REPLACE_EXISTING);
}
List<File> files = FSUtils.walk(smali.getCanonicalPath(), ".smali");
for (File f : files) {
for (String key : replaceAllFiles.keySet()) {
String replaceable_origin = new String(IOUtils.readFile(f), "UTF-8");
String replaceable = new String(IOUtils.readFile(f), "UTF-8");
replaceable = replaceable.replace(StringEscapeUtils.unescapeJson(key), unicodeEscape(StringEscapeUtils.unescapeJson(replaceAllFiles.get(key))));
if (!replaceable_origin.equals(replaceable)) {
LOGGER.info("Replacing " + StringEscapeUtils.unescapeJson(key) + " to " + unicodeEscape(StringEscapeUtils.unescapeJson(replaceAllFiles.get(key))) + " in " + f.getName());
IOUtils.writeFile(replaceable.getBytes("UTF-8"), f);
}
}
}
for (String key : replaceinfile.keySet()) {
File patchable = new File(FileUtils.fixSeparator(key.replace("%here%", here.getCanonicalPath()).replace("%smali%", smali.getCanonicalPath())));
if (!patchable.exists()) continue;
LinkedHashMap<String, String> stringStringHashMap = replaceinfile.get(key);
for (String key_r : stringStringHashMap.keySet()) {
String replaceable_origin = new String(IOUtils.readFile(patchable), "UTF-8");
String replaceable = new String(IOUtils.readFile(patchable), "UTF-8");
replaceable = replaceable.replace(StringEscapeUtils.unescapeJson(key_r), unicodeEscape(StringEscapeUtils.unescapeJson(stringStringHashMap.get(key_r))));
if (!replaceable_origin.equals(replaceable)) {
LOGGER.info("Replacing " + StringEscapeUtils.unescapeJson(key_r) + " to " + unicodeEscape(StringEscapeUtils.unescapeJson(stringStringHashMap.get(key_r))) + " in " + patchable.getName());
IOUtils.writeFile(replaceable.getBytes("UTF-8"), patchable);
}
}
}
for (String key : replacemethod.keySet()) {
File patchable = new File(FileUtils.fixSeparator(key.replace("%here%", here.getCanonicalPath()).replace("%smali%", smali.getCanonicalPath())));
if (!patchable.exists()) continue;
LinkedHashMap<String, MethodData> stringStringHashMap = replacemethod.get(key);
for (String key_r : stringStringHashMap.keySet()) {
File methodFile = new File(FileUtils.fixSeparator(key_r.replace("%here%", here.getCanonicalPath()).replace("%smali%", smali.getCanonicalPath())));
String replaceable_origin = new String(IOUtils.readFile(patchable), "UTF-8");
String replaceable = new String(IOUtils.readFile(patchable), "UTF-8");
String method = new String(IOUtils.readFile(methodFile), "UTF-8");
MethodData md = stringStringHashMap.get(key_r);
String pat = Pattern.quote(".method " + md.getAccess() + " " + md.getName() + "(" + (md.getParameters().equals("<none>") ? "" : md.getParameters()) + ")" + md.getReturn());
Pattern ptn = Pattern.compile(pat + "([\\s\\S]*?)\\.end method");
Matcher m = ptn.matcher(replaceable);
replaceable = m.replaceAll(unicodeEscape(Matcher.quoteReplacement(method)));
if (!replaceable_origin.equals(replaceable)) {
LOGGER.info("Replacing " + md.getName() + "(" + md.getParameters() + ") in " + patchable.getName());
IOUtils.writeFile(replaceable.getBytes("UTF-8"), patchable);
}
}
}
for (String key : replacestrings.keySet()) {
File patchable = new File(FileUtils.fixSeparator(key.replace("%here%", here.getCanonicalPath()).replace("%smali%", smali.getCanonicalPath())));
if (!patchable.exists()) continue;
String replaceable_origin = new String(IOUtils.readFile(patchable), "UTF-8");
String replaceable = new String(IOUtils.readFile(patchable), "UTF-8");
KDevAPI kapi = new KDevAPI();
for(ReplaceData replacer : replacestrings.get(key)) {
String originalResourceId = kapi.getResouceId(apk, replacer.getType(), replacer.getName());
String newResourceId = kapi.getResouceId(apk, replacer.getType(), replacer.getReplacename());
replaceable = replaceable.replace(originalResourceId + replacer.getAdditional1(), newResourceId + replacer.getAdditional2());
if (!replaceable_origin.equals(replaceable)) {
LOGGER.info("Replacing " + originalResourceId + replacer.getAdditional1() + " to " + newResourceId + replacer.getAdditional2() + " in " + patchable.getName());
IOUtils.writeFile(replaceable.getBytes("UTF-8"), patchable);
}
}
}
}
private final static Logger LOGGER = Logger.getLogger(PatchData.class.getName());
}