feat(gui): 重构 FridaWindow 类并添加新功能

-重新设计了窗口布局和样式,增加了更多控制按钮
-集成了自动补全功能,支持 Frida 相关的关键字和 API
- 优化了代码编辑器的配色方案,支持语法高亮
- 改进了日志输出区域的可读性- 移除了未使用的 LanguageManager 导入
This commit is contained in:
tzdwindows 7
2025-03-01 16:19:19 +08:00
parent f62db0f91d
commit f4baf0b1e4
15 changed files with 1398 additions and 182 deletions

View File

@@ -3,6 +3,12 @@ plugins {
id 'application'
id 'edu.sc.seis.launch4j' version '2.5.4'
id 'org.openjfx.javafxplugin' version '0.1.0'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
configurations {
all*.exclude group: 'org.openjfx', module: 'javafx'
}
// JDK 版本检查
@@ -16,17 +22,16 @@ group = 'com.axis.innovators.box'
version = '0.0.1'
repositories {
maven { setUrl("https://maven.aliyun.com/repository/central") }
maven { setUrl("https://maven.aliyun.com/repository/jcenter") }
maven { setUrl("https://maven.aliyun.com/repository/google") }
maven { setUrl("https://maven.aliyun.com/repository/gradle-plugin") }
maven { setUrl("https://maven.aliyun.com/repository/public") }
maven { setUrl("https://jitpack.io") }
maven { setUrl("https://maven.aliyun.com/nexus/content/groups/public/") }
maven { setUrl("https://maven.aliyun.com/nexus/content/repositories/jcenter") }
gradlePluginPortal()
google()
mavenCentral()
maven {
url 'https://maven.aliyun.com/repository/public'
metadataSources {
mavenPom()
artifact()
ignoreGradleMetadataRedirection()
}
}
maven { url 'https://jitpack.io' }
// mavenCentral()
}
dependencies {
@@ -40,11 +45,11 @@ dependencies {
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0'
implementation 'org.ow2.asm:asm:7.1'
implementation 'org.ow2.asm:asm-commons:7.1'
implementation 'org.ow2.asm:asm-analysis:7.1'
implementation 'org.ow2.asm:asm-util:7.0'
implementation 'org.ow2.asm:asm-tree:7.1'
implementation 'org.ow2.asm:asm:9.7.1'
implementation 'org.ow2.asm:asm-commons:9.7.1'
implementation 'org.ow2.asm:asm-analysis:9.7.1'
implementation 'org.ow2.asm:asm-util:9.7.1'
implementation 'org.ow2.asm:asm-tree:9.7.1'
implementation 'org.jsoup:jsoup:1.17.2'
@@ -63,7 +68,13 @@ dependencies {
implementation 'org.bitbucket.mstrobel:procyon-core:0.5.36' // 使用JitPack版本
implementation 'org.bitbucket.mstrobel:procyon-compilertools:0.5.36'
implementation 'com.fifesoft:rsyntaxtextarea:3.3.0'
// 必须的核心依赖
implementation 'com.fifesoft:rsyntaxtextarea:3.3.1'
implementation 'com.fifesoft:autocomplete:3.3.1'
// 可选UI增强
implementation 'com.fifesoft:rstaui:3.3.1'
implementation 'org.apache.commons:commons-compress:1.23.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
implementation 'org.controlsfx:controlsfx:11.1.2' // 现代化UI组件
@@ -76,6 +87,27 @@ dependencies {
implementation 'org.benf:cfr:0.152'
implementation 'com.github.javaparser:javaparser-core:3.25.1'
implementation 'org.springframework.boot:spring-boot-starter-web' // Web支持
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // JPA数据库支持
implementation 'org.springframework.boot:spring-boot-starter-validation' // 参数校验
// 安全相关依赖
implementation 'org.springframework.boot:spring-boot-starter-security' // Spring Security
implementation 'io.jsonwebtoken:jjwt-api:0.12.3' // JWT API
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3', // JWT实现
'io.jsonwebtoken:jjwt-jackson:0.12.3' // JWT序列化
runtimeOnly 'com.mysql:mysql-connector-j'
// 开发工具
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// 测试依赖
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
// 分离依赖项到 libs 目录

Binary file not shown.

View File

@@ -1,90 +0,0 @@
"""
工具模块初始化脚本
功能向Axis Innovators Box注册自定义工具类别和工具项
作者tzdwindows 7
版本1.1
"""
from com.axis.innovators.box.python import PyLocalSide
from javax.swing import AbstractAction, JFrame,JDialog, JLabel, JButton, JPanel, JOptionPane
from java.awt import BorderLayout, Dimension
from java.awt.event import ActionListener
class MyAction(AbstractAction):
def actionPerformed(self, event):
"""工具项点击事件处理"""
print("[DEBUG] Tool item clicked! Event source:", event.getSource())
# 创建 JDialog 作为子窗口
parent_frame = event.getSource().getTopLevelAncestor() # 获取父窗口
dialog = JDialog(parent_frame, u"工具面板", True) # True 表示模态对话框
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE) # 关闭时释放资源
dialog.setSize(300, 200)
dialog.setLocationRelativeTo(parent_frame) # 居中于父窗口
# 创建面板并设置布局
panel = JPanel()
panel.layout = BorderLayout() # 使用边界布局
# 添加标签
label = JLabel(u"这是工具项的子面板")
panel.add(label, BorderLayout.CENTER)
# 添加关闭按钮
close_btn = JButton(u"关闭")
close_btn.addActionListener(lambda e: dialog.dispose()) # 点击关闭窗口
panel.add(close_btn, BorderLayout.SOUTH)
# 将面板添加到窗口
dialog.add(panel)
dialog.visible = True # 显示窗口
def onStartup():
"""
系统启动时自动执行的初始化逻辑
功能:
1. 创建工具类别
2. 创建工具项并绑定动作
3. 注册到系统全局工具集
"""
print('[INFO] 正在初始化自定义工具...')
# --------------------------
# 创建工具类别(参数顺序:显示名称,图标资源名,描述)
# --------------------------
tool_category = PyLocalSide.getToolCategory(
u"数据分析工具", # 显示名称GUI可见
u"analytics_icon.png", # 图标文件名(需存在于资源目录)
u"高级数据分析功能集合" # 悬停提示描述
)
# --------------------------
# 创建工具项参数顺序显示名称图标描述ID动作对象
# --------------------------
tool_action = MyAction()
tool_item = PyLocalSide.getToolItem(
u"数据可视化", # 工具项显示名称
u"chart_icon.png", # 工具项图标
u"生成交互式数据图表", # 工具项描述
1001, # 工具项唯一ID需在配置中统一管理
tool_action # 点击触发的动作
)
tool_category.addTool(tool_item)
# --------------------------
# 注册工具类别到系统(参数:类别对象,全局唯一注册名称)
# --------------------------
PyLocalSide.addToolCategory(
tool_category,
u"custom_module::data_analysis_tools" # 推荐命名规则:模块名::功能名
)
print('[SUCCESS] 工具类别注册成功')
if __name__ == '__main__':
result = 0
errorResult = ""
# 确保Jython运行时可以访问onStartup函数
# 原理:将函数显式绑定到全局字典
globals()['onStartup'] = onStartup

View File

@@ -1,13 +0,0 @@
{
"id": "testing",
"name": "测试",
"version": "0.0.1",
"description": "测试插件",
"author": "tzdwindows 7",
"dependencies": [],
"_comment": {
"warning": "本文件为插件元数据配置,修改后需重启应用生效",
"path": "插件资源应放置在plugins/{id}/目录下"
}
}

View File

@@ -68,7 +68,6 @@ public class AxisInnovatorsBox {
try {
LibraryLoad.loadLibrary("FridaNative");
LibraryLoad.loadLibrary("ThrowSafely");
LM.loadLibrary(LM.CUDA);
} catch (Exception e) {
logger.error("Failed to load the 'FridaNative' library", e);
throw new RuntimeException(e);
@@ -231,7 +230,6 @@ public class AxisInnovatorsBox {
* 初始化Log4j2
*/
public void initLog4j2() {
Log4j2OutputStream.redirectSystemStreams();
logger.info("Application Version: {}", VERSIONS);
logger.info("Authors: {}", String.join(", ", AUTHOR));
@@ -245,6 +243,8 @@ public class AxisInnovatorsBox {
logger.info("Java Home: {}", System.getProperty("java.home"));
logger.info("Java Class Path: {}", System.getProperty("java.class.path"));
logger.info("ClassLoader.getSystemClassLoader(): {}", ClassLoader.getSystemClassLoader());
Log4j2OutputStream.redirectSystemStreams();
}
/**
@@ -277,6 +277,12 @@ public class AxisInnovatorsBox {
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:flatLightLaf_theme");
main.registrationTopic.addTopic(new com.formdev.flatlaf.FlatDarculaLaf(),
"Darcula主题",
"Darcula主题",
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:darcula_theme");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
logger.warn("Failed to load the system facade class", e);
@@ -334,7 +340,7 @@ public class AxisInnovatorsBox {
public static void run(String[] args) {
main = new AxisInnovatorsBox(args);
try {
main.initLog4j2();
//main.initLog4j2();
main.setTopic();
List<Map<String, String>> validFiles = ArgsParser.parseArgs(args);
for (Map<String, String> fileInfo : validFiles) {

View File

@@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
@@ -26,6 +27,7 @@ public class Log4j2OutputStream extends OutputStream {
systemOutContent.write(b, off, len);
String message = new String(b, off, len).trim();
logger.info(message);
}
/**

View File

@@ -1,8 +1,6 @@
package com.axis.innovators.box.decompilation.gui;
import com.axis.innovators.box.gui.LoadIcon;
import com.axis.innovators.box.gui.WindowsJDialog;
import com.axis.innovators.box.register.LanguageManager;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.Position;
@@ -19,7 +17,6 @@ import java.awt.event.*;
import java.util.concurrent.ConcurrentHashMap;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
@@ -283,7 +280,7 @@ public class ModernJarViewer extends JFrame {
int offsetX = -5;
int offsetY = 0;
currentSearchDialog.setLocation(editorLocation.x + editorWidth - dialogWidth - offsetX, editorLocation.y + offsetY);
//currentSearchDialog.setLocation(editorLocation.x + editorWidth - dialogWidth - offsetX, editorLocation.y + offsetY);
currentSearchDialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {

View File

@@ -0,0 +1,445 @@
package com.axis.innovators.box.decompilation.util;
import org.objectweb.asm.*;
import org.objectweb.asm.commons.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.jar.*;
/**
* 混淆工具(未完工)
* @author tzdwindows 7
*/
public class JarObfuscator {
private final File jarFile;
private final Map<String, byte[]> jarEntries = new LinkedHashMap<>();
private final List<String> whitelistList = new ArrayList<>();
private final Map<String, String> classMapping = new HashMap<>();
private final Map<String, String> classNameMapping = new HashMap<>();
private final Map<String, String> fieldMapping = new HashMap<>();
private final Map<String, String> methodMapping = new HashMap<>();
private final ClassNameGenerator classNameGenerator = new ClassNameGenerator();
private final MemberNameGenerator fieldNameGenerator = new MemberNameGenerator();
private final MemberNameGenerator methodNameGenerator = new MemberNameGenerator();
public JarObfuscator(File file) {
this.jarFile = file;
}
public void obfuscate() throws IOException {
collectObfuscationNames();
applyObfuscation();
}
public void addWhitelist(String classPath) {
whitelistList.add(classPath.replace(".", "/"));
}
private void collectObfuscationNames() throws IOException {
try (JarFile jar = new JarFile(jarFile)) {
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
if (entry.isDirectory() || !entryName.endsWith(".class")) {
continue;
}
try (InputStream is = jar.getInputStream(entry)) {
byte[] bytes = readAllBytes(is);
ClassReader cr = new ClassReader(bytes);
cr.accept(new MappingCollector(), ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
}
}
}
}
private class MappingCollector extends ClassVisitor {
private String originalClassName;
public MappingCollector() {
super(Opcodes.ASM9);
}
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
this.originalClassName = name;
if (whitelistList.contains(originalClassName)){
classMapping.put(originalClassName, originalClassName);
return;
}
String originalPackage = name.contains("/") ?
name.substring(0, name.lastIndexOf('/')) : "";
String className = name.contains("/") ?
name.substring(name.lastIndexOf('/') + 1) : name;
String obfuscatedPackage = classNameGenerator.generatePackageName(originalPackage);
String obfuscatedClassName = classNameGenerator.generateClassName(className);
String newInternalName = obfuscatedPackage.isEmpty() ?
obfuscatedClassName : obfuscatedPackage + "/" + obfuscatedClassName;
classMapping.put(originalClassName, newInternalName);
classNameMapping.put(originalClassName, obfuscatedClassName);
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor,
String signature, Object value) {
if (whitelistList.contains(originalClassName)) {
fieldMapping.put(originalClassName + "#" + name + "#" + descriptor, name);
return super.visitField(access, name, descriptor, signature, value);
}
String newName = fieldNameGenerator.generate(name);
fieldMapping.put(originalClassName + "#" + name + "#" + descriptor, newName);
return super.visitField(access, name, descriptor, signature, value);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
if (!"<init>".equals(name) && !"<clinit>".equals(name)
|| whitelistList.contains(originalClassName)) {
String newName = methodNameGenerator.generate(name);
methodMapping.put(originalClassName + "#" + name + "#" + descriptor, newName);
} else {
methodMapping.put(originalClassName + "#" + name + "#" + descriptor, name);
}
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
}
private void applyObfuscation() throws IOException {
try (JarFile jar = new JarFile(jarFile)) {
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
if (entry.isDirectory()) {
continue;
}
try (InputStream is = jar.getInputStream(entry)) {
byte[] bytes = readAllBytes(is);
if (entryName.endsWith(".class")) {
bytes = processClass(bytes);
String newName = classMapping.get(entryName.replace(".class", "")) + ".class";
jarEntries.put(newName, bytes);
} else {
jarEntries.put(entryName, bytes);
}
}
}
}
}
private static class ClassNameGenerator {
private final Map<String, String> packageMappings = new HashMap<>();
private final Map<String, String> classMappings = new HashMap<>();
private final Map<String, String> pathMappings = new HashMap<>();
private int packageCounter = 0;
private int classCounter = 0;
public String generatePackageName(String originalPath) {
return pathMappings.computeIfAbsent(originalPath, k -> {
String[] parts = originalPath.split("/");
StringBuilder newPath = new StringBuilder();
for (String part : parts) {
String pkg = packageMappings.computeIfAbsent(part, p -> generateShortName(packageCounter++, 'a'));
newPath.append(pkg).append('/');
}
return newPath.substring(0, newPath.length() - 1);
});
}
public String generateClassName(String originalName) {
return classMappings.computeIfAbsent(originalName, k -> generateShortName(classCounter++, 'A'));
}
private String generateShortName(int index, char base) {
StringBuilder sb = new StringBuilder();
do {
sb.append((char) (base + index % 26));
index = index / 26 - 1;
} while (index >= 0);
return sb.reverse().toString();
}
}
// 专用成员名生成器(处理字段和方法名)
private static class MemberNameGenerator {
private final Map<String, String> cache = new HashMap<>();
private int counter = 0;
public String generate(String original) {
return cache.computeIfAbsent(original, k -> generateShortName(counter++));
}
private String generateShortName(int index) {
StringBuilder sb = new StringBuilder();
do {
sb.append((char) ('a' + index % 26));
index = index / 26 - 1;
} while (index >= 0);
return sb.reverse().toString();
}
}
private byte[] processClass(byte[] original) {
ClassReader cr = new ClassReader(original);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
Remapper remapper = new CustomRemapper();
ClassVisitor cv = new ClassRemapper(cw, remapper);
ClassVisitor chain = new ClassVisitor(Opcodes.ASM9, cv) {
private String originalClassName;
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
this.originalClassName = name;
String newInternalName = classMapping.get(name);
super.visit(version, access, newInternalName,
remapper.mapSignature(signature, false),
remapper.mapType(superName),
interfaces != null ? Arrays.stream(interfaces)
.map(remapper::mapType)
.toArray(String[]::new) : null);
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor,
String signature, Object value) {
String newName = fieldMapping.get(originalClassName + "#" + name + "#" + descriptor);
return super.visitField(access, newName,
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true),
value);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
if ("<init>".equals(name) || "<clinit>".equals(name)) {
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
String newName = methodMapping.get(originalClassName + "#" + name + "#" + descriptor);
MethodVisitor mv = super.visitMethod(access, newName,
remapper.mapMethodDesc(descriptor),
remapper.mapSignature(signature, false),
exceptions != null ? Arrays.stream(exceptions)
.map(remapper::mapType)
.toArray(String[]::new) : null);
return new MethodVisitor(Opcodes.ASM9, mv) {
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String descriptor, boolean isInterface) {
super.visitMethodInsn(opcode,
remapper.mapType(owner),
remapper.mapMethodName(owner, name, descriptor),
remapper.mapMethodDesc(descriptor),
isInterface);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name,
String descriptor) {
super.visitFieldInsn(opcode,
remapper.mapType(owner),
remapper.mapFieldName(owner, name, descriptor),
remapper.mapDesc(descriptor));
}
@Override
public void visitTypeInsn(int opcode, String type) {
String mappedType = remapper.mapType(type);
super.visitTypeInsn(opcode, mappedType);
}
@Override
public void visitLocalVariable(String name, String descriptor,
String signature, Label start, Label end, int index) {
super.visitLocalVariable(name,
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true),
start, end, index);
}
@Override
public void visitLdcInsn(Object value) {
if (value instanceof String) {
String encrypted = xorEncrypt((String) value);
super.visitLdcInsn(encrypted);
super.visitMethodInsn(
Opcodes.INVOKESTATIC,
"StringDecoder",
"decode",
"(Ljava/lang/String;)Ljava/lang/String;",
false
);
} else {
super.visitLdcInsn(value);
}
}
};
}
};
cr.accept(chain, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
}
private class CustomRemapper extends Remapper {
@Override
public String mapType(String internalName) {
return classMapping.getOrDefault(internalName, internalName);
}
@Override
public String mapMethodName(String owner, String name, String descriptor) {
return methodMapping.getOrDefault(owner + "#" + name + "#" + descriptor, name);
}
@Override
public String mapFieldName(String owner, String name, String descriptor) {
return fieldMapping.getOrDefault(owner + "#" + name + "#" + descriptor, name);
}
@Override
public String mapSignature(String signature, boolean typeSignature) {
return super.mapSignature(signature, typeSignature);
}
@Override
public String map(String internalName) {
return classMapping.getOrDefault(internalName, internalName);
}
}
public void save(String path) throws IOException {
injectStringDecoder();
try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(path))) {
for (Map.Entry<String, byte[]> entry : jarEntries.entrySet()) {
String name = entry.getKey();
jos.putNextEntry(new JarEntry(name));
jos.write(entry.getValue());
jos.closeEntry();
}
}
}
private void injectStringDecoder() {
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER,
"StringDecoder", null, "java/lang/Object", null);
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
"decode", "(Ljava/lang/String;)Ljava/lang/String;", null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "toCharArray", "()[C", false);
mv.visitVarInsn(Opcodes.ASTORE, 1);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitInsn(Opcodes.ARRAYLENGTH);
mv.visitVarInsn(Opcodes.ISTORE, 2);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ISTORE, 3);
Label loop = new Label();
mv.visitLabel(loop);
mv.visitVarInsn(Opcodes.ILOAD, 3);
mv.visitVarInsn(Opcodes.ILOAD, 2);
Label end = new Label();
mv.visitJumpInsn(Opcodes.IF_ICMPGE, end);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitVarInsn(Opcodes.ILOAD, 3);
mv.visitInsn(Opcodes.DUP2);
mv.visitInsn(Opcodes.CALOAD);
mv.visitIntInsn(Opcodes.BIPUSH, 0x55);
mv.visitInsn(Opcodes.IXOR);
mv.visitInsn(Opcodes.I2C);
mv.visitInsn(Opcodes.CASTORE);
mv.visitIincInsn(3, 1);
mv.visitJumpInsn(Opcodes.GOTO, loop);
mv.visitLabel(end);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/String", "valueOf", "([C)Ljava/lang/String;", false);
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(4, 4);
mv.visitEnd();
cw.visitEnd();
jarEntries.put("StringDecoder.class", cw.toByteArray());
}
public Map<String, String> getComparisonTable() {
return Collections.unmodifiableMap(classMapping);
}
public void saveMappingTable(String path) throws IOException {
Properties prop = new Properties();
classMapping.forEach((k, v) -> {
//System.out.println("[Class Mapping] " + k + " → " + v);
prop.setProperty("class:" + k, v);
});
fieldMapping.forEach((k, v) -> {
//System.out.println("[Field Mapping] " + k + " → " + v);
prop.setProperty("field:" + k, v);
});
methodMapping.forEach((k, v) -> {
//System.out.println("[Method Mapping] " + k + " → " + v);
prop.setProperty("method:" + k, v);
});
try (Writer writer = new OutputStreamWriter(new FileOutputStream(path), StandardCharsets.UTF_8)) {
prop.store(writer, "Obfuscation Mapping Table");
}
}
private static String xorEncrypt(String input) {
char[] chars = input.toCharArray();
for (int i = 0; i < chars.length; i++) {
chars[i] ^= 0x55;
}
return new String(chars);
}
private static byte[] readAllBytes(InputStream is) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, bytesRead);
}
return buffer.toByteArray();
}
public static void main(String[] args) throws IOException {
File inputJar = new File("C:\\Users\\Administrator\\MCreatorWorkspaces\\AxisInnovatorsBox\\build\\libs\\AxisInnovatorsBox-0.0.1.jar");
JarObfuscator obfuscator = new JarObfuscator(inputJar);
//obfuscator.addWhitelist("com/axis/innovators/box/Main");
//obfuscator.addWhitelist("com/axis/innovators/box/plugins/BoxClassLoader");
//obfuscator.addWhitelist("com/axis/innovators/box/plugins/IClassTransformer");
//obfuscator.addWhitelist("com/axis/innovators/box/plugins/LoadingCorePlugin");
//obfuscator.addWhitelist("com/axis/innovators/box/plugins/PluginDescriptor");
//obfuscator.addWhitelist("com/axis/innovators/box/plugins/PluginDescriptor");
obfuscator.obfuscate();
obfuscator.saveMappingTable("C:\\Users\\Administrator\\Desktop\\mapping.properties");
obfuscator.save("C:\\Users\\Administrator\\Desktop\\obfuscated.jar");
}
}

