下面列出了怎么用org.objectweb.asm.tree.MethodNode的API类实例代码及写法,或者点击链接到github查看源代码。
public boolean patch(ClassNode cnode) {
LinkedList<String> names = new LinkedList<String>();
for(MethodNode method : cnode.methods) {
ObfMapping m = new ObfMapping(cnode.name, method.name, method.desc).toRuntime();
names.add(m.s_name+m.s_desc);
}
boolean changed = false;
for(MethodNode impl : impls) {
if(names.contains(impl.name+impl.desc))
continue;
MethodNode copy = new MethodNode(impl.access, impl.name, impl.desc,
impl.signature, impl.exceptions == null ? null : impl.exceptions.toArray(new String[0]));
ASMHelper.copy(impl, copy);
cnode.methods.add(impl);
changed = true;
}
return changed;
}
private void addGlobalInjectInvokes()
{
MethodNode codeBefore = new MethodNode();
MethodNode codeAfter = new MethodNode();
this.fillMethodInvokes(codeBefore, codeAfter, this.classData);
for (Entry<MethodNode, TransformerInitMethodData> initEntry : this.inits.entrySet())
{
MethodNode init = initEntry.getKey();
TransformerInitMethodData initPair = initEntry.getValue();
MethodInsnNode superInvoke = initPair.superInvoke;
if (codeAfter.instructions.size() > 0)
{
for (InsnNode node : initPair.returns)
{
init.instructions.insertBefore(node, codeAfter.instructions);
}
}
if (codeBefore.instructions.size() > 0)
{
init.instructions.insert(superInvoke, codeBefore.instructions);
}
}
}
@Inject(description = "Add hook to disable pushing out of blocks")
public void inject(MethodNode main) {
AbstractInsnNode preNode = main.instructions.getFirst();
AbstractInsnNode postNode =
ASMHelper.findPattern(main.instructions.getFirst(), new int[]{ICONST_0, IRETURN}, "xx");
Objects.requireNonNull(preNode, "Find pattern failed for pre node");
Objects.requireNonNull(postNode, "Find pattern failed for post node");
LabelNode endJump = new LabelNode();
InsnList insnPre = new InsnList();
insnPre.add(ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onPushOutOfBlocks));
insnPre.add(new JumpInsnNode(IFNE, endJump));
main.instructions.insertBefore(preNode, insnPre);
main.instructions.insertBefore(postNode, endJump);
}
private boolean isParameterAnnotationFound(List<Annotation> annotationRules, MethodNode methodNode) {
boolean annotationFound = true;
List<AnnotationNode> allParameterAnnotations = new ArrayList<>();
List<AnnotationNode>[] visibleParameterAnnotations = methodNode.visibleParameterAnnotations;
if (visibleParameterAnnotations != null && visibleParameterAnnotations.length != 0) {
addIfNotNull(allParameterAnnotations, visibleParameterAnnotations);
}
List<AnnotationNode>[] inVisibleParameterAnnotations = methodNode.invisibleParameterAnnotations;
if (inVisibleParameterAnnotations != null && inVisibleParameterAnnotations.length != 0) {
addIfNotNull(allParameterAnnotations, inVisibleParameterAnnotations);
}
if (annotationRules != null && !annotationRules.isEmpty()) {
for (Annotation annotationRule : annotationRules) {
annotationFound &= RuleHelper.containsAnnotation(annotationRule, allParameterAnnotations);
}
}
return annotationFound;
}
/**
* Returns the actual method access right or a best guess if we don't have access to the
* method definition.
*
* @param owner the method owner class
* @param name the method name
* @param desc the method signature
* @return the {@link AccessRight} for that method.
*/
private AccessRight getMethodAccessRight(String owner, String name, String desc) {
AccessRight accessRight;
if (owner.equals(visitedClassName)) {
MethodNode methodByName = getMethodByName(name, desc);
if (methodByName == null) {
// we did not find the method invoked on ourselves, which mean that it really
// is a parent class method invocation and we just don't have access to it.
// the most restrictive access right in that case is protected.
return AccessRight.PROTECTED;
}
accessRight = AccessRight.fromNodeAccess(methodByName.access);
} else {
// we are accessing another class method, and since we make all protected and
// package-private methods public, we can safely assume it is public.
accessRight = AccessRight.PUBLIC;
}
return accessRight;
}
@Test
public void methodOfNioBufferWithCovariantTypes_afterDesugar(
@AsmNode(className = "NioBufferInvocations", memberName = "getByteBufferPosition", round = 1)
MethodNode after) {
ImmutableList<AbstractInsnNode> methodInvocations =
Arrays.stream(after.instructions.toArray())
.filter(insnNode -> insnNode.getType() == METHOD_INSN)
.collect(toImmutableList());
assertThat(methodInvocations).hasSize(1);
MethodInsnNode methodInsnNode = (MethodInsnNode) Iterables.getOnlyElement(methodInvocations);
assertThat(methodInsnNode.owner).isEqualTo("java/nio/ByteBuffer");
assertThat(methodInsnNode.name).isEqualTo("position");
assertThat(methodInsnNode.desc).isEqualTo("(I)Ljava/nio/Buffer;");
TypeInsnNode typeInsnNode = (TypeInsnNode) methodInsnNode.getNext();
assertThat(typeInsnNode.getOpcode()).isEqualTo(Opcodes.CHECKCAST);
assertThat(typeInsnNode.desc).isEqualTo("java/nio/ByteBuffer");
assertThat(typeInsnNode.getNext().getOpcode()).isEqualTo(Opcodes.ARETURN);
}
public void addGetterMethod(final String methodName, final ASMFieldNodeAdapter fieldNode) {
Assert.requireNonNull(methodName, "methodName");
Assert.requireNonNull(fieldNode, "fieldNode");
// no argument is ().
final String desc = "()" + fieldNode.getDesc();
final MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, methodName, desc, null, null);
final InsnList instructions = getInsnList(methodNode);
// load this.
instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
// get fieldNode.
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldNode.getName(), fieldNode.getDesc()));
// return of type.
final Type type = Type.getType(fieldNode.getDesc());
instructions.add(new InsnNode(type.getOpcode(Opcodes.IRETURN)));
addMethodNode0(methodNode);
}
public static byte[] transform(byte[] bytes) {
ClassNode cnode = ASMHelper.createClassNode(bytes, ClassReader.EXPAND_FRAMES);
boolean changed = false;
Iterator<MethodNode> it = cnode.methods.iterator();
while (it.hasNext()) {
MethodNode mnode = it.next();
ReferenceDetector r = new ReferenceDetector();
mnode.accept(new RemappingMethodAdapter(mnode.access, mnode.desc, new MethodVisitor(Opcodes.ASM4) {
}, r));
if (r.found) {
it.remove();
changed = true;
}
}
if (changed) {
bytes = ASMHelper.createBytes(cnode, 0);
}
return bytes;
}
@Inject(description = "Changes in layer code so that we can change it")
public void inject(MethodNode main) {
AbstractInsnNode node =
ASMHelper.findPattern(main.instructions.getFirst(), new int[]{INVOKEVIRTUAL}, "x");
Objects.requireNonNull(node, "Find pattern failed for node");
InsnList insnList = new InsnList();
// starting after INVOKEVIRTUAL on Block.getBlockLayer()
insnList.add(new VarInsnNode(ASTORE, 3)); // store the result from getBlockLayer()
insnList.add(new VarInsnNode(ALOAD, 0)); // push this
insnList.add(new VarInsnNode(ALOAD, 1)); // push block state
insnList.add(new VarInsnNode(ALOAD, 3)); // push this.getBlockLayer() result
insnList.add(
new VarInsnNode(ALOAD, 2)); // push the block layer of the block we are comparing to
insnList.add(
ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onRenderBlockInLayer));
// now our result is on the stack
main.instructions.insert(node, insnList);
}
@Inject(description = "Add hook to set boat yaw when it's rendered")
public void inject(MethodNode main) {
InsnList insnList = new InsnList();
insnList.add(new VarInsnNode(ALOAD, 1)); // load the boat entity
insnList.add(new VarInsnNode(FLOAD, 8)); // load the boat yaw
insnList.add(
ASMHelper.call(
INVOKESTATIC,
TypesHook.Methods
.ForgeHaxHooks_onRenderBoat)); // fire the event and get the value(player
// rotationYaw) returned by the method in
// ForgeHaxHooks
insnList.add(new VarInsnNode(FSTORE, 8)); // store it in entityYaw
main.instructions.insert(insnList); // insert code at the top of the method
}
protected void duplicate(MethodNode mn, AbstractInsnNode ain) {
try {
if (ain instanceof LabelNode) {
mn.instructions.insert(ain, new LabelNode());
OpUtils.clearLabelCache();
} else if (ain instanceof JumpInsnNode) {
mn.instructions.insert(ain, new JumpInsnNode(ain.getOpcode(), ((JumpInsnNode) ain).label));
} else {
mn.instructions.insert(ain, ain.clone(new HashMap<>()));
}
MyCodeList.this.loadInstructions(mn);
} catch (Exception e1) {
new ErrorDisplay(e1);
}
}
@Inject(description = "Insert hook before buffer is uploaded")
public void inject(MethodNode main) {
AbstractInsnNode node =
ASMHelper.findPattern(
main.instructions.getFirst(),
new int[]{
INVOKESTATIC, IFEQ, 0x00, 0x00, ALOAD,
},
"xx??x");
Objects.requireNonNull(node, "Find pattern failed for node");
InsnList insnList = new InsnList();
insnList.add(new VarInsnNode(ALOAD, 3));
insnList.add(new VarInsnNode(ALOAD, 2));
insnList.add(ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onChunkUploaded));
main.instructions.insertBefore(node, insnList);
}
@Override
public void transform(JarArchive ja, ClassNode node) {
if (twoLongType) {
// init surroundings before decryption
Outer: for (ClassNode cn : ja.getClasses().values()) {
for (MethodNode mn : cn.methods) {
for (AbstractInsnNode ain : mn.instructions.toArray()) {
if (ain.getOpcode() == INVOKESPECIAL) {
MethodInsnNode min = (MethodInsnNode) ain;
if (min.owner.equals(node.name) && min.name.equals("<init>")) {
try {
Class.forName(cn.name.replace("/", "."), true, vm);
} catch (ClassNotFoundException e) {
}
continue Outer;
}
}
}
}
}
}
node.methods.forEach(mn -> removeDynamicCalls(node, mn));
}
@SuppressWarnings("unchecked") // ASM API
public static void scanForAndCheckSetOnTouchListenerCalls(
ClassContext context,
ClassNode classNode) {
List<MethodNode> methods = classNode.methods;
for (MethodNode methodNode : methods) {
ListIterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
while (iterator.hasNext()) {
AbstractInsnNode abstractInsnNode = iterator.next();
if (abstractInsnNode.getType() == AbstractInsnNode.METHOD_INSN) {
MethodInsnNode methodInsnNode = (MethodInsnNode) abstractInsnNode;
if (methodInsnNode.name.equals(SET_ON_TOUCH_LISTENER)
&& methodInsnNode.desc.equals(SET_ON_TOUCH_LISTENER_SIG)) {
checkSetOnTouchListenerCall(context, methodNode, methodInsnNode);
}
}
}
}
}
/**
* "Pass through" a synthetic inner class. Transforms package-private
* members in the class into public so that they are accessible from their
* new home in the target class
*/
private void processSyntheticInner(ClassNode classNode) {
classNode.access |= Opcodes.ACC_PUBLIC;
for (FieldNode field : classNode.fields) {
if ((field.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) == 0) {
field.access |= Opcodes.ACC_PUBLIC;
}
}
for (MethodNode method : classNode.methods) {
if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) == 0) {
method.access |= Opcodes.ACC_PUBLIC;
}
}
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
String[] exceptions) {
AcesoProguardMap.instance().putMethod(visitedClassName, IncrementalTool.getMtdSig(name, desc));
access = IncrementalTool.transformAccessForInstantRun(access);
MethodVisitor defaultVisitor = super.visitMethod(access, name, desc, signature, exceptions);
MethodNode method = getMethodByNameInClass(name, desc, classNode);
// does the method use blacklisted APIs.
boolean hasIncompatibleChange = InstantRunMethodVerifier.verifyMethod(method);
if (hasIncompatibleChange || disableRedirectionForClass
|| !isAccessCompatibleWithInstantRun(access)
|| name.equals(ByteCodeUtils.CLASS_INITIALIZER)) {
return defaultVisitor;
} else {
ArrayList<Type> args = new ArrayList<Type>(Arrays.asList(Type.getArgumentTypes(desc)));
boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
if (!isStatic) {
args.add(0, Type.getType(Object.class));
}
ISMethodVisitor mv = new ISMethodVisitor(defaultVisitor, access, name, desc);
if (name.equals(ByteCodeUtils.CONSTRUCTOR)) {
} else {
mv.addRedirection(new MethodRedirection(
new LabelNode(mv.getStartLabel()),
visitedClassName,
name,
desc,
args,
Type.getReturnType(desc), isStatic));
}
method.accept(mv);
return null;
}
}
@Override
public void transform(ClassNode classNode, String name) {
for (MethodNode methodNode : classNode.methods) {
if (TransformerMethod.playSound.matches(methodNode)) {
// Objective:
// Find: this.getNormalizedVolume(p_sound, soundpoolentry, soundcategory);
// Replace method with: SoundManagerHook.getNormalizedVolume(this, p_sound, soundpoolentry, soundcategory);
Iterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
while (iterator.hasNext()) {
AbstractInsnNode abstractNode = iterator.next();
if (abstractNode instanceof MethodInsnNode) {
MethodInsnNode methodInsnNode = (MethodInsnNode)abstractNode;
if (nameMatches(methodInsnNode.owner, TransformerClass.SoundManager.getNameRaw()) && TransformerMethod.getNormalizedVolume.matches(methodInsnNode)) {
methodNode.instructions.insertBefore(abstractNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "codes/biscuit/skyblockaddons/asm/hooks/SoundManagerHook", "getNormalizedVolume",
"("+TransformerClass.SoundManager.getName()+TransformerClass.ISound.getName()+TransformerClass.SoundPoolEntry.getName()+TransformerClass.SoundCategory.getName()+")F",
false)); // Add SoundManagerHook.getNormalizedVolume(this, p_sound, soundpoolentry, soundcategory);
iterator.remove(); // Remove the old method call.
break;
}
}
}
break;
}
}
}
private MethodNode findMethodNode(final String methodName, final List<MethodNode> methodNodes) {
for (MethodNode methodNode : methodNodes) {
if (methodNode.name.equals(methodName)) {
return methodNode;
}
}
return null;
}
public String decompile(byte[] b, MethodNode mn) {
try {
//TODO decompile method only
this.bytes = b;
HashMap<String, Object> map = new HashMap<>();
for (String key : options.keySet()) {
map.put(key, JByteMod.ops.get("ff_" + key).getBoolean() ? "1" : "0");
}
Fernflower f = new Fernflower(this, this, map, new PrintStreamLogger(JByteMod.LOGGER));
StructContext sc = f.getStructContext();
StructClass cl = new StructClass(b, true, sc.getLoader());
sc.getClasses().put(cn.name, cl);
//instead of loading a file use custom bridge, created a few getters
String fakePath = new File("none.class").getAbsolutePath();
ContextUnit unit = new ContextUnit(ContextUnit.TYPE_FOLDER, null, fakePath, true, sc.getSaver(), sc.getDecompiledData());
sc.getUnits().put(fakePath, unit);
unit.addClass(cl, "none.class");
sc.getLoader().addClassLink(cn.name, new LazyLoader.Link(LazyLoader.Link.CLASS, fakePath, null));
f.decompileContext();
return returned;
} catch (Exception e) {
e.printStackTrace();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return sw.toString();
}
}
/**
* Retrieve filtered {@link AbstractInsnNode}'s of a {@link MethodNode} and put them into an array.
* @param m MethodNode to get instructions from.
* @param filter Filter to filter instructions.
* @return Filtered {@link AbstractInsnNode}'s.
*/
public static AbstractInsnNode[] getInstructions(MethodNode m, InstructionFilter filter) {
ArrayList<AbstractInsnNode> insns = new ArrayList<AbstractInsnNode>();
ListIterator<?> it = m.instructions.iterator();
while (it.hasNext()) {
AbstractInsnNode ain = (AbstractInsnNode) it.next();
if (filter.accept(ain))
insns.add(ain);
}
return insns.toArray(new AbstractInsnNode[insns.size()]);
}
/**
* Check for second decryption method (two / three params (int, int, int))
*/
private boolean hasMathMethod(ClassNode cn) {
for (MethodNode mn : cn.methods) {
if (InsnUtils.matches(mn.instructions, new int[] { ILOAD, ILOAD, IXOR, SIPUSH, IXOR, LDC })) {
return true;
}
}
return false;
}
@Override
public void transform(ClassNode cnode) {
Game.logger().info("Transforming TileEntity class for dynamic instance injection.");
ObfMapping obfMap = new ObfMapping("bcm", "c", "(Lfn;)Lbcm;");
ObfMapping deobfMap = new ObfMapping("net/minecraft/tileentity/TileEntity", "createAndLoadEntity", "(Lnet/minecraft/nbt/NBTTagCompound;)Lnet/minecraft/tileentity/TileEntity;");
MethodNode method = ASMHelper.findMethod(obfMap, cnode);
if (method == null) {
Game.logger().warn("Lookup {} failed. You are probably in a deobf environment.", obfMap);
method = ASMHelper.findMethod(deobfMap, cnode);
if (method == null) {
throw new IllegalStateException("[NOVA] Lookup " + deobfMap + " failed!");
}
}
Game.logger().info("Transforming method {}", method.name);
ASMHelper.removeBlock(method.instructions, new InstructionComparator.InsnListSection(method.instructions, 23, 26));
InsnList list = new InsnList();
list.add(new VarInsnNode(ALOAD, 0));
list.add(new VarInsnNode(ALOAD, 2));
list.add(new MethodInsnNode(INVOKESTATIC, "nova/core/wrapper/mc/forge/v18/asm/StaticForwarder", "loadTileEntityHook", "(Lnet/minecraft/nbt/NBTTagCompound;Ljava/lang/Class;)Lnet/minecraft/tileentity/TileEntity;", false));
list.add(new VarInsnNode(ASTORE, 1));
method.instructions.insert(method.instructions.get(22), list);
Game.logger().info("Injected instruction to method: {}", method.name);
}
Constructor(VarInsnNode loadThis, int lineForLoad, MethodNode args, MethodInsnNode delegation, MethodNode body) {
this.loadThis = loadThis;
this.lineForLoad = lineForLoad;
this.args = args;
this.delegation = delegation;
this.body = body;
}
public ASMMethodNodeAdapter addDelegatorMethod(final ASMMethodNodeAdapter superMethodNode) {
Assert.requireNonNull(superMethodNode, "superMethodNode");
final String[] exceptions = getSuperMethodExceptions(superMethodNode);
final MethodNode rawMethodNode = new MethodNode(superMethodNode.getAccess(), superMethodNode.getName(), superMethodNode.getDesc(), superMethodNode.getSignature(), exceptions);
final ASMMethodNodeAdapter methodNode = new ASMMethodNodeAdapter(getInternalName(), rawMethodNode);
methodNode.addDelegator(superMethodNode.getDeclaringClassInternalName());
addMethodNode0(methodNode.getMethodNode());
return methodNode;
}
private boolean hasAnnotation(MethodNode mn, String lAnnotationDescriptor, boolean checkMetaUsage) {
if (checkMetaUsage) {
return findMetaAnnotationUsage(toAnnotations(mn.visibleAnnotations), lAnnotationDescriptor);
} else {
List<AnnotationNode> vAnnotations = mn.visibleAnnotations;
if (vAnnotations != null) {
for (AnnotationNode an : vAnnotations) {
if (an.desc.equals(lAnnotationDescriptor)) {
return true;
}
}
}
}
return false;
}
/**
* Finds references to the class's field in the given method.
*
* @param target
* @param targetField
* @param method
* @return
*/
public static List<Reference> getReferences(ClassNode target, FieldNode targetField, ClassNode inThisNode, MethodNode method) {
List<Reference> references = new ArrayList<Reference>();
for (AbstractInsnNode ain : method.instructions.toArray()) {
if (ain.getType() == AbstractInsnNode.FIELD_INSN) {
FieldInsnNode fin = (FieldInsnNode) ain;
if (fin.owner.contains(target.name) && fin.name.equals(targetField.name) && fin.desc.equals(targetField.desc)) {
references.add(new Reference(inThisNode, method, ain));
}
}
}
return references;
}
public static MethodNode findMethod(@NotNull ClassNode classNode, String name, String desc) {
return classNode.methods
.stream()
.filter(methodNode -> name.equals(methodNode.name) && desc.equals(methodNode.desc))
.findAny()
.orElse(null);
}
private static void report(final ClassContext context, String message, AbstractInsnNode node,
MethodNode method, String patternStart, String patternEnd, SearchHints hints) {
int lineNumber = node != null ? ClassContext.findLineNumber(node) : -1;
// If looking for a constructor, the string we'll see in the source is not the
// method name (<init>) but the class name
if (patternStart != null && patternStart.equals(CONSTRUCTOR_NAME)
&& node instanceof MethodInsnNode) {
if (hints != null) {
hints = hints.matchConstructor();
}
patternStart = ((MethodInsnNode) node).owner;
}
if (patternStart != null) {
int index = patternStart.lastIndexOf('$');
if (index != -1) {
patternStart = patternStart.substring(index + 1);
}
index = patternStart.lastIndexOf('/');
if (index != -1) {
patternStart = patternStart.substring(index + 1);
}
}
Location location = context.getLocationForLine(lineNumber, patternStart, patternEnd,
hints);
context.report(UNSUPPORTED, method, node, location, message);
}
public ArrayList<Detour> load(ClassNode cn) {
ArrayList<Detour> detours = new ArrayList<Detour>();
for (Object o : cn.methods) {
MethodNode mn = (MethodNode) o;
AnnotationNode a = getAnnotation(mn);
if (a != null) {
Detour detour = null;
if (a.desc
.equals("Lcom/rakuten/tech/mobile/perf/core/annotations/DetourConstructorParameter;")) {
detour = constructorParameterDetour(cn, mn, a);
} else if (a.desc.equals("Lcom/rakuten/tech/mobile/perf/core/annotations/DetourCall;")) {
detour = callDetour(cn, mn, a);
} else if (a.desc
.equals("Lcom/rakuten/tech/mobile/perf/core/annotations/DetourStaticCall;")) {
detour = staticCallDetour(cn, mn, a);
}
if (detour != null) {
_log.debug("Loaded detour for " + detour.matchMethod + detour.matchDesc);
detours.add(detour);
}
}
}
return detours;
}
/**
* Finds the line number closest to the given class declaration
*
* @param node the method node to get a line number for
* @return the closest line number, or -1 if not known
*/
public static int findLineNumber(@NonNull ClassNode node) {
if (node.methods != null && !node.methods.isEmpty()) {
MethodNode firstMethod = getFirstRealMethod(node);
if (firstMethod != null) {
return findLineNumber(firstMethod);
}
}
return -1;
}