d2j-smali support polymorphic/custom

This commit is contained in:
Bob Pan 2017-08-02 16:32:20 +08:00
parent bac5d542a6
commit 3e93d2021f
6 changed files with 155 additions and 43 deletions

View File

@ -53,14 +53,14 @@ VOID_TYPE:'V';
fragment
FRAGMENT_PRIMITIVE_TYPE:'B'|'Z'|'S'|'C'|'I'|'F'|'J'|'D';
fragment
FRAGMENT_OBJECT_TYPE: 'L' (ESC_SEQ |~(';'|':'|'\\'|' '|'\n'|'\t'|'\r'|'('|')'|'-'))+ ';' ;
FRAGMENT_OBJECT_TYPE: 'L' (ESC_SEQ |~(';'|':'|'\\'|' '|'\n'|'\t'|'\r'|'('|')'))+ ';' ;
fragment
FRAGMENT_ARRAY_TYPE: ('[')+ (FRAGMENT_PRIMITIVE_TYPE|FRAGMENT_OBJECT_TYPE);
fragment
FRAGMENT_ID: (ESC_SEQ| ~('\\'|'\r'|'\n'|'\t'|' '|':'|'-'|'='|','|'{'|'}'|'('|')'|'+'|'\"'|'\''|'#'|'/'|'.'|';'))+;
fragment
FRAGMENT_METHOD_PART: FRAGMENT_ID '(' (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)* ')' ('V' | FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)
FRAGMENT_METHOD_PROTO: '(' (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)* ')' ('V' | FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE|FRAGMENT_PRIMITIVE_TYPE)
;
fragment
FRAGMENT_FIELD_PART:
@ -69,8 +69,9 @@ FRAGMENT_FIELD_PART:
;
METHOD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_METHOD_PART;
METHOD_PART: FRAGMENT_METHOD_PART;
METHOD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_ID FRAGMENT_METHOD_PROTO;
METHOD_PART: FRAGMENT_ID FRAGMENT_METHOD_PROTO;
METHOD_PROTO: FRAGMENT_METHOD_PROTO;
FIELD_FULL: (FRAGMENT_OBJECT_TYPE|FRAGMENT_ARRAY_TYPE) '->' FRAGMENT_FIELD_PART;
FIELD_PART: FRAGMENT_FIELD_PART;
@ -174,6 +175,8 @@ sAnnotationValue
:sSubannotation
|sBaseValue
|sArrayValue
| ( '.iget' | '.iput' | '.sget' | '.sput' ) FIELD_FULL
| ( '.invoke-instance' | '.invoke-static' ) METHOD_FULL
;// field,method,array,subannotation
sBaseValue
:STRING
@ -181,7 +184,11 @@ sBaseValue
|BASE_FLOAT| FLOAT_INFINITY | FLOAT_NAN
|BASE_DOUBLE|DOUBLE_INFINITY|DOUBLE_NAN
|METHOD_FULL
|METHOD_PROTO
|OBJECT_TYPE
|ARRAY_TYPE
|PRIMITIVE_TYPE
|VOID_TYPE
|NULL
|DENUM FIELD_FULL
;
@ -213,6 +220,10 @@ sInstruction
|ft5c
|fm5c
|fmrc
|fm45cc
|fm4rcc
|fmcustomc
|fmcustomrc
|ftrc
|sLabel
|f2sb
@ -394,6 +405,14 @@ fmrc : op=('invoke-virtual/range'|'invoke-super/range'
|'invoke-interface/range'
) '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' method=METHOD_FULL
;
fm45cc : op='invoke-polymorphic' '{' (REGISTER (',' REGISTER)* )? '}' ',' method=METHOD_FULL ',' proto=METHOD_PROTO
;
fm4rcc : op='invoke-polymorphic/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' method=METHOD_FULL ',' proto=METHOD_PROTO
;
fmcustomc : op='invoke-custom' '{' (REGISTER (',' REGISTER)* )? '}' ',' sArrayValue
;
fmcustomrc : op='invoke-custom/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' sArrayValue
;
ftrc : op='filled-new-array/range' '{' (rstart=REGISTER '..' rend=REGISTER)? '}' ',' type=(OBJECT_TYPE|ARRAY_TYPE);
f31t: op=('fill-array-data'|'packed-switch'|'sparse-switch') r1=REGISTER ',' label=LABEL;
f1t :op=('if-eqz'|'if-nez'|'if-ltz'|'if-gez'|'if-gtz'|'if-lez') r1=REGISTER ',' label=LABEL

