From bf654b7ea33ad43f25b2ac0eb082fc981fa03b48 Mon Sep 17 00:00:00 2001 From: tzdwindows 7 <3076584115@qq.com> Date: Mon, 10 Feb 2025 15:32:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(plugins):=20=E5=AE=9E=E7=8E=B0=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=E7=B3=BB=E7=BB=9F=E5=B9=B6=E4=BC=98=E5=8C=96=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E8=BF=87=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 BoxClassLoader、IClassTransformer、LoadingCorePlugin 等核心类 - 重构 Main 类,采用多线程和 ProgressBarManager 优化加载过程 - 完善 PluginLoader 类,支持核心插件和字节码转换器的加载- 重定向系统输出到 Log4j2,提高日志管理的灵活性 --- build.gradle | 14 +- .../innovators/box/Log4j2OutputStream.java | 33 ++++ .../java/com/axis/innovators/box/Main.java | 161 +++++++----------- .../box/gui/ProgressBarManager.java | 109 ++++++++++++ .../box/plugins/BoxClassLoader.java | 52 ++++++ .../box/plugins/IClassTransformer.java | 16 ++ .../box/plugins/LoadingCorePlugin.java | 14 ++ .../innovators/box/plugins/PluginLoader.java | 59 ++++++- src/main/resources/log4j2.xml | 10 +- 9 files changed, 349 insertions(+), 119 deletions(-) create mode 100644 src/main/java/com/axis/innovators/box/Log4j2OutputStream.java create mode 100644 src/main/java/com/axis/innovators/box/gui/ProgressBarManager.java create mode 100644 src/main/java/com/axis/innovators/box/plugins/BoxClassLoader.java create mode 100644 src/main/java/com/axis/innovators/box/plugins/IClassTransformer.java create mode 100644 src/main/java/com/axis/innovators/box/plugins/LoadingCorePlugin.java diff --git a/build.gradle b/build.gradle index 3ad347e..38d38f3 100644 --- a/build.gradle +++ b/build.gradle @@ -24,11 +24,8 @@ repositories { dependencies { testImplementation platform('org.junit:junit-bom:5.10.0') testImplementation 'org.junit.jupiter:junit-jupiter' - // https://mvnrepository.com/artifact/org.commonmark/commonmark implementation 'org.commonmark:commonmark:0.24.0' - // https://mvnrepository.com/artifact/org.commonjava.googlecode.markdown4j/markdown4j implementation 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.1' - // https://mvnrepository.com/artifact/com.google.code.gson/gson implementation 'com.google.code.gson:gson:2.8.9' implementation 'org.apache.logging.log4j:log4j-api:2.20.0' @@ -42,16 +39,19 @@ dependencies { implementation 'org.ow2.asm:asm-tree:7.1' } -application { - mainClass = 'com.axis.innovators.box.Main' -} - jar { manifest { attributes 'Main-Class': 'com.axis.innovators.box.Main' } } +application { + mainClass = 'com.axis.innovators.box.Main' + applicationDefaultJvmArgs = [ + "-Djava.system.class.loader=com.axis.innovators.box.plugins.BoxClassLoader" + ] +} + test { useJUnitPlatform() } \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/Log4j2OutputStream.java b/src/main/java/com/axis/innovators/box/Log4j2OutputStream.java new file mode 100644 index 0000000..22ab8ed --- /dev/null +++ b/src/main/java/com/axis/innovators/box/Log4j2OutputStream.java @@ -0,0 +1,33 @@ +package com.axis.innovators.box; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.OutputStream; +import java.io.PrintStream; + +/** + * 将输出传递给 Log4j2 的日志记录器 + * @author tzdwindows 7 + */ +public class Log4j2OutputStream extends OutputStream { + private static final Logger logger = LogManager.getLogger(Log4j2OutputStream.class); + + @Override + public void write(int b) { + logger.info(String.valueOf((char) b)); + } + + @Override + public void write(byte[] b, int off, int len) { + logger.info(new String(b, off, len)); + } + + /** + * 重定向 System.out 和 System.err 到 Log4j2 + */ + public static void redirectSystemStreams() { + System.setOut(new PrintStream(new Log4j2OutputStream())); + System.setErr(new PrintStream(new Log4j2OutputStream())); + } +} diff --git a/src/main/java/com/axis/innovators/box/Main.java b/src/main/java/com/axis/innovators/box/Main.java index 14b27f6..a331612 100644 --- a/src/main/java/com/axis/innovators/box/Main.java +++ b/src/main/java/com/axis/innovators/box/Main.java @@ -3,10 +3,7 @@ package com.axis.innovators.box; import com.axis.innovators.box.events.GlobalEventBus; import com.axis.innovators.box.events.SettingsLoadEvents; import com.axis.innovators.box.events.SubscribeEvent; -import com.axis.innovators.box.gui.FridaWindow; -import com.axis.innovators.box.gui.LocalWindow; -import com.axis.innovators.box.gui.MainWindow; -import com.axis.innovators.box.gui.LoadIcon; +import com.axis.innovators.box.gui.*; import com.axis.innovators.box.plugins.PluginLoader; import com.axis.innovators.box.tools.LibraryLoad; import com.axis.innovators.box.tools.SystemInfoUtil; @@ -29,9 +26,10 @@ public class Main { "tzdwindows 7" }; /** 我是总任务数 **/ - public static int totalTasks = 1; + public static int totalTasks = 0; /** 我是当前任务数 **/ public static int completedTasks = 0; + public static ProgressBarManager progressBarManager = new ProgressBarManager("加载中...", totalTasks); static { try { @@ -52,6 +50,7 @@ public class Main { } public static void main(String[] args) { + Log4j2OutputStream.redirectSystemStreams(); // 输出版本和作者信息 logger.info("Application Version: {}", VERSIONS); logger.info("Authors: {}", String.join(", ", AUTHOR)); @@ -61,6 +60,11 @@ public class Main { logger.info("OS Architecture: {}", SystemInfoUtil.getOSArch()); logger.info("CPU: {}", SystemInfoUtil.getCPUInfo()); logger.info("GPU: {}", SystemInfoUtil.getGPUInfo()); + logger.info("Java Version: {}", System.getProperty("java.version")); + logger.info("Java Vendor: {}", System.getProperty("java.vendor")); + logger.info("Java Home: {}", System.getProperty("java.home")); + logger.info("Java Class Path: {}", System.getProperty("java.class.path")); + logger.info("ClassLoader.getSystemClassLoader(): {}", ClassLoader.getSystemClassLoader()); // 注册事件 GlobalEventBus.EVENT_BUS.register(new Main()); @@ -71,109 +75,66 @@ public class Main { } catch (Exception e) { logger.warn("Failed to load the system facade class", e); } + Thread thread = new Thread(() -> { + try { + // 主任务1:加载插件 + progressBarManager.updateMainProgress(++completedTasks); + PluginLoader.loadPlugins(); + logger.info("Loaded plugins"); - JFrame loadingFrame = new JFrame("加载中..."); - loadingFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - loadingFrame.setSize(400, 200); - loadingFrame.setLocationRelativeTo(null); - loadingFrame.setIconImage(LoadIcon.loadIcon("logo.png", 64).getImage()); + progressBarManager.close(); - JPanel loadingPanel = new JPanel(new BorderLayout()); - JProgressBar progressBar = new JProgressBar(0, 100); - progressBar.setStringPainted(true); - JLabel statusLabel = new JLabel("Initializing...", SwingConstants.CENTER); - JLabel timeLabel = new JLabel("Time elapsed: 0s", SwingConstants.CENTER); - JLabel logoLabel = new JLabel(LoadIcon.loadIcon("logo.png", 64)); + SwingUtilities.invokeLater(() -> { + try { + MainWindow ex = new MainWindow(); + int id = 0; + MainWindow.ToolCategory debugCategory = new MainWindow.ToolCategory("调试工具", + "debug/debug.png", + "用于调试指定Windows工具的一个分类"); - loadingPanel.add(logoLabel, BorderLayout.NORTH); - loadingPanel.add(progressBar, BorderLayout.CENTER); - loadingPanel.add(statusLabel, BorderLayout.SOUTH); - loadingPanel.add(timeLabel, BorderLayout.SOUTH); + debugCategory.addTool(new MainWindow.ToolItem("Frida注入工具", "debug/frida/frida_main.png", + "使用frida注入目标进程的脚本程序 " + + "\n作者:tzdwindows 7", ++id, new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + Window owner = SwingUtilities.windowForComponent((Component) e.getSource()); + FridaWindow fridaWindow = new FridaWindow(owner); + fridaWindow.setVisible(true); + } + })); - loadingFrame.add(loadingPanel); - loadingFrame.setVisible(true); + ex.addToolCategory(debugCategory); - new Thread(() -> { - long startTime = System.currentTimeMillis(); - int classifyTask = 0; + MainWindow.ToolCategory aICategory = new MainWindow.ToolCategory("AI工具", + "ai/ai.png", + "人工智能/大语言模型"); - new Thread(() -> { - while (completedTasks < totalTasks) { - completedTasks++; - final int progress = (int) ((completedTasks / (double) totalTasks) * 100); + aICategory.addTool(new MainWindow.ToolItem("本地AI执行工具", "ai/local/local_main.png", + "在本机对开源大语言模型进行推理" + + "\n作者:tzdwindows 7", ++id, new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + Window owner = SwingUtilities.windowForComponent((Component) e.getSource()); + LocalWindow dialog = new LocalWindow(owner); + dialog.setVisible(true); + } + })); - SwingUtilities.invokeLater(() -> { - progressBar.setValue(progress); - statusLabel.setText("Loading: " + progress + "%"); - long elapsedTime = (System.currentTimeMillis() - startTime) / 1000; - timeLabel.setText("Time elapsed: " + elapsedTime + "s"); - }); - } - }); - while (completedTasks < totalTasks) { - try { - if (classifyTask == 0){ - PluginLoader.loadPlugins(); - logger.info("Loaded plugins"); - classifyTask++; + ex.addToolCategory(aICategory); + + ex.initUI(); + ex.setVisible(true); + } catch (Exception e) { + logger.error("There was a problem starting the main thread", e); + throw new RuntimeException(e); } - // 非显示任务请添加在这添加 - // .... - } catch (IOException e) { - logger.error("Failed to load plugins", e); - throw new RuntimeException(e); - } + }); + } catch (Exception e) { + logger.error("Failed to load plugins", e); + throw new RuntimeException(e); } - - SwingUtilities.invokeLater(() -> { - loadingFrame.dispose(); - try { - MainWindow ex = new MainWindow(); - int id = 0; - MainWindow.ToolCategory debugCategory = new MainWindow.ToolCategory("调试工具", - "debug/debug.png", - "用于调试指定Windows工具的一个分类"); - - debugCategory.addTool(new MainWindow.ToolItem("Frida注入工具", "debug/frida/frida_main.png", - "使用frida注入目标进程的脚本程序 " + - "\n作者:tzdwindows 7", ++id, new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - Window owner = SwingUtilities.windowForComponent((Component) e.getSource()); - FridaWindow fridaWindow = new FridaWindow(owner); - fridaWindow.setVisible(true); - } - })); - - // 在后面注册你自己的项或是添加你自己的分类 - // .... - - ex.addToolCategory(debugCategory); - - MainWindow.ToolCategory aICategory = new MainWindow.ToolCategory("AI工具", - "ai/ai.png", - "人工智能/大语言模型"); - - aICategory.addTool(new MainWindow.ToolItem("本地AI执行工具", "ai/local/local_main.png", - "在本机对开源大语言模型进行推理" + - "\n作者:tzdwindows 7", ++id, new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - Window owner = SwingUtilities.windowForComponent((Component) e.getSource()); - LocalWindow dialog = new LocalWindow(owner); - dialog.setVisible(true); - } - })); - - ex.addToolCategory(aICategory); - - ex.initUI(); - ex.setVisible(true); - } catch (Exception e) { - logger.error("There was a problem starting the main thread", e); - throw new RuntimeException(e); - } - }); - }).start(); + }); + thread.setName("Main Thread"); + thread.start(); } } \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/gui/ProgressBarManager.java b/src/main/java/com/axis/innovators/box/gui/ProgressBarManager.java new file mode 100644 index 0000000..83e843d --- /dev/null +++ b/src/main/java/com/axis/innovators/box/gui/ProgressBarManager.java @@ -0,0 +1,109 @@ +package com.axis.innovators.box.gui; + +import javax.swing.*; +import java.awt.*; +import java.util.HashMap; +import java.util.Map; + +/** + * 启动窗口的任务系统 + * @author tzdwindows 7 + */ +public class ProgressBarManager { + private JFrame loadingFrame; + private JProgressBar mainProgressBar; + private JProgressBar subProgressBar; + private JLabel statusLabel; + private JLabel timeLabel; + private long startTime; + + private int totalTasks; + private int completedTasks; + private Map subTasks = new HashMap<>(); + + public ProgressBarManager(String title, int totalTasks) { + this.totalTasks = totalTasks; + this.completedTasks = 0; + this.startTime = System.currentTimeMillis(); + + loadingFrame = new JFrame(title); + loadingFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + loadingFrame.setSize(400, 250); + loadingFrame.setLocationRelativeTo(null); + loadingFrame.setIconImage(LoadIcon.loadIcon("logo.png", 64).getImage()); + + JPanel loadingPanel = new JPanel(new BorderLayout()); + + mainProgressBar = new JProgressBar(0, 100); + mainProgressBar.setStringPainted(true); + + subProgressBar = new JProgressBar(0, 100); + subProgressBar.setStringPainted(true); + subProgressBar.setString("Subtask Progress"); + + statusLabel = new JLabel("Initializing...", SwingConstants.CENTER); + timeLabel = new JLabel("Time elapsed: 0s", SwingConstants.CENTER); + + JLabel logoLabel = new JLabel(LoadIcon.loadIcon("logo.png", 64)); + + JPanel progressPanel = new JPanel(new GridLayout(2, 1)); + progressPanel.add(mainProgressBar); + progressPanel.add(subProgressBar); + + loadingPanel.add(logoLabel, BorderLayout.NORTH); + loadingPanel.add(progressPanel, BorderLayout.CENTER); + loadingPanel.add(statusLabel, BorderLayout.SOUTH); + loadingPanel.add(timeLabel, BorderLayout.SOUTH); + + loadingFrame.add(loadingPanel); + loadingFrame.setVisible(true); + } + + /** + * 更新主任务进度 + * @param completedTasks 已完成的主任务数量 + */ + public void updateMainProgress(int completedTasks) { + this.completedTasks = completedTasks; + int progress = (int) ((completedTasks / (double) totalTasks) * 100); + mainProgressBar.setValue(progress); + statusLabel.setText("Main Progress: " + progress + "%"); + updateTimeLabel(); + } + + /** + * 更新子任务进度 + * @param subTaskName 子任务名称 + * @param subTaskCompleted 已完成的子任务数量 + * @param subTaskTotal 子任务总数 + */ + public void updateSubProgress(String subTaskName, int subTaskCompleted, int subTaskTotal) { + subTasks.put(subTaskName, subTaskCompleted); + int progress = (int) ((subTaskCompleted / (double) subTaskTotal) * 100); + subProgressBar.setValue(progress); + subProgressBar.setString(subTaskName + ": " + progress + "%"); + updateTimeLabel(); + } + + /** + * 更新总任务数 + */ + public void setTotalTasks(int totalTasks) { + this.totalTasks = totalTasks; + } + + /** + * 关闭加载窗口 + */ + public void close() { + loadingFrame.dispose(); + } + + /** + * 更新时间标签 + */ + private void updateTimeLabel() { + long elapsedTime = (System.currentTimeMillis() - startTime) / 1000; + timeLabel.setText("Time elapsed: " + elapsedTime + "s"); + } +} \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/plugins/BoxClassLoader.java b/src/main/java/com/axis/innovators/box/plugins/BoxClassLoader.java new file mode 100644 index 0000000..6987c7e --- /dev/null +++ b/src/main/java/com/axis/innovators/box/plugins/BoxClassLoader.java @@ -0,0 +1,52 @@ +package com.axis.innovators.box.plugins; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * 自定义加载器 + * @author tzdwindows 7 + */ +public class BoxClassLoader extends URLClassLoader { + + public BoxClassLoader(ClassLoader parent) { + super(new URL[0], parent); + } + + public BoxClassLoader(URL[] sources) { + super(sources); + } + + public BoxClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] classBytes; + try { + classBytes = getClassBytes(name); + } catch (IOException e) { + throw new RuntimeException(e); + } + byte[] transformedClass = transformClass(name, null, classBytes); + return defineClass(name, transformedClass, 0, transformedClass.length); + } + + public byte[] getClassBytes(String className) throws IOException, ClassNotFoundException { + String path = className.replace('.', '/') + ".class"; + URL classUrl = getResource(path); + if (classUrl == null) { + throw new ClassNotFoundException("Class not found: " + className); + } + try (InputStream is = classUrl.openStream()) { + return is.readAllBytes(); + } + } + + public byte[] transformClass(String className, String transformedName, byte[] basicClass) { + return PluginLoader.transformClass(className, transformedName, basicClass); + } +} diff --git a/src/main/java/com/axis/innovators/box/plugins/IClassTransformer.java b/src/main/java/com/axis/innovators/box/plugins/IClassTransformer.java new file mode 100644 index 0000000..ca1117c --- /dev/null +++ b/src/main/java/com/axis/innovators/box/plugins/IClassTransformer.java @@ -0,0 +1,16 @@ +package com.axis.innovators.box.plugins; + +/** + * 字节码操作接口 + * @author tzdwindows 7 + */ +public interface IClassTransformer { + /** + * 字节码操作 + * @param name 类名 + * @param transformedName 当前core插件名 + * @param bytes 字节码 + * @return 修改后的字节码 + */ + byte[] transform(String name, String transformedName, byte[] bytes); +} \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/plugins/LoadingCorePlugin.java b/src/main/java/com/axis/innovators/box/plugins/LoadingCorePlugin.java new file mode 100644 index 0000000..bf12e64 --- /dev/null +++ b/src/main/java/com/axis/innovators/box/plugins/LoadingCorePlugin.java @@ -0,0 +1,14 @@ +package com.axis.innovators.box.plugins; + +import java.util.Map; + +/** + * Core插件接口 + * @author tzdwindows 7 + */ +public interface LoadingCorePlugin { + String[] getLibraryRequestClass(); + String[] getASMTransformerClass(); + String getSetupClass(); + void injectData(Map data); +} \ No newline at end of file diff --git a/src/main/java/com/axis/innovators/box/plugins/PluginLoader.java b/src/main/java/com/axis/innovators/box/plugins/PluginLoader.java index 434683a..531739d 100644 --- a/src/main/java/com/axis/innovators/box/plugins/PluginLoader.java +++ b/src/main/java/com/axis/innovators/box/plugins/PluginLoader.java @@ -11,18 +11,15 @@ import java.util.*; import java.util.jar.*; /** - * 加载插件的系统 + * 插件加载器 * @author tzdwindows 7 */ public class PluginLoader { private static final Logger logger = LogManager.getLogger(PluginLoader.class); public static final String PLUGIN_PATH = FolderCreator.getPluginFolder(); private static final List loadedPlugins = new ArrayList<>(); + private static final List transformers = new ArrayList<>(); - /** - * 加载插件 - * @throws IOException 插件加载失败 - */ public static void loadPlugins() throws IOException { File pluginDir = new File(PLUGIN_PATH); File[] jars = pluginDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".jar")); @@ -30,10 +27,12 @@ public class PluginLoader { if (jars == null) { return; } - Main.totalTasks = jars.length; for (int i = 0; i < jars.length; i++) { processJarFile(jars[i]); - Main.completedTasks = i; + Main.progressBarManager.updateSubProgress( + "Loading Plugin " + i, + i, + jars.length); } } @@ -45,6 +44,45 @@ public class PluginLoader { } else { processWithAnnotations(jar, jarFile); } + + // Check for CorePlugin in MANIFEST.MF + Attributes attributes = jar.getManifest().getMainAttributes(); + String corePluginClass = attributes.getValue("CorePlugin"); + if (corePluginClass != null) { + processCorePlugin(jarFile, corePluginClass); + } + } + } + + private static void processCorePlugin(File jarFile, String corePluginClass) { + try (URLClassLoader classLoader = new URLClassLoader( + new URL[]{jarFile.toURI().toURL()}, + PluginLoader.class.getClassLoader()) + ) { + Class coreClass = classLoader.loadClass(corePluginClass); + if (LoadingCorePlugin.class.isAssignableFrom(coreClass)) { + LoadingCorePlugin corePlugin = (LoadingCorePlugin) coreClass.getDeclaredConstructor().newInstance(); + registerTransformers(corePlugin); + } + } catch (Exception e) { + logger.error("Failed to load core plugin: {}", corePluginClass, e); + } + } + + private static void registerTransformers(LoadingCorePlugin corePlugin) { + String[] transformerClasses = corePlugin.getASMTransformerClass(); + if (transformerClasses != null) { + for (String transformerClass : transformerClasses) { + try { + Class transformerClazz = Class.forName(transformerClass); + if (IClassTransformer.class.isAssignableFrom(transformerClazz)) { + IClassTransformer transformer = (IClassTransformer) transformerClazz.getDeclaredConstructor().newInstance(); + transformers.add(transformer); + } + } catch (Exception e) { + logger.error("Failed to register transformer: {}", transformerClass, e); + } + } } } @@ -145,4 +183,11 @@ public class PluginLoader { public static List getLoadedPlugins() { return Collections.unmodifiableList(loadedPlugins); } + + public static byte[] transformClass(String name, String transformedName, byte[] basicClass) { + for (IClassTransformer transformer : transformers) { + basicClass = transformer.transform(name, transformedName, basicClass); + } + return basicClass; + } } \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index ef41df4..710aeac 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -3,8 +3,8 @@ + fileName="logs/box.log" + filePattern="logs/box-%d{yyyy-MM-dd}-%i.log"> %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n @@ -15,10 +15,10 @@ - +