use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class RuneliteBufferTransformer method injectPacketFinish.
private void injectPacketFinish(ClassGroup group) {
PacketFlushFinder pff = new PacketFlushFinder(group);
pff.find();
for (InstructionContext queueForWriteCtx : pff.getQueueForWrite()) {
Instruction before = // socket
queueForWriteCtx.getPops().get(3).getPushed().getInstruction();
GetStatic getBuffer;
try {
getBuffer = (GetStatic) // buffer
queueForWriteCtx.getPops().get(2).getPushed().getPops().get(// getstatic
0).getPushed().getInstruction();
} catch (ClassCastException ex) {
continue;
}
Instructions instructions = before.getInstructions();
int idx = instructions.getInstructions().indexOf(before);
assert idx != -1;
instructions.addInstruction(idx++, getBuffer.clone());
net.runelite.asm.pool.Method method = new net.runelite.asm.pool.Method(new net.runelite.asm.pool.Class(getBuffer.getField().getType().getInternalName()), RUNELITE_FINISH_PACKET, new Signature("()V"));
instructions.addInstruction(idx++, new InvokeVirtual(instructions, method));
}
}
use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class PacketFlushFinder method find.
private void find(Method method) {
Code code = method.getCode();
Set<Instruction> checked = new HashSet<>();
Execution e = new Execution(group);
e.addMethod(method);
e.noInvoke = true;
e.noExceptions = true;
e.addExecutionVisitor(ic -> {
Instruction i = ic.getInstruction();
if (checked.contains(i)) {
return;
}
checked.add(i);
if (i.getType() != INVOKEVIRTUAL) {
return;
}
InvokeVirtual iv = (InvokeVirtual) i;
// queueForWrite
if (!iv.getMethod().getType().equals(new Signature("([BII)V"))) {
return;
}
InstructionContext lengthCtx = ic.getPops().get(0).getPushed();
if (lengthCtx.getInstruction().getType() != GETFIELD) {
return;
}
queueForWrite.add(ic);
});
e.run();
}
use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class ModArith method findUses.
// find potential getters/setters for each field
private void findUses(MethodContext mctx) {
for (InstructionContext ctx : mctx.getInstructionContexts()) {
if (ctx.getInstruction() instanceof IMul || ctx.getInstruction() instanceof LMul) {
Instruction one = ctx.getPops().get(0).getPushed().getInstruction();
Instruction two = ctx.getPops().get(1).getPushed().getInstruction();
PushConstantInstruction pc = null;
GetFieldInstruction gf = null;
if (one instanceof PushConstantInstruction && two instanceof GetFieldInstruction) {
pc = (PushConstantInstruction) one;
gf = (GetFieldInstruction) two;
} else if (two instanceof PushConstantInstruction && one instanceof GetFieldInstruction) {
pc = (PushConstantInstruction) two;
gf = (GetFieldInstruction) one;
}
if (pc == null) {
continue;
}
Field field = gf.getMyField();
if (field == null) {
continue;
}
FieldInfo fieldInfo = getFieldInfo(field);
// parse the full multiplication expression to
// get all associated constants
List<InstructionContext> insInExpr = getInsInExpr(ctx, new HashSet(), true);
for (InstructionContext ctx2 : insInExpr) {
if (!(ctx2.getInstruction() instanceof PushConstantInstruction)) {
continue;
}
PushConstantInstruction pci3 = (PushConstantInstruction) ctx2.getInstruction();
Number value = (Number) pci3.getConstant();
// field * constant
if (value instanceof Integer || value instanceof Long) {
fieldInfo.getters.add(value);
}
}
} else if (ctx.getInstruction() instanceof SetFieldInstruction) {
SetFieldInstruction sf = (SetFieldInstruction) ctx.getInstruction();
Field field = sf.getMyField();
if (field == null) {
continue;
}
FieldInfo fieldInfo = getFieldInfo(field);
// value being set
InstructionContext pushedsfi = ctx.getPops().get(0).getPushed();
pushedsfi = pushedsfi.resolve(ctx.getPops().get(0));
if (!(pushedsfi.getInstruction() instanceof IMul) && !(pushedsfi.getInstruction() instanceof LMul) && !(pushedsfi.getInstruction() instanceof IAdd) && !(pushedsfi.getInstruction() instanceof LAdd) && !(pushedsfi.getInstruction() instanceof ISub) && !(pushedsfi.getInstruction() instanceof LSub)) {
if (pushedsfi.getInstruction() instanceof LDC) {
PushConstantInstruction ldc = (PushConstantInstruction) pushedsfi.getInstruction();
if (ldc.getConstant() instanceof Integer || ldc.getConstant() instanceof Long) {
Number i = (Number) ldc.getConstant();
// field = constant
fieldInfo.setters.add(i);
}
}
continue;
}
Instruction one = pushedsfi.getPops().get(0).getPushed().getInstruction();
Instruction two = pushedsfi.getPops().get(1).getPushed().getInstruction();
// field = field + imul
if (pushedsfi.getInstruction() instanceof IAdd) {
if (one instanceof IMul && two instanceof GetFieldInstruction) {
one = pushedsfi.getPops().get(0).getPushed().getPops().get(0).getPushed().getInstruction();
two = pushedsfi.getPops().get(0).getPushed().getPops().get(1).getPushed().getInstruction();
}
}
// if both one and two are constants then one of them must not be a setter
PushConstantInstruction pc = null;
if (one instanceof PushConstantInstruction && !(two instanceof PushConstantInstruction)) {
pc = (PushConstantInstruction) one;
} else if (two instanceof PushConstantInstruction && !(one instanceof PushConstantInstruction)) {
pc = (PushConstantInstruction) two;
}
if (pc == null) {
continue;
}
Number value2 = (Number) pc.getConstant();
// field = something * constant
if (value2 instanceof Integer || value2 instanceof Long) {
fieldInfo.setters.add(value2);
}
}
}
}
use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class MultiplyOneDeobfuscator method visit.
private void visit(MethodContext mctx) {
for (InstructionContext ictx : mctx.getInstructionContexts()) {
Instruction instruction = ictx.getInstruction();
if (!(instruction instanceof IMul) && !(instruction instanceof LMul)) {
continue;
}
Instructions ins = ictx.getInstruction().getInstructions();
if (ins == null) {
continue;
}
List<Instruction> ilist = ins.getInstructions();
if (!ilist.contains(ictx.getInstruction())) {
// already done
continue;
}
StackContext one = ictx.getPops().get(0);
StackContext two = ictx.getPops().get(1);
StackContext other = null;
int removeIdx = -1;
if (one.getPushed().getInstruction() instanceof PushConstantInstruction && DMath.equals((Number) ((PushConstantInstruction) one.getPushed().getInstruction()).getConstant(), 1)) {
removeIdx = 0;
other = two;
} else if (two.getPushed().getInstruction() instanceof PushConstantInstruction && DMath.equals((Number) ((PushConstantInstruction) two.getPushed().getInstruction()).getConstant(), 1)) {
removeIdx = 1;
other = one;
}
if (removeIdx == -1) {
continue;
}
if (onlyConstants && !(other.getPushed().getInstruction() instanceof PushConstantInstruction)) {
continue;
}
if (!MultiplicationDeobfuscator.isOnlyPath(ictx, removeIdx == 0 ? one : two)) {
continue;
}
// remove 1
ictx.removeStack(removeIdx);
// remove mul
ins.remove(instruction);
++count;
}
}
use of net.runelite.asm.attributes.code.Instruction in project runelite by runelite.
the class ControlFlowDeobfuscator method run.
private void run(Code code) {
Instructions ins = code.getInstructions();
Exceptions exceptions = code.getExceptions();
ControlFlowGraph graph = new ControlFlowGraph.Builder().build(code);
for (Block block : graph.getBlocks()) {
assert block.getFlowsFrom() == null;
assert block.getFlowsInto() == null;
}
if (// graph.toString() is expensive
logger.isDebugEnabled()) {
logger.debug(graph.toString());
}
List<Exception> originalExceptions = new ArrayList<>(exceptions.getExceptions());
// Clear existing exceptions and instructions as we are going to
// rebuild them
exceptions.clear();
ins.clear();
List<Block> done = new ArrayList<>();
Queue<Block> queue = new PriorityQueue<>(this::compareBlock);
// add initial code block
queue.add(graph.getHead());
while (!queue.isEmpty()) {
Block block = queue.remove();
if (done.contains(block)) {
continue;
}
done.add(block);
++placedBlocks;
logger.debug("Placed block {}", block.getId());
List<Block> next = block.getNext();
if (next.isEmpty() == false) {
// jumps are added in order their instructions are reached by ControlFlowGraph,
// so the last jump is the goto.
//
// removing this line causes the priority queue (due to implementation detail on how
// it handles objects with equal priority) to try to optimize for block closeness
// (how close blocks which are neighbors are to each other in bytecode).
// I get a jump delta of ~+14k with this on 143, vs ~-47k when priotiziing optimizing
// out jumps. I can't tell which is better.
next.get(next.size() - 1).setJumptarget(true);
}
// add next reachable blocks
for (Block bl : next) {
queue.add(bl);
}
for (Instruction i : block.getInstructions()) {
assert i.getInstructions() == null;
// I shouldn't have to do this here
i.setInstructions(ins);
ins.addInstruction(i);
}
}
}
Aggregations