use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class EnumDeobfuscator method makeEnum.
private void makeEnum(ClassFile cf) {
// make class an enum
cf.setEnum();
// enums super class is java/lang/Enum
assert cf.getParentClass().getName().equals("java/lang/Object");
cf.setSuperName("java/lang/Enum");
// all static fields of the type of the class become enum members
for (Field field : cf.getFields()) {
if (field.isStatic() && field.getType().equals(new Type("L" + cf.getName() + ";"))) {
field.setEnum();
}
}
for (Method method : cf.getMethods()) {
if (!method.getName().equals("<init>")) {
continue;
}
// Add string as first argument, which is the field name,
// and ordinal as second argument
Signature signature = new Signature.Builder().setReturnType(method.getDescriptor().getReturnValue()).addArgument(Type.STRING).addArgument(Type.INT).addArguments(method.getDescriptor().getArguments()).build();
method.setDescriptor(signature);
// Remove instructions up to invokespecial
Instructions ins = method.getCode().getInstructions();
Instruction i;
do {
i = ins.getInstructions().get(0);
ins.remove(i);
} while (i.getType() != InstructionType.INVOKESPECIAL);
// load this
ins.addInstruction(0, new ALoad(ins, 0));
// load constant name
ins.addInstruction(1, new ALoad(ins, 1));
// ordinal
ins.addInstruction(2, new ILoad(ins, 2));
// invoke enum constructor
ins.addInstruction(3, new InvokeSpecial(ins, ENUM_INIT));
// Shift all indexes after this up +2 because of the new String and int argument
for (int j = 4; j < ins.getInstructions().size(); ++j) {
i = ins.getInstructions().get(j);
if (i instanceof LVTInstruction) {
LVTInstruction lvt = ((LVTInstruction) i);
int idx = lvt.getVariableIndex();
if (idx != 0) {
lvt.setVariableIndex(idx + 2);
}
}
}
}
// Order of fields being set in clinit, which is the order
// the enum fields are actually in
List<Field> order = new ArrayList<>();
for (Method method : cf.getMethods()) {
if (!method.getName().equals("<clinit>")) {
continue;
}
Instructions ins = method.getCode().getInstructions();
int count = 0;
// sometimes there is new new invokespecial invokespecial putfield
// for eg enum member field30(1, 2, String.class, new class5());
boolean seenDup = false;
for (int j = 0; j < ins.getInstructions().size(); ++j) {
Instruction i = ins.getInstructions().get(j);
if (i.getType() == InstructionType.DUP && !seenDup) {
// XXX this should actually be the field name, but it seems to have no effect on fernflower
ins.addInstruction(j + 1, new LDC(ins, "runelite"));
ins.addInstruction(j + 2, new LDC(ins, count++));
seenDup = true;
} else if (i.getType() == InstructionType.INVOKESPECIAL) {
Instruction next = ins.getInstructions().get(j + 1);
// check if this is the invokespecial on the enum, putstatic comes next
if (next.getType() == InstructionType.PUTSTATIC) {
InvokeSpecial is = (InvokeSpecial) i;
PutStatic ps = (PutStatic) next;
net.runelite.asm.pool.Method pmethod = new net.runelite.asm.pool.Method(is.getMethod().getClazz(), is.getMethod().getName(), new Signature.Builder().setReturnType(is.getMethod().getType().getReturnValue()).addArgument(Type.STRING).addArgument(Type.INT).addArguments(is.getMethod().getType().getArguments()).build());
is.setMethod(pmethod);
Field field = ps.getMyField();
assert field != null;
order.add(field);
seenDup = false;
}
}
}
}
// Enum fields must be first. Also they are in order in clinit.
// Sort fields
Collections.sort(cf.getFields(), (f1, f2) -> {
int idx1 = order.indexOf(f1);
int idx2 = order.indexOf(f2);
if (idx1 == -1) {
idx1 = Integer.MAX_VALUE;
}
if (idx2 == -1) {
idx2 = Integer.MAX_VALUE;
}
return Integer.compare(idx1, idx2);
});
}
use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class Frame method execute.
public void execute() {
Instructions ins = method.getCode().getInstructions();
List<Instruction> instructions = ins.getInstructions();
assert !execution.paused;
while (executing) {
Instruction oldCur = cur;
InstructionContext ictx;
try {
logger.trace("executing {}", cur);
ictx = cur.execute(this);
this.addInstructionContext(ictx);
} catch (Throwable ex) {
System.err.println("Error executing instruction " + cur);
System.err.println("Frame stack (grows downward):");
while (stack.getSize() > 0) {
StackContext stacki = stack.pop();
InstructionContext pushed = stacki.getPushed();
Frame frame = pushed.getFrame();
System.err.println(pushed.getInstruction());
}
System.err.println("end of stack");
ex.printStackTrace();
throw ex;
}
assert ictx.getInstruction() == oldCur;
ctx.contexts.put(oldCur, ictx);
execution.executed.add(oldCur);
execution.accept(ictx);
processExceptions(ictx);
if (!executing) {
// this can be mappable, too, but we stop executing anyway
// to set paused
checkMappable(ictx);
incrementOrder(ictx);
break;
}
if (oldCur == cur) {
this.nextInstruction();
} else {
/* jump */
}
// it is important we move cur first as when the step executor
// resumes it will start there
incrementOrder(ictx);
if (checkMappable(ictx)) {
return;
}
}
}
use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class DupDeobfuscatorTest method test.
@Test
public void test() {
ClassGroup group = ClassGroupFactory.generateGroup();
Code code = group.findClass("test").findMethod("func").getCode();
Instructions ins = code.getInstructions();
code.setMaxStack(5);
Instruction[] prepareVariables = { new LDC(ins, 1), new IStore(ins, 0) };
for (Instruction i : prepareVariables) {
ins.addInstruction(i);
}
LDC constant1 = new LDC(ins, 1129258489), constant2 = new LDC(ins, -1692330935), constant3 = new LDC(ins, 1641298955), constant4 = new LDC(ins, 1043501435);
Instruction[] body = { // this
new AConstNull(ins), // this
new AConstNull(ins), new ILoad(ins, 0), constant1, new IMul(ins), new Dup_X1(ins), constant2, new IMul(ins), // putfield
new Pop2(ins), constant3, new IMul(ins), constant4, new IMul(ins), // putfield
new Pop2(ins), new VReturn(ins) };
for (Instruction i : body) {
ins.addInstruction(i);
}
Execution e = new Execution(group);
e.populateInitialMethods();
e.run();
assert constant1.getConstantAsInt() * constant2.getConstantAsInt() == 1;
assert constant3.getConstantAsInt() * constant4.getConstantAsInt() * constant1.getConstantAsInt() == 1;
Deobfuscator d = new DupDeobfuscator();
d.run(group);
// assert the dup_x1 was removed
long dupCount = ins.getInstructions().stream().filter(i -> i instanceof Dup_X1).count();
Assert.assertEquals(0, dupCount);
}
use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class DupDeobfuscatorTest method test2.
// 035 aload_0 // this
// 036 dup // this this
// 037 getfield class153/field2097 I // this I
// 038 ldc 830083863
// 039 imul // this I
// 040 ldc 830083863
// 041 iadd // this I
// 042 dup_x1 // I this I
@Test
public void test2() {
ClassGroup group = ClassGroupFactory.generateGroup();
Code code = group.findClass("test").findMethod("func").getCode();
Instructions ins = code.getInstructions();
code.setMaxStack(3);
Instruction[] body = { // this
new AConstNull(ins), // this this
new Dup(ins), new GetField(ins, new Field(new Class("test"), "field", Type.INT)), // this this I I
new LDC(ins, 830083863), // this this I
new IMul(ins), new LDC(ins, 830083863), new IAdd(ins), new Dup_X1(ins), new LDC(ins, 636900519), // pops dup
new IMul(ins), new VReturn(ins) };
for (Instruction i : body) {
ins.addInstruction(i);
}
Execution e = new Execution(group);
e.populateInitialMethods();
e.run();
Deobfuscator d = new DupDeobfuscator();
d.run(group);
// assert the dup wasn't duplicated
long dupCount = ins.getInstructions().stream().filter(i -> i instanceof Dup).count();
Assert.assertEquals(1, dupCount);
// assert the dup_x1 was removed
dupCount = ins.getInstructions().stream().filter(i -> i instanceof Dup_X1).count();
Assert.assertEquals(0, dupCount);
}
use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class MultiplicationDeobfuscatorTest method test3.
@Test
public void test3() {
ClassGroup group = ClassGroupFactory.generateGroup();
Code code = group.findClass("test").findMethod("func").getCode();
Instructions ins = code.getInstructions();
code.setMaxStack(2);
Instruction[] prepareVariables = { new LDC(ins, 3), new IStore(ins, 0) };
for (Instruction i : prepareVariables) {
ins.addInstruction(i);
}
LDC constant1 = new LDC(ins, 1381104939), constant2 = new LDC(ins, 1381104939), constant3 = new LDC(ins, 981643079), constant4 = new LDC(ins, 1807370871), constant5 = new LDC(ins, 981643079);
Label label1 = new Label(ins);
Instruction[] body = { constant4, constant1, new ILoad(ins, 0), new IMul(ins), new LDC(ins, 0), new IfEq(ins, label1), constant2, new IMul(ins), label1, constant3, new IMul(ins), // constant4
new IMul(ins), constant5, new IMul(ins), new Pop(ins), new VReturn(ins) };
for (Instruction i : body) {
ins.addInstruction(i);
}
Execution e = new Execution(group);
e.populateInitialMethods();
e.run();
assert constant4.getConstantAsInt() * constant5.getConstantAsInt() == 1;
// {
// Collection<InstructionContext> ctxs = e.getInstructonContexts(body[3]);
// assert ctxs.size() == 1;
//
// InstructionContext ictx = ctxs.iterator().next();
// boolean onlyPath = MultiplicationDeobfuscator.isOnlyPath(e, ictx);
// Assert.assertFalse(onlyPath);
// }
Deobfuscator d = new MultiplicationDeobfuscator();
d.run(group);
Assert.assertEquals(1381104939, constant1.getConstantAsInt());
Assert.assertEquals(1381104939, constant2.getConstantAsInt());
Assert.assertEquals(1, constant3.getConstantAsInt());
Assert.assertEquals(1, constant4.getConstantAsInt());
// assumes result is moved to the end here.
Assert.assertEquals(981643079, constant5.getConstantAsInt());
}
Aggregations