Skip to content

Commit

Permalink
automatically calculate how many stack values to pop
Browse files Browse the repository at this point in the history
  • Loading branch information
EpicPlayerA10 committed Jan 26, 2025
1 parent a7dad4d commit cf1a423
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import uwu.narumi.deobfuscator.api.asm.NamedOpcodes;
import org.objectweb.asm.Type;

Expand Down Expand Up @@ -648,6 +649,66 @@ public String namedOpcode() {
return NamedOpcodes.map(this.getOpcode());
}

/**
* Returns the number of stack values required by this instruction.
*/
public int getRequiredStackValuesCount() {
return switch (this.opcode) {
// Unary operations (one value)
case Opcodes.ISTORE, Opcodes.LSTORE, Opcodes.FSTORE, Opcodes.DSTORE, Opcodes.ASTORE, Opcodes.POP, Opcodes.POP2,
Opcodes.DUP, Opcodes.DUP_X1, Opcodes.DUP_X2, Opcodes.DUP2, Opcodes.DUP2_X1, Opcodes.DUP2_X2, Opcodes.SWAP,
Opcodes.INEG, Opcodes.LNEG, Opcodes.FNEG, Opcodes.DNEG, Opcodes.I2L, Opcodes.I2F, Opcodes.I2D, Opcodes.L2I,
Opcodes.L2F, Opcodes.L2D, Opcodes.F2I, Opcodes.F2L, Opcodes.F2D, Opcodes.D2I, Opcodes.D2L, Opcodes.D2F,
Opcodes.I2B, Opcodes.I2C, Opcodes.I2S, Opcodes.IFEQ, Opcodes.IFNE, Opcodes.IFLT, Opcodes.IFGE, Opcodes.IFGT,
Opcodes.IFLE, Opcodes.TABLESWITCH, Opcodes.LOOKUPSWITCH, Opcodes.IRETURN, Opcodes.LRETURN, Opcodes.FRETURN,
Opcodes.DRETURN, Opcodes.ARETURN, Opcodes.PUTSTATIC, Opcodes.GETFIELD, Opcodes.NEWARRAY, Opcodes.ANEWARRAY,
Opcodes.ARRAYLENGTH, Opcodes.ATHROW, Opcodes.CHECKCAST, Opcodes.INSTANCEOF, Opcodes.MONITORENTER,
Opcodes.MONITOREXIT, Opcodes.IFNULL, Opcodes.IFNONNULL -> 1;
// Binary operations (two values)
case Opcodes.IALOAD, Opcodes.LALOAD, Opcodes.FALOAD, Opcodes.DALOAD, Opcodes.AALOAD, Opcodes.BALOAD,
Opcodes.CALOAD, Opcodes.SALOAD, Opcodes.IADD, Opcodes.LADD, Opcodes.FADD, Opcodes.DADD, Opcodes.ISUB,
Opcodes.LSUB, Opcodes.FSUB, Opcodes.DSUB, Opcodes.IMUL, Opcodes.LMUL, Opcodes.FMUL, Opcodes.DMUL,
Opcodes.IDIV, Opcodes.LDIV, Opcodes.FDIV, Opcodes.DDIV, Opcodes.IREM, Opcodes.LREM, Opcodes.FREM,
Opcodes.DREM, Opcodes.ISHL, Opcodes.LSHL, Opcodes.ISHR, Opcodes.LSHR, Opcodes.IUSHR, Opcodes.LUSHR,
Opcodes.IAND, Opcodes.LAND, Opcodes.IOR, Opcodes.LOR, Opcodes.IXOR, Opcodes.LXOR, Opcodes.LCMP,
Opcodes.FCMPL, Opcodes.FCMPG, Opcodes.DCMPL, Opcodes.DCMPG, Opcodes.IF_ICMPEQ, Opcodes.IF_ICMPNE,
Opcodes.IF_ICMPLT, Opcodes.IF_ICMPGE, Opcodes.IF_ICMPGT, Opcodes.IF_ICMPLE, Opcodes.IF_ACMPEQ,
Opcodes.IF_ACMPNE, Opcodes.PUTFIELD -> 2;
// Ternary operations (three values)
case Opcodes.IASTORE, Opcodes.LASTORE, Opcodes.FASTORE, Opcodes.DASTORE, Opcodes.AASTORE, Opcodes.BASTORE,
Opcodes.CASTORE, Opcodes.SASTORE -> 3;

// Method invocation
case Opcodes.INVOKEVIRTUAL, Opcodes.INVOKESPECIAL, Opcodes.INVOKESTATIC, Opcodes.INVOKEINTERFACE,
Opcodes.INVOKEDYNAMIC -> getRequiredStackValuesCountForMethodInvocation();
// Multi-dimensional array creation
case Opcodes.MULTIANEWARRAY -> ((MultiANewArrayInsnNode) this).dims;

default -> throw new IllegalStateException("Unknown opcode: " + this);
};
}

/**
* Calculates the number of stack values required for a method invocation by descriptor.
*/
private int getRequiredStackValuesCountForMethodInvocation() {
String desc;
if (this instanceof MethodInsnNode methodInsn) {
desc = methodInsn.desc;
} else if (this instanceof InvokeDynamicInsnNode invokeDynamicInsn) {
desc = invokeDynamicInsn.desc;
} else {
throw new IllegalStateException("Not a method instruction");
}

int count = Type.getArgumentCount(desc); // Arguments count = Stack values count
if (this.getOpcode() != Opcodes.INVOKESTATIC && this.getOpcode() != Opcodes.INVOKEDYNAMIC) {
count++; // "this" reference
}

return count;
}

