├── .classpath ├── .gitignore ├── .project ├── .settings └── org.eclipse.jdt.core.prefs ├── README.md └── src ├── Main.java ├── Smali ├── SmaliClass.java ├── SmaliField.java ├── SmaliMethod.java ├── SmaliModifier.java └── SmaliObject.java └── Utils.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ObfuseRestore 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.8 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.8 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 字符串解密 2 | 3 | 适用加密方法单String参数,返回类型为String。 4 | 5 | 有的字符串不能处理是因为编码坑爹。。 6 | 7 | ubuntu下测试正常,其余未测。 8 | 9 | **注:使用baksmali d 和smali a,不要使用dex2jar里的smali和baksmali。** 10 | 11 | use: 12 | 13 | java -jar restore.jar \ \ \ 14 | 15 | 例: 16 | java -jar restore.jar classes-dex2jar.jar out Lcom/inca/security/coM6;->goto 17 | -------------------------------------------------------------------------------- /src/Main.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.lang.reflect.InvocationTargetException; 3 | import java.lang.reflect.Method; 4 | import java.net.MalformedURLException; 5 | import java.net.URL; 6 | import java.net.URLClassLoader; 7 | import java.util.ArrayList; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | import Smali.SmaliClass; 12 | import Smali.SmaliMethod; 13 | import Smali.SmaliModifier.ModifierAttribute; 14 | import Smali.SmaliModifier.ModifierPremission; 15 | public class Main { 16 | public static String jar; 17 | public static String smaliDir; 18 | public static String enMtdSig; 19 | 20 | public static URLClassLoader clsLoader; 21 | public static Class deCls; 22 | public static Method deMtd; 23 | public static int num; 24 | 25 | public static void main(String args[]) throws Exception{ 26 | jar = args[0]; 27 | smaliDir = args[1]; 28 | enMtdSig = args[2]; 29 | 30 | Pattern sigPtn = Pattern.compile("L([a-zA-Z0-9/$_]{1,128});->([a-zA-Z0-9/$_]{1,128})"); 31 | Matcher mtc = sigPtn.matcher(enMtdSig); 32 | if(!mtc.find()){ 33 | System.out.println("not matche methodSig"); 34 | return; 35 | } 36 | String className = mtc.group(1).replace("/", "."); 37 | String mtdName = mtc.group(2); 38 | URLClassLoader clsLoader = new URLClassLoader(new URL[]{new File(jar).toURI().toURL()}); 39 | Class deCls = clsLoader.loadClass(className); 40 | deMtd = deCls.getMethod(mtdName, String.class); 41 | ArrayList files = Utils.GetInDirFiles(new File(smaliDir)); 42 | for(File file : files){ 43 | SmaliClass cls = SmaliClass.PraseClass(file); 44 | restore(cls); 45 | } 46 | System.out.println("restored, restore num is " + num); 47 | // if(args[0].equals("-p")){ 48 | // if(args.length>= 4 && args[2].equals("--f")){ 49 | // SafeProject(new File(args[1]),args[3]); 50 | // } 51 | // else{ 52 | // SafeProject(new File(args[1]),null); 53 | // } 54 | // } 55 | // 56 | 57 | } 58 | 59 | 60 | public static void restore(SmaliClass cls) throws Exception{ 61 | ArrayList codes = cls.getCodes(); 62 | 63 | 64 | 65 | Pattern invokePtn = Pattern.compile("invoke-static \\{([vp\\d]{0,4})\\}, "+enMtdSig); 66 | for(int i = 0;i " + deText); 100 | num++; 101 | } 102 | } 103 | cls.saveChange(); 104 | } 105 | 106 | 107 | // public static void restore(File dex,String methidSig){ 108 | // File maniFile = new File(projectDir.toString() + "\\AndroidManifest.xml"); 109 | // if(!maniFile.exists()){ 110 | // System.out.println("[*SafeProjectError]AndroidManifest.xml is not found"); 111 | // return; 112 | // } 113 | // String mainClassName = Utils.FindMainClass(maniFile); 114 | // if(mainClassName == null){ 115 | // System.out.println("[*SafeProjectError]Launcher Class is not found"); 116 | // return; 117 | // } 118 | // ArrayList files = Utils.GetInDirFiles(new File(projectDir.toString() +"\\smali\\")); 119 | // if(files == null){ 120 | // System.out.println("[*SafeProjectError]Files is null"); 121 | // return; 122 | // } 123 | // for(File file : files){ 124 | // SmaliClass cls = SmaliUtils.PraseClass(file); 125 | // if(cls == null || cls.isAbstract() || cls.isInterface() || cls.toString().indexOf("$") != -1){ 126 | // continue; 127 | // } 128 | // if(cls.toString().startsWith("Landroid")){ 129 | // continue; 130 | // } 131 | // String className = cls.toString(); 132 | // className = className.startsWith("L") ? className.substring(1,className.length()-1) : className; 133 | // className = className.endsWith(";") ? className.substring(0,className.length()-1) : className; 134 | // className = className.replace("/","."); 135 | // if(filter != null){ 136 | // if(className.indexOf(filter) == -1){ 137 | // if(mainClassName.equals(className)){ 138 | // SmaliClass.ClassTable.add(cls); 139 | // AddClinit(cls); 140 | // cls.saveChange(); 141 | // } 142 | // continue; 143 | // } 144 | // } 145 | // SmaliClass.ClassTable.add(cls); 146 | // System.out.println("[I:ChangeSmali]: " + cls.toString()); 147 | // ChangeSmali(cls); 148 | // if(mainClassName.equals(className)){ 149 | // AddClinit(cls); 150 | // } 151 | // cls.saveChange(); 152 | // } 153 | // NativeHelper helper = NativeHelper.getInstance(); 154 | // helper.setOnLoadCode(helper.createOnLoadCode()); 155 | // helper.writeSource(); 156 | // } 157 | // 158 | // public static void ChangeSmali(SmaliClass cls){ 159 | // String methodArrayName = Utils.GetRandomMethodName(0); //������� 160 | // NativeHelper helper = NativeHelper.getInstance(); 161 | // NativeArray array = new NativeArray(cls.toString(),methodArrayName); 162 | // ArrayList smaliMethods = cls.getMethods(); 163 | // ArrayList addMethod = new ArrayList(); 164 | // for(int i = 0 ;i < smaliMethods.size() ; i++){ 165 | // SmaliMethod method = smaliMethods.get(i); 166 | // String srcName = method.getMethodName(); 167 | // if(method.isNative() || method.isSynthetic() || method.isFinal()){ 168 | // continue; 169 | // } 170 | // //�����������;�̬����� 171 | // if(!"".equals(srcName) && !"".equals(srcName) ){ 172 | // String reName = Utils.GetRandomMethodName(1); //������� 173 | // method.rename(reName); 174 | // NativeMethod nativeMethod = NativeMethod.smaliMethod2NativeMethod(method,Utils.GetRandomMethodName(2)); //nativeName������� 175 | // helper.addMethod(nativeMethod); 176 | // array.add(new JNINativeMethod(srcName,method.getMethodSig().toString(),NativeHelper.SmaliType2NativeType(method.getReturnTypeName()),nativeMethod.getMethodName())); 177 | // ArrayList attributes = method.getAttributes(); 178 | // attributes.add(ModifierAttribute.ATTRIBUTE_NATIVE); 179 | // addMethod.add(new SmaliMethod(method.getPremission(),attributes,method.getArgs(),method.getReturnTypeName(),method.getSuperClassName(),srcName,-1)); 180 | // } 181 | // } 182 | // for(SmaliMethod method : addMethod){ 183 | // cls.addMethod(method, ""); 184 | // } 185 | // helper.addJNIMethod(array); 186 | // } 187 | // 188 | // public static void AddClinit(SmaliClass cls){ 189 | // ArrayList attr = new ArrayList(); 190 | // attr.add(ModifierAttribute.ATTRIBUTE_STATIC); 191 | // attr.add(ModifierAttribute.ATTRIBUTE_CONSTRUCTOR); 192 | // SmaliMethod clinit = new SmaliMethod(ModifierPremission.PREMISSION_DEFAULT,attr,new ArrayList(),"V",cls.toString(),"",-1); 193 | // StringBuilder codes = new StringBuilder(); 194 | // if(cls.findMethod(clinit) == null){ 195 | // codes.append(" .locals 1\r\n"); 196 | // codes.append(" const-string v0,\"smalisafe\"\r\n"); 197 | // codes.append(" invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V\r\n"); 198 | // codes.append(" return-void\r\n"); 199 | // cls.addMethod(clinit, codes.toString()); 200 | // } 201 | // else{ 202 | // clinit = cls.findMethod(clinit); 203 | // clinit.addLineCodeToEnd(" const-string v0,\"smalisafe\""); 204 | // clinit.addLineCodeToEnd(" invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V"); 205 | // } 206 | // } 207 | } 208 | -------------------------------------------------------------------------------- /src/Smali/SmaliClass.java: -------------------------------------------------------------------------------- 1 | package Smali; 2 | import java.io.BufferedReader; 3 | import java.io.BufferedWriter; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.regex.Matcher; 11 | import java.util.regex.Pattern; 12 | 13 | import Smali.SmaliClass.SmaliType; 14 | import Smali.SmaliModifier.ModifierAttribute; 15 | import Smali.SmaliModifier.ModifierPremission; 16 | import Smali.SmaliModifier.ModifierType; 17 | 18 | public class SmaliClass extends SmaliObject{ 19 | private final String ClassName; 20 | private final ArrayList fields; 21 | private final ArrayList methods; 22 | private File classFile; 23 | private BufferedReader reader; 24 | private BufferedWriter writer; 25 | private ArrayList codeLines; 26 | 27 | private static final ArrayList ClassTable = new ArrayList(); 28 | 29 | public static class SmaliType extends SmaliClass{ 30 | private boolean isArr; 31 | private int arrNum; 32 | 33 | 34 | public SmaliType(ModifierPremission premission,ArrayList attributes,ArrayList fields,ArrayList methods,String name,boolean isArr,int arrNum){ 35 | super(premission,attributes,fields,methods,name,null); 36 | this.isArr = isArr; 37 | this.arrNum = arrNum; 38 | } 39 | 40 | public boolean isArr() { 41 | return isArr; 42 | } 43 | 44 | public void setArr(boolean isArr) { 45 | this.isArr = isArr; 46 | } 47 | 48 | public int getArrNum() { 49 | return arrNum; 50 | } 51 | 52 | public void setArrNum(int arrNum) { 53 | this.arrNum = arrNum; 54 | } 55 | 56 | 57 | public static final SmaliType V = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"V",false,0); 58 | public static final SmaliType Z = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"Z",false,0); 59 | public static final SmaliType I = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"I",false,0); 60 | public static final SmaliType B = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"B",false,0); 61 | public static final SmaliType S = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"S",false,0); 62 | public static final SmaliType C = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"C",false,0); 63 | public static final SmaliType J = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"J",false,0); 64 | public static final SmaliType F = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"F",false,0); 65 | public static final SmaliType D = new SmaliType(ModifierPremission.PREMISSION_PUBLIC,null,null,null,"D",false,0); 66 | 67 | public char getChar(){ 68 | return toString().charAt(0); 69 | } 70 | 71 | public static SmaliType GetBaseType(char c){ 72 | if(c == V.getChar()){ 73 | return V; 74 | } 75 | else if(c == Z.getChar()){ 76 | return Z; 77 | } 78 | else if(c == I.getChar()){ 79 | return I; 80 | } 81 | else if(c == B.getChar()){ 82 | return B; 83 | } 84 | else if(c == S.getChar()){ 85 | return S; 86 | } 87 | else if(c == C.getChar()){ 88 | return C; 89 | } 90 | else if(c == J.getChar()){ 91 | return J; 92 | } 93 | else if(c == F.getChar()){ 94 | return F; 95 | } 96 | else if(c == D.getChar()){ 97 | return D; 98 | } 99 | else{ 100 | return null; 101 | } 102 | } 103 | } 104 | 105 | private SmaliClass(ModifierPremission premission,ArrayList attributes,ArrayList fields,ArrayList methods,String name,File classFile){ 106 | super(premission,attributes,0); 107 | this.ClassName = name; 108 | this.fields = fields; 109 | this.methods = methods; 110 | this.classFile = classFile; 111 | } 112 | 113 | public static SmaliClass PraseClass(File file){ 114 | BufferedReader reader; 115 | try { 116 | reader = new BufferedReader(new FileReader(file)); 117 | } catch (FileNotFoundException e) { 118 | System.out.println("[*PraseClassError]FileNotFoundException: " + e.toString()); 119 | return null; 120 | } 121 | String line; 122 | String className = ""; 123 | int lineInFile = 0; 124 | ModifierPremission premission = ModifierPremission.PREMISSION_DEFAULT; 125 | ArrayList attributes = new ArrayList(); 126 | ArrayList fields = new ArrayList(); 127 | ArrayList methods = new ArrayList(); 128 | try { 129 | while((line = reader.readLine()) != null){ 130 | line = line.trim(); 131 | if(line.startsWith(ModifierType.TYPE_CLASS.toString())){ 132 | String[] sp = line.split(" "); //sp[] = {".class",Premission,{Attributes},ClassName} 133 | premission = ModifierPremission.Get(sp[1]); 134 | for(int i = 2;i < sp.length - 1;i++){ 135 | attributes.add(ModifierAttribute.Get(sp[i])); 136 | } 137 | className = sp[sp.length-1]; 138 | } 139 | /* 140 | if(line.startsWith(SmaliModifier.ModifierType.TYPE_FIELD.getModifierText())){ 141 | String[] sp = line.split(" "); 142 | SmaliModifier.ModifierPremission fieldPremission = SmaliModifier.ModifierPremission.Get(sp[0]); 143 | ArrayList fieldAttributes = new ArrayList(); 144 | for(int i = 2;i < sp.length - 1 ;i++){ 145 | fieldAttributes.add(SmaliModifier.ModifierAttribute.Get(sp[i])); 146 | } 147 | String sp1[] = sp[sp.length-1].split(":"); 148 | SmaliField field = new SmaliField(); 149 | }*/ 150 | 151 | if(line.startsWith(ModifierType.TYPE_METHOD.toString())){ 152 | String[] sp = line.split(" "); //sp[] = {".method",Premission,{Attributes},MethodName+MethodSig} 153 | ModifierPremission methodPremission= ModifierPremission.Get(sp[1]); 154 | ArrayList methodAttributes = new ArrayList(); 155 | for(int i = 2;i < sp.length - 1 ;i++){ 156 | methodAttributes.add(ModifierAttribute.Get(sp[i])); 157 | } 158 | String[] sp1 = sp[sp.length-1].split("\\("); 159 | String methodName = sp1[0]; 160 | ArrayList args = SmaliMethod.PraseMethodArgs(sp1[1].split("\\)")[0]); 161 | String returnType = sp1[1].split("\\)")[1]; 162 | SmaliMethod method = new SmaliMethod(methodPremission,methodAttributes,args,returnType,className,methodName,lineInFile); 163 | methods.add(method); 164 | } 165 | lineInFile++; 166 | } 167 | reader.close(); 168 | SmaliClass cls = new SmaliClass(premission,attributes,fields,methods,className,file); 169 | SmaliClass.ClassTable.add(cls); 170 | return cls; 171 | } catch (IOException e) { 172 | System.out.println("[*PraseClassError]IOException: " + e.toString()); 173 | return null; 174 | } 175 | } 176 | 177 | public String toString(){ 178 | return ClassName; 179 | } 180 | 181 | public boolean equals(SmaliClass cls){ 182 | if(cls == null){ 183 | return false; 184 | } 185 | return cls.toString() == this.toString(); 186 | } 187 | 188 | public ArrayList getFields(){ 189 | return fields; 190 | } 191 | 192 | public BufferedWriter getWriter(){ 193 | if(writer == null){ 194 | if(classFile == null){ 195 | return null; 196 | } 197 | try { 198 | writer = new BufferedWriter(new FileWriter(classFile)); 199 | } catch (IOException e) { 200 | System.out.println("[*E] FileNotFound:" + e.toString()); 201 | } 202 | } 203 | return writer; 204 | } 205 | 206 | public ArrayList getCodes(){ 207 | if(codeLines == null){ 208 | if(reader == null ){ 209 | if(classFile == null){ 210 | return null; 211 | } 212 | try { 213 | reader = new BufferedReader(new FileReader(classFile)); 214 | } catch (FileNotFoundException e) { 215 | System.out.println("[*GetCodesError] FileNotFound: " + e.toString()); 216 | return null; 217 | } 218 | } 219 | ArrayList codes = new ArrayList(); 220 | String tmp; 221 | try { 222 | while((tmp = reader.readLine()) != null){ 223 | codes.add(tmp); 224 | } 225 | reader.close(); 226 | } catch (IOException e) { 227 | System.out.println("[*GetCodesError] IOExceotion: " + e.toString()); 228 | return null; 229 | } 230 | 231 | codeLines = codes; 232 | } 233 | return codeLines; 234 | } 235 | 236 | public ArrayList getMethods(){ 237 | return methods; 238 | } 239 | 240 | public File getClassFile(){ 241 | return classFile; 242 | } 243 | 244 | public ArrayList getInvokeMethodList(){ 245 | ArrayList list = new ArrayList(); 246 | for(String line : getCodes()){ 247 | line = line.trim(); 248 | String[] sp = line.split(" "); 249 | if(sp[0].indexOf("invoke") != -1){ 250 | Pattern pattern = Pattern.compile("([a-zA-Z0-9/_$]{0,128});->([0-9a-zA-Z_$]{0,128})\\(([a-zA-Z0-9/_$;]{0,512})\\)([a-zA-Z0-9/_$;]{0,128})"); 251 | Matcher matcher = pattern.matcher(line); 252 | if(matcher.find()){ 253 | String superClass = matcher.group(1); 254 | String returnType; 255 | SmaliMethod method; 256 | ArrayList args = SmaliMethod.PraseMethodArgs(matcher.group(3)); 257 | returnType = matcher.group(4); 258 | method = new SmaliMethod(ModifierPremission.PREMISSION_DEFAULT,null,args,returnType,superClass,matcher.group(2),-1); 259 | list.add(method); 260 | } 261 | } 262 | } 263 | return list; 264 | } 265 | 266 | public int addMethod(SmaliMethod method,String smaliCode){ 267 | if(method == null){ 268 | return -1; 269 | } 270 | method.setLineInFile(getCodes().size()+2); 271 | StringBuilder builder = new StringBuilder(); 272 | ArrayList codeLines = getCodes(); 273 | codeLines.add(""); 274 | builder.append(SmaliModifier.ModifierType.TYPE_METHOD+" "); 275 | builder.append(method.getPremission().toString()+" "); 276 | if(method.getAttributes() != null && method.getAttributes().size() != 0){ 277 | for(SmaliModifier modifier : method.getAttributes()){ 278 | builder.append(modifier + " "); 279 | } 280 | } 281 | builder.append(method.getMethodName()+"("); 282 | if(method.getArgs() != null){ 283 | for(String type : method.getArgs()){ 284 | builder.append(type.toString()); 285 | } 286 | } 287 | builder.append(")"); 288 | builder.append(method.getReturnTypeName()); 289 | codeLines.add(builder.toString()); 290 | String[] smaliLines = smaliCode.split("\r\n"); 291 | for(String line : smaliLines){ 292 | codeLines.add(line); 293 | } 294 | codeLines.add(".end method"); 295 | this.codeLines = codeLines; 296 | method.setSuperClass(this.toString()); 297 | methods.add(method); 298 | 299 | return 0; 300 | 301 | } 302 | 303 | public int saveChange(){ 304 | try { 305 | if(writer != null){ 306 | writer.close(); 307 | writer = null; 308 | } 309 | if(this.codeLines == null){ 310 | return 0; 311 | } 312 | writer = getWriter(); 313 | for(String tmp : getCodes()){ 314 | writer.write(tmp+"\r\n"); 315 | } 316 | writer.flush(); 317 | cleanMem(); 318 | return 0; 319 | } catch (IOException e) { 320 | System.out.println("[*SaveChangeError: ]" +e.toString()); 321 | return -1; 322 | } 323 | } 324 | 325 | public void cleanMem(){ 326 | if(reader != null){ 327 | try { 328 | reader.close(); 329 | } catch (IOException e) { 330 | } 331 | } 332 | if(writer != null){ 333 | try { 334 | writer.close(); 335 | } catch (IOException e) { 336 | } 337 | 338 | } 339 | codeLines = null; 340 | reader = null; 341 | writer = null; 342 | } 343 | 344 | public SmaliMethod findMethod(SmaliMethod method){ 345 | for(SmaliMethod m : methods){ 346 | if(m.equals(method)){ 347 | return m; 348 | } 349 | } 350 | return null; 351 | } 352 | 353 | public static SmaliClass FindClass(String cls){ 354 | if(cls == null || cls.isEmpty()){ 355 | return null; 356 | } 357 | if(cls.length() == 1 ){ 358 | return SmaliType.GetBaseType(cls.charAt(0)); 359 | } 360 | for(SmaliClass sc : ClassTable){ 361 | if(sc.equals(cls)){ 362 | return sc; 363 | } 364 | } 365 | return null; 366 | } 367 | 368 | public boolean isInterface(){ 369 | if(getAttributes().indexOf(ModifierAttribute.ATTRIBUTE_INTERFACE) != -1){ 370 | return true; 371 | } 372 | return false; 373 | } 374 | 375 | public boolean isAbstract(){ 376 | if(getAttributes().indexOf(ModifierAttribute.ATTRIBUTE_ABSTRACT) != -1){ 377 | return true; 378 | } 379 | return false; 380 | } 381 | 382 | public boolean equals(Object cls){ 383 | return cls.toString().equals(this.toString()); 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /src/Smali/SmaliField.java: -------------------------------------------------------------------------------- 1 | package Smali; 2 | import java.util.ArrayList; 3 | 4 | import Smali.SmaliModifier.ModifierAttribute; 5 | import Smali.SmaliModifier.ModifierPremission; 6 | 7 | public class SmaliField extends SmaliObject{ 8 | private final String type; 9 | private final String fieldName; 10 | 11 | public SmaliField(ModifierPremission premission,ArrayList attributes,String type,String name,int lineInFile){ 12 | super(premission,attributes,lineInFile); 13 | this.type = type; 14 | this.fieldName = name; 15 | } 16 | 17 | public String toString(){ 18 | return fieldName; 19 | } 20 | 21 | public String getName(){ 22 | return fieldName; 23 | } 24 | 25 | public SmaliClass getType(){ 26 | return SmaliClass.FindClass(type); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/Smali/SmaliMethod.java: -------------------------------------------------------------------------------- 1 | package Smali; 2 | import java.util.ArrayList; 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | import Smali.SmaliClass.SmaliType; 7 | import Smali.SmaliModifier.ModifierAttribute; 8 | import Smali.SmaliModifier.ModifierPremission; 9 | import Smali.SmaliModifier.ModifierType; 10 | 11 | public class SmaliMethod extends SmaliObject{ 12 | private String methodName; 13 | private ArrayList args; 14 | private String superClass; 15 | private String returnType; 16 | 17 | public static final String MethodRegEx = ModifierType.TYPE_METHOD +" ([a-z ]{0,64}) ([a-zA-Z0-9_$<>]{0,128})\\(([a-zA-Z0-9_$;/\\[]{0,512})\\)([a-zA-Z0-9_$;/\\[]{0,256})"; 18 | public static final String MethodRegEx_NotPre = ModifierType.TYPE_METHOD +" ([a-zA-Z0-9_$<>]{0,128})\\(([a-zA-Z0-9_$;\\[/]{0,512})\\)([a-zA-Z0-9_$;/\\[]{0,256})"; 19 | 20 | 21 | 22 | /** 23 | * @param premission: ModifierPremission 24 | * **/ 25 | public SmaliMethod(ModifierPremission premission,ArrayList attributes,ArrayList args,String returnType,String superCls,String name,int lineInFile){ 26 | super(premission,attributes,lineInFile); 27 | this.args = args; 28 | this.returnType = returnType; 29 | this.methodName = name; 30 | this.superClass = superCls; 31 | } 32 | 33 | public SmaliMethod(String name,ArrayList args,String returnType){ 34 | this(null,null,args,returnType,null,name,-1); 35 | } 36 | 37 | /** 38 | * @return ClassName+"->"+MethodName 39 | * **/ 40 | public String toString(){ 41 | return superClass+"->"+methodName; 42 | } 43 | 44 | public boolean equals(SmaliMethod method){ 45 | if(method == null){ 46 | return false; 47 | } 48 | if(!this.methodName.equals(method.methodName)){ 49 | return false; 50 | } 51 | if(!this.getMethodSig().equals(method.getMethodSig())){ 52 | return false; 53 | } 54 | return true; 55 | } 56 | 57 | private void setMethodName(String name){ 58 | this.methodName = name; 59 | } 60 | 61 | public void setSuperClass(String clsName){ 62 | this.superClass = clsName; 63 | } 64 | 65 | public boolean isSynthetic(){ 66 | if(getAttributes().indexOf(ModifierAttribute.ATTRIBUTE_SYNTHETIC) == -1 && getAttributes().indexOf(ModifierAttribute.ATTRIBUTE_DECLARED_SYNCHRONIZED) == -1){ 67 | return false; 68 | } 69 | return true; 70 | } 71 | 72 | public boolean isNative(){ 73 | if(getAttributes().indexOf(ModifierAttribute.ATTRIBUTE_NATIVE) != -1){ 74 | return true; 75 | } 76 | return false; 77 | } 78 | 79 | public String getMethodName(){ 80 | return methodName; 81 | } 82 | 83 | public ArrayList getArgs(){ 84 | return args; 85 | } 86 | 87 | public String getMethodSig(){ 88 | StringBuilder sig = new StringBuilder("("); 89 | for(String arg : args){ 90 | sig.append(arg); 91 | } 92 | sig.append(")"); 93 | sig.append(returnType); 94 | return sig.toString(); 95 | } 96 | 97 | public SmaliClass getReturnType(){ 98 | return SmaliClass.FindClass(returnType); 99 | } 100 | 101 | public SmaliClass getSuperClass(){ 102 | return SmaliClass.FindClass(superClass); 103 | } 104 | 105 | public String getReturnTypeName(){ 106 | return returnType; 107 | } 108 | 109 | public String getSuperClassName(){ 110 | return superClass; 111 | } 112 | 113 | public int rename(String text){ 114 | ArrayList codes = getSuperClass().getCodes(); 115 | String line = codes.get(getLineInFile()).toString(); 116 | if(line == null){ 117 | return -1; 118 | } 119 | boolean havePre = true; 120 | Pattern pattern = Pattern.compile(MethodRegEx); 121 | Matcher matcher = pattern.matcher(line); 122 | if(!matcher.find()){ 123 | pattern = Pattern.compile(MethodRegEx_NotPre); 124 | matcher = pattern.matcher(line); 125 | if(!matcher.find()){ 126 | return -2; 127 | } 128 | havePre = false; 129 | } 130 | if(havePre){ 131 | codes.set(getLineInFile(),SmaliModifier.ModifierType.TYPE_METHOD +" " + matcher.group(1) + " " + text + "(" + matcher.group(3) + ")" +matcher.group(4)) ; 132 | } 133 | else{ 134 | codes.set(getLineInFile(),SmaliModifier.ModifierType.TYPE_METHOD+" " + text + "(" + matcher.group(2) + ")" +matcher.group(3)); 135 | } 136 | setMethodName(text); 137 | return 0; 138 | } 139 | 140 | public void addLineCodeToEnd(String code){ 141 | int startLine = getLineInFile(); 142 | ArrayList codes = getSuperClass().getCodes(); 143 | while(!codes.get(startLine + 1).equals(ModifierType.TYPE_METHOD_END.toString())){ 144 | startLine++; 145 | } 146 | codes.add(startLine,code); 147 | setOverAddLine(startLine); 148 | } 149 | 150 | public static ArrayList PraseMethodArgs(String text){ 151 | char[] c = text.toCharArray(); 152 | ArrayList args = new ArrayList(); 153 | int fristi = 0; 154 | int endi = 0; 155 | for(int i = 0;i attributes = new ArrayList(); 12 | private int lineInFile; 13 | private int overAddLine = 0; 14 | public int lineOffset = 0; 15 | 16 | 17 | public SmaliObject(ModifierPremission premission,ArrayList attributes,int lineInFile){ 18 | this.lineInFile = lineInFile; 19 | if(premission != null){ 20 | this.premission = premission; 21 | } 22 | else{ 23 | this.premission = ModifierPremission.PREMISSION_DEFAULT; 24 | } 25 | if(attributes == null){ 26 | return; 27 | } 28 | for(ModifierAttribute attribute : attributes){ 29 | this.attributes.add(attribute); 30 | } 31 | } 32 | 33 | public ModifierPremission getPremission(){ 34 | return premission; 35 | } 36 | 37 | public int getOverAddLine() { 38 | return overAddLine; 39 | } 40 | 41 | public void setOverAddLine(int overAddLine) { 42 | this.overAddLine = overAddLine; 43 | } 44 | 45 | public int getLineInFile(){ 46 | if(lineInFile > overAddLine){ 47 | return lineInFile + lineOffset; 48 | } 49 | return lineInFile; 50 | } 51 | 52 | public void setLineInFile(int line){ 53 | this.lineInFile = line; 54 | } 55 | 56 | public ArrayList getAttributes(){ 57 | return attributes; 58 | } 59 | 60 | public boolean isStatic(){ 61 | if(getAttributes().indexOf(ModifierAttribute.ATTRIBUTE_STATIC) != -1){ 62 | return true; 63 | } 64 | return false; 65 | } 66 | 67 | public boolean isFinal(){ 68 | if(getAttributes().indexOf(ModifierAttribute.ATTRIBUTE_FINAL) != -1){ 69 | return true; 70 | } 71 | return false; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Utils.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.File; 3 | import java.io.FileNotFoundException; 4 | import java.io.FileReader; 5 | import java.io.IOException; 6 | import java.util.ArrayList; 7 | import java.util.Random; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | public class Utils { 12 | public static String gbEncoding(final String gbString) { //gbString = "测试" 13 | char[] utfBytes = gbString.toCharArray(); //utfBytes = [测, 试] 14 | String unicodeBytes = ""; 15 | for (int byteIndex = 0; byteIndex < utfBytes.length; byteIndex++) { 16 | String hexB = Integer.toHexString(utfBytes[byteIndex]); //转换为16进制整型字符串 17 | if (hexB.length() <= 2) { 18 | while(hexB.length() != 4){ 19 | hexB = "0" + hexB; 20 | } 21 | } 22 | unicodeBytes = unicodeBytes + "\\u" + hexB; 23 | } 24 | return unicodeBytes; 25 | } 26 | public static ArrayList GetInDirFiles(File dir){ 27 | ArrayList fileList = new ArrayList(); 28 | if(!dir.isDirectory()){ 29 | return fileList; 30 | } 31 | File[] list = dir.listFiles(); 32 | if(list == null){ 33 | return fileList; 34 | } 35 | for(File file : list){ 36 | if(file.isDirectory()){ 37 | fileList.addAll(GetInDirFiles(file)); 38 | } 39 | else{ 40 | fileList.add(file); 41 | } 42 | } 43 | return fileList; 44 | } 45 | } 46 | --------------------------------------------------------------------------------