✵Simple Injection Client Creation Tutorial✵

Status
This thread has been locked.

Improper

Feedback score
0
Posts
147
Reactions
50
Resources
0
What is an injection client?
An injection client is one that modifies the client at runtime, rather than compile-time (Such as a client exported with Minecraft Coder Pack).

What is an agent and why do I need one?
An agent gives a program instrumentation capabilities which allows it to re-define classes on the fly. In the context of an injection client, it will be used to insert hooks.

What is ASM?
ASM is an all purpose Java bytecode manipulation and analysis framework written by the OW2 consortium.

Why ASM?
ASM is objectively the fastest library when it comes to bytecode modification. It will be used to make bytecode modification with agents simple. In this scenario we will be using ASM's tree API for inserting & changing existing classes.
Pro-tip: Use the source of ASM rather than downloading the binary. They compact their output and remove generics which makes iterating lists cumbersome. The source comes with the download which can be located here.

Where can I learn ASM?(Specifically the Tree API)
The official 4.0 documentation PDF (Page 95)
David Tiller's "Not-So-Secret Java Agents"
The examples provided in the ASM download


Getting Started


Step 0: Setting up your workspace
I will be using a library that I wrote. All of my examples will revolve around it. If you would like to use it I suggest downloading and adding the source to your project.
SkidHijack on Github


Step 1: Setting up an agent
Rather than re-hashing what's been said before I'll provide some good links to other tutorials on agents:
Oracle docs on Instrumentation
Basic agent setup
How to use ASM with Agent's instrumentation


Step 2: How to make Minecraft easy to access
There are multiple ways to approach this. I will only be going over which revolves around what I call "shell" classes. Shell classes are used to access class members regardless of their modifiers (private / final / protected). For example I've made a shell class of PlayerControllerMP.
Code:
Code:
@RemappedName(name = "blm")
public class PlayerControllerMP {

    @RemappedName(name = "g")
    public int hitDelay;

    @RemappedName(name = "e")
    public float currentDamage;

    @RemappedName(name = "a")
    public void attack(EntityPlayer attacker, Entity target) {}
}
Normally hitDelay and currentDamageMP aren't public. When we create our mods (Like Fastmine) we will referrer to this shell's fields & methods. Then we will have our agent rewrite all classes in our client package so that references to our shell classes are replaced with the original classes. As for the original classes, we will change all member's access to be public when possible (certain members should not be touched, such as the <clinit> and <init> methods).

Here is how I register classes & packages for bytecode modification:
Code:
Code:
// Modding a package
    PackageMatcher clientPkgMatcher = new PackageMatcher("me/lpk/client");
    clientPkgMatcher.addReceiver(new ShellReplacementModder(clientPkgMatcher, "mcshell"));
    Refactorer.register(clientPkgMatcher);
// Modding a specific class
    ClassMatcher player = new ClassMatcher("bnn");
    player.addReceiver(new PlayerModder(player));
    Refactorer.register(player);
Here is an example ClassModder implementation (PlayerModder):
Code:
Code:
public class PlayerModder extends ClassModder {
    public PlayerModder(AbstractMatcher<?> matcher) {
        super(matcher);
    }

    @Override
    public void modify(ClassNode cn) {
        for (MethodNode mn : cn.methods) {
            if (mn.name.equals("m") && mn.desc.equals("()V")) {
                // onUpdate
                mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, "Events", "callTick", "()V", false));
            } else if (mn.name.equals("a") && mn.desc.equals("(Ljava/lang/String;)V")) {
                LabelNode end = new LabelNode();
                mn.instructions.insert(new JumpInsnNode(Opcodes.IFNE, end));
                mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, "Events", "callChatMessage", "(Ljava/lang/String;)Z", false));
                mn.instructions.insert(new VarInsnNode(Opcodes.ALOAD, 1));
                mn.instructions.add(end);
            }
        }
    }
}
Here is how I re-direct references from the shell class to the obfuscated ones: (Source too long for post)
RemappedName
ShellReplacementModder
Here is how I make everything accessible at runtime.
AccessModder


Step 3: Writing the client
This step should be familiar to you if you've written a client using Minecraft Coder Pack (Especially due to the shells). The only "hard" part is injecting events.

Here's an example of a cancellable event. It invokes a method that returns the cancelled state of the event.
Code:
Code:
    // EntityPlayerSP
    @Override
    public void modify(ClassNode cn) {
        for (MethodNode mn : cn.methods) {
            if (mn.name.equals("a") && mn.desc.equals("(Ljava/lang/String;)V")) {
                // Logic (pseudo-code):
                //
                // boolean cancelled = Events.callChatMessage(parameter_string)
                // if (cencelled) --> Jump to end of method
                //
                LabelNode end = new LabelNode();
                mn.instructions.add(end);
                mn.instructions.insert(new JumpInsnNode(Opcodes.IFNE, end));
                mn.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, "me/lpk/client/Events", "callChatMessage", "(Ljava/lang/String;)Z", false));
                mn.instructions.insert(new VarInsnNode(Opcodes.ALOAD, 1));
            }
        }
    }


Step 4: Compile & Use
Export as a normal jar.
Overwrite META-INF/Manifest.mf - Ensure Manifest's Agent attributes are correct.
Edit Minecraft launch args and play


Launch args: (Noverify is used because we may invalidate existing stack-frames with out changes. Using COMPUTE_FRAMES can remedy this but may result in some problems with reflection since it uses that in computing the new frames)
Code:
Code:
-javaagent:"path/to/Agent.jar" -noverify

Credits
-------
GenericSkid
https://hentaiandecchi.ayzhin.com/forums/showthread.php?tid=4540
 
Last edited:
PebbleHost
High performance, consistent uptime and fast support. Minecraft hosting that just works.

Improper

Feedback score
0
Posts
147
Reactions
50
Resources
0
Did not state it was mine, I posted it for the access of other users; I have edited the post w/credits, apologies for the confusion.
 
Last edited:
Status
This thread has been locked.
Top