View File

@ -16,9 +16,7 @@
*/
package com.googlecode.d2j.smali;
import com.googlecode.d2j.DexLabel;
import com.googlecode.d2j.Field;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.*;
import com.googlecode.d2j.node.DexDebugNode;
import com.googlecode.d2j.reader.InstructionFormat;
import com.googlecode.d2j.reader.Op;
@ -237,11 +235,9 @@ import java.util.*;
@Override
public void visitFieldStmt(Op op, int a, int b, Field field) {
if (op.format == InstructionFormat.kFmt22c) {// iget,iput
out.s("%s %s, %s, %s->%s:%s", op.displayName, reg(a), reg(b), BaksmaliDumper.escapeType(field.getOwner()),
BaksmaliDumper.escapeId(field.getName()), BaksmaliDumper.escapeType(field.getType()));
out.s("%s %s, %s, %s", op.displayName, reg(a), reg(b), BaksmaliDumper.escapeField(field));
} else {
out.s("%s %s, %s->%s:%s", op.displayName, reg(a), BaksmaliDumper.escapeType(field.getOwner()),
BaksmaliDumper.escapeId(field.getName()), BaksmaliDumper.escapeType(field.getType()));
out.s("%s %s, %s", op.displayName, reg(a), BaksmaliDumper.escapeField(field));
}
}
@ -341,9 +337,8 @@ import java.util.*;
if (args.length > 0) {
if (op.format == InstructionFormat.kFmt3rc) { // invoke-x/range
out.s("%s { %s .. %s }, %s->%s%s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
BaksmaliDumper.escapeType(method.getOwner()), BaksmaliDumper.escapeId(method.getName()),
BaksmaliDumper.escapeMethodDesc(method));
out.s("%s { %s .. %s }, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
BaksmaliDumper.escapeMethod(method));
} else {
boolean first = true;
StringBuilder buff = new StringBuilder();
@ -355,16 +350,72 @@ import java.util.*;
}
buff.append(reg(i));
}
out.s("%s { %s }, %s->%s%s", op.displayName, buff, BaksmaliDumper.escapeType(method.getOwner()),
BaksmaliDumper.escapeId(method.getName()), BaksmaliDumper.escapeMethodDesc(method));
out.s("%s { %s }, %s", op.displayName, buff, BaksmaliDumper.escapeMethod(method));
}
} else {
out.s("%s { }, %s->%s%s", op.displayName, BaksmaliDumper.escapeType(method.getOwner()),
BaksmaliDumper.escapeId(method.getName()), BaksmaliDumper.escapeMethodDesc(method));
out.s("%s { }, %s", op.displayName, BaksmaliDumper.escapeMethod(method));
}
}
@Override
public void visitMethodStmt(Op op, int[] args, Method method, Proto proto) {
if (args.length > 0) {
if (op.format == InstructionFormat.kFmt4rcc) { // invoke-x/range
out.s("%s { %s .. %s }, %s, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
BaksmaliDumper.escapeMethod(method), BaksmaliDumper.escapeMethodDesc(proto));
} else {
boolean first = true;
StringBuilder buff = new StringBuilder();
for (int i : args) {
if (first) {
first = false;
} else {
buff.append(", ");
}
buff.append(reg(i));
}
out.s("%s { %s }, %s, %s", op.displayName, buff, BaksmaliDumper.escapeMethod(method),
BaksmaliDumper.escapeMethodDesc(proto));
}
} else {
out.s("%s { }, %s, %s", op.displayName, BaksmaliDumper.escapeMethod(method),
BaksmaliDumper.escapeMethodDesc(proto));
}
}
@Override
public void visitMethodStmt(Op op, int[] args, String name, Proto proto, MethodHandle bsm, Object... bsmArgs) {
StringBuilder sb = new StringBuilder();
sb.append("{ ").append( BaksmaliDumper.escapeValue(bsm)).append(", ").append(BaksmaliDumper.escapeValue(name)).append(", ").append(BaksmaliDumper.escapeMethodDesc(proto));
for(Object o: bsmArgs) {
sb.append(", ").append(BaksmaliDumper.escapeValue(o));
}
sb.append("}");
if (args.length > 0) {
if (op.format == InstructionFormat.kFmt3rc) { // invoke-x/range
out.s("%s { %s .. %s }, %s", op.displayName, reg(args[0]), reg(args[args.length - 1]),
sb);
} else {
boolean first = true;
StringBuilder buff = new StringBuilder();
for (int i : args) {
if (first) {
first = false;
} else {
buff.append(", ");
}
buff.append(reg(i));
}
out.s("%s { %s }, %s", op.displayName, buff, sb);
}
} else {
out.s("%s { }, %s", op.displayName, sb);
}
}
@Override
public void visitPackedSwitchStmt(Op op, int ra, int first_case, DexLabel[] labels) {
DexLabel dx = new DexLabel();

View File

@ -119,7 +119,13 @@ public class BaksmaliDumper implements DexConstants {
}
}
static String escapeMethod(Method method) {
return BaksmaliDumper.escapeType(method.getOwner()) + "->" + BaksmaliDumper.escapeId(method.getName()) + BaksmaliDumper.escapeMethodDesc(method);
}
static String escapeMethodDesc(Method m) {
return escapeMethodDesc(m.getProto());
}
static String escapeMethodDesc(Proto m) {
StringBuilder escapeBuff = new StringBuilder();
escapeBuff.append("(");
for (String t : m.getParameterTypes()) {
@ -211,10 +217,12 @@ public class BaksmaliDumper implements DexConstants {
if (obj instanceof DexType) {
return escapeType(((DexType) obj).desc);
}
// if (obj instanceof Method) {
// return v((Method) obj);
// }
if(obj instanceof Proto) {
return escapeMethodDesc((Proto) obj);
}
if(obj instanceof MethodHandle) {
return escapeMethodHandle((MethodHandle) obj);
}
if (obj instanceof Field) {
Field f = ((Field) obj);
String owner = f.getOwner();
@ -262,22 +270,39 @@ public class BaksmaliDumper implements DexConstants {
return ((Boolean) obj).toString();
}
if (obj instanceof Method) {
Method m = (Method) obj;
StringBuilder buf = new StringBuilder();
escapeType0(buf, m.getOwner());
buf.append("->");
escapeId0(buf, m.getName());
buf.append("(");
for (String a : m.getParameterTypes()) {
escapeType0(buf, a);
}
buf.append(")");
escapeType0(buf, m.getReturnType());
return buf.toString();
return escapeMethod((Method) obj);
}
return null;
}
private static String escapeMethodHandle(MethodHandle obj) {
switch (obj.getType()) {
case MethodHandle.INSTANCE_GET:
return ".iget " + escapeField(obj.getField());
case MethodHandle.INSTANCE_PUT:
return ".iput " + escapeField(obj.getField());
case MethodHandle.STATIC_GET:
return ".sget " + escapeField(obj.getField());
case MethodHandle.STATIC_PUT:
return ".sput " + escapeField(obj.getField());
case MethodHandle.INVOKE_INSTANCE:
return ".invoke-instance " + escapeMethod(obj.getMethod());
case MethodHandle.INVOKE_STATIC:
return ".invoke-static " + escapeMethod(obj.getMethod());
default:
}
return "?";
}
public static String escapeField(Field f) {
String owner = f.getOwner();
if (owner == null) {
owner = f.getType();
}
return escapeType(owner) + "->" + f.getName() + ":" + escapeType(f.getType());
}
private static void dumpAnns(List<DexAnnotationNode> anns, Out out) {
for (DexAnnotationNode ann : anns) {
dumpAnn(ann, out);

View File

@ -74,14 +74,18 @@ public class InvokeExpr extends AbstractInvokeExpr {
public String toString0() {
StringBuilder sb = new StringBuilder();
int i = 0;
if (super.vt == VT.INVOKE_NEW) {
sb.append("new ").append(Util.toShortClassName(method.getOwner())).append('(');
sb.append("new ").append(Util.toShortClassName(method.getOwner()));
} else if (super.vt == VT.INVOKE_STATIC) {
sb.append(Util.toShortClassName(method.getOwner())).append('.')
.append(this.method.getName());
} else {
sb.append(super.vt == VT.INVOKE_STATIC ? Util.toShortClassName(method.getOwner()) : ops[0]).append('.')
.append(this.method.getName()).append('(');
sb.append(ops[i++]).append('.').append(this.method.getName());
}
sb.append('(');
boolean first = true;
for (int i = (vt == VT.INVOKE_STATIC || vt == VT.INVOKE_NEW) ? 0 : 1; i < ops.length; i++) {
for (; i < ops.length; i++) {
if (first) {
first = false;
} else {

View File

@ -18,6 +18,7 @@ package com.googlecode.dex2jar.ir.expr;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.Proto;
import com.googlecode.dex2jar.ir.LabelAndLocalMapper;
import com.googlecode.dex2jar.ir.Util;
public class InvokePolymorphicExpr extends AbstractInvokeExpr {
public Proto proto;
@ -54,8 +55,22 @@ public class InvokePolymorphicExpr extends AbstractInvokeExpr {
@Override
public String toString0() {
StringBuilder sb = new StringBuilder();
int i = 0;
sb.append(ops[i++]).append('.').append(this.method.getName());
String[] argTypes = getProto().getParameterTypes();
sb.append('(');
int j = 0;
boolean first = true;
for (; i < ops.length; i++) {
if (first) {
first = false;
} else {
sb.append(',');
}
sb.append("(").append(Util.toShortClassName(argTypes[j++])).append(")").append(ops[i]);
}
sb.append(')');
sb.append("InvokePolymorphicExpr(...)");
return sb.toString();
}
}

View File

@ -103,8 +103,7 @@ public class NewTransformer implements Transformer {
if (orgOps[0].vt == NEW) {
NewExpr newExpr = (NewExpr) ie.getOps()[0];
if (newExpr != null) {
Value[] nOps = new Value[orgOps.length - 1];
System.arraycopy(orgOps, 1, nOps, 0, nOps.length);
Value[] nOps = Arrays.copyOfRange(orgOps, 1, orgOps.length);
InvokeExpr invokeNew = Exprs.nInvokeNew(nOps, ie.getArgs(), ie.getOwner());
method.stmts.insertBefore(p, Stmts.nVoidInvoke(invokeNew));
it.remove();
@ -156,8 +155,7 @@ public class NewTransformer implements Transformer {
}
InvokeExpr ie = findInvokeExpr(obj.invokeStmt, null);
Value[] orgOps = ie.getOps();
Value[] nOps = new Value[orgOps.length - 1];
System.arraycopy(orgOps, 1, nOps, 0, nOps.length);
Value[] nOps = Arrays.copyOfRange(orgOps, 1, orgOps.length);
InvokeExpr invokeNew = Exprs.nInvokeNew(nOps, ie.getArgs(), ie.getOwner());
method.stmts.replace(obj.invokeStmt, Stmts.nAssign(obj.local, invokeNew));
}