View File

@@ -0,0 +1,306 @@
package com.axis.innovators.box.gui;
import org.fife.ui.autocomplete.BasicCompletion;
import org.fife.ui.autocomplete.DefaultCompletionProvider;
public class FridaSyntax {
public static void addFridaCompletions(DefaultCompletionProvider provider) {
// Java 相关
provider.addCompletion(new BasicCompletion(provider,
"Java.perform(function() {\n // Your code here\n});",
"Java.perform",
"在 Java 上下文中执行代码"));
provider.addCompletion(new BasicCompletion(provider,
"Java.choose('$className$', {\n" +
" onMatch: function(instance) {\n // Handle instance\n },\n" +
" onComplete: function() {\n // Complete handler\n }\n})",
"Java.choose",
"枚举 Java 对象实例"));
provider.addCompletion(new BasicCompletion(provider,
"Java.use('$className$')",
"Java.use",
"获取 Java 类的引用"));
provider.addCompletion(new BasicCompletion(provider,
"Java.enumerateLoadedClasses({\n" +
" onMatch: function(className) {\n // Handle class name\n },\n" +
" onComplete: function() {\n // Complete handler\n }\n})",
"Java.enumerateLoadedClasses",
"枚举已加载的 Java 类"));
provider.addCompletion(new BasicCompletion(provider,
"Java.enumerateMethods('$className$')",
"Java.enumerateMethods",
"枚举指定 Java 类的方法"));
provider.addCompletion(new BasicCompletion(provider,
"Java.scheduleOnMainThread(function() {\n // Your code here\n});",
"Java.scheduleOnMainThread",
"在主线程中执行代码"));
provider.addCompletion(new BasicCompletion(provider,
"Java.deoptimizeEverything()",
"Java.deoptimizeEverything",
"禁用 JIT 优化"));
// 模块和符号相关
provider.addCompletion(new BasicCompletion(provider,
"Module.findExportByName('$module$', '$name$')",
"Module.findExportByName",
"查找模块导出函数"));
provider.addCompletion(new BasicCompletion(provider,
"Module.findBaseAddress('$module$')",
"Module.findBaseAddress",
"查找模块的基地址"));
provider.addCompletion(new BasicCompletion(provider,
"Module.enumerateImports('$module$')",
"Module.enumerateImports",
"枚举模块的导入函数"));
provider.addCompletion(new BasicCompletion(provider,
"Module.enumerateExports('$module$')",
"Module.enumerateExports",
"枚举模块的导出函数"));
provider.addCompletion(new BasicCompletion(provider,
"Module.enumerateSymbols('$module$')",
"Module.enumerateSymbols",
"枚举模块的符号"));
provider.addCompletion(new BasicCompletion(provider,
"Module.load('$path$')",
"Module.load",
"加载指定路径的模块"));
// 内存操作相关
provider.addCompletion(new BasicCompletion(provider,
"Memory.scan('$address$', $size$, '$pattern$', {\n" +
" onMatch: function(address, size) {\n // Handle match\n },\n" +
" onComplete: function() {\n // Complete handler\n }\n})",
"Memory.scan",
"扫描内存中的指定模式"));
provider.addCompletion(new BasicCompletion(provider,
"Memory.alloc($size$)",
"Memory.alloc",
"分配指定大小的内存"));
provider.addCompletion(new BasicCompletion(provider,
"Memory.copy('$destination$', '$source$', $size$)",
"Memory.copy",
"复制内存数据"));
provider.addCompletion(new BasicCompletion(provider,
"Memory.protect('$address$', $size$, '$protection$')",
"Memory.protect",
"修改内存保护属性"));
provider.addCompletion(new BasicCompletion(provider,
"Memory.readByteArray('$address$', $size$)",
"Memory.readByteArray",
"读取内存中的字节数组"));
provider.addCompletion(new BasicCompletion(provider,
"Memory.writeByteArray('$address$', [$bytes$])",
"Memory.writeByteArray",
"写入字节数组到内存"));
// 拦截器相关
provider.addCompletion(new BasicCompletion(provider,
"Interceptor.attach('$address$', {\n" +
" onEnter: function(args) {\n // Handle enter\n },\n" +
" onLeave: function(retval) {\n // Handle leave\n }\n})",
"Interceptor.attach",
"附加拦截器到指定地址"));
provider.addCompletion(new BasicCompletion(provider,
"Interceptor.replace('$address$', new NativeCallback(function(args) {\n // Your code here\n}, '$returnType$', ['$argTypes$']))",
"Interceptor.replace",
"替换函数实现"));
provider.addCompletion(new BasicCompletion(provider,
"Interceptor.detach('$address$')",
"Interceptor.detach",
"分离拦截器"));
// 进程和线程相关
provider.addCompletion(new BasicCompletion(provider,
"Process.enumerateModules()",
"Process.enumerateModules",
"枚举已加载的模块"));
provider.addCompletion(new BasicCompletion(provider,
"Process.enumerateThreads()",
"Process.enumerateThreads",
"枚举进程中的线程"));
provider.addCompletion(new BasicCompletion(provider,
"Process.getCurrentThreadId()",
"Process.getCurrentThreadId",
"获取当前线程 ID"));
provider.addCompletion(new BasicCompletion(provider,
"Process.setExceptionHandler(function(exception) {\n // Handle exception\n})",
"Process.setExceptionHandler",
"设置异常处理函数"));
// 文件系统相关
provider.addCompletion(new BasicCompletion(provider,
"File.open('$path$', '$mode$')",
"File.open",
"打开文件"));
provider.addCompletion(new BasicCompletion(provider,
"File.read('$file$', $size$)",
"File.read",
"读取文件内容"));
provider.addCompletion(new BasicCompletion(provider,
"File.write('$file$', $data$)",
"File.write",
"写入数据到文件"));
provider.addCompletion(new BasicCompletion(provider,
"File.remove('$path$')",
"File.remove",
"删除文件"));
// 网络相关
provider.addCompletion(new BasicCompletion(provider,
"Socket.listen('$address$', $port$)",
"Socket.listen",
"监听指定地址和端口"));
provider.addCompletion(new BasicCompletion(provider,
"Socket.connect('$address$', $port$)",
"Socket.connect",
"连接到指定地址和端口"));
provider.addCompletion(new BasicCompletion(provider,
"Socket.read('$socket$', $size$)",
"Socket.read",
"从套接字读取数据"));
provider.addCompletion(new BasicCompletion(provider,
"Socket.write('$socket$', $data$)",
"Socket.write",
"写入数据到套接字"));
// 其他实用工具
provider.addCompletion(new BasicCompletion(provider,
"send($message$)",
"send",
"发送消息到 Frida 客户端"));
provider.addCompletion(new BasicCompletion(provider,
"recv(function(message) {\n // Handle message\n})",
"recv",
"接收来自 Frida 客户端的消息"));
provider.addCompletion(new BasicCompletion(provider,
"hexdump('$address$', { offset: $offset$, length: $length$ })",
"hexdump",
"以十六进制格式打印内存内容"));
provider.addCompletion(new BasicCompletion(provider,
"console.log('$message$')",
"console.log",
"打印日志信息"));
provider.addCompletion(new BasicCompletion(provider,
"console.error('$message$')",
"console.error",
"打印错误信息"));
provider.addCompletion(new BasicCompletion(provider,
"setTimeout(function() {\n // Your code here\n}, $delay$)",
"setTimeout",
"设置延时执行"));
provider.addCompletion(new BasicCompletion(provider,
"setInterval(function() {\n // Your code here\n}, $interval$)",
"setInterval",
"设置定时执行"));
}
public static void addBasicCompletions(DefaultCompletionProvider provider) {
String[] jsKeywords = {"function", "var", "let", "const", "if", "else",
"for", "while(/* logic */)", "try", "catch", "true", "false","()", "for (int i = 0; i < ; i++) {\n" +
" \n" +
"}"};
String[] fridaTypes = {
"Frida", "Process", "Module", "ModuleMap", "Memory", "Thread", "ThreadBacktrace",
"ThreadDetails", "Instruction", "Interceptor", "NativePointer", "NativeFunction",
"NativeCallback", "SystemFunction", "SystemFunctionOptions", "SocketListener",
"SocketConnection", "File", "InputStream", "OutputStream", "Database", "Statement",
"SqliteError", "ObjC", "ObjC.Object", "ObjC.Class", "ObjC.Protocol", "ObjC.Block",
"ObjC.Method", "ObjC.Ivar", "ObjC.Property", "ObjC.Selector", "Java", "Java.Class",
"Java.Method", "Java.Field", "Java.Scheduler", "Java.Cast", "Java.Perform", "Java.use",
"Java.available", "Java.scheduleOnMainThread", "Java.deoptimizeEverything",
"Java.enumerateLoadedClasses", "Java.enumerateMethods", "Java.vm", "Java.vm.tryGetEnv",
"Java.vm.perform", "Java.vm.getEnv", "Java.vm.tryGetEnv", "Java.vm.tryGetEnv","Script",
"ScriptRuntime", "ScriptSource", "ScriptOptions", "CompiledScript",
"ScriptExports", "ScriptMessage", "ScriptMessageHandler", "ScriptPostMessageHandler",
"ScriptUnloadHandler", "ScriptDestroyHandler", "ScriptLogHandler", "ScriptErrorHandler",
"ScriptDebugHandler", "ScriptStdinHandler", "ScriptStdoutHandler", "ScriptStderrHandler",
"Memory.scan", "Memory.scanSync", "Memory.alloc", "Memory.allocUtf8String",
"Memory.allocAnsiString", "Memory.copy", "Memory.protect", "Memory.readByteArray",
"Memory.readCString", "Memory.readUtf8String", "Memory.readAnsiString",
"Memory.writeByteArray", "Memory.writeUtf8String", "Memory.writeAnsiString",
"Memory.writePointer", "Memory.writeS8", "Memory.writeS16", "Memory.writeS32",
"Memory.writeS64", "Memory.writeU8", "Memory.writeU16", "Memory.writeU32",
"Memory.writeU64", "Memory.writeFloat", "Memory.writeDouble",
"Process.id", "Process.arch", "Process.platform", "Process.pageSize", "Process.pointerSize",
"Process.codeSigningPolicy", "Process.enumerateThreads", "Process.enumerateModules",
"Process.enumerateRanges", "Process.enumerateMallocRanges", "Process.enumerateModuleRanges",
"Process.findModuleByName", "Process.findModuleByAddress", "Process.getModuleByName",
"Process.getModuleByAddress", "Process.getCurrentThreadId", "Process.getThreadById",
"Process.setExceptionHandler", "Module.load", "Module.ensureInitialized",
"Module.findBaseAddress", "Module.findExportByName", "Module.enumerateImports",
"Module.enumerateExports", "Module.enumerateSymbols", "Module.enumerateSections",
"Module.enumerateDependencies", "Module.findExportByAddress", "Module.getExportByName",
"Module.getExportByAddress", "Interceptor.attach", "Interceptor.detach",
"Interceptor.replace", "Interceptor.revert", "Interceptor.flush", "NativePointer.isNull",
"NativePointer.add", "NativePointer.sub", "NativePointer.and", "NativePointer.or",
"NativePointer.xor", "NativePointer.shr", "NativePointer.shl", "NativePointer.compare",
"NativePointer.toInt32", "NativePointer.toUInt32", "NativePointer.toString",
"NativePointer.readPointer", "NativePointer.writePointer", "NativePointer.readS8",
"NativePointer.readS16", "NativePointer.readS32", "NativePointer.readS64",
"NativePointer.readU8", "NativePointer.readU16", "NativePointer.readU32",
"NativePointer.readU64", "NativePointer.readFloat", "NativePointer.readDouble",
"NativePointer.writeS8", "NativePointer.writeS16", "NativePointer.writeS32",
"NativePointer.writeS64", "NativePointer.writeU8", "NativePointer.writeU16",
"NativePointer.writeU32", "NativePointer.writeU64", "NativePointer.writeFloat",
"NativePointer.writeDouble", "File.open", "File.close", "File.read", "File.write",
"File.flush", "File.seek", "File.tell", "File.size", "File.copy", "File.move",
"File.remove", "File.exists", "File.isDirectory", "File.list", "Database.open",
"Database.close", "Database.execute", "Database.prepare", "Database.step",
"Database.reset", "Database.finalize", "Database.lastInsertRowId", "Database.changes",
"Database.backup", "Socket.listen", "Socket.connect", "Socket.bind", "Socket.accept",
"Socket.read", "Socket.write", "Socket.close", "Socket.shutdown", "Socket.getPeerName",
"Socket.getSockName", "Socket.setTimeout", "Socket.setNoDelay", "Socket.setKeepAlive",
"ObjC.available", "ObjC.classes", "ObjC.protocols", "ObjC.registerClass", "ObjC.bind",
"ObjC.unbind", "ObjC.schedule", "ObjC.perform", "ObjC.choose", "ObjC.enumerateLoadedClasses",
"ObjC.enumerateMethods", "ObjC.enumerateProperties", "ObjC.enumerateIvars",
"ObjC.enumerateProtocols", "Java.enumerateLoadedClasses", "Java.enumerateMethods",
"Java.enumerateFields", "Java.enumerateClassLoaders", "Java.choose",
"Java.scheduleOnMainThread", "Java.perform", "Java.performNow", "Java.performSync",
"Java.deoptimizeEverything", "Java.vm.getEnv", "Java.vm.tryGetEnv", "Java.vm.perform",
"Java.vm.tryGetEnv", "send", "recv", "rpc", "WeakRef", "WeakCallback", "ptr", "NULL",
"hexdump", "console.log", "console.warn", "console.error", "console.dir", "console.trace",
"setTimeout", "clearTimeout", "setInterval", "clearInterval", "setImmediate", "clearImmediate"};
for (String type : fridaTypes) {
provider.addCompletion(new BasicCompletion(provider, type));
}
for (String kw : jsKeywords) {
provider.addCompletion(new BasicCompletion(provider, kw));
}
}
}