@Override
public String toString() {
return "(" + namedOpcode() + ") " + super.toString();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package uwu.narumi.deobfuscator.api.asm;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.analysis.Frame;
import org.objectweb.asm.tree.analysis.OriginalSourceValue;
Expand Down Expand Up @@ -50,12 +48,11 @@ public MethodContext methodContext() {
}

/**
* Places POP or POP2 instruction before current instruction to remove the value from the stack
*
* @param count Stack values count to pop
* Places POPs instructions before current instruction to remove source values from the stack.
* This method automatically calculates how many stack values to pop.
*/
public void pop(int count) {
for (int i = 0; i < count; i++) {
public void placePops() {
for (int i = 0; i < this.insn.getRequiredStackValuesCount(); i++) {
int stackValueIdx = frame().getStackSize() - (i + 1);
OriginalSourceValue sourceValue = frame().getStack(stackValueIdx);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public final class AsmMathHelper {
AbstractInsnNode originalInsn = originalSourceValue.getProducer();
if (!originalInsn.isString()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(originalInsn.asString().length())
Expand All @@ -152,7 +152,7 @@ public final class AsmMathHelper {
AbstractInsnNode originalInsn = originalSourceValue.getProducer();
if (!originalInsn.isString()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(originalInsn.asString().hashCode())
Expand All @@ -175,7 +175,7 @@ public final class AsmMathHelper {
// Integer#parseInt(String)
if (!originalInsn.isString()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(Integer.parseInt(originalInsn.asString()))
Expand All @@ -202,7 +202,7 @@ public final class AsmMathHelper {
// Integer#parseInt(String, int)
if (!originalFirstInsn.isString() || !originalSecondInsn.isInteger()) return false;

context.pop(2);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(
Expand All @@ -227,7 +227,7 @@ public final class AsmMathHelper {
// Integer#reverse(int)
if (!originalInsn.isInteger()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(Integer.reverse(originalInsn.asInteger()))
Expand All @@ -250,7 +250,7 @@ public final class AsmMathHelper {
// Long#reverse(long)
if (!originalInsn.isLong()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(Long.reverse(originalInsn.asLong()))
Expand All @@ -273,7 +273,7 @@ public final class AsmMathHelper {
// Float#floatToIntBits(float)
if (!originalInsn.isFloat()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(Float.floatToIntBits(originalInsn.asFloat()))
Expand All @@ -296,7 +296,7 @@ public final class AsmMathHelper {
// Float#intBitsToFloat(int)
if (!originalInsn.isInteger()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(Float.intBitsToFloat(originalInsn.asInteger()))
Expand All @@ -319,7 +319,7 @@ public final class AsmMathHelper {
// Double#doubleToLongBits(double)
if (!originalInsn.isDouble()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(Double.doubleToLongBits(originalInsn.asDouble()))
Expand All @@ -342,7 +342,7 @@ public final class AsmMathHelper {
// Double#longBitsToDouble(long)
if (!originalInsn.isLong()) return false;

context.pop(1);
context.placePops();
context.methodNode().instructions.set(
context.insn(),
AsmHelper.numberInsn(Double.longBitsToDouble(originalInsn.asLong()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ private void loadInput() {
LOGGER.error("Could not load external file: {}", externalFile.pathInJar(), e);
}
}

LOGGER.info("Loaded {} classes", this.context.getClassesMap().size());
}

private void loadClassOrFile(String pathInJar, byte[] bytes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ protected void transform() throws Exception {
InsnContext insnContext = methodContext.newInsnContext(insn);

// Pop the value from the stack
insnContext.pop(1);
insnContext.placePops();

methodNode.instructions.remove(insn);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ protected void transform() throws Exception {

boolean ifResult = optIfResult.get();

if (AsmMathHelper.isOneValueCondition(jumpInsn.getOpcode())) {
insnContext.pop(1);
} else if (AsmMathHelper.isTwoValuesCondition(jumpInsn.getOpcode())) {
insnContext.pop(2);
if (AsmMathHelper.isOneValueCondition(jumpInsn.getOpcode()) || AsmMathHelper.isTwoValuesCondition(jumpInsn.getOpcode())) {
insnContext.placePops();
}

// Replace if with corresponding GOTO or remove it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected void transform() throws Exception {

LabelNode predictedJump = optPredictedJump.get();
// Remove value from stack
insnContext.pop(1);
insnContext.placePops();
// Replace lookup switch with predicted jump
insnContext.methodNode().instructions.set(lookupSwitchInsn, new JumpInsnNode(GOTO, predictedJump));

Expand All @@ -39,7 +39,7 @@ protected void transform() throws Exception {

LabelNode predictedJump = optPredictedJump.get();
// Remove value from stack
insnContext.pop(1);
insnContext.placePops();
// Replace lookup switch with predicted jump
insnContext.methodNode().instructions.set(tableSwitchInsn, new JumpInsnNode(GOTO, predictedJump));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ protected void transform() throws Exception {
return;
}

insnContext.pop(2);
insnContext.placePops();
insnContext.methodNode().instructions.set(insnContext.insn(), AsmHelper.numberInsn(result));

markChange();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected void transform() throws Exception {
if (valueInsn.isNumber()) {
Number castedNumber = AsmMathHelper.mathUnaryOperation(valueInsn.asNumber(), insnContext.insn().getOpcode());

insnContext.pop(1);
insnContext.placePops();
insnContext.methodNode().instructions.set(insnContext.insn(), AsmHelper.numberInsn(castedNumber));

markChange();
Expand Down

0 comments on commit cf1a423

Please sign in to comment.