Skip to content

Commit

Permalink
fix Method code to large (pxb1988#513)
Browse files Browse the repository at this point in the history
* fix Method code to large

* format
  • Loading branch information
pxb1988 authored Oct 30, 2021
1 parent 80a81b3 commit 62eba63
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,10 @@ private boolean decryptByIr(ClassNode cn, Map<MethodConfig, MethodConfig> map) {
// 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,44 @@
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 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(IrMethod ir, MethodVisitor asm) {
public void convert() {
mapLabelStmt(ir);
reBuildInstructions(ir, asm);
reBuildTryCatchBlocks(ir, asm);
Expand Down Expand Up @@ -229,15 +249,45 @@ private void reBuildInstructions(IrMethod ir, MethodVisitor asm) {
} 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;
Expand All @@ -248,15 +298,47 @@ private void reBuildInstructions(IrMethod ir, MethodVisitor asm) {
} 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;
Expand Down Expand Up @@ -390,6 +472,35 @@ private void reBuildInstructions(IrMethod ir, MethodVisitor asm) {
}
}

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;
}
Expand Down Expand Up @@ -556,7 +667,7 @@ static int getOpcode(String v, int op) {
}
}

private static void accept(Value value, MethodVisitor asm) {
private void accept(Value value, MethodVisitor asm) {

switch (value.et) {
case E0:
Expand Down Expand Up @@ -595,10 +706,17 @@ private static void accept(Value value, MethodVisitor asm) {
}
}

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;
Expand All @@ -607,6 +725,25 @@ private static void reBuildEnExpression(EnExpr value, MethodVisitor asm) {
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;
Expand Down Expand Up @@ -720,6 +857,91 @@ private static void reBuildEnExpression(EnExpr value, MethodVisitor asm) {
}
}

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;
Expand Down Expand Up @@ -848,7 +1070,7 @@ private static void box(String provideType, String expectedType, MethodVisitor a
}
}

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: {
Expand Down Expand Up @@ -924,7 +1146,7 @@ private static void reBuildE1Expression(E1Expr e1, MethodVisitor asm) {
}
}

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) {
Expand Down
Loading

0 comments on commit 62eba63

Please sign in to comment.