Skip to content

Commit ddd8fb9

Browse files
committed
feat: deobfuscation
1 parent 8f49b22 commit ddd8fb9

11 files changed

Lines changed: 141 additions & 63 deletions

File tree

src/client/java/com/hamusuke/packetcap/Config.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ public class Config {
66
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
77

88
private static final ForgeConfigSpec.BooleanValue SHOW_PACKET_FLOW = BUILDER
9-
.comment("In overlay, whether to show packet flow: e.g. C2S or S2C")
9+
.comment("In hud, whether to show packet flow: e.g. C2S or S2C")
1010
.define("showPacketFlow", false);
1111
private static final ForgeConfigSpec.BooleanValue SHOW_PACKET_NAME_POSTFIX = BUILDER
12-
.comment("In overlay, whether to show postfix of packet name: e.g. ...Packet")
12+
.comment("In hud, whether to show postfix of packet name: e.g. ...Packet")
1313
.define("showPacketNamePostfix", false);
1414

1515
static final ForgeConfigSpec SPEC = BUILDER.build();
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.hamusuke.packetcap;
2+
3+
import com.google.common.collect.Maps;
4+
import it.unimi.dsi.fastutil.Pair;
5+
import org.apache.logging.log4j.LogManager;
6+
import org.apache.logging.log4j.Logger;
7+
8+
import java.nio.charset.StandardCharsets;
9+
import java.nio.file.Files;
10+
import java.nio.file.Path;
11+
import java.util.Map;
12+
import java.util.Map.Entry;
13+
import java.util.function.Predicate;
14+
15+
public class Deobfuscation {
16+
private static final Logger LOGGER = LogManager.getLogger();
17+
private final Path path;
18+
private final Predicate<String> shouldDeobfuscate;
19+
private final Deobfuscater deobfuscater;
20+
private final Map<String, String> deobMap;
21+
private boolean deobEnabled = true;
22+
23+
public Deobfuscation(Path path, Predicate<String> shouldDeobfuscate, Deobfuscater deobfuscater) {
24+
this.path = path;
25+
this.shouldDeobfuscate = shouldDeobfuscate;
26+
this.deobfuscater = deobfuscater;
27+
28+
this.deobMap = this.deobfuscate();
29+
}
30+
31+
public String deobfuscate(String name) {
32+
if (!this.deobEnabled) {
33+
return name;
34+
}
35+
36+
return this.deobMap.getOrDefault(name, name);
37+
}
38+
39+
protected Map<String, String> deobfuscate() {
40+
if (!this.path.toFile().exists() || this.path.toFile().isDirectory()) {
41+
this.deobEnabled = false;
42+
return Map.of();
43+
}
44+
45+
Map<String, String> map = Maps.newHashMap();
46+
try {
47+
var lines = Files.readAllLines(this.path, StandardCharsets.UTF_8)
48+
.stream()
49+
.map(String::trim)
50+
.toList();
51+
52+
for (var line : lines) {
53+
if (this.shouldDeobfuscate.test(line)) {
54+
var e = this.deobfuscater.deobfuscate(line);
55+
map.put(e.key(), e.value());
56+
}
57+
}
58+
} catch (Exception e) {
59+
LOGGER.warn("Failed to map for deobfuscation", e);
60+
}
61+
62+
return map;
63+
}
64+
65+
public interface Deobfuscater {
66+
Pair<String, String> deobfuscate(String text);
67+
}
68+
}

src/client/java/com/hamusuke/packetcap/PacketCapture.java

Lines changed: 31 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.hamusuke.packetcap;
22

3-
import com.google.common.collect.*;
3+
import com.google.common.collect.ImmutableList;
4+
import com.google.common.collect.ImmutableSet;
5+
import com.google.common.collect.Lists;
6+
import com.google.common.collect.Sets;
47
import com.google.gson.Gson;
58
import com.google.gson.stream.JsonWriter;
69
import com.hamusuke.packetcap.filter.FilterType;
710
import com.hamusuke.packetcap.filter.PacketFilter;
8-
import com.hamusuke.packetcap.gui.overlay.PacketCaptureOverlay;
11+
import com.hamusuke.packetcap.gui.hud.PacketCaptureHud;
912
import com.hamusuke.packetcap.gui.screen.PacketListScreen;
1013
import com.hamusuke.packetcap.highlight.DataHighlightInstruction;
1114
import com.hamusuke.packetcap.highlight.DataHighlightInstructions;
@@ -15,6 +18,7 @@
1518
import io.netty.buffer.ByteBuf;
1619
import io.netty.buffer.Unpooled;
1720
import io.netty.util.ReferenceCountUtil;
21+
import it.unimi.dsi.fastutil.Pair;
1822
import net.fabricmc.api.ClientModInitializer;
1923
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
2024
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
@@ -57,12 +61,12 @@
5761
public final class PacketCapture implements ClientModInitializer {
5862
public static final String MOD_ID = "packetcapture";
5963
public static final Identifier MONO_FONT = Identifier.of(MOD_ID, "mono");
60-
private static final Identifier PACKET_CAPTURE_OVERLAY_LAYER_ID = Identifier.of(MOD_ID, "layer");
64+
private static final Identifier PACKET_CAPTURE_HUD_LAYER_ID = Identifier.of(MOD_ID, "layer");
6165
private static final ExecutorService SENT_PACKET_DETAIL_RETRIEVER = Executors.newSingleThreadExecutor(r -> new Thread(r, "Sent-Packet-Detail-Retriever"));
6266
private static final ExecutorService RECEIVED_PACKET_DETAIL_RETRIEVER = Executors.newSingleThreadExecutor(r -> new Thread(r, "Received-Packet-Detail-Retriever"));
6367
private static final Logger LOGGER = LogManager.getLogger();
6468
private static final int MAX_PACKET_SIZE = 16384;
65-
private static final KeyBinding RENDER_CAPTURE_OVERLAY = new KeyBinding(MOD_ID + ".key.render_cap", GLFW.GLFW_KEY_HOME, KeyBinding.MISC_CATEGORY);
69+
private static final KeyBinding RENDER_CAPTURE_HUD = new KeyBinding(MOD_ID + ".key.render_cap", GLFW.GLFW_KEY_HOME, KeyBinding.MISC_CATEGORY);
6670
private static final KeyBinding OPEN_PACKET_LIST_SCREEN = new KeyBinding(MOD_ID + ".key.open.packetListScreen", GLFW.GLFW_KEY_END, KeyBinding.MISC_CATEGORY);
6771
private static final Gson GSON = new Gson();
6872
private static final Set<PacketFilter> DEFAULT_PACKET_FILTERS = Set.of(
@@ -89,12 +93,11 @@ public final class PacketCapture implements ClientModInitializer {
8993
);
9094
private static PacketCapture instance;
9195
private final MinecraftClient mc;
92-
private final PacketCaptureOverlay overlay;
96+
private final PacketCaptureHud hud;
9397
private final PacketListScreen screen;
9498
private final Path filterConfig;
95-
private final Path fieldsCsv;
96-
private final boolean deobfuscationEnabled;
97-
private final Map<String, String> deobMap = Maps.newHashMap();
99+
public final Deobfuscation classNameDeobfuscater;
100+
public final Deobfuscation fieldNameDeobfuscater;
98101
private final Set<PacketFilter> packetFilters = Collections.synchronizedSet(Sets.newHashSet());
99102
private final AtomicBoolean capturing = new AtomicBoolean(true);
100103
private final AtomicLong sentBytes = new AtomicLong();
@@ -109,22 +112,35 @@ public PacketCapture() {
109112
instance = this;
110113

111114
this.mc = MinecraftClient.getInstance();
112-
this.overlay = new PacketCaptureOverlay(this.mc, this);
115+
this.hud = new PacketCaptureHud(this.mc, this);
113116
this.screen = new PacketListScreen(this);
114117
var configDir = FabricLoader.getInstance().getConfigDir().resolve(MOD_ID);
115118
this.filterConfig = configDir.resolve("packet_filter.json");
116-
this.fieldsCsv = configDir.resolve("fields.csv");
117-
this.deobfuscationEnabled = this.loadCsv();
119+
var path = configDir.resolve("fields");
120+
this.classNameDeobfuscater = new Deobfuscation(path, s -> s.startsWith("c") && s.split(" ").length == 4, text -> {
121+
var split = text.split(" ");
122+
var named = split[1].split("/");
123+
var intermediary = split[3].split("/");
124+
125+
return Pair.of(intermediary[intermediary.length - 1], named[named.length - 1]);
126+
});
127+
this.fieldNameDeobfuscater = new Deobfuscation(path, s -> s.startsWith("f") && s.split(" ").length == 5, text -> {
128+
var split = text.split(" ");
129+
var named = split[2];
130+
var intermediary = split[4];
131+
132+
return Pair.of(intermediary, named);
133+
});
118134
this.loadFilters();
119135
}
120136

121137
@Override
122138
public void onInitializeClient() {
123-
KeyBindingHelper.registerKeyBinding(RENDER_CAPTURE_OVERLAY);
139+
KeyBindingHelper.registerKeyBinding(RENDER_CAPTURE_HUD);
124140
KeyBindingHelper.registerKeyBinding(OPEN_PACKET_LIST_SCREEN);
125141

126142
ClientTickEvents.END_CLIENT_TICK.register(mc -> {
127-
if (RENDER_CAPTURE_OVERLAY.wasPressed()) {
143+
if (RENDER_CAPTURE_HUD.wasPressed()) {
128144
this.showCapture = !this.showCapture;
129145
if (this.mc.getDebugHud().shouldShowDebugHud() && this.showCapture) {
130146
this.mc.getDebugHud().toggleDebugHud();
@@ -150,9 +166,9 @@ public void onInitializeClient() {
150166
});
151167

152168
HudLayerRegistrationCallback.EVENT.register(w -> {
153-
w.addLayer(IdentifiedLayer.of(PACKET_CAPTURE_OVERLAY_LAYER_ID, (context, tickCounter) -> {
169+
w.addLayer(IdentifiedLayer.of(PACKET_CAPTURE_HUD_LAYER_ID, (context, tickCounter) -> {
154170
if (this.showCapture) {
155-
this.overlay.render(context);
171+
this.hud.render(context);
156172
}
157173
}));
158174
});
@@ -266,25 +282,6 @@ public <T extends PacketListener> void onDecodingPacketInMultiplayer(NetworkStat
266282
});
267283
}
268284

269-
private boolean loadCsv() {
270-
var file = this.fieldsCsv.toFile();
271-
if (!file.exists() || !file.isFile()) {
272-
return false;
273-
}
274-
275-
try {
276-
this.deobMap.clear();
277-
for (var line : Files.readAllLines(this.fieldsCsv, StandardCharsets.UTF_8)) {
278-
var dataArray = line.split(",");
279-
this.deobMap.put(dataArray[0], dataArray[1]);
280-
}
281-
return true;
282-
} catch (Throwable e) {
283-
LOGGER.warn("Error occurred while loading csv file", e);
284-
return false;
285-
}
286-
}
287-
288285
public synchronized void loadFilters() {
289286
var file = this.filterConfig.toFile();
290287
if (!file.getParentFile().exists()) {
@@ -431,8 +428,4 @@ public long getReceivedBytes() {
431428
public long getReceivedPacketNum() {
432429
return this.receivedPacketNum.get();
433430
}
434-
435-
public String deobfuscate(String obfuscated) {
436-
return this.deobfuscationEnabled ? this.deobMap.getOrDefault(obfuscated, obfuscated) : obfuscated;
437-
}
438431
}

src/client/java/com/hamusuke/packetcap/clazz/field/SimpleClassField.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public SimpleClassField(Field field, Object instance) {
3636
name = "Could not access the field: " + e.getMessage();
3737
}
3838

39-
this.fieldName = PacketCapture.getInstance().deobfuscate(name);
39+
this.fieldName = PacketCapture.getInstance().fieldNameDeobfuscater.deobfuscate(name);
4040
this.visitor = visitor;
4141
this.errorOccurred = error;
4242
this.isStatic = isStatic;

src/client/java/com/hamusuke/packetcap/clazz/visitor/ClassVisitor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.collect.ImmutableList;
44
import com.google.common.collect.Lists;
5+
import com.hamusuke.packetcap.PacketCapture;
56
import com.hamusuke.packetcap.clazz.field.ClassField;
67
import com.hamusuke.packetcap.clazz.field.SimpleClassField;
78

@@ -18,7 +19,7 @@ public class ClassVisitor {
1819

1920
public ClassVisitor(Class<?> clazz, Object instance) {
2021
this.clazz = clazz;
21-
this.className = getClassName(clazz);
22+
this.className = PacketCapture.getInstance().classNameDeobfuscater.deobfuscate(getClassName(clazz));
2223
this.instance = instance;
2324
}
2425

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.hamusuke.packetcap.event;
2+
3+
import net.fabricmc.fabric.api.event.Event;
4+
import net.fabricmc.fabric.api.event.EventFactory;
5+
6+
public interface RegisterHighlightInstructionEvent {
7+
Event<RegisterHighlightInstructionEvent> EVENT = EventFactory.createArrayBacked(RegisterHighlightInstructionEvent.class, listeners -> () -> {
8+
for (var listener : listeners) {
9+
listener.onRegister();
10+
}
11+
});
12+
13+
void onRegister();
14+
}

src/client/java/com/hamusuke/packetcap/gui/overlay/PacketCaptureOverlay.java renamed to src/client/java/com/hamusuke/packetcap/gui/hud/PacketCaptureHud.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.hamusuke.packetcap.gui.overlay;
1+
package com.hamusuke.packetcap.gui.hud;
22

33
import com.hamusuke.packetcap.Config;
44
import com.hamusuke.packetcap.PacketCapture;
@@ -8,12 +8,12 @@
88
import net.minecraft.text.Text;
99
import net.minecraft.util.math.MathHelper;
1010

11-
public class PacketCaptureOverlay {
11+
public class PacketCaptureHud {
1212
private static final int INDEX_OFFSET = 4;
1313
private final MinecraftClient mc;
1414
private final PacketCapture capture;
1515

16-
public PacketCaptureOverlay(MinecraftClient mc, PacketCapture capture) {
16+
public PacketCaptureHud(MinecraftClient mc, PacketCapture capture) {
1717
this.mc = mc;
1818
this.capture = capture;
1919
}

src/client/java/com/hamusuke/packetcap/highlight/DataHighlightInstructions.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
import com.google.common.collect.ForwardingMultimap;
44
import com.google.common.collect.Maps;
5+
import com.hamusuke.packetcap.event.RegisterHighlightInstructionEvent;
56
import com.hamusuke.packetcap.highlight.DataHighlightInstruction.PacketDataHighlighterBuilder;
67
import com.hamusuke.packetcap.invoker.LoginHelloS2CPacketAccessor;
78
import com.hamusuke.packetcap.invoker.LoginKeyC2SPacketAccessor;
89
import com.mojang.authlib.GameProfile;
910
import com.mojang.authlib.properties.Property;
1011
import com.mojang.authlib.properties.PropertyMap;
1112
import io.netty.buffer.ByteBuf;
12-
import it.unimi.dsi.fastutil.ints.IntList;
1313
import net.minecraft.component.ComponentChanges;
1414
import net.minecraft.component.MergedComponentMap;
1515
import net.minecraft.item.ItemStack;
@@ -41,7 +41,6 @@
4141
import java.util.List;
4242
import java.util.Map;
4343
import java.util.Objects;
44-
import java.util.Set;
4544
import java.util.function.Consumer;
4645
import java.util.function.Function;
4746

@@ -50,26 +49,27 @@
5049
public class DataHighlightInstructions {
5150
private static final Map<Class<?>, DataHighlightInstruction<? extends ByteBuf, ?>> HIGHLIGHTERS = Maps.newHashMap();
5251

53-
private static final DataHighlightInstruction<ByteBuf, Property> PROPERTY = register(Property.class, builder -> builder
52+
public static final DataHighlightInstruction<ByteBuf, Property> PROPERTY = register(Property.class, builder -> builder
5453
.field(STRING.withDescription(s -> "Property Name: " + s), Property::name)
5554
.field(STRING.withDescription(s -> "Property Value: " + s), Property::value)
5655
.sub(bufNullable(String.class, s -> "Signature", (buf, value) -> StringEncoding.encode(buf, value, 1024)), Property::signature));
5756

58-
private static final DataHighlightInstruction<ByteBuf, PropertyMap> PROPERTY_MAP = register(PropertyMap.class, builder -> builder
57+
public static final DataHighlightInstruction<ByteBuf, PropertyMap> PROPERTY_MAP = register(PropertyMap.class, builder -> builder
5958
.list(PROPERTY, ForwardingMultimap::values));
6059

61-
private static final DataHighlightInstruction<ByteBuf, GameProfile> GAME_PROFILE = register(GameProfile.class, builder -> builder
60+
public static final DataHighlightInstruction<ByteBuf, GameProfile> GAME_PROFILE = register(GameProfile.class, builder -> builder
6261
.field(UUID.withDescription(uuid -> "UUID: " + uuid), GameProfile::getId)
6362
.field(STRING.withDescription(s -> "Name: " + s), GameProfile::getName)
6463
.sub(PROPERTY_MAP, GameProfile::getProperties));
6564

66-
private static final DataHighlightInstruction<RegistryByteBuf, RegistryKey> REGISTRY_KEY = registry(RegistryKey.class, builder -> builder
65+
public static final DataHighlightInstruction<RegistryByteBuf, RegistryKey> REGISTRY_KEY = registry(RegistryKey.class, builder -> builder
6766
.packetEncoder(PacketByteBuf::writeRegistryKey, RegistryKey::toString, Function.identity()));
6867

69-
private static final DataHighlightInstruction<PacketByteBuf, byte[]> BYTE_ARRAY_WITH_LEN = packet(byte[].class, builder -> builder
68+
public static final DataHighlightInstruction<PacketByteBuf, byte[]> BYTE_ARRAY_WITH_LEN = packet(byte[].class, builder -> builder
7069
.field(VAR_INT.withDescription(length -> "Byte Array Length: " + length), bytes -> bytes.length)
7170
.field(BYTE_ARRAY.withDescription(bytes -> "Data"), Function.identity()));
72-
private static final DataHighlightInstruction<RegistryByteBuf, ItemStack> ITEM_STACK = registry(ItemStack.class, builder -> builder
71+
72+
public static final DataHighlightInstruction<RegistryByteBuf, ItemStack> ITEM_STACK = registry(ItemStack.class, builder -> builder
7373
.field(VAR_INT.withDescription(count -> count <= 0 ? "Empty" : "Count: " + count), ItemStack::getCount, count -> count > 0)
7474
.packetCodec(PacketCodecs.registryEntry(RegistryKeys.ITEM), e -> "ID: " + e.getIdAsString(), ItemStack::getRegistryEntry)
7575
.packetCodec(ComponentChanges.PACKET_CODEC, componentChanges -> "ComponentChanges", stack -> stack.getComponents() instanceof MergedComponentMap m ? m.getChanges() : ComponentChanges.EMPTY));
@@ -157,37 +157,40 @@ public class DataHighlightInstructions {
157157
.field(VAR_INT, ScreenHandlerSlotUpdateS2CPacket::getRevision)
158158
.field(SHORT, p -> (short) p.getSlot())
159159
.sub(ITEM_STACK, ScreenHandlerSlotUpdateS2CPacket::getStack));
160+
161+
// Fire event
162+
RegisterHighlightInstructionEvent.EVENT.invoker().onRegister();
160163
}
161164

162-
private static <T> DataHighlightInstruction<PacketByteBuf, T> nullable(Class<T> clazz, PacketEncoder<PacketByteBuf, T> encoder) {
165+
public static <T> DataHighlightInstruction<PacketByteBuf, T> nullable(Class<T> clazz, PacketEncoder<PacketByteBuf, T> encoder) {
163166
return nullable(clazz, t -> "", encoder);
164167
}
165168

166-
private static <T> DataHighlightInstruction<PacketByteBuf, T> nullable(Class<T> clazz, Function<T, String> descriptor, PacketEncoder<PacketByteBuf, T> encoder) {
169+
public static <T> DataHighlightInstruction<PacketByteBuf, T> nullable(Class<T> clazz, Function<T, String> descriptor, PacketEncoder<PacketByteBuf, T> encoder) {
167170
return packet(clazz, b -> b
168171
.field(BOOL.withDescription(bool -> bool ? "Not Null" : "Null"), Objects::nonNull, Boolean::booleanValue)
169172
.packetEncoder(encoder, descriptor, Function.identity()));
170173
}
171174

172-
private static <T> DataHighlightInstruction<ByteBuf, T> bufNullable(Class<T> clazz, PacketEncoder<ByteBuf, T> encoder) {
175+
public static <T> DataHighlightInstruction<ByteBuf, T> bufNullable(Class<T> clazz, PacketEncoder<ByteBuf, T> encoder) {
173176
return bufNullable(clazz, t -> "", encoder);
174177
}
175178

176-
private static <T> DataHighlightInstruction<ByteBuf, T> bufNullable(Class<T> clazz, Function<T, String> descriptor, PacketEncoder<ByteBuf, T> encoder) {
179+
public static <T> DataHighlightInstruction<ByteBuf, T> bufNullable(Class<T> clazz, Function<T, String> descriptor, PacketEncoder<ByteBuf, T> encoder) {
177180
return register(clazz, b -> b
178181
.field(BOOL.withDescription(bool -> bool ? "Not Null" : "Null"), Objects::nonNull, Boolean::booleanValue)
179182
.packetEncoder(encoder, descriptor, Function.identity()));
180183
}
181184

182-
private static <T> DataHighlightInstruction<PacketByteBuf, T> packet(Class<T> clazz, Consumer<PacketDataHighlighterBuilder<PacketByteBuf, T>> consumer) {
185+
public static <T> DataHighlightInstruction<PacketByteBuf, T> packet(Class<T> clazz, Consumer<PacketDataHighlighterBuilder<PacketByteBuf, T>> consumer) {
183186
return register(clazz, consumer);
184187
}
185188

186-
private static <T> DataHighlightInstruction<RegistryByteBuf, T> registry(Class<T> clazz, Consumer<PacketDataHighlighterBuilder<RegistryByteBuf, T>> consumer) {
189+
public static <T> DataHighlightInstruction<RegistryByteBuf, T> registry(Class<T> clazz, Consumer<PacketDataHighlighterBuilder<RegistryByteBuf, T>> consumer) {
187190
return register(clazz, consumer);
188191
}
189192

190-
private static <B extends ByteBuf, T> DataHighlightInstruction<B, T> register(Class<T> clazz, Consumer<PacketDataHighlighterBuilder<B, T>> consumer) {
193+
public static <B extends ByteBuf, T> DataHighlightInstruction<B, T> register(Class<T> clazz, Consumer<PacketDataHighlighterBuilder<B, T>> consumer) {
191194
var builder = PacketDataHighlighterBuilder.<B, T>builder();
192195
consumer.accept(builder);
193196
var built = builder.build();

0 commit comments

Comments
 (0)