首页
社区
课程
招聘
[原创]MC禁止多人游戏引发的破解
2023-6-9 12:38 16271

[原创]MC禁止多人游戏引发的破解

2023-6-9 12:38
16271

本文章使用了javassistjavaagent对方法字节码进行动态修改。
从凌晨23:50开始研究这个问题,现在4:00成功

问题起因

朋友玩服务器,发现从6.8日9:00开始1.16.5客户端无法进入多人模式
图片描述
搜索发现好像是当天8号才出现这个问题
图片描述

摸索

对mc不太熟,觉得是微软搞了什么动作,抓包啥的,没抓到。
在语言资源里找到这串字符串
图片描述
简单说就是玩的离dao线ban模式,没权限给你多人模式。那为啥以前离线模式可以玩呢?不懂,研究一下Minecraft源代码

Minecraft逆向

一开始我是直接jadx打开主程序,发现没什么东西。通过上面字符串引用的签名,直接搜索,发现有个引用的地方调用了账号验证方法,然后抛出异常:
图片描述
找到jar包:
图片描述
图片描述
发现有个传统验证方法,但是应该已经弃用了:
图片描述

源码分析

一开始找到了一个项目:yushijinhun/authlib-injector: Build your own Minecraft authentication system.
图片描述
但是我试了,不行,可能是版本啥的问题。
于是尝试去找反混淆的项目,比如MCP啥的,看MC的源码。
这里用了forge的开发环境,反混淆映射表是mapped_official频道的,可以看authlib包的源代码:
图片描述
找来找去找到了mc主类和主界面类:
图片描述
感觉不远了,继续找:
图片描述
检查是否多人模式。跟进去,调用了authlib。
socialInteractionsService是一个接口,通过工厂方法创建一个com.mojang.authlib.yggdrasil.YggdrasilSocialInteractionsService实例。发现这里就是判断是否允许多人登录的地方:
图片描述

修改方法逻辑

本来想用forge写一个mod修改,但是好像不行,或者我没找到文档。然后想着mod里写一个动态hook,尝试了一下没成功。最后想着用javaagent动态修改方法字节码。
找了一些教程,研究了一下,踩了很多坑,找了很多bug。
具体解决的问题:

  1. ClassPool.getDefault()报错java.lang.NoClassDefFoundError,因为依赖冲突,加上shade插件。
  2. javassist.NotFoundException:classname传进去的是左斜杠分隔路径的类名,跟了下javassist源码才知道类池用点分隔的类名查。
  3. 转换成字节码时找不到类:应该是javassist编译的时候没有引入这个包,后来直接删掉了,因为这个检测的方法功能单一,全部置true。

步骤如下:
创建一个maven项目(java8),编辑配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>org.example</groupId>
    <artifactId>agnet</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>agnet</name>
    <url>http://maven.apache.org</url>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <archive>
                        <!--打包时,设置MANIFEST.MF的信息-->
                        <manifestEntries>
                            <Premain-Class>org.example.PremainTest</Premain-Class>
                            <Can-Redefine-Classes>true</Can-Redefine-Classes>
                            <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
            <plugin>
                <!-- 防止引用该jar的项目也使用javassist,与jar中javassist冲突-->
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <createSourcesJar>true</createSourcesJar>
                            <relocations>
                                <relocation>
                                    <pattern>javassist</pattern>
                                    <shadedPattern>org.example.javassist</shadedPattern>
                                </relocation>
                            </relocations>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency><!-- 修改字节码时,使用javassist -->
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.27.0-GA</version>
        </dependency>
 
    </dependencies>
</project>

创建一个org.example.PremainTest类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package org.example;
 
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
 
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
 
 
public class PremainTest {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("\n\n\n\nagent跑起来啦!=====================================");
        inst.addTransformer(new JavassistTransformer(), true);
    }
 
    public static void agentmain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
        inst.addTransformer(new JavassistTransformer(), true);
        Class classes[] = inst.getAllLoadedClasses();
        for (int i = 0; i < classes.length; i++) {
            if (classes[i].getName().equals("YggdrasilSocialInteractionsService")) {
                System.out.println("成功转换类:" + classes[i].getName());
                inst.retransformClasses(classes[i]);
                break;
            }
        }
    }
 
    static class JavassistTransformer implements ClassFileTransformer {
        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
 
            if ("com/mojang/authlib/yggdrasil/YggdrasilSocialInteractionsService".equals(className)) {
                try {
                    System.out.println("正在转换类名:" + className);
 
                    ClassPool classPool = ClassPool.getDefault();
 
                    CtClass clazz = classPool.get("com.mojang.authlib.yggdrasil.YggdrasilSocialInteractionsService");
 
                    CtMethod method = clazz.getDeclaredMethod("checkPrivileges");
 
                    // 修改方法
                    method.setBody("{\n" +
                            "        chatAllowed = true;\n" +
                            "        serversAllowed = true;\n" +
                            "        realmsAllowed = true;\n" +
                            "    }");
 
                    System.out.println("成功修改checkPrivileges方法!方法签名:" + method.getLongName());
 
                    byte[] bytes = clazz.toBytecode();
                    clazz.detach();
 
                    return bytes;
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
            return classfileBuffer;
        }
    }
}

mvn package编译,生成jar包。
回到forge项目(或者启动器),运行参数加上-javaagent
图片描述
修改方法成功:
图片描述
多人游戏也开放了:
图片描述

 

启动器命令行参数里加上这行:

 

图片描述
完美
图片描述


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞8
打赏
分享
最新回复 (1)
雪    币: 12
活跃值: (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
paofu88 2023-6-25 14:00
2
0
学习了
游客
登录 | 注册 方可回帖
返回