^
努力加载中,你可以静静欣赏音乐不受干扰...

JAVAFX整合代码高亮

前言

最近一直在写一款工具,用于移动安全测试辅助。它是为了降低使用者的技术门槛并无需记忆很多操作命令才开发的,已经实现了自动化的微信小程序反编译(无需操作手机)与Jadx的联动使用。插件化的开发使得项目实现了解耦,拓展了工具的使用范围。

此前,某个模块是用于保存hook脚本代码,在Frida注入时会调用框内的js代码,方便用户直接编辑无需操作其他文件。并且通过上下文菜单插件,还能使得用户快速获取常用脚本:P。



原先的样子是这样的,用textarea组件保存resources下的hook.js


非常报看,代码一多就难受,所以我想着高亮代码去支持一下。

实现

某天看到冰蝎作者的新工具,是一个高度可定制化的JNDI和Java反序列化利用工具。在演示的视频里看到作者对于gadget的编辑实现了代码高亮,于是想去看看是怎么实现的。

很可惜,项目代码是闭源的。只能够用jadx去反编译一下代码,祈祷没有做混淆。通过定位关键字:依赖库格式错误,找到部分代码如下


发现是用webview实现的,找到对应的html代码


发现用了第三方的库,ace编辑器。查阅文档和相关examples后也知道怎么用了,首先在源码目录中,ace.js是必须的文件。

此外,设置主题,就需要用到主题的相关文件,以mode开头,


挑选自己喜欢的就行,我们还需要根据高亮语言的类型选择snippets下的文件。例如我们的脚本是javascript,那么就找这个就行了。

定义一个webview的组件,在maincontroller中对他进行初始化。在resources目录下放你的这些资源文件,定义一个html代码。


<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><title>Editor</title><style type="text/css" media="screen">
        body {
            overflow: hidden;
        }

        #editor {
            margin: 0;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            font-size: 15px;
        }</style></head><body><pre id="editor"></pre><script src="./ace.js" type="text/javascript" charset="utf-8"></script><script>
    var editor = ace.edit("editor");
    editor.setOption("wrap", "free")
    editor.setTheme("ace/theme/twilight");
    editor.session.setMode("ace/mode/javascript");
    editor.setValue(document.window)</script></body></html>

我自己添加了对代码的换行和设置mode为javascript,注意一下资源引用即可。之后就可以初始化webview了

      WebEngine webEngine = this.codeview.getEngine();
        webEngine.load(getClass().getResource("/ace/code.html").toExternalForm());
        webEngine.documentProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {
           String sourcecode = ""
                this.editor = (JSObject) webEngine.executeScript("window.editor");
                editor.call("setValue", new Object[]{sourceCode});
            }
        });

这里需要注意,由于webview的初始化需要一定时间。所以如果不放在对webview的监听事件内,会出现this.editor赋值为空的错误

代码通过call setvalue来注入内容到框内,保存的相关代码略过。通过jsbridge调用java层的代码就行了。

这样就可以愉快的使用了。


整合一下上下文菜单

由于webview没有类似其他node一样的setcontextmenu这个方法 只能够通过contextmenu.show来产生

需要注意的是 必须是右键点击、必须在鼠标的位置,所以我们只需要监听webview的右键点击事件并且点左键的时候隐藏上下文菜单即可

代码如下

        codeview.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {

                MouseButton button = e.getButton();
                codeview.setContextMenuEnabled(false);
                //右键点击
                if(button == MouseButton.SECONDARY){
                    System.out.println("right click");            //在你鼠标所处屏幕的xy处显示
                    contextMenu.show(codeview, e.getScreenX(), e.getScreenY());
                }else{

                    if (contextMenu != null) {
                        contextMenu.hide();
                    }
                }


            }
        });