11package com .nmmedit .apkprotect .dex2c .filters ;
22
3+ import com .google .common .collect .HashMultimap ;
4+ import com .google .common .collect .Maps ;
5+ import com .google .common .collect .Sets ;
36import com .nmmedit .apkprotect .deobfus .MappingProcessor ;
47import com .nmmedit .apkprotect .deobfus .MappingReader ;
58import org .jf .dexlib2 .iface .ClassDef ;
69import org .jf .dexlib2 .iface .Method ;
10+ import org .jf .dexlib2 .iface .reference .MethodReference ;
11+ import org .jf .dexlib2 .immutable .reference .ImmutableMethodReference ;
712
13+ import javax .annotation .Nonnull ;
814import java .io .IOException ;
9- import java .util .HashMap ;
15+ import java .util .ArrayList ;
16+ import java .util .List ;
1017import java .util .Map ;
18+ import java .util .Set ;
1119
1220/**
1321 * 读取proguard的mapping.txt文件,根据它得到class和方法名混淆前后映射关系,然后再执行过滤规则
1422 */
1523
16- public abstract class ProguardMappingConfig implements ClassAndMethodFilter , MappingProcessor {
24+ public class ProguardMappingConfig implements ClassAndMethodFilter , MappingProcessor {
1725 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 {
2135 this .filter = filter ;
36+ this .simpleRule = simpleRule ;
2237 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+ }
2357 }
2458
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+
2569 @ Override
2670 public final boolean acceptClass (ClassDef classDef ) {
2771 //先处理上游的过滤规则,如果上游不通过则直接返回不再处理,如果上游通过再处理当前的过滤规则
2872 if (filter != null && !filter .acceptClass (classDef )) {
2973 return false ;
3074 }
3175 //得到混淆之前的className
32- final String oldName = getOriginClassName (classDef .getType ());
33- if (oldName == null ) {
76+ final String oldType = getOriginClassType (classDef .getType ());
77+ if (oldType == null ) {
3478 return false ;
3579 }
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 );
3889 }
3990
40- protected abstract boolean keepClass (ClassDef classDef );
4191
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 ;
4498 }
4599
46100 @ Override
47101 public final boolean acceptMethod (Method method ) {
48102 if (filter != null && !filter .acceptMethod (method )) {
49103 return false ;
50104 }
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+
53111
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+ }
55126
56127 private static String classNameToType (String className ) {
57128 return "L" + className .replace ('.' , '/' ) + ";" ;
58129 }
59130
60131 @ Override
61132 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 ));
63135 }
64136
65137 @ Override
66138 public final void processFieldMapping (String className , String fieldType , String fieldName , String newClassName , String newFieldName ) {
67139
68140 }
69141
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+
70193 @ 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 ;
72230
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+ }
73251 }
74252}
0 commit comments