use of com.googlecode.dex2jar.ir.StmtTraveler in project dex2jar by pxb1988.
the class MultiArrayTransformer method transformReportChanged.
@Override
public boolean transformReportChanged(IrMethod method) {
final boolean[] changed = { false };
new StmtTraveler() {
@Override
public Value travel(Value op) {
if (op.vt == Value.VT.CHECK_CAST) {
TypeExpr te = (TypeExpr) op;
if (te.op.vt == Value.VT.CHECK_CAST) {
TypeExpr te2 = (TypeExpr) te.op;
if (te.type.equals(te2.type)) {
op = te2;
}
}
}
op = super.travel(op);
if (op.vt == Value.VT.CHECK_CAST) {
TypeExpr te = (TypeExpr) op;
if (te.type.charAt(0) == '[') {
Value from = te.getOp();
if (from.vt == Value.VT.INVOKE_STATIC) {
InvokeExpr invokeExpr = (InvokeExpr) from;
if (invokeExpr.name.equals("newInstance") && invokeExpr.owner.equals("Ljava/lang/reflect/Array;") && invokeExpr.args.length == 2 && invokeExpr.args[0].equals("Ljava/lang/Class;")) {
Value arg0 = invokeExpr.getOps()[0];
String elementType = null;
if (arg0.vt == Value.VT.CONSTANT) {
elementType = ((Constant.Type) ((Constant) invokeExpr.getOps()[0]).value).desc;
} else {
if (arg0.vt == Value.VT.STATIC_FIELD) {
StaticFieldExpr sfe = (StaticFieldExpr) arg0;
if (sfe.owner.startsWith("Ljava/lang/") && sfe.name.equals("TYPE")) {
switch(sfe.owner) {
case "Ljava/lang/Boolean;":
elementType = "Z";
break;
case "Ljava/lang/Byte;":
elementType = "B";
break;
case "Ljava/lang/Short;":
elementType = "S";
break;
case "Ljava/lang/Character;":
elementType = "C";
break;
case "Ljava/lang/Integer;":
elementType = "I";
break;
case "Ljava/lang/Long;":
elementType = "J";
break;
case "Ljava/lang/Float;":
elementType = "F";
break;
case "Ljava/lang/Double;":
elementType = "D";
break;
case "Ljava/lang/Void;":
elementType = "V";
break;
default:
}
}
}
}
if (elementType != null) {
Value dt = invokeExpr.getOps()[1];
if (invokeExpr.args[1].equals("I")) {
if (te.type.equals("[" + elementType)) {
int d = 0;
while (elementType.charAt(d) == '[') {
d++;
}
changed[0] = true;
if (d > 0) {
return Exprs.nNewMutiArray(elementType.substring(d), d + 1, new Value[] { dt });
} else {
return Exprs.nNewArray(elementType, dt);
}
}
} else {
// [I
if (dt.vt == Value.VT.FILLED_ARRAY) {
FilledArrayExpr filledArrayExpr = (FilledArrayExpr) dt;
int d = filledArrayExpr.getOps().length;
if (te.type.length() > d && te.type.substring(d).equals(elementType)) {
int d1 = 0;
while (elementType.charAt(d1) == '[') {
d1++;
}
changed[0] = true;
return Exprs.nNewMutiArray(elementType.substring(d1), d1 + d, filledArrayExpr.getOps());
}
}
}
}
}
}
}
}
return op;
}
}.travel(method);
return changed[0];
}
use of com.googlecode.dex2jar.ir.StmtTraveler in project dex2jar by pxb1988.
the class NewTransformer method makeSureUsedBeforeConstructor.
void makeSureUsedBeforeConstructor(IrMethod method, final Map<Local, TObject> init, final int size) {
Cfg.createCFG(method);
Cfg.dfs(method.stmts, new Cfg.FrameVisitor<Vx[]>() {
boolean keepFrame = false;
Vx[] tmp = new Vx[size];
StmtTraveler stmtTraveler = new StmtTraveler() {
Stmt current;
@Override
public Stmt travel(Stmt stmt) {
this.current = stmt;
if (stmt.et == ET.E2) {
if (stmt.getOp1().vt == LOCAL) {
Local op1 = (Local) stmt.getOp1();
if (stmt.getOp2().vt == LOCAL) {
Local op2 = (Local) stmt.getOp2();
tmp[op1._ls_index] = tmp[op2._ls_index];
return stmt;
} else if (stmt.getOp2().vt == NEW) {
tmp[op1._ls_index] = new Vx(init.get(op1), false);
return stmt;
} else {
travel(stmt.getOp2());
tmp[op1._ls_index] = IGNORED;
return stmt;
}
}
}
if (stmt.st == LABEL) {
LabelStmt labelStmt = (LabelStmt) stmt;
if (labelStmt.phis != null) {
for (AssignStmt phi : labelStmt.phis) {
Local local = (Local) phi.getOp1();
tmp[local._ls_index] = IGNORED;
}
}
return stmt;
}
return super.travel(stmt);
}
@Override
public Value travel(Value op) {
if (op.vt == INVOKE_SPECIAL) {
if (op.getOps().length >= 1) {
InvokeExpr ie = (InvokeExpr) op;
if ("<init>".equals(ie.name)) {
Value thiz = op.getOps()[0];
if (thiz.vt == LOCAL) {
Local local = (Local) thiz;
Vx vx = tmp[local._ls_index];
TObject object = vx.obj;
if (object != null) {
if (object.invokeStmt != null) {
object.useBeforeInit = true;
} else {
vx.init = true;
object.invokeStmt = current;
for (int i = 0; i < tmp.length; i++) {
Vx s = tmp[i];
if (s != null && s.obj == object) {
tmp[i] = IGNORED;
}
}
keepFrame = true;
}
}
}
}
}
}
op = super.travel(op);
if (op.vt == LOCAL) {
use((Local) op);
}
return op;
}
};
@Override
public Vx[] merge(Vx[] srcFrame, Vx[] distFrame, Stmt src, Stmt dist) {
if (distFrame == null) {
distFrame = new Vx[size];
System.arraycopy(srcFrame, 0, distFrame, 0, size);
} else {
for (int i = 0; i < size; i++) {
Vx s = srcFrame[i];
Vx d = distFrame[i];
if (s != null) {
if (d == null) {
distFrame[i] = s;
} else {
if (s != d) {
TObject obj = s.obj;
if (obj != null) {
obj.useBeforeInit = true;
}
obj = d.obj;
if (obj != null) {
obj.useBeforeInit = true;
}
}
}
}
}
}
if (dist.st == LABEL) {
List<AssignStmt> phis = ((LabelStmt) dist).phis;
if (phis != null && phis.size() > 0) {
for (AssignStmt phi : phis) {
for (Value value : phi.getOp2().getOps()) {
Local local = (Local) value;
int i = local._ls_index;
Vx s = srcFrame[i];
Vx d = distFrame[i];
if (d != null) {
if (!d.init) {
TObject obj = d.obj;
if (obj != null) {
obj.useBeforeInit = true;
}
}
} else if (s != null) {
if (!s.init) {
TObject obj = s.obj;
if (obj != null) {
obj.useBeforeInit = true;
}
}
}
}
}
}
}
return distFrame;
}
@Override
public Vx[] initFirstFrame(Stmt first) {
return new Vx[size];
}
@Override
public Vx[] exec(Vx[] frame, Stmt stmt) {
keepFrame = false;
System.arraycopy(frame, 0, tmp, 0, size);
stmtTraveler.travel(stmt);
if (stmt._cfg_froms.size() > 1) {
keepFrame = true;
}
if (!keepFrame) {
stmt.frame = null;
}
return tmp;
}
void use(Local local) {
Vx vx = tmp[local._ls_index];
if (!vx.init) {
TObject object = vx.obj;
if (object != null) {
object.useBeforeInit = true;
}
tmp[local._ls_index] = IGNORED;
}
}
});
for (Iterator<Map.Entry<Local, TObject>> iterator = init.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<Local, TObject> e = iterator.next();
boolean keep = true;
TObject obj = e.getValue();
if (obj.useBeforeInit) {
keep = false;
}
if (obj.invokeStmt == null) {
keep = false;
}
if (!keep) {
iterator.remove();
}
}
}
use of com.googlecode.dex2jar.ir.StmtTraveler in project dex2jar by pxb1988.
the class NpeTransformer method replace.
private void replace(final IrMethod m, final Stmt p) {
StmtTraveler traveler = new StmtTraveler() {
@Override
public Value travel(Value op) {
switch(op.vt) {
case INVOKE_VIRTUAL:
case INVOKE_SPECIAL:
case INVOKE_INTERFACE:
{
Value[] ops = op.getOps();
if (isNull(ops[0])) {
for (int i = 1; i < ops.length; i++) {
travel(ops[i]);
}
throw NPE;
}
}
break;
case ARRAY:
{
if (isNull(op.getOp1())) {
travel(op.getOp2());
throw NPE;
}
}
break;
case FIELD:
{
if (isNull(op.getOp())) {
throw NPE;
}
}
break;
case IDIV:
if (op.getOp2().vt == Value.VT.CONSTANT) {
Constant constant = (Constant) op.getOp2();
if (((Number) constant.value).intValue() == 0) {
travel(op.getOp1());
throw DIVE;
}
}
break;
case LDIV:
if (op.getOp2().vt == Value.VT.CONSTANT) {
Constant constant = (Constant) op.getOp2();
if (((Number) constant.value).longValue() == 0) {
travel(op.getOp1());
throw DIVE;
}
}
break;
case NEW_ARRAY:
if (op.getOp().vt == Value.VT.CONSTANT) {
Constant constant = (Constant) op.getOp();
if (((Number) constant.value).intValue() < 0) {
throw NEGATIVE_ARRAY_SIZE;
}
}
break;
case NEW_MUTI_ARRAY:
for (Value size : op.getOps()) {
if (size.vt == Value.VT.CONSTANT) {
Constant constant = (Constant) size;
if (((Number) constant.value).intValue() < 0) {
throw NEGATIVE_ARRAY_SIZE;
} else {
travel(size);
}
}
}
break;
default:
}
Value sop = super.travel(op);
if (sop.vt == Value.VT.LOCAL || sop.vt == Value.VT.CONSTANT) {
return sop;
} else {
Local local = new Local();
m.locals.add(local);
m.stmts.insertBefore(p, Stmts.nAssign(local, sop));
return local;
}
}
};
try {
switch(p.et) {
case E0:
// impossible
break;
case E1:
traveler.travel(p.getOp());
break;
case E2:
if (p.st == Stmt.ST.ASSIGN) {
switch(p.getOp1().vt) {
case ARRAY:
traveler.travel(p.getOp1().getOp1());
traveler.travel(p.getOp1().getOp2());
traveler.travel(p.getOp2());
break;
case FIELD:
traveler.travel(p.getOp1().getOp());
traveler.travel(p.getOp2());
break;
case STATIC_FIELD:
case LOCAL:
traveler.travel(p.getOp2());
break;
default:
}
} else if (p.st == Stmt.ST.FILL_ARRAY_DATA) {
if (isNull(p.getOp1())) {
throw NPE;
} else {
traveler.travel(p.getOp1());
}
}
break;
case En:
}
} catch (MustThrowException e) {
if (e == NPE) {
m.stmts.insertBefore(p, Stmts.nThrow(Exprs.nInvokeNew(new Value[0], new String[0], "Ljava/lang/NullPointerException;")));
} else if (e == DIVE) {
m.stmts.insertBefore(p, Stmts.nThrow(Exprs.nInvokeNew(new Value[] { Exprs.nString("divide by zero") }, new String[] { "Ljava/lang/String;" }, "Ljava/lang/ArithmeticException;")));
} else if (e == NEGATIVE_ARRAY_SIZE) {
m.stmts.insertBefore(p, Stmts.nThrow(Exprs.nInvokeNew(new Value[0], new String[0], "Ljava/lang/NegativeArraySizeException;")));
}
}
}
use of com.googlecode.dex2jar.ir.StmtTraveler in project dex2jar by pxb1988.
the class DecryptStringCmd method optAndDecrypt.
public void optAndDecrypt(IrMethod irMethod, final Map<MethodConfig, MethodConfig> map) {
T_deadCode.transform(irMethod);
T_cleanLabel.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
T_zero.transform(irMethod);
if (T_npe.transformReportChanged(irMethod)) {
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
}
T_new.transform(irMethod);
T_fillArray.transform(irMethod);
T_agg.transform(irMethod);
T_voidInvoke.transform(irMethod);
new StmtTraveler() {
@Override
public Value travel(Value op) {
op = super.travel(op);
if (op.vt == Value.VT.INVOKE_STATIC) {
InvokeExpr ie = (InvokeExpr) op;
MethodConfig key = DecryptStringCmd.this.key;
key.owner = ie.owner.substring(1, ie.owner.length() - 1);
key.name = ie.name;
key.desc = buildMethodDesc(ie.args, ie.ret);
MethodConfig c = map.get(key);
if (c != null) {
try {
Method jmethod = c.jmethod;
if (ie.args.length != jmethod.getParameterTypes().length) {
throw new RuntimeException();
}
Object[] args = new Object[ie.args.length];
for (int i = 0; i < args.length; i++) {
args[i] = convertIr2Jobj(ie.getOps()[i], ie.args[i]);
}
if (verbose) {
System.out.println(" > calling " + jmethod + " with arguments " + v(args));
}
String str = (String) jmethod.invoke(null, args);
if (verbose) {
System.out.println(" -> " + Escape.v(str));
}
return Exprs.nString(str);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return op;
}
}.travel(irMethod.stmts);
T_type.transform(irMethod);
T_unssa.transform(irMethod);
T_trimEx.transform(irMethod);
T_ir2jRegAssign.transform(irMethod);
}
use of com.googlecode.dex2jar.ir.StmtTraveler in project dex2jar by pxb1988.
the class ArrayElementTransformer method transformReportChanged.
@Override
public boolean transformReportChanged(IrMethod method) {
Set<Local> arrays = searchForArrayObject(method);
if (arrays.size() == 0) {
return false;
}
for (Local local : method.locals) {
local._ls_index = -1;
}
int i = 0;
for (Local local : arrays) {
local._ls_index = i++;
}
final int size = i;
Cfg.createCFG(method);
final List<ArrayValue> values = new ArrayList<>();
final List<Stmt> used = new ArrayList<>();
Cfg.dfs(method.stmts, new Cfg.FrameVisitor<ArrayValue[]>() {
Set<Integer> phis = new HashSet<>();
@Override
public ArrayValue[] merge(ArrayValue[] srcFrame, ArrayValue[] distFrame, Stmt src, Stmt dist) {
if (dist.st == Stmt.ST.LABEL) {
LabelStmt labelStmt = (LabelStmt) dist;
if (labelStmt.phis != null) {
for (AssignStmt phi : labelStmt.phis) {
int idx = ((Local) phi.getOp1())._ls_index;
if (idx >= 0) {
phis.add(idx);
}
}
}
}
if (distFrame == null) {
distFrame = new ArrayValue[size];
for (int i = 0; i < size; i++) {
if (phis.contains(i)) {
ArrayValue aov = new ArrayValue();
values.add(aov);
aov.s = ArrayValue.S.UNKNOWN;
aov.indexType = ArrayValue.IndexType.NONE;
aov.stmt = dist;
distFrame[i] = aov;
} else {
ArrayValue arc = srcFrame[i];
if (arc != null) {
ArrayValue aov = new ArrayValue();
values.add(aov);
aov.s = ArrayValue.S.INHERIT;
aov.indexType = ArrayValue.IndexType.NONE;
aov.stmt = dist;
aov.parent = arc;
distFrame[i] = aov;
}
}
}
} else {
for (int i = 0; i < size; i++) {
if (phis.contains(i)) {
continue;
}
ArrayValue arc = srcFrame[i];
ArrayValue aov = distFrame[i];
if (arc != null && aov != null) {
if (aov.parent == null) {
aov.parent = arc;
} else if (!aov.parent.equals(arc)) {
if (aov.otherParents == null) {
aov.otherParents = new HashSet<>();
}
aov.otherParents.add(arc);
}
}
}
}
phis.clear();
return distFrame;
}
@Override
public ArrayValue[] initFirstFrame(Stmt first) {
return new ArrayValue[size];
}
ArrayValue[] tmp = new ArrayValue[size];
Stmt currentStmt;
@Override
public ArrayValue[] exec(ArrayValue[] frame, Stmt stmt) {
currentStmt = stmt;
System.arraycopy(frame, 0, tmp, 0, size);
if (stmt.st == Stmt.ST.ASSIGN) {
// create an array
if (stmt.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) stmt.getOp1();
use(stmt.getOp2());
if (local._ls_index >= 0) {
Value op2 = stmt.getOp2();
if (op2.vt == Value.VT.NEW_ARRAY) {
ArrayValue av = new ArrayValue();
av.s = ArrayValue.S.DEFAULT;
av.size = op2.getOp();
values.add(av);
tmp[local._ls_index] = av;
} else if (op2.vt == Value.VT.FILLED_ARRAY) {
ArrayValue av = new ArrayValue();
av.s = ArrayValue.S.DEFAULT;
av.indexType = ArrayValue.IndexType.CONST;
av.stmt = stmt;
FilledArrayExpr fae = (FilledArrayExpr) stmt.getOp2();
av.size = Exprs.nInt(fae.getOps().length);
Value[] ops = fae.getOps();
for (int i = 0; i < ops.length; i++) {
av.elements1.put(i, ops[i]);
}
values.add(av);
tmp[local._ls_index] = av;
} else if (op2.vt == Value.VT.CONSTANT) {
Object cst = ((Constant) op2).value;
if (cst != null && !cst.equals(Constant.Null) && cst.getClass().isArray()) {
ArrayValue av = new ArrayValue();
av.s = ArrayValue.S.DEFAULT;
av.indexType = ArrayValue.IndexType.CONST;
av.stmt = stmt;
int size = Array.getLength(cst);
av.size = Exprs.nInt(size);
for (int i = 0; i < size; i++) {
av.elements1.put(i, Exprs.nConstant(Array.get(cst, size)));
}
values.add(av);
tmp[local._ls_index] = av;
} else {
ArrayValue av = new ArrayValue();
values.add(av);
av.s = ArrayValue.S.UNKNOWN;
av.indexType = ArrayValue.IndexType.NONE;
av.stmt = stmt;
tmp[local._ls_index] = av;
}
} else {
ArrayValue av = new ArrayValue();
values.add(av);
av.s = ArrayValue.S.UNKNOWN;
av.indexType = ArrayValue.IndexType.NONE;
av.stmt = stmt;
tmp[local._ls_index] = av;
}
}
// assign index1
} else if (stmt.getOp1().vt == Value.VT.ARRAY) {
use(stmt.getOp2());
ArrayExpr ae = (ArrayExpr) stmt.getOp1();
if (ae.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) ae.getOp1();
Value index = ae.getOp2();
if (local._ls_index >= 0) {
if (index.vt == Value.VT.CONSTANT) {
ArrayValue parent = tmp[local._ls_index];
ArrayValue av = new ArrayValue();
values.add(av);
av.parent = parent;
av.elements1.put(((Number) (((Constant) index).value)).intValue(), stmt.getOp2());
av.indexType = ArrayValue.IndexType.CONST;
av.s = ArrayValue.S.INHERIT;
av.stmt = stmt;
tmp[local._ls_index] = av;
} else if (index.vt == Value.VT.LOCAL) {
ArrayValue parent = tmp[local._ls_index];
ArrayValue av = new ArrayValue();
values.add(av);
av.parent = parent;
av.elements1.put(index, stmt.getOp2());
av.indexType = ArrayValue.IndexType.LOCAL;
av.s = ArrayValue.S.INHERIT;
av.stmt = stmt;
tmp[local._ls_index] = av;
} else {
ArrayValue av = new ArrayValue();
values.add(av);
av.s = ArrayValue.S.UNKNOWN;
av.indexType = ArrayValue.IndexType.NONE;
av.stmt = stmt;
tmp[local._ls_index] = av;
}
} else {
use(stmt.getOp1());
}
} else {
use(stmt.getOp1());
}
} else {
use(stmt.getOp1());
use(stmt.getOp2());
}
// assign index2
} else if (stmt.st == Stmt.ST.FILL_ARRAY_DATA) {
if (stmt.getOp1().vt == Value.VT.LOCAL) {
Local local = (Local) stmt.getOp1();
if (local._ls_index >= 0) {
Object array = ((Constant) stmt.getOp2()).value;
ArrayValue parent = tmp[local._ls_index];
ArrayValue av = new ArrayValue();
values.add(av);
av.parent = parent;
int size = Array.getLength(array);
av.size = Exprs.nInt(size);
for (int i = 0; i < size; i++) {
av.elements1.put(i, Exprs.nConstant(Array.get(array, i)));
}
av.indexType = ArrayValue.IndexType.CONST;
av.s = ArrayValue.S.INHERIT;
av.stmt = stmt;
tmp[local._ls_index] = av;
}
} else {
use(stmt.getOp1());
}
} else {
switch(stmt.et) {
case E0:
break;
case E1:
use(stmt.getOp());
break;
case E2:
use(stmt.getOp1());
use(stmt.getOp2());
break;
case En:
throw new RuntimeException();
}
}
return tmp;
}
private void use(Value v) {
switch(v.et) {
case E0:
break;
case E1:
use(v.getOp());
break;
case E2:
Value op1 = v.getOp1();
Value op2 = v.getOp2();
use(op1);
use(op2);
if (v.vt == Value.VT.ARRAY) {
if (op1.vt == Value.VT.LOCAL && (op2.vt == Value.VT.LOCAL || op2.vt == Value.VT.CONSTANT)) {
Local local = (Local) op1;
if (local._ls_index > 0) {
used.add(currentStmt);
}
}
}
break;
case En:
for (Value op : v.getOps()) {
use(op);
}
break;
}
}
});
for (Stmt p : method.stmts) {
}
new StmtTraveler() {
@Override
public Value travel(Value op) {
op = super.travel(op);
if (op.vt == Value.VT.ARRAY) {
}
return op;
}
}.travel(method.stmts);
return false;
}
Aggregations