use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction in project runelite by runelite.
the class MenuActionDeobfuscator method run.
private void run(Method method) {
if (method.getCode() == null) {
return;
}
Execution execution = new Execution(method.getClassFile().getGroup());
execution.addMethod(method);
execution.noInvoke = true;
Multimap<Integer, Comparison> comps = HashMultimap.create();
execution.addExecutionVisitor((InstructionContext ictx) -> {
Instruction i = ictx.getInstruction();
Frame frame = ictx.getFrame();
if (i instanceof If) {
// constant
InstructionContext ctx1 = ictx.getPops().get(0).getPushed();
// lvt
InstructionContext ctx2 = ictx.getPops().get(1).getPushed();
if (ctx1.getInstruction() instanceof PushConstantInstruction && ctx2.getInstruction() instanceof LVTInstruction) {
Comparison comparison = new Comparison();
comparison.cmp = i;
comparison.ldc = ctx1.getInstruction();
comparison.lvt = (LVTInstruction) ctx2.getInstruction();
comps.put(comparison.lvt.getVariableIndex(), comparison);
}
}
});
execution.run();
for (int i : comps.keySet()) {
Collection<Comparison> get = comps.get(i);
long l = get.stream().filter(c -> c.cmp.getType() == IF_ICMPGE || c.cmp.getType() == IF_ICMPGT || c.cmp.getType() == IF_ICMPLE || c.cmp.getType() == IF_ICMPLT).count();
List<Comparison> eqcmp = get.stream().filter(c -> c.cmp.getType() == IF_ICMPEQ || c.cmp.getType() == IF_ICMPNE).collect(Collectors.toList());
if (get.size() > THRESHOLD_EQ && l <= THRESHOLD_LT) {
logger.info("Sorting {} comparisons in {}", eqcmp.size(), method);
insert(method, eqcmp);
}
}
}
use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction in project runelite by runelite.
the class IfICmpEq method is.
static boolean is(StackContext s, int val) {
if (s.getPushed().getInstruction() instanceof PushConstantInstruction) {
PushConstantInstruction pc = (PushConstantInstruction) s.getPushed().getInstruction();
Object o = pc.getConstant();
if (o instanceof Integer && (int) o == val) {
return true;
}
}
return false;
}
use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction in project runelite by runelite.
the class DrawAfterWidgets method injectDrawAfterWidgets.
private void injectDrawAfterWidgets() throws InjectionException {
/*
This call has to be injected using raw injection because the
drawWidgets method gets inlined in some revisions. If it wouldn't be,
mixins would be used to add the call to the end of drawWidgets.
--> This hook depends on the positions of "if (535573958 * kl != -1)" and "jz.db();".
Revision 153 - client.ll():
______________________________________________________
if (535573958 * kl != -1) {
me = 0;
var1 = kl * 1593233303;
var2 = 523525871 * q;
var3 = -1668171507 * h.n;
if (!bo.p(var1, (byte)111)) {
for(var4 = 0; var4 < 100; ++var4) {
mb[var4] = true;
}
} else {
z.lj = null;
bl.hz(fa.g[var1], -1, 0, 0, var2, var3, 0, 0, -1, 1505114436);
if (z.lj != null) {
bl.hz(z.lj, -1412584499, 0, 0, var2, var3, 1475313862 * bq.la, aq.lc * 1205565233, -1, 2123188146);
z.lj = null;
}
}
}
// <-- INJECT CALL HERE
jz.db(); <-- noClip method
______________________________________________________
*/
boolean injected = false;
Method noClip = findStaticMethod("noClip");
if (noClip == null) {
throw new InjectionException("Mapped method \"noClip\" could not be found.");
}
net.runelite.asm.pool.Method poolNoClip = noClip.getPoolMethod();
for (ClassFile c : inject.getVanilla().getClasses()) {
for (Method m : c.getMethods()) {
if (m.getCode() == null) {
continue;
}
Instructions instructions = m.getCode().getInstructions();
Set<Label> labels = new HashSet<>();
// Let's find "invokestatic <some class>.noClip()" and its label
ListIterator<Instruction> labelIterator = instructions.getInstructions().listIterator();
while (labelIterator.hasNext()) {
Instruction i = labelIterator.next();
if (!(i instanceof InvokeStatic)) {
continue;
}
InvokeStatic is = (InvokeStatic) i;
if (!is.getMethod().equals(poolNoClip)) {
continue;
}
labelIterator.previous();
Instruction i2 = labelIterator.previous();
labelIterator.next();
labelIterator.next();
// Find the label that marks the code path for the instruction
if (!(i2 instanceof Label)) {
continue;
}
// There can be several noClip invocations in a method, so let's catch them all
labels.add((Label) i2);
}
if (labels.isEmpty()) {
// If we get here, we're either in the wrong method
// or Jagex has removed the "if (535573958 * kl != -1)"
logger.debug("Could not find the label for jumping to the " + noClip + " call in " + m);
continue;
}
Set<Label> labelsToInjectAfter = new HashSet<>();
ListIterator<Instruction> jumpIterator = instructions.getInstructions().listIterator();
while (jumpIterator.hasNext()) {
Instruction i = jumpIterator.next();
if (!(i instanceof JumpingInstruction)) {
continue;
}
JumpingInstruction ji = (JumpingInstruction) i;
Label label = null;
for (Label l : labels) {
if (ji.getJumps().contains(l)) {
label = l;
break;
}
}
if (label == null) {
continue;
}
jumpIterator.previous();
Set<Instruction> insns = new HashSet<>();
insns.add(jumpIterator.previous());
insns.add(jumpIterator.previous());
insns.add(jumpIterator.previous());
insns.add(jumpIterator.previous());
// Get the iterator back to i's position
jumpIterator.next();
jumpIterator.next();
jumpIterator.next();
jumpIterator.next();
jumpIterator.next();
/*
Check that these instruction types are passed into the if-statement:
ICONST_M1
GETSTATIC client.kr : I
LDC 634425425
IMUL
We cannot depend on the order of these because of the obfuscation,
so let's make it easier by just checking that they are there.
*/
if (insns.stream().filter(i2 -> i2 instanceof PushConstantInstruction).count() != 2 || insns.stream().filter(i2 -> i2 instanceof IMul).count() != 1 || insns.stream().filter(i2 -> i2 instanceof GetStatic).count() != 1) {
continue;
}
// At this point, we have found the real injection point
labelsToInjectAfter.add(label);
}
for (Label l : labelsToInjectAfter) {
InvokeStatic invoke = new InvokeStatic(instructions, new net.runelite.asm.pool.Method(new net.runelite.asm.pool.Class(HOOKS), "drawAfterWidgets", new Signature("()V")));
instructions.addInstruction(instructions.getInstructions().indexOf(l) + 1, invoke);
logger.info("injectDrawAfterWidgets injected a call after " + l);
injected = true;
}
}
}
if (!injected) {
throw new InjectionException("injectDrawAfterWidgets failed to inject!");
}
}
use of net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction 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.instruction.types.PushConstantInstruction in project runelite by runelite.
the class MultiplicationExpression method simplify.
int simplify(Number start) {
int count = 0;
Number result = start;
// calculate result
for (InstructionContext i : instructions) {
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
Number value = (Number) pci.getConstant();
result = DMath.multiply(result, value);
}
if (dupmagic != null) {
// mul dupmagic by result of dup ins?
PushConstantInstruction pci = (PushConstantInstruction) dupmagic.getInstruction();
Number value = (Number) pci.getConstant();
for (InstructionContext ic : dupedInstructions) {
PushConstantInstruction pci2 = (PushConstantInstruction) ic.getInstruction();
Number value2 = (Number) pci2.getConstant();
value = DMath.multiply(value, value2);
}
Instruction newIns = pci.setConstant(value);
assert newIns == (Instruction) pci;
}
// multiply subexpressions by result
if (!subexpressions.isEmpty()) {
for (MultiplicationExpression me : subexpressions) {
count += me.simplify(result);
}
if (dupmagic != null) {
PushConstantInstruction pci = (PushConstantInstruction) dupmagic.getInstruction();
Number value = (Number) pci.getConstant();
value = DMath.multiply(value, DMath.modInverse(result));
pci.setConstant(value);
}
// constant has been distributed, outer numbers all go to 1
if (result instanceof Long)
result = 1L;
else
result = 1;
}
// set result on ins
for (InstructionContext i : instructions) {
PushConstantInstruction pci = (PushConstantInstruction) i.getInstruction();
Instruction newIns = pci.setConstant(result);
++count;
assert newIns == pci;
// rest of the results go to 1
if (result instanceof Long)
result = 1L;
else
result = 1;
}
return count;
}
Aggregations