下面列出了org.objectweb.asm.Opcodes# POP2 ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private List<AbstractInsnNode> getPossibleDupPop(AbstractInsnNode ain)
{
AbstractInsnNode next = ain;
List<AbstractInsnNode> instrs = new ArrayList<>();
while(next != null)
{
if(Utils.isInstruction(next) && next.getOpcode() != Opcodes.IINC)
instrs.add(next);
if(instrs.size() >= 3)
break;
next = next.getNext();
}
if(instrs.size() >= 3 && (willPush(instrs.get(0)) || ain.getOpcode() == Opcodes.DUP)
&& (willPush(instrs.get(1)) || instrs.get(1).getOpcode() == Opcodes.DUP)
&& instrs.get(2).getOpcode() == Opcodes.POP2)
return instrs;
else
return null;
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
if ((Opcodes.PUTFIELD == opcode) && shouldMutate(name)) {
// removed setting field
// pop the values which PUTFIELD would have used
if (Type.getType(desc).getSize() == 2) {
super.visitInsn(Opcodes.POP2);
super.visitInsn(Opcodes.POP);
} else {
super.visitInsn(Opcodes.POP);
super.visitInsn(Opcodes.POP);
}
} else {
super.visitFieldInsn(opcode, owner, name, desc);
}
}
/**
* Mutates a primitive double return (<code>Opcode.DRETURN</code>). The
* strategy used was translated from jumble BCEL code. The following is
* complicated by the problem of <tt>NaN</tt>s. By default the new value is
* <code>-(x + 1)</code>, but this doesn't work for <tt>NaN</tt>s. But for a
* <tt>NaN</tt> <code>x != x</code> is true, and we use this to detect them.
*
* @see #mutatePrimitiveFloatReturn()
*/
private void mutatePrimitiveDoubleReturn() {
if (shouldMutate("primitive double", "(x != NaN)? -(x + 1) : -1 ")) {
final Label label = new Label();
super.visitInsn(Opcodes.DUP2);
super.visitInsn(Opcodes.DUP2);
super.visitInsn(Opcodes.DCMPG);
super.visitJumpInsn(Opcodes.IFEQ, label);
super.visitInsn(Opcodes.POP2);
super.visitInsn(Opcodes.DCONST_0);
// the following code is executed in NaN case, too
super.visitLabel(label);
super.visitInsn(Opcodes.DCONST_1);
super.visitInsn(Opcodes.DADD);
super.visitInsn(Opcodes.DNEG);
super.visitInsn(Opcodes.DRETURN);
}
}
private void emptyStack(final int opcode) {
switch (opcode) {
// EQUAL
case Opcodes.IF_ICMPNE:
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ACMPEQ:
case Opcodes.IF_ACMPNE:
// ORDER
case Opcodes.IF_ICMPGE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPLE:
case Opcodes.IF_ICMPLT:
super.visitInsn(Opcodes.POP2);
break;
default:
super.visitInsn(Opcodes.POP);
}
}
/**
* Returns the operation code for pop operations with a single instruction support by their type
* sizes on stack top
*/
public static int getTypeSizeAlignedPopOpcode(ImmutableList<Type> elementsToPop) {
int totalWordsToPop = getTotalWords(elementsToPop);
switch (totalWordsToPop) {
case 1:
return Opcodes.POP;
case 2:
return Opcodes.POP2;
default:
throw new IllegalStateException(
String.format(
"Expected either 1 or 2 words to be popped, but actually requested to pop (%d)"
+ " words from <top/>%s...<bottom/>",
totalWordsToPop, elementsToPop));
}
}
public static int getPopOpcode(Type type) {
if (type.getSize() == 1) {
return Opcodes.POP;
} else if (type.getSize() == 2) {
return Opcodes.POP2;
} else {
throw new IllegalArgumentException(type.toString());
}
}
@Override
public boolean transform() throws Throwable {
DelegatingProvider provider = new DelegatingProvider();
provider.register(new JVMMethodProvider());
provider.register(new JVMComparisonProvider());
provider.register(new MappedMethodProvider(classes));
provider.register(new MappedFieldProvider());
AtomicInteger fixed = new AtomicInteger();
System.out.println("[Allatori] [LightFlowObfuscationTransformer] Starting");
for(ClassNode classNode : classNodes())
for(MethodNode method : classNode.methods)
{
boolean modified;
do
{
modified = false;
for(AbstractInsnNode ain : method.instructions.toArray())
if((willPush(ain) || ain.getOpcode() == Opcodes.DUP) && ain.getNext() != null
&& (willPush(ain.getNext()) || ain.getNext().getOpcode() == Opcodes.DUP)
&& ain.getNext().getNext() != null && ain.getNext().getNext().getOpcode() == Opcodes.POP2)
{
method.instructions.remove(ain.getNext().getNext());
method.instructions.remove(ain.getNext());
method.instructions.remove(ain);
modified = true;
fixed.incrementAndGet();
}
}while(modified);
}
System.out.println("[Allatori] [LightFlowObfuscationTransformer] Removed " + fixed + " dead instructions");
System.out.println("[Allatori] [LightFlowObfuscationTransformer] Done");
return true;
}
/**
* NOTE: All calls to instruction visitation routines are made against super, directly, since we do frame offset accounting within our overrides
* and that offset only applies to incoming bytecodes, not outgoing ones.
*
* @param opcode The opcode.
* @param descriptor The type descriptor of the field to which the opcode is applied.
*/
private void checkInjectLazyLoad(int opcode, String descriptor) {
// If this is a PUTFIELD or GETFIELD, we want to call "lazyLoad()":
// -PUTIFELD: DUP2, POP, INVOKEVIRTUAL
// -GETIFELD: DUP, INVOKEVIRTUAL
if ((Opcodes.PUTFIELD == opcode) && ((null == this.tracker) || !this.tracker.isThisTargetOfPut(this.frameOffset))) {
// We need to see how big this type is since double and long need a far more complex dance.
if ((1 == descriptor.length()) && ((DescriptorParser.LONG == descriptor.charAt(0)) || (DescriptorParser.DOUBLE == descriptor.charAt(0)))) {
// Here, the stack looks like: ... OBJECT, VAR1, VAR2 (top)
// Where we need: ... OBJECT, VAR1, VAR2, OBJECT (top)
// This is multiple stages:
// DUP2_X1: ... VAR1, VAR2, OBJECT, VAR1, VAR2 (top)
super.visitInsn(Opcodes.DUP2_X1);
// POP2: ... VAR1, VAR2, OBJECT (top)
super.visitInsn(Opcodes.POP2);
// DUP: ... VAR1, VAR2, OBJECT, OBJECT (top)
super.visitInsn(Opcodes.DUP);
// INOKE: ... VAR1, VAR2, OBJECT (top)
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SHADOW_OBJECT_NAME, LAZY_LOAD_NAME, LAZY_LOAD_DESCRIPTOR, false);
// DUP_X2: ... OBJECT, VAR1, VAR2, OBJECT (top)
super.visitInsn(Opcodes.DUP_X2);
// POP: ... OBJECT, VAR1, VAR2 (top)
super.visitInsn(Opcodes.POP);
} else {
// Here, the stack looks like: ... OBJECT, VAR, (top)
// Where we need: ... OBJECT, VAR, OBJECT (top)
// Stages:
// DUP2: ... OBJECT, VAR, OBJECT, VAR (top)
super.visitInsn(Opcodes.DUP2);
// POP: ... OBJECT, VAR, OBJECT (top)
super.visitInsn(Opcodes.POP);
// INOKE: ... OBJECT, VAR (top)
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SHADOW_OBJECT_NAME, LAZY_LOAD_NAME, LAZY_LOAD_DESCRIPTOR, false);
}
} else if ((Opcodes.GETFIELD == opcode) && ((null == this.tracker) || !this.tracker.isThisTargetOfGet(this.frameOffset))) {
// Here, the stack looks like: ... OBJECT, (top)
// Where we need: ... OBJECT, OBJECT (top)
super.visitInsn(Opcodes.DUP);
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SHADOW_OBJECT_NAME, LAZY_LOAD_NAME, LAZY_LOAD_DESCRIPTOR, false);
}
}