Patching
Since you are applying changes to the bytecode of a class, this must necessarily happen before said class is loaded in memory. The component that applies said changes is called a loader; don't concern yourself on the inner workings of loaders for now, just know that they are in charge of that initial step: we'll cover them in detail in their own chapter.
Generally speaking, you can solve any problem that can be solved via patching by modifying one or more methods in the correct way. This is preferrable, as you're unlikely to inadvertedly break compatibility with other parts of the program relying on that method if you stick to making small changes to the function body.
Suppose that you already have a working loader in place. This loader calls your injector method, and passes it a ClassNode
and a MethodNode
as arguments, representing respectively the container class and the method you're targeting. This is the most common type of ASM patching, and it's probably why you're here; more advanced subjects may be covered in additional chapters later on.
At a glance, if you're targeting something written in Java, this might seem restrictive. However, do keep in mind that even code outside of methods - in field declarations, in loose blocks, or in static
blocks - is actually considered to be part of a method by the compiler. Specifically, the constructor (<init>
) for instance fields and loose blocks, and the static constructor (<clinit>
) for static fields and static
blocks.