mirror of
https://github.com/pxb1988/dex2jar.git
synced 2024-11-23 05:10:11 +00:00
parent
80a81b317f
commit
62eba635fd
@ -292,7 +292,10 @@ public class DecryptStringCmd extends BaseCmd {
|
||||
// convert ir to m3
|
||||
MethodNode m3 = new MethodNode();
|
||||
m3.tryCatchBlocks = new ArrayList<>();
|
||||
new IR2JConverter(true).convert(irMethod, m3);
|
||||
new IR2JConverter()
|
||||
.ir(irMethod)
|
||||
.asm(m3)
|
||||
.convert();
|
||||
|
||||
// copy back m3 to m
|
||||
m.maxLocals = -1;
|
||||
|
@ -34,24 +34,44 @@ import com.googlecode.dex2jar.ir.stmt.Stmt.ST;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
public class IR2JConverter implements Opcodes {
|
||||
|
||||
public static final int MAX_FILL_ARRAY_BYTES = 500;
|
||||
private boolean optimizeSynchronized = false;
|
||||
|
||||
Dex2Asm.ClzCtx clzCtx;
|
||||
IrMethod ir;
|
||||
MethodVisitor asm;
|
||||
public IR2JConverter() {
|
||||
super();
|
||||
}
|
||||
|
||||
public IR2JConverter(boolean optimizeSynchronized) {
|
||||
super();
|
||||
public IR2JConverter optimizeSynchronized(boolean optimizeSynchronized) {
|
||||
this.optimizeSynchronized = optimizeSynchronized;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void convert(IrMethod ir, MethodVisitor asm) {
|
||||
public IR2JConverter clzCtx(Dex2Asm.ClzCtx clzCtx) {
|
||||
this.clzCtx = clzCtx;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IR2JConverter ir(IrMethod ir) {
|
||||
this.ir = ir;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IR2JConverter asm(MethodVisitor asm) {
|
||||
this.asm = asm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void convert() {
|
||||
mapLabelStmt(ir);
|
||||
reBuildInstructions(ir, asm);
|
||||
reBuildTryCatchBlocks(ir, asm);
|
||||
@ -229,15 +249,45 @@ public class IR2JConverter implements Opcodes {
|
||||
} else {
|
||||
elementType = "I";
|
||||
}
|
||||
int iastoreOP = getOpcode(elementType, IASTORE);
|
||||
accept(e2.getOp1(), asm);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
asm.visitInsn(DUP);
|
||||
asm.visitLdcInsn(i);
|
||||
asm.visitLdcInsn(Array.get(arrayData, i));
|
||||
asm.visitInsn(iastoreOP);
|
||||
boolean genBig = false;
|
||||
try {
|
||||
if (this.clzCtx != null
|
||||
&& "BSIJ".contains(elementType)) {
|
||||
|
||||
byte[] data = toLittleEndianArray(arrayData);
|
||||
|
||||
if (data != null && data.length > MAX_FILL_ARRAY_BYTES) {
|
||||
accept(e2.getOp1(), asm);
|
||||
asm.visitLdcInsn(0);
|
||||
constLargeArray(asm, data, elementType);
|
||||
asm.visitLdcInsn(0);
|
||||
asm.visitLdcInsn(arraySize);
|
||||
|
||||
asm.visitMethodInsn(Opcodes.INVOKESTATIC,
|
||||
"java/lang/System",
|
||||
"arraycopy",
|
||||
"(Ljava/lang/Object;ILjava/lang/Object;II)V",
|
||||
false
|
||||
);
|
||||
genBig = true;
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
// any exception, revert to normal
|
||||
}
|
||||
|
||||
if (!genBig) {
|
||||
int iastoreOP = getOpcode(elementType, IASTORE);
|
||||
accept(e2.getOp1(), asm);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
asm.visitInsn(DUP);
|
||||
asm.visitLdcInsn(i);
|
||||
asm.visitLdcInsn(Array.get(arrayData, i));
|
||||
asm.visitInsn(iastoreOP);
|
||||
}
|
||||
asm.visitInsn(POP);
|
||||
}
|
||||
asm.visitInsn(POP);
|
||||
} else {
|
||||
FilledArrayExpr filledArrayExpr = (FilledArrayExpr) e2.getOp2();
|
||||
int arraySize = filledArrayExpr.ops.length;
|
||||
@ -248,15 +298,47 @@ public class IR2JConverter implements Opcodes {
|
||||
} else {
|
||||
elementType = "I";
|
||||
}
|
||||
int iastoreOP = getOpcode(elementType, IASTORE);
|
||||
accept(e2.getOp1(), asm);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
asm.visitInsn(DUP);
|
||||
asm.visitLdcInsn(i);
|
||||
accept(filledArrayExpr.ops[i], asm);
|
||||
asm.visitInsn(iastoreOP);
|
||||
|
||||
boolean genBig = false;
|
||||
try {
|
||||
if (this.clzCtx != null
|
||||
&& "BSIJ".contains(elementType)
|
||||
&& isConstant(filledArrayExpr.ops)) {
|
||||
// create a 500-len byte array, may cause 'Method code too large!'
|
||||
// convert it to a base64 decoding
|
||||
byte[] data = collectDataAsByteArray(filledArrayExpr.ops, elementType);
|
||||
if (data != null && data.length > MAX_FILL_ARRAY_BYTES) {
|
||||
accept(e2.getOp1(), asm);
|
||||
asm.visitLdcInsn(0);
|
||||
constLargeArray(asm, data, elementType);
|
||||
asm.visitLdcInsn(0);
|
||||
asm.visitLdcInsn(arraySize);
|
||||
|
||||
asm.visitMethodInsn(INVOKESTATIC,
|
||||
"java/lang/System",
|
||||
"arraycopy",
|
||||
"(Ljava/lang/Object;ILjava/lang/Object;II)V",
|
||||
false
|
||||
);
|
||||
|
||||
genBig = true;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
// any exception, revert to normal
|
||||
}
|
||||
|
||||
if (!genBig) {
|
||||
int iastoreOP = getOpcode(elementType, IASTORE);
|
||||
accept(e2.getOp1(), asm);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
asm.visitInsn(DUP);
|
||||
asm.visitLdcInsn(i);
|
||||
accept(filledArrayExpr.ops[i], asm);
|
||||
asm.visitInsn(iastoreOP);
|
||||
}
|
||||
asm.visitInsn(POP);
|
||||
}
|
||||
asm.visitInsn(POP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -390,6 +472,35 @@ public class IR2JConverter implements Opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
private void constLargeArray(MethodVisitor asm, byte[] data, String elementType) {
|
||||
String cst = hexEncode(data);
|
||||
if (cst.length() > 65535) { // asm have the limit
|
||||
asm.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder");
|
||||
asm.visitInsn(Opcodes.DUP);
|
||||
asm.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
|
||||
|
||||
for (int i = 0; i < cst.length(); i += 65500) {
|
||||
int a = Math.min(65500, cst.length() - i);
|
||||
asm.visitLdcInsn(cst.substring(i, i + a));
|
||||
asm.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder",
|
||||
"append",
|
||||
"(Ljava/lang/String;)Ljava/lang/StringBuilder;",
|
||||
false
|
||||
);
|
||||
}
|
||||
asm.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder",
|
||||
"toString",
|
||||
"()Ljava/lang/String;",
|
||||
false
|
||||
);
|
||||
} else {
|
||||
asm.visitLdcInsn(cst);
|
||||
}
|
||||
|
||||
asm.visitMethodInsn(Opcodes.INVOKESTATIC, toInternal(this.clzCtx.classDescriptor),
|
||||
this.clzCtx.buildHexDecodeMethodName(elementType), "(Ljava/lang/String;)[" + elementType, false);
|
||||
}
|
||||
|
||||
private static boolean isLocalWithIndex(Value v, int i) {
|
||||
return v.vt == VT.LOCAL && ((Local) v)._ls_index == i;
|
||||
}
|
||||
@ -556,7 +667,7 @@ public class IR2JConverter implements Opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
private static void accept(Value value, MethodVisitor asm) {
|
||||
private void accept(Value value, MethodVisitor asm) {
|
||||
|
||||
switch (value.et) {
|
||||
case E0:
|
||||
@ -595,10 +706,17 @@ public class IR2JConverter implements Opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
private static void reBuildEnExpression(EnExpr value, MethodVisitor asm) {
|
||||
public static String hexEncode(byte[] data) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : data) {
|
||||
sb.append(String.format("%02x", b & 0xFF));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void reBuildEnExpression(EnExpr value, MethodVisitor asm) {
|
||||
if (value.vt == VT.FILLED_ARRAY) {
|
||||
FilledArrayExpr fae = (FilledArrayExpr) value;
|
||||
reBuildE1Expression(Exprs.nNewArray(fae.type, Exprs.nInt(fae.ops.length)), asm);
|
||||
String tp1 = fae.valueType;
|
||||
int xastore = IASTORE;
|
||||
String elementType = null;
|
||||
@ -607,6 +725,25 @@ public class IR2JConverter implements Opcodes {
|
||||
xastore = getOpcode(elementType, IASTORE);
|
||||
}
|
||||
|
||||
try {
|
||||
if (this.clzCtx != null
|
||||
&& elementType != null
|
||||
&& "BSIJ".contains(elementType)
|
||||
&& isConstant(fae.ops)) {
|
||||
|
||||
byte[] data = collectDataAsByteArray(fae.ops, elementType);
|
||||
if (data != null && data.length > MAX_FILL_ARRAY_BYTES) {
|
||||
constLargeArray(asm, data, elementType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
// any exception, revert to normal
|
||||
}
|
||||
|
||||
reBuildE1Expression(Exprs.nNewArray(fae.type, Exprs.nInt(fae.ops.length)), asm);
|
||||
|
||||
|
||||
for (int i = 0; i < fae.ops.length; i++) {
|
||||
if (fae.ops[i] == null)
|
||||
continue;
|
||||
@ -720,6 +857,91 @@ public class IR2JConverter implements Opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] collectDataAsByteArray(Value[] ops, String t) {
|
||||
switch (t) {
|
||||
case "B": {
|
||||
byte[] d = new byte[ops.length];
|
||||
for (int i = 0, opsLength = ops.length; i < opsLength; i++) {
|
||||
Value op = ops[i];
|
||||
Constant cst = (Constant) op;
|
||||
d[i] = ((Number) cst.value).byteValue();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
case "S": {
|
||||
short[] d = new short[ops.length];
|
||||
for (int i = 0, opsLength = ops.length; i < opsLength; i++) {
|
||||
Value op = ops[i];
|
||||
Constant cst = (Constant) op;
|
||||
d[i] = ((Number) cst.value).shortValue();
|
||||
}
|
||||
return toLittleEndianArray(d);
|
||||
}
|
||||
case "I": {
|
||||
int[] d = new int[ops.length];
|
||||
for (int i = 0, opsLength = ops.length; i < opsLength; i++) {
|
||||
Value op = ops[i];
|
||||
Constant cst = (Constant) op;
|
||||
d[i] = ((Number) cst.value).intValue();
|
||||
}
|
||||
return toLittleEndianArray(d);
|
||||
}
|
||||
case "J": {
|
||||
long[] d = new long[ops.length];
|
||||
for (int i = 0, opsLength = ops.length; i < opsLength; i++) {
|
||||
Value op = ops[i];
|
||||
Constant cst = (Constant) op;
|
||||
d[i] = ((Number) cst.value).longValue();
|
||||
}
|
||||
return toLittleEndianArray(d);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[] toLittleEndianArray(Object d) {
|
||||
if (d instanceof byte[]) {
|
||||
return (byte[]) d;
|
||||
} else if (d instanceof short[]) {
|
||||
return toLittleEndianArray((short[]) d);
|
||||
} else if (d instanceof int[]) {
|
||||
return toLittleEndianArray((int[]) d);
|
||||
} else if (d instanceof long[]) {
|
||||
return toLittleEndianArray((long[]) d);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static byte[] toLittleEndianArray(long[] d) {
|
||||
ByteBuffer b = ByteBuffer.allocate(d.length *8);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
b.asLongBuffer().put(d);
|
||||
return b.array();
|
||||
}
|
||||
|
||||
private static byte[] toLittleEndianArray(int[] d) {
|
||||
ByteBuffer b = ByteBuffer.allocate(d.length *4);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
b.asIntBuffer().put(d);
|
||||
return b.array();
|
||||
}
|
||||
|
||||
private static byte[] toLittleEndianArray(short[] d) {
|
||||
ByteBuffer b = ByteBuffer.allocate(d.length *2);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
b.asShortBuffer().put(d);
|
||||
return b.array();
|
||||
}
|
||||
|
||||
private static boolean isConstant(Value[] ops) {
|
||||
for (Value op : ops) {
|
||||
if (op.vt != VT.CONSTANT) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void box(String provideType, String expectedType, MethodVisitor asm) {
|
||||
if(provideType.equals(expectedType)){
|
||||
return;
|
||||
@ -848,7 +1070,7 @@ public class IR2JConverter implements Opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
private static void reBuildE1Expression(E1Expr e1, MethodVisitor asm) {
|
||||
private void reBuildE1Expression(E1Expr e1, MethodVisitor asm) {
|
||||
accept(e1.getOp(), asm);
|
||||
switch (e1.vt) {
|
||||
case STATIC_FIELD: {
|
||||
@ -924,7 +1146,7 @@ public class IR2JConverter implements Opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
private static void reBuildE2Expression(E2Expr e2, MethodVisitor asm) {
|
||||
private void reBuildE2Expression(E2Expr e2, MethodVisitor asm) {
|
||||
String type = e2.op2.valueType;
|
||||
accept(e2.op1, asm);
|
||||
if ((e2.vt == VT.ADD || e2.vt == VT.SUB) && e2.op2.vt == VT.CONSTANT) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.googlecode.d2j.dex;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
import com.googlecode.d2j.converter.Dex2IRConverter;
|
||||
@ -14,7 +16,19 @@ import com.googlecode.dex2jar.ir.ts.*;
|
||||
import com.googlecode.dex2jar.ir.ts.array.FillArrayTransformer;
|
||||
|
||||
public class Dex2Asm {
|
||||
public static class ClzCtx {
|
||||
public String classDescriptor;
|
||||
public String hexDecodeMethodNamePrefix;
|
||||
|
||||
public String buildHexDecodeMethodName(String x) {
|
||||
if (hexDecodeMethodNamePrefix == null) {
|
||||
byte[] d = new byte[4];
|
||||
new Random().nextBytes(d);
|
||||
hexDecodeMethodNamePrefix = "$d2j$hex$" + IR2JConverter.hexEncode(d);
|
||||
}
|
||||
return hexDecodeMethodNamePrefix + "$decode_" + x;
|
||||
}
|
||||
}
|
||||
protected static class Clz {
|
||||
public int access;
|
||||
public Clz enclosingClass;
|
||||
@ -440,17 +454,42 @@ public class Dex2Asm {
|
||||
}
|
||||
}
|
||||
if (classNode.methods != null) {
|
||||
ClzCtx clzCtx = new ClzCtx();
|
||||
clzCtx.classDescriptor = classNode.className;
|
||||
for (DexMethodNode methodNode : classNode.methods) {
|
||||
convertMethod(classNode, methodNode, cv);
|
||||
convertMethod(classNode, methodNode, cv, clzCtx);
|
||||
}
|
||||
if (clzCtx.hexDecodeMethodNamePrefix != null) {
|
||||
addHexDecodeMethod(cv, clzCtx.hexDecodeMethodNamePrefix);
|
||||
}
|
||||
}
|
||||
cv.visitEnd();
|
||||
}
|
||||
|
||||
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
|
||||
private void addHexDecodeMethod(ClassVisitor outCV, String hexDecodeMethodNameBase) {
|
||||
// the .data is a class file compiled from res.Hex
|
||||
try (InputStream is = Dex2Asm.class.getResourceAsStream("/d2j_hex_decode_stub.data")) {
|
||||
ClassReader cr = new ClassReader(is);
|
||||
cr.accept(new ClassVisitor(Opcodes.ASM5) {
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
if (name.startsWith("decode")) {
|
||||
return outCV.visitMethod(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
|
||||
hexDecodeMethodNameBase + "$" + name,
|
||||
desc, signature, exceptions
|
||||
);
|
||||
} else {
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
}
|
||||
}, ClassReader.EXPAND_FRAMES);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("fail to add hex.decode", e);
|
||||
}
|
||||
}
|
||||
public void convertCode(DexMethodNode methodNode, MethodVisitor mv, ClzCtx clzCtx) {
|
||||
IrMethod irMethod = dex2ir(methodNode);
|
||||
optimize(irMethod);
|
||||
ir2j(irMethod, mv);
|
||||
ir2j(irMethod, mv, clzCtx);
|
||||
}
|
||||
|
||||
public void convertDex(DexFileNode fileNode, ClassVisitorFactory cvf) {
|
||||
@ -546,7 +585,7 @@ public class Dex2Asm {
|
||||
return ele;
|
||||
}
|
||||
|
||||
public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, ClassVisitor cv) {
|
||||
public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, ClassVisitor cv, ClzCtx clzCtx) {
|
||||
|
||||
MethodVisitor mv = collectBasicMethodInfo(methodNode, cv);
|
||||
|
||||
@ -593,7 +632,7 @@ public class Dex2Asm {
|
||||
if ((NO_CODE_MASK & methodNode.access) == 0) { // has code
|
||||
if (methodNode.codeNode != null) {
|
||||
mv.visitCode();
|
||||
convertCode(methodNode, mv);
|
||||
convertCode(methodNode, mv, clzCtx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -624,8 +663,13 @@ public class Dex2Asm {
|
||||
return clz;
|
||||
}
|
||||
|
||||
public void ir2j(IrMethod irMethod, MethodVisitor mv) {
|
||||
new IR2JConverter(false).convert(irMethod, mv);
|
||||
public void ir2j(IrMethod irMethod, MethodVisitor mv, ClzCtx clzCtx) {
|
||||
new IR2JConverter()
|
||||
.optimizeSynchronized(false)
|
||||
.clzCtx(clzCtx)
|
||||
.ir(irMethod)
|
||||
.asm(mv)
|
||||
.convert();
|
||||
mv.visitMaxs(-1, -1);
|
||||
}
|
||||
|
||||
@ -645,15 +689,16 @@ public class Dex2Asm {
|
||||
T_agg.transform(irMethod);
|
||||
T_multiArray.transform(irMethod);
|
||||
T_voidInvoke.transform(irMethod);
|
||||
T_type.transform(irMethod);
|
||||
|
||||
{
|
||||
// https://github.com/pxb1988/dex2jar/issues/477
|
||||
// dead code found in unssa, clean up
|
||||
T_deadCode.transform(irMethod);
|
||||
T_removeLocal.transform(irMethod);
|
||||
T_removeConst.transform(irMethod);
|
||||
T_unssa.transform(irMethod);
|
||||
}
|
||||
T_type.transform(irMethod);
|
||||
T_unssa.transform(irMethod);
|
||||
T_trimEx.transform(irMethod);
|
||||
T_ir2jRegAssign.transform(irMethod);
|
||||
}
|
||||
|
@ -124,12 +124,12 @@ public class Dex2jar {
|
||||
};
|
||||
|
||||
new ExDex2Asm(exceptionHandler) {
|
||||
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
|
||||
public void convertCode(DexMethodNode methodNode, MethodVisitor mv, ClzCtx clzCtx) {
|
||||
if ((readerConfig & DexFileReader.SKIP_CODE) != 0 && methodNode.method.getName().equals("<clinit>")) {
|
||||
// also skip clinit
|
||||
return;
|
||||
}
|
||||
super.convertCode(methodNode, mv);
|
||||
super.convertCode(methodNode, mv, clzCtx);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -169,8 +169,13 @@ public class Dex2jar {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ir2j(IrMethod irMethod, MethodVisitor mv) {
|
||||
new IR2JConverter(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config)).convert(irMethod, mv);
|
||||
public void ir2j(IrMethod irMethod, MethodVisitor mv, ClzCtx clzCtx) {
|
||||
new IR2JConverter()
|
||||
.optimizeSynchronized(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config))
|
||||
.clzCtx(clzCtx)
|
||||
.ir(irMethod)
|
||||
.asm(mv)
|
||||
.convert();
|
||||
}
|
||||
}.convertDex(fileNode, cvf);
|
||||
|
||||
|
@ -32,12 +32,12 @@ public class ExDex2Asm extends Dex2Asm {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
|
||||
public void convertCode(DexMethodNode methodNode, MethodVisitor mv, ClzCtx clzCtx) {
|
||||
MethodVisitor mw = AsmBridge.searchMethodWriter(mv);
|
||||
MethodNode mn = new MethodNode(Opcodes.ASM5, methodNode.access, methodNode.method.getName(),
|
||||
methodNode.method.getDesc(), null, null);
|
||||
try {
|
||||
super.convertCode(methodNode, mn);
|
||||
super.convertCode(methodNode, mn, clzCtx);
|
||||
} catch (Exception ex) {
|
||||
if (exceptionHandler == null) {
|
||||
throw new DexException(ex, "fail convert code for %s", methodNode.method);
|
||||
|
BIN
dex-translator/src/main/resources/d2j_hex_decode_stub.data
Normal file
BIN
dex-translator/src/main/resources/d2j_hex_decode_stub.data
Normal file
Binary file not shown.
@ -296,9 +296,9 @@ public abstract class TestUtils {
|
||||
// 1. convert to .class
|
||||
Dex2Asm dex2Asm = new Dex2Asm() {
|
||||
@Override
|
||||
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
|
||||
public void convertCode(DexMethodNode methodNode, MethodVisitor mv, ClzCtx clzCtx) {
|
||||
try {
|
||||
super.convertCode(methodNode, mv);
|
||||
super.convertCode(methodNode, mv, clzCtx);
|
||||
} catch (Exception ex) {
|
||||
BaksmaliDumper d = new BaksmaliDumper();
|
||||
try {
|
||||
|
65
dex-translator/src/test/java/res/Hex.java
Normal file
65
dex-translator/src/test/java/res/Hex.java
Normal file
@ -0,0 +1,65 @@
|
||||
package res;
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class Hex {
|
||||
public static long[] decode_J(String src) {
|
||||
byte[] d = decode_B(src);
|
||||
ByteBuffer b = ByteBuffer.wrap(d);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
LongBuffer s = b.asLongBuffer();
|
||||
long[] data = new long[d.length / 8];
|
||||
s.get(data);
|
||||
return data;
|
||||
}
|
||||
public static int[] decode_I(String src) {
|
||||
byte[] d = decode_B(src);
|
||||
ByteBuffer b = ByteBuffer.wrap(d);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
IntBuffer s = b.asIntBuffer();
|
||||
int[] data = new int[d.length / 4];
|
||||
s.get(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static short[] decode_S(String src) {
|
||||
byte[] d = decode_B(src);
|
||||
ByteBuffer b = ByteBuffer.wrap(d);
|
||||
b.order(ByteOrder.LITTLE_ENDIAN);
|
||||
ShortBuffer s = b.asShortBuffer();
|
||||
short[] data = new short[d.length / 2];
|
||||
s.get(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static byte[] decode_B(String src) {
|
||||
char[] d = src.toCharArray();
|
||||
byte[] ret = new byte[src.length() / 2];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
char h = d[2 * i];
|
||||
char l = d[2 * i + 1];
|
||||
int hh = 0;
|
||||
if (h >= '0' && h <= '9') {
|
||||
hh = h - '0';
|
||||
} else if (h >= 'a' && h <= 'f') {
|
||||
hh = h - 'a' + 10;
|
||||
} else if (h >= 'A' && h <= 'F') {
|
||||
hh = h - 'A' + 10;
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
int ll = 0;
|
||||
if (l >= '0' && l <= '9') {
|
||||
ll = h - '0';
|
||||
} else if (l >= 'a' && l <= 'f') {
|
||||
ll = h - 'a' + 10;
|
||||
} else if (l >= 'A' && l <= 'F') {
|
||||
ll = h - 'A' + 10;
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
d[i] = (char) ((hh << 4) | ll);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
|
||||
.class Lcode.Large;
|
||||
.class Lcode/Large;
|
||||
.super Lcode/LargeS;
|
||||
|
||||
.method private static constructor <clinit>()V
|
||||
.catchall { :L2 .. :L3 } :L0
|
Loading…
Reference in New Issue
Block a user