View File

@@ -1,21 +1,27 @@
package com.axis.innovators.box.gui;
import com.axis.innovators.box.register.LanguageManager;
import com.axis.innovators.box.gui.renderer.DarculaCompletionCellRenderer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.fife.ui.autocomplete.*;
import org.tzd.frida.windows.Frida;
import org.fife.ui.rsyntaxtextarea.*;
import org.fife.ui.rtextarea.RTextScrollPane;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -24,11 +30,16 @@ import java.util.List;
*/
public class FridaWindow extends WindowsJDialog {
private static final Logger logger = LogManager.getLogger(FridaWindow.class);
private JTextArea scriptArea;
private RSyntaxTextArea scriptArea;
private JTextArea logArea;
private JTextField pidField;
private boolean isRepetition = false;
// IDEA风格配色
private static final Color BACKGROUND = new Color(0x2B2B2B);
private static final Color FOREGROUND = new Color(0xBBBBBB);
private static final Color SELECTION_COLOR = new Color(0x214283);
public FridaWindow(Window owner) {
super(owner, language.getText("fridaWindow.title"), ModalityType.APPLICATION_MODAL);
initUI();
@@ -37,110 +48,246 @@ public class FridaWindow extends WindowsJDialog {
@Override
public void initUI() {
super.initUI();
setSize(800, 600);
setSize(1280, 800);
setLocationRelativeTo(getOwner());
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JPanel mainPanel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color color1 = new Color(235, 241, 250);
Color color2 = new Color(255, 255, 255);
GradientPaint gp = new GradientPaint(0, 0, color1, getWidth(), getHeight(), color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
};
mainPanel.setLayout(new BorderLayout(10, 10));
mainPanel.setBorder(new EmptyBorder(15, 15, 15, 15));
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
mainPanel.setBackground(BACKGROUND);
// 输入面板
JPanel inputPanel = createInputPanel();
mainPanel.add(inputPanel, BorderLayout.NORTH);
// 脚本编辑区
// 中心区域(代码编辑器和日志)
JSplitPane centerSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
centerSplit.setDividerLocation(500);
centerSplit.setContinuousLayout(true);
// 脚本编辑器
JPanel scriptPanel = createScriptPanel();
mainPanel.add(scriptPanel, BorderLayout.CENTER);
centerSplit.setTopComponent(scriptPanel);
// 日志输出
JPanel logPanel = createLogPanel();
mainPanel.add(logPanel, BorderLayout.SOUTH);
centerSplit.setBottomComponent(logPanel);
mainPanel.add(centerSplit, BorderLayout.CENTER);
setContentPane(mainPanel);
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
scriptArea.requestFocusInWindow();
}
});
}
private JPanel createInputPanel() {
JPanel panel = new JPanel(new GridLayout(1, 3, 10, 10));
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
panel.setOpaque(false);
pidField = new JTextField(20);
styleTextField(pidField, "输入进程ID或选择进程...");
pidField = new JTextField(language.getText("fridaWindow.pidField"));
pidField.setFont(new Font("微软雅黑", Font.PLAIN, 14));
pidField.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(57, 56, 56)),
BorderFactory.createEmptyBorder(5, 10, 5, 10)
));
JButton browseButton = new JButton(language.getText("fridaWindow.browseButton"));
styleButton(browseButton, new Color(60, 179, 113));
JButton browseButton = new JButton("选择进程");
styleButton(browseButton, new Color(65, 131, 215));
browseButton.addActionListener(this::openProcessSelectionWindow);
JButton injectButton = new JButton("注入脚本");
styleButton(injectButton, new Color(215, 65, 65));
injectButton.addActionListener(this::handleInject);
panel.add(new JLabel("目标进程:"));
panel.add(pidField);
//panel.add(attachButton);
panel.add(browseButton);
panel.add(injectButton);
return panel;
}
private JPanel createScriptPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setOpaque(false);
panel.setBorder(BorderFactory.createTitledBorder(language.getText("fridaWindow.panel")));
panel.setBorder(BorderFactory.createTitledBorder("Frida脚本编辑器"));
scriptArea = new JTextArea();
scriptArea.setFont(new Font("Consolas", Font.PLAIN, 14));
JScrollPane scrollPane = new JScrollPane(scriptArea);
scrollPane.setBorder(BorderFactory.createLineBorder(new Color(0, 0, 0)));
scriptArea = new RSyntaxTextArea();
scriptArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
scriptArea.setCodeFoldingEnabled(true);
scriptArea.setAntiAliasingEnabled(true);
scriptArea.setTabSize(4);
scriptArea.setCaretPosition(0);
scriptArea.setSelectionColor(SELECTION_COLOR);
scriptArea.setCurrentLineHighlightColor(new Color(0x323232));
scriptArea.setMarkOccurrences(true);
scriptArea.setBracketMatchingEnabled(true);
setupAutoCompletion();
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 5));
buttonPanel.setOpaque(false);
Font ideaFont = new Font("JetBrains Mono", Font.PLAIN, 13);
if (!Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()).contains("JetBrains Mono")) {
ideaFont = new Font("Consolas", Font.PLAIN, 14);
}
scriptArea.setFont(ideaFont);
JButton injectButton = new JButton(language.getText("fridaWindow.injectButton"));
styleButton(injectButton, new Color(220, 20, 60));
injectButton.addActionListener(this::handleInject);
scriptArea.setBackground(new Color(0x1E1F22));
//codeArea.setForeground(new Color(0xBBBBBB));
scriptArea.setSelectionColor(new Color(0x214283));
scriptArea.setCurrentLineHighlightColor(new Color(0x323232));
buttonPanel.add(injectButton);
SyntaxScheme scheme = new SyntaxScheme(true);
scheme = configureIDEATheme(scheme);
scriptArea.setSyntaxScheme(scheme);
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(buttonPanel, BorderLayout.SOUTH);
RTextScrollPane scrollPane = new RTextScrollPane(scriptArea);
scrollPane.setBorder(BorderFactory.createLineBorder(new Color(0x3C3F41)));
scrollPane.setFoldIndicatorEnabled(true);
panel.add(scrollPane);
return panel;
}
private SyntaxScheme configureIDEATheme(SyntaxScheme scheme) {
// 基础颜色配置
Color background = new Color(0x2B2B2B); // 背景色
Color foreground = new Color(0xE0E0E0); // 前景色(默认文本颜色)
// 设置全局默认样式
Style defaultStyle = scheme.getStyle(Token.NULL);
defaultStyle.foreground = foreground;
defaultStyle.background = background;
// ======== Frida 关键字和 API 配置 ========
// Frida 关键字(如 Java.perform, Interceptor.attach 等)
setTokenStyle(scheme, Token.RESERVED_WORD, 0xCC7832); // 橙色
// Frida API如 Java, Module, Memory 等)
setTokenStyle(scheme, Token.FUNCTION, 0xFFC66D); // 黄色
// 字符串
setTokenStyle(scheme, Token.LITERAL_STRING_DOUBLE_QUOTE, 0x6A8759); // 绿色
// 数字
setTokenStyle(scheme, Token.LITERAL_NUMBER_DECIMAL_INT, 0x6897BB); // 蓝色
// 注释
setTokenStyle(scheme, Token.COMMENT_EOL, 0x629755); // 浅绿色
setTokenStyle(scheme, Token.COMMENT_MULTILINE, 0x629755); // 浅绿色
setTokenStyle(scheme, Token.COMMENT_DOCUMENTATION, 0x629755); // 浅绿色
// 运算符
setTokenStyle(scheme, Token.OPERATOR, 0xFFD700); // 金色
// 标识符(变量名、函数名等)
setTokenStyle(scheme, Token.IDENTIFIER, 0xE0E0E0); // 白色
// 分隔符(如括号、逗号等)
setTokenStyle(scheme, Token.SEPARATOR, 0x4EC9B0); // 青色
// 正则表达式
setTokenStyle(scheme, Token.REGEX, 0xD25252); // 红色
// ======== Frida 特有 API 配置 ========
// Java 相关 API
setTokenStyle(scheme, Token.RESERVED_WORD_2, 0xCC7832); // 橙色
// 内存操作 API
setTokenStyle(scheme, Token.DATA_TYPE, 0xE8BF6A); // 浅黄色
// 拦截器相关 API
setTokenStyle(scheme, Token.ANNOTATION, 0xBBB529); // 黄色
// ======== 跨语言通用配置 ========
// XML/HTML 标签(如果有需要)
setTokenStyle(scheme, Token.MARKUP_TAG_NAME, 0xE8BF6A); // 浅黄色
setTokenStyle(scheme, Token.MARKUP_TAG_DELIMITER, 0xCC7832); // 橙色
setTokenStyle(scheme, Token.MARKUP_ENTITY_REFERENCE, 0x6897BB); // 蓝色
// 设置当前行高亮
scriptArea.setHighlightCurrentLine(true);
scriptArea.setCurrentLineHighlightColor(new Color(0x323232));
return scheme;
}
private void setTokenStyle(SyntaxScheme scheme, int tokenType, int rgb) {
Style style = scheme.getStyle(tokenType);
style.foreground = new Color(rgb);
}
private JPanel createLogPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(0, 150));
panel.setBorder(BorderFactory.createTitledBorder(language.getText("fridaWindow.panel.log")));
panel.setOpaque(false);
panel.setBorder(BorderFactory.createTitledBorder("日志输出"));
logArea = new JTextArea();
logArea.setEditable(false);
logArea.setFont(new Font("微软雅黑", Font.PLAIN, 12));
logArea.setFont(new Font("Consolas", Font.PLAIN, 12));
logArea.setBackground(new Color(0x1E1E1E));
logArea.setForeground(Color.WHITE);
JScrollPane scrollPane = new JScrollPane(logArea);
scrollPane.setBorder(BorderFactory.createLineBorder(new Color(0, 0, 0)));
scrollPane.setBorder(BorderFactory.createLineBorder(new Color(0x3C3F41)));
panel.add(scrollPane);
return panel;
}
private void setupAutoCompletion() {
try {
CompletionProvider provider = createCompletionProvider();
AutoCompletion ac = new AutoCompletion(provider);
// 关键配置
ac.setAutoActivationEnabled(true);
ac.setParameterAssistanceEnabled(true);
ac.setShowDescWindow(true);
ac.setListCellRenderer(new DarculaCompletionCellRenderer());
ac.install(scriptArea);
ac.setDescriptionWindowColor(new Color(0x323232));
//ac.setChoicesWindowSize(386,200);
scriptArea.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
char keyChar = e.getKeyChar();
if (Character.isLetterOrDigit(keyChar)) {
SwingUtilities.invokeLater(ac::doCompletion);
}
}
});
} catch (Exception e) {
logger.error("Autocompletion failed to initialize ", e);
}
}
private CompletionProvider createCompletionProvider() {
DefaultCompletionProvider provider = new DefaultCompletionProvider();
FridaSyntax.addFridaCompletions(provider);
FridaSyntax.addBasicCompletions(provider);
return provider;
}
private void styleTextField(JTextField field, String placeholder) {
field.setFont(new Font("JetBrains Mono", Font.PLAIN, 14));
field.setBackground(new Color(0x3C3F41));
field.setForeground(Color.WHITE);
field.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(0x515658)),
BorderFactory.createEmptyBorder(5, 8, 5, 8)
));
field.putClientProperty("JTextField.placeholderText", placeholder);
}
private void styleButton(JButton button, Color bgColor) {
button.setFont(new Font("微软雅黑", Font.BOLD, 14));
button.setFont(new Font("Segoe UI", Font.PLAIN, 13));
button.setFocusPainted(false);
button.setBackground(bgColor);
button.setForeground(Color.black);
button.setBorder(BorderFactory.createEmptyBorder(8, 20, 8, 20));
button.setForeground(Color.WHITE);
button.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(bgColor.darker()),
BorderFactory.createEmptyBorder(5, 15, 5, 15)
));
}
private void handleInject(ActionEvent e) {

View File

@@ -0,0 +1,116 @@
package com.axis.innovators.box.gui.renderer;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
public class DarculaCompletionCellRenderer extends JPanel implements ListCellRenderer<Object> {
private final JLabel titleLabel = new JLabel();
private final JLabel descLabel = new JLabel();
private final Color defaultBg = new Color(0x2B2B2B);
private final Color hoverBg = new Color(0x323232);
private final Color selectedBg = new Color(0x214283);
private final Color textColor = new Color(0xBBBBBB);
private final Color descColor = new Color(0x808080);
public DarculaCompletionCellRenderer() {
setLayout(new BorderLayout());
setOpaque(false); // 确保面板透明
setBorder(new RoundedBorder(8, 1, new Color(0x3C3F41))); // 圆角边框
Font baseFont;
try {
baseFont = new Font("JetBrains Mono", Font.PLAIN, 13);
} catch (Exception e) {
baseFont = new Font("Consolas", Font.PLAIN, 13);
}
titleLabel.setFont(baseFont);
titleLabel.setForeground(textColor);
add(titleLabel, BorderLayout.NORTH);
try {
baseFont = new Font("JetBrains Mono", Font.PLAIN, 11);
} catch (Exception e) {
baseFont = new Font("Consolas", Font.PLAIN, 11);
}
descLabel.setFont(baseFont);
descLabel.setForeground(descColor);
add(descLabel, BorderLayout.SOUTH);
setBorder(BorderFactory.createCompoundBorder(
getBorder(),
BorderFactory.createEmptyBorder(4, 12, 4, 12)
));
}
@Override
public Component getListCellRendererComponent(
JList<?> list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
if (value instanceof Completion comp) {
titleLabel.setText(comp.getTitle());
descLabel.setText(comp.getDescription());
} else {
titleLabel.setText(value.toString());
descLabel.setText("");
}
if (isSelected) {
setBackground(selectedBg);
titleLabel.setForeground(Color.WHITE);
} else {
setBackground(index % 2 == 0 ? defaultBg : hoverBg);
titleLabel.setForeground(textColor);
}
return this;
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground());
g2.fillRoundRect(0, 0, getWidth(), getHeight(), 8, 8);
g2.dispose();
super.paintComponent(g);
}
private static class RoundedBorder extends AbstractBorder {
private final int radius;
private final int thickness;
private final Color color;
public RoundedBorder(int radius, int thickness, Color color) {
this.radius = radius;
this.thickness = thickness;
this.color = color;
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(color);
g2.draw(new RoundRectangle2D.Float(x, y, width-1, height-1, radius, radius));
g2.dispose();
}
@Override
public Insets getBorderInsets(Component c) {
return new Insets(thickness, thickness, thickness, thickness);
}
}
public interface Completion {
String getTitle();
String getDescription();
}
}

