1
1
package com .nmmedit .apkprotect .dex2c .filters ;
2
2
3
+ import com .google .common .collect .HashMultimap ;
4
+ import com .google .common .collect .Maps ;
5
+ import com .google .common .collect .Sets ;
3
6
import com .nmmedit .apkprotect .deobfus .MappingProcessor ;
4
7
import com .nmmedit .apkprotect .deobfus .MappingReader ;
5
8
import org .jf .dexlib2 .iface .ClassDef ;
6
9
import org .jf .dexlib2 .iface .Method ;
10
+ import org .jf .dexlib2 .iface .reference .MethodReference ;
11
+ import org .jf .dexlib2 .immutable .reference .ImmutableMethodReference ;
7
12
13
+ import javax .annotation .Nonnull ;
8
14
import java .io .IOException ;
9
- import java .util .HashMap ;
15
+ import java .util .ArrayList ;
16
+ import java .util .List ;
10
17
import java .util .Map ;
18
+ import java .util .Set ;
11
19
12
20
/**
13
21
* 读取proguard的mapping.txt文件,根据它得到class和方法名混淆前后映射关系,然后再执行过滤规则
14
22
*/
15
23
16
- public abstract class ProguardMappingConfig implements ClassAndMethodFilter , MappingProcessor {
24
+ public class ProguardMappingConfig implements ClassAndMethodFilter , MappingProcessor {
17
25
private final ClassAndMethodFilter filter ;
18
- private final Map <String , String > newTypeOldTypeMap = new HashMap <>();
19
-
20
- public ProguardMappingConfig (ClassAndMethodFilter filter , MappingReader mappingReader ) throws IOException {
26
+ private final Map <String , String > newTypeOldTypeMap = Maps .newHashMap ();
27
+ private final Map <String , String > oldTypeNewTypeMap = Maps .newHashMap ();
28
+ private final Set <MethodMapping > methodSet = Sets .newHashSet ();
29
+ private final HashMultimap <MethodReference , MethodReference > newMethodRefMap = HashMultimap .create ();
30
+ private final SimpleRule simpleRule ;
31
+
32
+ public ProguardMappingConfig (ClassAndMethodFilter filter ,
33
+ MappingReader mappingReader ,
34
+ SimpleRule simpleRule ) throws IOException {
21
35
this .filter = filter ;
36
+ this .simpleRule = simpleRule ;
22
37
mappingReader .parse (this );
38
+
39
+ for (MethodMapping methodMapping : methodSet ) {
40
+ final List <String > args = parseArgs (methodMapping .args );
41
+ final ImmutableMethodReference oldMethodRef = new ImmutableMethodReference (
42
+ javaType2jvm (methodMapping .className ),
43
+ methodMapping .methodName , args ,
44
+ javaType2jvm (methodMapping .returnType ));
45
+
46
+ final List <String > newArgs = getNewArgs (args );
47
+ String newRetType = oldTypeNewTypeMap .get (methodMapping .returnType );
48
+ if (newRetType == null ) {
49
+ newRetType = methodMapping .returnType ;
50
+ }
51
+ final ImmutableMethodReference newMethodRef = new ImmutableMethodReference (javaType2jvm (
52
+ methodMapping .newClassName ),
53
+ methodMapping .newMethodName , newArgs ,
54
+ javaType2jvm (newRetType ));
55
+ newMethodRefMap .put (newMethodRef , oldMethodRef );
56
+ }
23
57
}
24
58
59
+ private List <String > getNewArgs (List <String > args ) {
60
+ final ArrayList <String > newArgs = new ArrayList <>();
61
+ for (String arg : args ) {
62
+ final String newType = oldTypeNewTypeMap .get (arg );
63
+ newArgs .add (newType == null ? arg : newType );
64
+ }
65
+ return newArgs ;
66
+ }
67
+
68
+
25
69
@ Override
26
70
public final boolean acceptClass (ClassDef classDef ) {
27
71
//先处理上游的过滤规则,如果上游不通过则直接返回不再处理,如果上游通过再处理当前的过滤规则
28
72
if (filter != null && !filter .acceptClass (classDef )) {
29
73
return false ;
30
74
}
31
75
//得到混淆之前的className
32
- final String oldName = getOriginClassName (classDef .getType ());
33
- if (oldName == null ) {
76
+ final String oldType = getOriginClassType (classDef .getType ());
77
+ if (oldType == null ) {
34
78
return false ;
35
79
}
36
- //需要保留的class返回false,
37
- return !keepClass (classDef );
80
+ final ArrayList <String > ifacs = new ArrayList <>();
81
+ for (String ifac : classDef .getInterfaces ()) {
82
+ ifacs .add (getOriginClassType (ifac ));
83
+ }
84
+
85
+ return simpleRule != null && simpleRule .matchClass (
86
+ oldType ,
87
+ getOriginClassType (classDef .getSuperclass ()),
88
+ ifacs );
38
89
}
39
90
40
- protected abstract boolean keepClass (ClassDef classDef );
41
91
42
- protected String getOriginClassName (String type ) {
43
- return newTypeOldTypeMap .get (type );
92
+ private String getOriginClassType (String type ) {
93
+ final String oldType = newTypeOldTypeMap .get (type );
94
+ if (oldType == null ) {
95
+ return type ;
96
+ }
97
+ return oldType ;
44
98
}
45
99
46
100
@ Override
47
101
public final boolean acceptMethod (Method method ) {
48
102
if (filter != null && !filter .acceptMethod (method )) {
49
103
return false ;
50
104
}
51
- return !keepMethod (method );
52
- }
105
+ final String oldType = getOriginClassType (method .getDefiningClass ());
106
+ if (oldType == null ) {
107
+ return false ;
108
+ }
109
+ final Set <MethodReference > oldMethodRefSet = newMethodRefMap .get (method );
110
+
53
111
54
- protected abstract boolean keepMethod (Method method );
112
+ if (oldMethodRefSet != null ) {
113
+
114
+ for (MethodReference reference : oldMethodRefSet ) {
115
+ if (oldType .equals (reference .getDefiningClass ())) {
116
+ if (simpleRule != null && simpleRule .matchMethod (reference .getName ())) {
117
+ return true ;
118
+ }
119
+ }
120
+ }
121
+
122
+ }
123
+
124
+ return simpleRule != null && simpleRule .matchMethod (method .getName ());
125
+ }
55
126
56
127
private static String classNameToType (String className ) {
57
128
return "L" + className .replace ('.' , '/' ) + ";" ;
58
129
}
59
130
60
131
@ Override
61
132
public final void processClassMapping (String className , String newClassName ) {
62
- newTypeOldTypeMap .put (classNameToType (newClassName ), className );
133
+ newTypeOldTypeMap .put (classNameToType (newClassName ), classNameToType (className ));
134
+ oldTypeNewTypeMap .put (classNameToType (className ), classNameToType (newClassName ));
63
135
}
64
136
65
137
@ Override
66
138
public final void processFieldMapping (String className , String fieldType , String fieldName , String newClassName , String newFieldName ) {
67
139
68
140
}
69
141
142
+ @ Nonnull
143
+ private static String javaType2jvm (@ Nonnull String type ) {
144
+ switch (type .trim ()) {
145
+ case "boolean" :
146
+ return "Z" ;
147
+ case "byte" :
148
+ return "B" ;
149
+ case "char" :
150
+ return "C" ;
151
+ case "short" :
152
+ return "S" ;
153
+ case "int" :
154
+ return "I" ;
155
+ case "float" :
156
+ return "F" ;
157
+ case "long" :
158
+ return "J" ;
159
+ case "double" :
160
+ return "D" ;
161
+ case "void" :
162
+ return "V" ;
163
+ default :
164
+ int i = type .indexOf ('[' );
165
+ if (i != -1 ) {
166
+ String t = type .substring (0 , i );
167
+ StringBuilder arr = new StringBuilder ("[" );
168
+ while ((i = type .indexOf ('[' , i + 1 )) != -1 ) {
169
+ arr .append ('[' );
170
+ }
171
+ arr .append (javaType2jvm (t ));
172
+ return arr .toString ();
173
+ } else {
174
+ return classNameToType (type );
175
+ }
176
+
177
+ }
178
+ }
179
+
180
+ @ Nonnull
181
+ private List <String > parseArgs (String methodArgs ) {
182
+ final ArrayList <String > args = new ArrayList <>();
183
+ if ("" .equals (methodArgs )) {
184
+ return args ;
185
+ }
186
+ final String [] split = methodArgs .split ("," );
187
+ for (String type : split ) {
188
+ args .add (javaType2jvm (type ));
189
+ }
190
+ return args ;
191
+ }
192
+
70
193
@ Override
71
- public final void processMethodMapping (String className , int firstLineNumber , int lastLineNumber , String methodReturnType , String methodName , String methodArguments , String newClassName , int newFirstLineNumber , int newLastLineNumber , String newMethodName ) {
194
+ public final void processMethodMapping (String className ,
195
+ int firstLineNumber , int lastLineNumber ,
196
+ String methodReturnType ,
197
+ String methodName ,
198
+ String methodArguments ,
199
+ String newClassName ,
200
+ int newFirstLineNumber , int newLastLineNumber ,
201
+ String newMethodName ) {
202
+ final MethodMapping mapping = new MethodMapping (className , methodName , newClassName , newMethodName , methodArguments , methodReturnType );
203
+ methodSet .add (mapping );
204
+ }
205
+
206
+ private static class MethodMapping {
207
+ private final String className ;
208
+ private final String methodName ;
209
+
210
+ private final String newClassName ;
211
+ private final String newMethodName ;
212
+ private final String args ;
213
+ private final String returnType ;
214
+
215
+ public MethodMapping (String className , String methodName ,
216
+ String newClassName , String newMethodName ,
217
+ String args , String returnType ) {
218
+ this .className = className ;
219
+ this .methodName = methodName ;
220
+ this .newClassName = newClassName ;
221
+ this .newMethodName = newMethodName ;
222
+ this .args = args ;
223
+ this .returnType = returnType ;
224
+ }
225
+
226
+ @ Override
227
+ public boolean equals (Object o ) {
228
+ if (this == o ) return true ;
229
+ if (o == null || getClass () != o .getClass ()) return false ;
72
230
231
+ MethodMapping that = (MethodMapping ) o ;
232
+
233
+ if (!className .equals (that .className )) return false ;
234
+ if (!methodName .equals (that .methodName )) return false ;
235
+ if (!newClassName .equals (that .newClassName )) return false ;
236
+ if (!newMethodName .equals (that .newMethodName )) return false ;
237
+ if (!args .equals (that .args )) return false ;
238
+ return returnType .equals (that .returnType );
239
+ }
240
+
241
+ @ Override
242
+ public int hashCode () {
243
+ int result = className .hashCode ();
244
+ result = 31 * result + methodName .hashCode ();
245
+ result = 31 * result + newClassName .hashCode ();
246
+ result = 31 * result + newMethodName .hashCode ();
247
+ result = 31 * result + args .hashCode ();
248
+ result = 31 * result + returnType .hashCode ();
249
+ return result ;
250
+ }
73
251
}
74
252
}
0 commit comments