use of net.runelite.asm.attributes.code.instructions.IInc in project runelite by runelite.
the class CodeVisitor method visitIincInsn.
@Override
public void visitIincInsn(int var, int increment) {
IInc iinc = new IInc(code.getInstructions(), InstructionType.IINC);
iinc.setVariableIndex(var);
iinc.setIncrement(increment);
code.getInstructions().addInstruction(iinc);
}
use of net.runelite.asm.attributes.code.instructions.IInc in project runelite by runelite.
the class MultiplicationDeobfuscator method parseExpression.
public static MultiplicationExpression parseExpression(InstructionContext ctx, Class want) {
MultiplicationExpression me = new MultiplicationExpression();
if (ctx.getInstruction() instanceof LVTInstruction) {
LVTInstruction lvt = (LVTInstruction) ctx.getInstruction();
// loading a variable
if (!lvt.store()) {
// var index
int idx = lvt.getVariableIndex();
// variables at time of execution
Variables vars = ctx.getVariables();
// get the variable
VariableContext vctx = vars.get(idx);
if (// ?
vctx.getRead().size() == 1) {
// this is an istore
InstructionContext storeCtx = vctx.getInstructionWhichStored();
if (storeCtx.getInstruction() instanceof LVTInstruction) {
// invoking funcs can put stuff in lvt
LVTInstruction storelvt = (LVTInstruction) storeCtx.getInstruction();
if (storelvt instanceof IInc)
throw new IllegalStateException();
assert storelvt.store();
InstructionContext pushed = storeCtx.getPops().get(0).getPushed();
return parseExpression(pushed, want);
}
}
}
}
if (ctx.getInstruction() instanceof PushConstantInstruction) {
if (ctx.getInstruction() instanceof BiPush || ctx.getInstruction() instanceof SiPush) {
throw new IllegalStateException();
}
me.instructions.add(ctx);
return me;
}
for (StackContext sctx : ctx.getPops()) {
if (ctx.getInstruction().getClass() == want) {
if (!isOnlyPath(ctx, sctx))
continue;
}
InstructionContext i = sctx.getPushed();
// if this instruction is imul, look at pops
if (ctx.getInstruction().getClass() == want) {
if (i.getInstruction() instanceof Swap) {
logger.debug("Resolving swap");
Swap swap = (Swap) i.getInstruction();
sctx = swap.getOriginal(sctx);
i = sctx.getPushed();
}
if (i.getInstruction() instanceof PushConstantInstruction) {
// bipush/sipush are always not obfuscated
if (i.getInstruction() instanceof BiPush || i.getInstruction() instanceof SiPush)
continue;
// a constant of imul
me.instructions.add(i);
} else if (i.getInstruction().getClass() == want) {
// chained imul, append to me
try {
MultiplicationExpression other = parseExpression(i, want);
if (other.dupmagic != null) {
assert me.dupmagic == null;
me.dupmagic = other.dupmagic;
}
me.instructions.addAll(other.instructions);
me.dupedInstructions.addAll(other.dupedInstructions);
me.subexpressions.addAll(other.subexpressions);
} catch (IllegalStateException ex) {
// this is ok? just don't include it?
}
} else if (i.getInstruction() instanceof IAdd || i.getInstruction() instanceof ISub || i.getInstruction() instanceof LAdd || i.getInstruction() instanceof LSub) {
// imul using result of iadd or isub. evaluate expression
try {
MultiplicationExpression other = parseExpression(i, want);
assert other.dupmagic == null;
// subexpr
me.subexpressions.add(other);
} catch (IllegalStateException ex) {
assert me.subexpressions.isEmpty();
// subexpression is too complex. we can still simplify the top level though
}
} else if (i.getInstruction() instanceof DupInstruction) {
DupInstruction dup = (DupInstruction) i.getInstruction();
// find other branch of the dup instruction
// sctx = what dup pushed, find other
// other side of dup
StackContext otherCtx = dup.getOtherBranch(sctx);
// what popped other side of dup. is this right?
InstructionContext otherCtxI = otherCtx.getPopped().get(0);
if (otherCtxI.getInstruction().getClass() == want) {
// assert otherCtxI.getInstruction() instanceof IMul;
// other side of that imul
InstructionContext pushConstant = otherCtxI.getPops().get(0).getPushed();
assert pushConstant.getInstruction() instanceof LDC;
me.dupmagic = pushConstant;
// original
StackContext orig = dup.getOriginal(sctx);
try {
MultiplicationExpression other = parseExpression(orig.getPushed(), want);
// done to it affect that, too. so multiply it by existing values?
if (orig.getPushed().getInstruction() instanceof IAdd || orig.getPushed().getInstruction() instanceof ISub || orig.getPushed().getInstruction() instanceof LAdd || orig.getPushed().getInstruction() instanceof LSub) {
me.subexpressions.add(other);
} else {
assert other.dupmagic == null;
me.instructions.addAll(other.instructions);
me.dupedInstructions.addAll(other.instructions);
me.subexpressions.addAll(other.subexpressions);
}
} catch (IllegalStateException ex) {
assert me.subexpressions.isEmpty();
}
}
} else if (i.getInstruction() instanceof GetFieldInstruction) {
me.fieldInstructions.add(i);
// non constant, ignore
} else {
// System.out.println("imul pops something I don't know " + i.getInstruction());
}
} else // this is an iadd/sub
if (ctx.getInstruction() instanceof IAdd || ctx.getInstruction() instanceof ISub || ctx.getInstruction() instanceof LAdd || ctx.getInstruction() instanceof LSub) {
// parse this side of the add/sub
MultiplicationExpression other = parseExpression(i, want);
me.subexpressions.add(other);
} else {
// System.out.println(ctx.getInstruction() + " pops something I dont know " + i.getInstruction());
}
}
if (me.instructions.isEmpty() && me.subexpressions.isEmpty())
throw new IllegalStateException();
return me;
}
use of net.runelite.asm.attributes.code.instructions.IInc in project runelite by runelite.
the class ExprArgOrder method canRemove.
private boolean canRemove(MethodContext mctx, Instructions ins, Instruction i) {
Set<InstructionContext> ctxs = new HashSet<>(mctx.getInstructonContexts(i));
if (!alwaysPoppedBySameInstruction(ctxs, i) || !alwaysPopsFromSameInstructions(ctxs, i)) {
return false;
}
if (i instanceof InvokeInstruction) {
// func1() + func2() vs func2() + func1() is not the same thing
return false;
}
int idx = ins.getInstructions().indexOf(i);
if (idx == -1) {
return false;
}
for (InstructionContext ictx : ctxs) {
for (StackContext sctx : ictx.getPops()) {
Instruction pushed = sctx.getPushed().getInstruction();
int idx2 = ins.getInstructions().indexOf(pushed);
if (idx2 == -1) {
return false;
}
assert idx > idx2;
// instructions, we can't move them
for (int j = idx2; j <= idx; ++j) {
Instruction i2 = ins.getInstructions().get(j);
if (i2 instanceof LVTInstruction) {
if (((LVTInstruction) i2).store()) {
return false;
}
}
if (i2 instanceof IInc) {
return false;
}
}
if (!canRemove(mctx, ins, pushed)) {
return false;
}
}
}
return true;
}
use of net.runelite.asm.attributes.code.instructions.IInc in project runelite by runelite.
the class ScriptVM method injectScriptVMHooks.
private void injectScriptVMHooks() throws InjectionException {
/*
This hooks local variable assignments in the copied version of runScript:
- The currently executing script > client.currentScript
- The currently executing script's program counter > client.currentScriptPC
- The currently executing opcode > client.vmExecuteOpcode(I)Z
The currently executing script variable is located as the outermost Script local
The PC is located by its use in PutField ScriptState::invokedFromPC
The currently executing opcode is found by searching for iaload with the script's instruction array
The script's instruction array is identified by looking for the getfield from script.instructions
bn.g @ rev 163 :
// Jump back to here if vmExecuteOpcode returns true
aload6 // Script.instructions
iinc 5 1 // ++PC
iload5 // PC
iaload
istore8
// <- Inject here
iload8
bipush 100
if_icmpge L52
*/
String scriptObName = DeobAnnotations.getObfuscatedName(inject.getDeobfuscated().findClass("Script").getAnnotations());
Method runScript = findObMethod("copy$runScript");
Method vmExecuteOpcode = findObMethod("vmExecuteOpcode");
Field scriptInstructions = findDeobField("instructions");
Field scriptStatePC = findDeobField("invokedFromPc");
Field currentScriptField = findObField("currentScript");
Field currentScriptPCField = findObField("currentScriptPC");
Execution e = new Execution(inject.getVanilla());
e.addMethod(runScript);
e.noInvoke = true;
AtomicReference<MethodContext> pcontext = new AtomicReference<>(null);
e.addMethodContextVisitor(pcontext::set);
e.run();
Instructions instrs = runScript.getCode().getInstructions();
Set<AStore> scriptStores = new HashSet<>();
Integer pcLocalVar = null;
Integer instructionArrayLocalVar = null;
IStore currentOpcodeStore = null;
ALoad localInstructionLoad = null;
MethodContext methodContext = pcontext.get();
for (InstructionContext instrCtx : methodContext.getInstructionContexts()) {
Instruction instr = instrCtx.getInstruction();
if (instr instanceof AStore) {
AStore store = (AStore) instr;
StackContext storedVarCtx = instrCtx.getPops().get(0);
// Find AStores that store a Script
if (storedVarCtx.getType().getInternalName().equals(scriptObName)) {
scriptStores.add(store);
}
// Find AStores that store the instructions
InstructionContext pusherCtx = storedVarCtx.getPushed();
if (pusherCtx.getInstruction() instanceof GetField) {
GetField getField = (GetField) pusherCtx.getInstruction();
if (getField.getMyField().equals(scriptInstructions)) {
instructionArrayLocalVar = store.getVariableIndex();
}
}
}
// Find the local that invokedFromPc is set from
if (instr instanceof PutField) {
PutField put = (PutField) instr;
if (put.getMyField() == scriptStatePC) {
StackContext pc = instrCtx.getPops().get(0);
assert Type.INT.equals(pc.getType()) : pc.getType();
InstructionContext mulctx = pc.pushed;
assert mulctx.getInstruction() instanceof IMul;
pcLocalVar = mulctx.getPops().stream().map(StackContext::getPushed).filter(i -> i.getInstruction() instanceof ILoad).map(i -> ((ILoad) i.getInstruction()).getVariableIndex()).findFirst().orElse(null);
}
}
}
// This has to run after the first loop because it relies on instructionArrayLocalVar being set
if (instructionArrayLocalVar == null) {
throw new InjectionException("Unable to find local instruction array");
}
for (InstructionContext instrCtx : methodContext.getInstructionContexts()) {
Instruction instr = instrCtx.getInstruction();
if (instr instanceof IALoad) {
StackContext array = instrCtx.getPops().get(1);
// Check where the array came from (looking for a getField scriptInstructions
InstructionContext pushedCtx = array.getPushed();
Instruction pushed = pushedCtx.getInstruction();
if (pushed instanceof ALoad) {
ALoad arrayLoad = (ALoad) pushed;
if (arrayLoad.getVariableIndex() == instructionArrayLocalVar) {
// Find the istore
IStore istore = (IStore) instrCtx.getPushes().get(0).getPopped().stream().map(InstructionContext::getInstruction).filter(i -> i instanceof IStore).findFirst().orElse(null);
if (istore != null) {
currentOpcodeStore = istore;
localInstructionLoad = arrayLoad;
}
}
}
}
}
// Add PutStatics to all Script AStores
{
int outerSciptIdx = scriptStores.stream().mapToInt(AStore::getVariableIndex).reduce(Math::min).orElseThrow(() -> new InjectionException("Unable to find any Script AStores in runScript"));
log.debug("Found script index {}", outerSciptIdx);
ListIterator<Instruction> instrIter = instrs.getInstructions().listIterator();
while (instrIter.hasNext()) {
Instruction instr = instrIter.next();
if (instr instanceof AStore) {
AStore il = (AStore) instr;
if (il.getVariableIndex() == outerSciptIdx) {
instrIter.previous();
instrIter.add(new Dup(instrs));
instrIter.add(new PutStatic(instrs, currentScriptField));
instrIter.next();
}
}
}
}
// Add PutStatics to all PC IStores and IIncs
{
if (pcLocalVar == null) {
throw new InjectionException("Unable to find ILoad for invokedFromPc IStore");
}
log.debug("Found pc index {}", pcLocalVar);
ListIterator<Instruction> instrIter = instrs.getInstructions().listIterator();
while (instrIter.hasNext()) {
Instruction instr = instrIter.next();
if (instr instanceof IStore) {
IStore il = (IStore) instr;
if (il.getVariableIndex() == pcLocalVar) {
instrIter.previous();
instrIter.add(new Dup(instrs));
instrIter.add(new PutStatic(instrs, currentScriptPCField));
instrIter.next();
}
}
if (instr instanceof IInc) {
IInc iinc = (IInc) instr;
if (iinc.getVariableIndex() == pcLocalVar) {
instrIter.add(new ILoad(instrs, pcLocalVar));
instrIter.add(new PutStatic(instrs, currentScriptPCField));
}
}
}
}
// Inject call to vmExecuteOpcode
log.debug("Found instruction array index {}", instructionArrayLocalVar);
if (currentOpcodeStore == null) {
throw new InjectionException("Unable to find IStore for current opcode");
}
int istorepc = instrs.getInstructions().indexOf(currentOpcodeStore);
assert istorepc >= 0;
Label nextIteration = instrs.createLabelFor(localInstructionLoad);
instrs.addInstruction(istorepc + 1, new ILoad(instrs, currentOpcodeStore.getVariableIndex()));
instrs.addInstruction(istorepc + 2, new InvokeStatic(instrs, vmExecuteOpcode.getPoolMethod()));
instrs.addInstruction(istorepc + 3, new IfNe(instrs, nextIteration));
}
Aggregations