View File

@@ -0,0 +1,137 @@
package com.axis.innovators.box.network;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
public class NetworkFileManagement {
private static final String BASE_URL = NetworkUserManagement.BASE_URL;
private static final int TIMESTAMP_THRESHOLD = 300;
/**
* 上传文件
* @param user 上传用户
* @param file 要上传的文件
* @return 文件id
* @throws IOException 上传失败抛出异常
*/
public int uploadFile(Users user, File file) throws IOException {
validateTimestamp(user);
String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
HttpURLConnection connection = (HttpURLConnection) new URL(BASE_URL + "/upload").openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Authorization", "Bearer " + user.getToken());
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
connection.setDoOutput(true);
try (OutputStream output = connection.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8))) {
// Timestamp part
writer.append("--").append(boundary).append("\r\n");
writer.append("Content-Disposition: form-data; name=\"timestamp\"\r\n\r\n");
writer.append(String.valueOf(user.getTimestamp())).append("\r\n").flush();
// File part
writer.append("--").append(boundary).append("\r\n");
writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"").append(file.getName()).append("\"\r\n");
writer.append("Content-Type: application/octet-stream\r\n\r\n").flush();
try (FileInputStream input = new FileInputStream(file)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
output.flush();
}
writer.append("\r\n--").append(boundary).append("--\r\n").flush();
}
String response = handleResponse(connection);
return extractFileId(response);
}
/**
* 从JSON响应中提取file_id字段
*/
private int extractFileId(String jsonResponse) {
String[] parts = jsonResponse.split("\"file_id\":");
if (parts.length < 2) {
throw new RuntimeException("Invalid response format: " + jsonResponse);
}
return Integer.parseInt(parts[1].replaceAll("[^0-9]", ""));
}
/**
* 下载文件
* @param user 下载用户
* @param fileId 文件ID
* @param savePath 保存路径
* @return 文件
* @throws IOException 下载失败抛出异常
*/
public File downloadFile(Users user, int fileId, String savePath) throws IOException {
validateTimestamp(user);
String query = String.format("file_id=%d&timestamp=%d", fileId, user.getTimestamp());
HttpURLConnection connection = (HttpURLConnection) new URL(BASE_URL + "/download?" + query).openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + user.getToken());
int status = connection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
String fileName = "downloaded_file";
try (InputStream input = connection.getInputStream();
FileOutputStream output = new FileOutputStream(savePath + File.separator + fileName)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
}
return new File(savePath + File.separator + fileName);
} else {
handleErrorResponse(connection);
return null;
}
}
private void validateTimestamp(Users user) {
long currentTimestamp = Instant.now().getEpochSecond();
if (Math.abs(currentTimestamp - user.getTimestamp()) > TIMESTAMP_THRESHOLD) {
throw new SecurityException("Timestamp validation failed");
}
}
private String handleResponse(HttpURLConnection connection) throws IOException {
int status = connection.getResponseCode();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
status >= 400 ? connection.getErrorStream() : connection.getInputStream()
))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
if (status >= 400) {
throw new RuntimeException("HTTP Error " + status + ": " + response);
}
return response.toString();
}
}
private void handleErrorResponse(HttpURLConnection connection) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
throw new RuntimeException("HTTP Error " + connection.getResponseCode() + ": " + response);
}
}
}

