use of net.runelite.injector.InjectHookMethod.HOOKS 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.injector.InjectHookMethod.HOOKS in project runelite by runelite.
the class InjectHookMethodTest method testProcess.
@Test
public void testProcess() throws IOException, InjectionException {
InputStream in = getClass().getResourceAsStream("Actor.class");
ClassFile cf = ClassUtil.loadClass(in);
cf.setName("Actor");
cf.findMethod("bar").setDescriptor(new Signature("(LActor;I)I"));
ClassGroup deobfuscated = new ClassGroup();
deobfuscated.addClass(cf);
in = getClass().getResourceAsStream("Obfuscated.class");
ClassFile obcf = ClassUtil.loadClass(in);
obcf.setName("Obfuscated");
obcf.findMethod("foo").setDescriptor(new Signature("(LObfuscated;I)I"));
ClassGroup obfuscated = new ClassGroup();
obfuscated.addClass(obcf);
Method method = cf.findMethod("bar");
assert method != null;
Inject inject = new Inject(deobfuscated, obfuscated);
InjectHookMethod injectHookMethod = new InjectHookMethod(inject);
injectHookMethod.process(method);
method = obcf.findMethod("foo");
assert method != null;
Code code = method.getCode();
List<InvokeStatic> invokeIns = code.getInstructions().getInstructions().stream().filter(i -> i instanceof InvokeStatic).map(i -> (InvokeStatic) i).filter(i -> i.getMethod().getClazz().getName().equals(HOOKS)).collect(Collectors.toList());
assertTrue(!invokeIns.isEmpty());
assertEquals(2, invokeIns.size());
InvokeStatic invokeStatic = invokeIns.get(0);
Signature signature = invokeStatic.getMethod().getType();
// this + patamers
assertEquals(3, signature.size());
Type arg = signature.getTypeOfArg(1);
assertEquals(RL_API_PACKAGE_BASE.replace('.', '/') + "Actor", arg.getInternalName());
}
Aggregations