Skip to content

Commit

Permalink
Adds convert rule file. #15
Browse files Browse the repository at this point in the history
  • Loading branch information
maoabc committed Jun 21, 2021
1 parent 50c8d67 commit 8a50134
Show file tree
Hide file tree
Showing 8 changed files with 519 additions and 109 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,74 +1,252 @@
package com.nmmedit.apkprotect.dex2c.filters;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.nmmedit.apkprotect.deobfus.MappingProcessor;
import com.nmmedit.apkprotect.deobfus.MappingReader;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* 读取proguard的mapping.txt文件,根据它得到class和方法名混淆前后映射关系,然后再执行过滤规则
*/

public abstract class ProguardMappingConfig implements ClassAndMethodFilter, MappingProcessor {
public class ProguardMappingConfig implements ClassAndMethodFilter, MappingProcessor {
private final ClassAndMethodFilter filter;
private final Map<String, String> newTypeOldTypeMap = new HashMap<>();

public ProguardMappingConfig(ClassAndMethodFilter filter, MappingReader mappingReader) throws IOException {
private final Map<String, String> newTypeOldTypeMap = Maps.newHashMap();
private final Map<String, String> oldTypeNewTypeMap = Maps.newHashMap();
private final Set<MethodMapping> methodSet = Sets.newHashSet();
private final HashMultimap<MethodReference, MethodReference> newMethodRefMap = HashMultimap.create();
private final SimpleRule simpleRule;

public ProguardMappingConfig(ClassAndMethodFilter filter,
MappingReader mappingReader,
SimpleRule simpleRule) throws IOException {
this.filter = filter;
this.simpleRule = simpleRule;
mappingReader.parse(this);

for (MethodMapping methodMapping : methodSet) {
final List<String> args = parseArgs(methodMapping.args);
final ImmutableMethodReference oldMethodRef = new ImmutableMethodReference(
javaType2jvm(methodMapping.className),
methodMapping.methodName, args,
javaType2jvm(methodMapping.returnType));

final List<String> newArgs = getNewArgs(args);
String newRetType = oldTypeNewTypeMap.get(methodMapping.returnType);
if (newRetType == null) {
newRetType = methodMapping.returnType;
}
final ImmutableMethodReference newMethodRef = new ImmutableMethodReference(javaType2jvm(
methodMapping.newClassName),
methodMapping.newMethodName, newArgs,
javaType2jvm(newRetType));
newMethodRefMap.put(newMethodRef, oldMethodRef);
}
}

private List<String> getNewArgs(List<String> args) {
final ArrayList<String> newArgs = new ArrayList<>();
for (String arg : args) {
final String newType = oldTypeNewTypeMap.get(arg);
newArgs.add(newType == null ? arg : newType);
}
return newArgs;
}


@Override
public final boolean acceptClass(ClassDef classDef) {
//先处理上游的过滤规则,如果上游不通过则直接返回不再处理,如果上游通过再处理当前的过滤规则
if (filter != null && !filter.acceptClass(classDef)) {
return false;
}
//得到混淆之前的className
final String oldName = getOriginClassName(classDef.getType());
if (oldName == null) {
final String oldType = getOriginClassType(classDef.getType());
if (oldType == null) {
return false;
}
//需要保留的class返回false,
return !keepClass(classDef);
final ArrayList<String> ifacs = new ArrayList<>();
for (String ifac : classDef.getInterfaces()) {
ifacs.add(getOriginClassType(ifac));
}

return simpleRule != null && simpleRule.matchClass(
oldType,
getOriginClassType(classDef.getSuperclass()),
ifacs);
}

protected abstract boolean keepClass(ClassDef classDef);

protected String getOriginClassName(String type) {
return newTypeOldTypeMap.get(type);
private String getOriginClassType(String type) {
final String oldType = newTypeOldTypeMap.get(type);
if (oldType == null) {
return type;
}
return oldType;
}

@Override
public final boolean acceptMethod(Method method) {
if (filter != null && !filter.acceptMethod(method)) {
return false;
}
return !keepMethod(method);
}
final String oldType = getOriginClassType(method.getDefiningClass());
if (oldType == null) {
return false;
}
final Set<MethodReference> oldMethodRefSet = newMethodRefMap.get(method);


protected abstract boolean keepMethod(Method method);
if (oldMethodRefSet != null) {

for (MethodReference reference : oldMethodRefSet) {
if (oldType.equals(reference.getDefiningClass())) {
if (simpleRule != null && simpleRule.matchMethod(reference.getName())) {
return true;
}
}
}

}

return simpleRule != null && simpleRule.matchMethod(method.getName());
}

private static String classNameToType(String className) {
return "L" + className.replace('.', '/') + ";";
}

@Override
public final void processClassMapping(String className, String newClassName) {
newTypeOldTypeMap.put(classNameToType(newClassName), className);
newTypeOldTypeMap.put(classNameToType(newClassName), classNameToType(className));
oldTypeNewTypeMap.put(classNameToType(className), classNameToType(newClassName));
}

@Override
public final void processFieldMapping(String className, String fieldType, String fieldName, String newClassName, String newFieldName) {

}

@Nonnull
private static String javaType2jvm(@Nonnull String type) {
switch (type.trim()) {
case "boolean":
return "Z";
case "byte":
return "B";
case "char":
return "C";
case "short":
return "S";
case "int":
return "I";
case "float":
return "F";
case "long":
return "J";
case "double":
return "D";
case "void":
return "V";
default:
int i = type.indexOf('[');
if (i != -1) {
String t = type.substring(0, i);
StringBuilder arr = new StringBuilder("[");
while ((i = type.indexOf('[', i + 1)) != -1) {
arr.append('[');
}
arr.append(javaType2jvm(t));
return arr.toString();
} else {
return classNameToType(type);
}

}
}

@Nonnull
private List<String> parseArgs(String methodArgs) {
final ArrayList<String> args = new ArrayList<>();
if ("".equals(methodArgs)) {
return args;
}
final String[] split = methodArgs.split(",");
for (String type : split) {
args.add(javaType2jvm(type));
}
return args;
}

@Override
public final void processMethodMapping(String className, int firstLineNumber, int lastLineNumber, String methodReturnType, String methodName, String methodArguments, String newClassName, int newFirstLineNumber, int newLastLineNumber, String newMethodName) {
public final void processMethodMapping(String className,
int firstLineNumber, int lastLineNumber,
String methodReturnType,
String methodName,
String methodArguments,
String newClassName,
int newFirstLineNumber, int newLastLineNumber,
String newMethodName) {
final MethodMapping mapping = new MethodMapping(className, methodName, newClassName, newMethodName, methodArguments, methodReturnType);
methodSet.add(mapping);
}

private static class MethodMapping {
private final String className;
private final String methodName;

private final String newClassName;
private final String newMethodName;
private final String args;
private final String returnType;

public MethodMapping(String className, String methodName,
String newClassName, String newMethodName,
String args, String returnType) {
this.className = className;
this.methodName = methodName;
this.newClassName = newClassName;
this.newMethodName = newMethodName;
this.args = args;
this.returnType = returnType;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

MethodMapping that = (MethodMapping) o;

if (!className.equals(that.className)) return false;
if (!methodName.equals(that.methodName)) return false;
if (!newClassName.equals(that.newClassName)) return false;
if (!newMethodName.equals(that.newMethodName)) return false;
if (!args.equals(that.args)) return false;
return returnType.equals(that.returnType);
}

@Override
public int hashCode() {
int result = className.hashCode();
result = 31 * result + methodName.hashCode();
result = 31 * result + newClassName.hashCode();
result = 31 * result + newMethodName.hashCode();
result = 31 * result + args.hashCode();
result = 31 * result + returnType.hashCode();
return result;
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.nmmedit.apkprotect.dex2c.filters;

import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Method;

public class SimpleConvertConfig implements ClassAndMethodFilter {
private final ClassAndMethodFilter filter;
private final SimpleRule simpleRule;

public SimpleConvertConfig(ClassAndMethodFilter filter, SimpleRule simpleRule) {
this.filter = filter;
this.simpleRule = simpleRule;
}

@Override
public boolean acceptClass(ClassDef classDef) {
if (filter != null && !filter.acceptClass(classDef)) {
return false;
}
return simpleRule != null && simpleRule.matchClass(
classDef.getType(),
classDef.getSuperclass(),
classDef.getInterfaces());
}

@Override
public boolean acceptMethod(Method method) {
if (filter != null && !filter.acceptMethod(method)) {
return false;
}
return simpleRule != null && simpleRule.matchMethod(method.getName());
}
}
Loading

0 comments on commit 8a50134

Please sign in to comment.