View File

@@ -0,0 +1,100 @@
package com.axis.innovators.box.network;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
/**
* 网络用户管理
* @author tzdwindows 7
*/
public class NetworkUserManagement {
static final String BASE_URL = "https://yourdomain.com";
/**
* 注册用户
* @param username 用户名
* @param password 用户密码
* @return 用户信息
* @throws IOException 注册失败时抛出异常
*/
public Users registerUser(String username, String password) throws IOException {
long timestamp = Instant.now().getEpochSecond();
String jsonInput = String.format(
"{\"username\": \"%s\", \"password\": \"%s\", \"timestamp\": %d}",
username, password, timestamp
);
HttpURLConnection connection = sendPostRequest("/register", jsonInput);
return parseUserResponse(connection, username, password);
}
/**
* 登录用户
* @param username 用户名
* @param password 用户密码
* @return 用户信息
* @throws IOException 登录失败时抛出异常
*/
public Users loginUser(String username, String password) throws IOException {
long timestamp = Instant.now().getEpochSecond();
String jsonInput = String.format(
"{\"username\": \"%s\", \"password\": \"%s\", \"timestamp\": %d}",
username, password, timestamp
);
HttpURLConnection connection = sendPostRequest("/login", jsonInput);
return parseUserResponse(connection, username, password);
}
private HttpURLConnection sendPostRequest(String endpoint, String jsonInput) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(BASE_URL + endpoint).openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
try (OutputStream os = connection.getOutputStream()) {
byte[] input = jsonInput.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
return connection;
}
private Users parseUserResponse(HttpURLConnection connection, String username, String password) throws IOException {
int status = connection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_CREATED) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
String token = extractToken(response.toString());
Users user = new Users();
user.setUsername(username);
user.setPassword(password);
// 注意:实际应存储哈希值
user.setToken(token);
user.setTimestamp(Instant.now().getEpochSecond());
return user;
}
} else {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()))) {
StringBuilder errorResponse = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
errorResponse.append(line);
}
throw new RuntimeException("Registration/Login failed: " + errorResponse);
}
}
}
private String extractToken(String jsonResponse) {
// 简单实现实际应使用JSON解析库
return jsonResponse.split("\"token\":\"")[1].split("\"")[0];
}
}

View File

@@ -0,0 +1,21 @@
package com.axis.innovators.box.network;
public class Users {
private String username;
private String password;
private String token;
private long timestamp;
// Getters and Setters
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getToken() { return token; }
public void setToken(String token) { this.token = token; }
public long getTimestamp() { return timestamp; }
public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
}

View File

@@ -7,6 +7,7 @@ import com.axis.innovators.box.gui.MainWindow;
import com.axis.innovators.box.plugins.PluginDescriptor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.tzd.lm.LM;
import javax.swing.*;
import java.awt.*;
@@ -54,6 +55,15 @@ public class RegistrationTool {
"\n作者tzdwindows 7", ++id, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
try {
LM.loadLibrary(LM.CUDA);
} catch (Exception ex) {
logger.error("无法加载AI推理库", ex);
JOptionPane.showMessageDialog(null, "无法加载AI推理库",
"无法加载AI推理库", JOptionPane.ERROR_MESSAGE);
}
Window owner = SwingUtilities.windowForComponent((Component) e.getSource());
LocalWindow dialog = new LocalWindow(owner);
main.popupWindow(dialog);