├── .gitignore ├── BappDescription.html ├── BappManifest.bmf ├── README.md ├── imgs ├── 0.png ├── 1.png └── 2.png ├── pom.xml └── src └── main └── java └── burp └── BurpExtender.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/ 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | 16 | ### Eclipse ### 17 | .apt_generated 18 | .classpath 19 | .factorypath 20 | .project 21 | .settings 22 | .springBeans 23 | .sts4-cache 24 | 25 | ### NetBeans ### 26 | /nbproject/private/ 27 | /nbbuild/ 28 | /dist/ 29 | /nbdist/ 30 | /.nb-gradle/ 31 | build/ 32 | !**/src/main/**/build/ 33 | !**/src/test/**/build/ 34 | 35 | ### VS Code ### 36 | .vscode/ 37 | 38 | ### Mac OS ### 39 | .DS_Store -------------------------------------------------------------------------------- /BappDescription.html: -------------------------------------------------------------------------------- 1 |

This extension can be used to change the nesting level of extension-generated context menu items.

2 | 3 |

Usage

4 |

Use the "Menu Level" menu bar option to choose the nesting level for extension-generated context menu items.

5 | -------------------------------------------------------------------------------- /BappManifest.bmf: -------------------------------------------------------------------------------- 1 | Uuid: e1156b3d48c4469f9f1e234a3119fab1 2 | ExtensionType: 1 3 | Name: Change Menu Level 4 | RepoName: change-menu-level 5 | ScreenVersion: 1.0 6 | SerialVersion: 3 7 | MinPlatformVersion: 0 8 | ProOnly: False 9 | Author: Ovie 10 | ShortDescription: Change the nesting level of extension-generated context menu items. 11 | EntryPoint: target/BurpMenuLevel-1.0-SNAPSHOT.jar 12 | BuildCommand: mvn clean package 13 | SupportedProducts: Pro, Community 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BurpSuite新版本中,插件注册的右键菜单是在第三层,即Extensions -> 插件名 -> 插件菜单,这样点起来有些麻烦。所以写了个小插件,用于修改菜单层级,可以将插件菜单放在第一或第二层。 2 | 3 | 如何实现的:《[Burpsuite 插件开发 - 修改右键菜单层级](https://ovi3.github.io/2023/09/27/burpsuite-extension-menu-level/)》 4 | 5 | A simple BurpSuite extension to change extension context menu level, using in BurpSuite v2021.7 version and newer. 6 | 7 | 8 | 9 | ## 截图 10 | 11 | 默认: 12 | 13 | ![0.png](imgs/0.png) 14 | 15 | 设置: 16 | 17 | ![1.png](imgs/1.png) 18 | 19 | 效果: 20 | 21 | ![2.png](imgs/2.png) 22 | -------------------------------------------------------------------------------- /imgs/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/change-menu-level/0bad112fa67cb6f9de83ec208ef6ef9c4830f704/imgs/0.png -------------------------------------------------------------------------------- /imgs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/change-menu-level/0bad112fa67cb6f9de83ec208ef6ef9c4830f704/imgs/1.png -------------------------------------------------------------------------------- /imgs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/change-menu-level/0bad112fa67cb6f9de83ec208ef6ef9c4830f704/imgs/2.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | burp 8 | BurpMenuLevel 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 8 13 | 8 14 | UTF-8 15 | 16 | 17 | 18 | 19 | 20 | org.apache.maven.plugins 21 | maven-jar-plugin 22 | 3.3.0 23 | 24 | 25 | false 26 | 27 | Test 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | net.portswigger.burp.extender 38 | burp-extender-api 39 | 1.7.22 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.HierarchyEvent; 6 | import java.awt.event.HierarchyListener; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class BurpExtender implements IBurpExtender, IExtensionStateListener, IContextMenuFactory { 11 | 12 | private static final String extensionName = "BurpMenuLevel"; 13 | private static final String menuLevel = "MENU_LEVEL"; 14 | 15 | private IBurpExtenderCallbacks callbacks; 16 | private JMenuBar burpMenuBar; 17 | private JMenu topMenus; 18 | 19 | @Override 20 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { 21 | this.callbacks = callbacks; 22 | callbacks.setExtensionName(extensionName); 23 | callbacks.registerContextMenuFactory(this); 24 | callbacks.registerExtensionStateListener(this); 25 | 26 | // 添加顶部栏 27 | burpMenuBar = getBurpFrame().getJMenuBar(); 28 | topMenus = new JMenu("Menu Level"); 29 | 30 | ButtonGroup group = new ButtonGroup(); 31 | JRadioButtonMenuItem level0Menu = new JRadioButtonMenuItem("Name - Scan"); 32 | JRadioButtonMenuItem level1Menu = new JRadioButtonMenuItem("Name -> Scan"); 33 | JRadioButtonMenuItem level2Menu = new JRadioButtonMenuItem("Extensions -> Name - Scan"); 34 | JRadioButtonMenuItem level3Menu = new JRadioButtonMenuItem("Extensions -> Name -> Scan"); 35 | group.add(level0Menu); 36 | group.add(level1Menu); 37 | group.add(level2Menu); 38 | group.add(level3Menu); 39 | 40 | int level = getMenuLevel(); 41 | switch (level) { 42 | case 0: 43 | level0Menu.setSelected(true); 44 | break; 45 | case 1: 46 | level1Menu.setSelected(true); 47 | break; 48 | case 2: 49 | level2Menu.setSelected(true); 50 | break; 51 | case 3: 52 | level3Menu.setSelected(true); 53 | break; 54 | } 55 | 56 | level0Menu.addActionListener(e -> setMenuLevel("0")); 57 | level1Menu.addActionListener(e -> setMenuLevel("1")); 58 | level2Menu.addActionListener(e -> setMenuLevel("2")); 59 | level3Menu.addActionListener(e -> setMenuLevel("3")); 60 | 61 | topMenus.add(level0Menu); 62 | topMenus.add(level1Menu); 63 | topMenus.add(level2Menu); 64 | topMenus.add(level3Menu); 65 | SwingUtilities.invokeLater(() -> { 66 | burpMenuBar.add(topMenus); 67 | burpMenuBar.revalidate(); 68 | burpMenuBar.repaint(); 69 | }); 70 | 71 | 72 | callbacks.printOutput("Usage: click \"Menu Level\" menu at the top of window to change extension context menu level."); 73 | } 74 | 75 | @Override 76 | public void extensionUnloaded() { 77 | SwingUtilities.invokeLater(() -> { 78 | burpMenuBar.remove(topMenus); 79 | burpMenuBar.revalidate(); 80 | burpMenuBar.repaint(); 81 | }); 82 | } 83 | 84 | private static JFrame getBurpFrame() { 85 | for (Frame f : Frame.getFrames()) { 86 | if (f.isVisible() && f.getTitle().startsWith(("Burp Suite"))) { 87 | return (JFrame) f; 88 | } 89 | } 90 | return null; 91 | } 92 | 93 | private int getMenuLevel() { 94 | String levelStr = callbacks.loadExtensionSetting(menuLevel); 95 | if (levelStr == null || levelStr.length() == 0) { 96 | levelStr = "3"; 97 | } 98 | 99 | return Integer.parseInt(levelStr); 100 | } 101 | 102 | private void setMenuLevel(String level) { 103 | callbacks.saveExtensionSetting(menuLevel, level); 104 | } 105 | 106 | @Override 107 | public List createMenuItems(IContextMenuInvocation invocation) { 108 | List menus = new ArrayList<>(); 109 | JMenuItem menu = new JMenuItem("flag"); 110 | menus.add(menu); 111 | 112 | int level = getMenuLevel(); 113 | if (level == 3) { 114 | return null; // 默认不处理; 返回null,不添加自身插件flag菜单 115 | } 116 | 117 | changeContextMenuLevel(menus, level); 118 | 119 | return menus; 120 | } 121 | 122 | /** 123 | * 124 | * @param myMenus 125 | * @param level 可选 0, 1, 2, 3 126 | */ 127 | private void changeContextMenuLevel(List myMenus, int level) { 128 | if (myMenus.size() == 0) { 129 | return; 130 | } 131 | 132 | JMenuItem flagMenu = myMenus.get(0); 133 | flagMenu.addHierarchyListener(new HierarchyListener() { 134 | private boolean ran = false; 135 | @Override 136 | public void hierarchyChanged(HierarchyEvent e) { 137 | if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0) { 138 | if (!ran) { 139 | ran = true; 140 | if (flagMenu.getParent() == null || !(flagMenu.getParent() instanceof JPopupMenu)) { 141 | return; 142 | } 143 | JPopupMenu popupMenu = (JPopupMenu) flagMenu.getParent(); 144 | Component invoker = popupMenu.getInvoker(); 145 | 146 | 147 | if (!(invoker instanceof JMenuItem)) { 148 | return; 149 | } 150 | JMenuItem extensionNameMenuItem = (JMenuItem)invoker; 151 | extensionNameMenuItem.addHierarchyListener(new HierarchyListener() { 152 | private boolean ran2 = false; 153 | @Override 154 | public void hierarchyChanged(HierarchyEvent e) { 155 | if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0) { 156 | if (!ran2) { 157 | ran2 = true; 158 | 159 | if (extensionNameMenuItem.getParent() == null || !(extensionNameMenuItem.getParent() instanceof JPopupMenu)) { 160 | return; 161 | } 162 | JPopupMenu extensionsPopupMenu = (JPopupMenu) extensionNameMenuItem.getParent(); 163 | 164 | if (level == 3) { // Extensions -> Name -> Scan 165 | // 默认不做处理 166 | } else { 167 | Component invoker2 = extensionsPopupMenu.getInvoker(); 168 | 169 | if (!(invoker2 instanceof JMenuItem) || !((JMenuItem) invoker2).getText().equals("Extensions")) { 170 | return; 171 | } 172 | JMenuItem extensionsMenuItem = (JMenuItem) invoker2; 173 | extensionsMenuItem.addHierarchyListener(new HierarchyListener() { 174 | private boolean ran3 = false; 175 | 176 | @Override 177 | public void hierarchyChanged(HierarchyEvent e) { 178 | if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0) { 179 | if (!ran3) { 180 | ran3 = true; 181 | 182 | if (extensionsMenuItem.getParent() == null || !(extensionsMenuItem.getParent() instanceof JPopupMenu)) { 183 | return; 184 | } 185 | extensionsPopupMenu.remove(extensionNameMenuItem); // 移除自身插件菜单 186 | 187 | JPopupMenu topLevelPopupMenu = (JPopupMenu) extensionsMenuItem.getParent(); // 拿到 topLevelPopupMenu 就能为所欲为 188 | 189 | // 获取 190 | List allMenus = new ArrayList<>(); 191 | for (int i = 0; i < extensionsPopupMenu.getComponentCount(); i++ ) { 192 | JMenu m = (JMenu) extensionsPopupMenu.getComponent(i); 193 | allMenus.add(m); 194 | } 195 | 196 | // 移除 197 | extensionsPopupMenu.removeAll(); 198 | 199 | // 添加 200 | if (level == 2) { // Extensions -> Name - Scan 201 | for (JMenu menu: allMenus) { 202 | List items = new ArrayList<>(); 203 | for (int i = 0; i < menu.getItemCount(); i++) { 204 | JMenuItem item = menu.getItem(i); 205 | item.setText(menu.getText() + " - " + item.getText()); 206 | items.add(item); 207 | } 208 | for (JMenuItem item : items) { 209 | extensionsPopupMenu.add(item); 210 | } 211 | } 212 | } else if (level == 1) { // Name -> Scan 213 | int index = topLevelPopupMenu.getComponentIndex(extensionsMenuItem) + 1; 214 | for (int i = 0; i < allMenus.size(); i++) { 215 | JMenu menu = allMenus.get(i); 216 | topLevelPopupMenu.add(menu, index + i); 217 | } 218 | 219 | // 隐藏Extensions菜单 220 | // extensionsMenuItem.setVisible(false); 221 | } else if (level == 0) { // Name - Scan 222 | int index = topLevelPopupMenu.getComponentIndex(extensionsMenuItem) + 1; 223 | int seq = 0; 224 | for (int i = 0; i < allMenus.size(); i++) { 225 | JMenu menu = allMenus.get(i); 226 | 227 | List items = new ArrayList<>(); 228 | for (int j = 0; j < menu.getItemCount(); j++) { 229 | JMenuItem item = menu.getItem(j); 230 | item.setText(menu.getText() + " - " + item.getText()); 231 | items.add(item); 232 | } 233 | for (JMenuItem item : items) { 234 | topLevelPopupMenu.add(item, index + seq); 235 | seq += 1; 236 | } 237 | } 238 | 239 | } 240 | 241 | 242 | } 243 | } 244 | } 245 | }); 246 | } 247 | 248 | } 249 | } 250 | } 251 | }); 252 | } 253 | } 254 | } 255 | }); 256 | 257 | } 258 | } --------------------------------------------------------------------------------