从凌晨23:50开始研究这个问题,现在4:00成功

问题起因

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

摸索

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

Minecraft逆向

一开始我是直接jadx打开主程序,发现没什么东西。通过上面字符串引用的签名,直接搜索,发现有个引用的地方调用了账号验证方法,然后抛出异常:
1686255043040-1e022800-970b-4e60-802c-1c845d237abd.png
找到jar包:
1686255114746-1a97ed41-ef6c-41f6-bc7c-0e3f4c8ea68f.png
1686255163452-d3b50b0f-e88e-4f60-8e91-c8e7d3ecf159.png
发现有个传统验证方法,但是应该已经弃用了:
1686255203621-b27b5fb8-3c7f-4d1e-a76f-77fb146ed616.png

源码分析

一开始找到了一个项目:yushijinhun/authlib-injector: Build your own Minecraft authentication system.
1686255268868-16690a54-dcae-4285-9bcb-52c5349769c9.png
但是我试了,不行,可能是版本啥的问题。
于是尝试去找反混淆的项目,比如MCP啥的,看MC的源码。
这里用了forge的开发环境,反混淆映射表是mapped_official频道的,可以看authlib包的源代码:
1686255368808-2d604869-1a04-475c-9885-d06f40e36fed.png
找来找去找到了mc主类和主界面类:
1686255511080-3c645232-0cda-4252-83ce-2f31cd2ad2e7.png
感觉不远了,继续找:
1686255539685-56d2e6f3-9fd5-4fea-809c-690f8767cd39.png
检查是否多人模式。跟进去,调用了authlib。
socialInteractionsService是一个接口,通过工厂方法创建一个com.mojang.authlib.yggdrasil.YggdrasilSocialInteractionsService实例。发现这里就是判断是否允许多人登录的地方:
1686255781758-e42fc21f-95f2-4cb8-a334-a31443097f45.png

修改方法逻辑

本来想用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
80
<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
66
67
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
1686256255142-0a4e515c-a86c-4da2-a093-0560f07d6897.png
修改方法成功:
1686256345717-05549c14-b70c-4e1d-be1a-e4c4ef318a3b.png
多人游戏也开放了:
1686256365898-48897d02-fefb-486e-9501-061098e3aced.png

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

1686257377489-dbae20c6-faa3-4221-aa88-08e19eb83e05.png
完美
1686257491286-201fae7c-c54c-4a02-8c0b-332f57a689d8.png

⬆︎TOP