├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── settings.gradle └── src └── main └── java └── cn └── enaium └── name └── obfuscator ├── Config.java ├── NameObfuscator.java ├── StringPool.java ├── annotation └── ExcludeUI.java ├── dialog ├── Dialog.java └── StringListSettingDialog.java ├── setting ├── EnableSetting.java ├── Setting.java ├── StringListSetting.java └── StringSetting.java ├── ui ├── MainGUI.java └── layout │ ├── bottom │ ├── BottomLayout.java │ └── StatusPanel.java │ └── center │ ├── CenterLayout.java │ └── panel │ ├── ControlPanel.java │ ├── SelectFilePanel.java │ └── control │ ├── LibrariesPanel.java │ ├── SettingPanel.java │ └── StringPoolPanel.java └── util ├── JFileChooserUtil.java ├── MessageUtil.java └── StringUtil.java /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | # mpeltonen/sbt-idea plugin 11 | .idea_modules/ 12 | 13 | # JIRA plugin 14 | atlassian-ide-plugin.xml 15 | 16 | # Compiled class file 17 | *.class 18 | 19 | # Log file 20 | *.log 21 | 22 | # BlueJ files 23 | *.ctxt 24 | 25 | # Package Files # 26 | *.jar 27 | *.war 28 | *.nar 29 | *.ear 30 | *.zip 31 | *.tar.gz 32 | *.rar 33 | 34 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 35 | hs_err_pid* 36 | 37 | *~ 38 | 39 | # temporary files which can be created if a process still has a handle open of a deleted file 40 | .fuse_hidden* 41 | 42 | # KDE directory preferences 43 | .directory 44 | 45 | # Linux trash folder which might appear on any partition or disk 46 | .Trash-* 47 | 48 | # .nfs files are created when an open file is removed but is still being accessed 49 | .nfs* 50 | 51 | # General 52 | .DS_Store 53 | .AppleDouble 54 | .LSOverride 55 | 56 | # Icon must end with two \r 57 | Icon 58 | 59 | # Thumbnails 60 | ._* 61 | 62 | # Files that might appear in the root of a volume 63 | .DocumentRevisions-V100 64 | .fseventsd 65 | .Spotlight-V100 66 | .TemporaryItems 67 | .Trashes 68 | .VolumeIcon.icns 69 | .com.apple.timemachine.donotpresent 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | # Windows thumbnail cache files 79 | Thumbs.db 80 | Thumbs.db:encryptable 81 | ehthumbs.db 82 | ehthumbs_vista.db 83 | 84 | # Dump file 85 | *.stackdump 86 | 87 | # Folder config file 88 | [Dd]esktop.ini 89 | 90 | # Recycle Bin used on file shares 91 | $RECYCLE.BIN/ 92 | 93 | # Windows Installer files 94 | *.cab 95 | *.msi 96 | *.msix 97 | *.msm 98 | *.msp 99 | 100 | # Windows shortcuts 101 | *.lnk 102 | 103 | .gradle 104 | build/ 105 | 106 | # Ignore Gradle GUI config 107 | gradle-app.setting 108 | 109 | # Cache of project 110 | .gradletasknamecache 111 | 112 | **/build/ 113 | 114 | # Common working directory 115 | run/ 116 | 117 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 118 | !gradle-wrapper.jar 119 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NameObfuscator 2 | 3 | ![image-20210712195104499](https://gitee.com/Enaium/imgbed/raw/master/image-20210712195104499.png) 4 | 5 | Usage JDK11+ 6 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import java.text.SimpleDateFormat 2 | 3 | plugins { 4 | id 'java' 5 | id 'com.github.johnrengelman.shadow' version '4.0.4' 6 | } 7 | 8 | group 'cn.enaium' 9 | version '1.1.0' 10 | 11 | targetCompatibility = JavaVersion.VERSION_11 12 | sourceCompatibility = JavaVersion.VERSION_11 13 | 14 | jar { 15 | manifest.attributes( 16 | 'Manifest-Version': 1.0, 17 | 'Main-Class': 'cn.enaium.name.obfuscator.NameObfuscator', 18 | "Implementation-Title": "${project.name}", 19 | "Implementation-Version": "${project.version}", 20 | "Implementation-Vendor": "${project.group}", 21 | "Implementation-Timestamp": new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) 22 | ) 23 | } 24 | 25 | tasks.withType(JavaCompile).configureEach { 26 | it.options.encoding = "UTF-8" 27 | it.options.release = 11 28 | } 29 | 30 | repositories { 31 | mavenCentral() 32 | } 33 | 34 | dependencies { 35 | implementation 'com.formdev:flatlaf:1.2' 36 | implementation 'com.google.code.gson:gson:2.8.6' 37 | implementation 'org.ow2.asm:asm-tree:9.2' 38 | implementation 'org.ow2.asm:asm-commons:9.2' 39 | implementation 'org.apache.commons:commons-lang3:3.11' 40 | } 41 | 42 | shadowJar { 43 | dependencies { 44 | include(dependency('com.formdev:flatlaf')) 45 | include(dependency('com.google.code.gson:gson')) 46 | include(dependency('org.ow2.asm:asm')) 47 | include(dependency('org.ow2.asm:asm-tree')) 48 | include(dependency('org.ow2.asm:asm-commons:')) 49 | include(dependency('org.apache.commons:commons-lang3')) 50 | } 51 | } 52 | 53 | build.dependsOn shadowJar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStorePath=wrapper/dists 5 | zipStoreBase=GRADLE_USER_HOME 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'NameObfuscator' -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/Config.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator; 2 | 3 | import cn.enaium.name.obfuscator.annotation.ExcludeUI; 4 | import cn.enaium.name.obfuscator.setting.EnableSetting; 5 | import cn.enaium.name.obfuscator.setting.Setting; 6 | import cn.enaium.name.obfuscator.setting.StringListSetting; 7 | import cn.enaium.name.obfuscator.setting.StringSetting; 8 | import cn.enaium.name.obfuscator.util.MessageUtil; 9 | import com.google.gson.Gson; 10 | import com.google.gson.GsonBuilder; 11 | import com.google.gson.JsonArray; 12 | import com.google.gson.JsonObject; 13 | 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.lang.reflect.Field; 17 | import java.nio.charset.StandardCharsets; 18 | import java.nio.file.Files; 19 | import java.util.ArrayList; 20 | import java.util.Collections; 21 | import java.util.List; 22 | 23 | /** 24 | * @author Enaium 25 | */ 26 | @SuppressWarnings("unchecked") 27 | public class Config { 28 | public static final EnableSetting CLASS_NAME = new EnableSetting("Class name", "Obfuscate class name", true); 29 | public static final EnableSetting FIELD_NAME = new EnableSetting("Field name", "Obfuscate field name", true); 30 | public static final EnableSetting METHOD_NAME = new EnableSetting("Method name", "Obfuscate method name", true); 31 | public static final EnableSetting LOCAL_VARIABLE_NAME = new EnableSetting("Local variable Name", "Obfuscate local variable name", true); 32 | public static final EnableSetting ENABLE_FILTER_CLASS_NAME = new EnableSetting("Enable Filter class", "Enable Filter class", true); 33 | public static final StringListSetting FILTER_CLASS_NAME = new StringListSetting("Filter class", "Not Obfuscate class", Collections.singletonList("cn.enaium.example")); 34 | public static final EnableSetting REMOVE_SOURCE = new EnableSetting("Remove source", "Remove class source name", true); 35 | public static final EnableSetting REMOVE_LINE_NUMBER = new EnableSetting("Remove line number", "Remove class line number", true); 36 | @ExcludeUI 37 | public static final StringSetting INPUT_JAR = new StringSetting("Input Jar", "Obfuscate input path", ""); 38 | @ExcludeUI 39 | public static final StringSetting OUTPUT_JAR = new StringSetting("Output Jar", "Obfuscate output path", ""); 40 | @ExcludeUI 41 | public static final StringListSetting LIBRARIES = new StringListSetting("Libraries", "Obfuscate libraries", Collections.emptyList()); 42 | 43 | 44 | private static final File path = new File(".", "config.json"); 45 | 46 | public static void load() { 47 | try { 48 | if (!path.exists()) { 49 | return; 50 | } 51 | 52 | final var jsonObject = new Gson().fromJson(Files.readString(path.toPath()), JsonObject.class); 53 | for (Field field : Config.class.getFields()) { 54 | try { 55 | final var o = field.get(null); 56 | if (o instanceof Setting) { 57 | final var name = ((Setting) o).getName(); 58 | if (jsonObject.has(name)) { 59 | if (o instanceof EnableSetting) { 60 | ((EnableSetting) o).setEnable(jsonObject.get(name).getAsBoolean()); 61 | } else if (o instanceof StringListSetting) { 62 | ((StringListSetting) o).setStringList(new Gson().fromJson(new Gson().toJson(jsonObject.get(name)), ArrayList.class)); 63 | } else if (o instanceof StringSetting) { 64 | ((StringSetting) o).setString(jsonObject.get(name).getAsString()); 65 | } 66 | } 67 | } 68 | } catch (IllegalAccessException e) { 69 | MessageUtil.error(e); 70 | } 71 | } 72 | 73 | } catch (IOException e) { 74 | MessageUtil.error(e); 75 | } 76 | } 77 | 78 | public static void save() { 79 | final var jsonObject = new JsonObject(); 80 | for (Field field : Config.class.getFields()) { 81 | try { 82 | final var o = field.get(null); 83 | if (o instanceof Setting) { 84 | final var name = ((Setting) o).getName(); 85 | if (o instanceof EnableSetting) { 86 | jsonObject.addProperty(name, ((EnableSetting) o).getEnable()); 87 | } else if (o instanceof StringListSetting) { 88 | List stringList = ((StringListSetting) o).getStringList(); 89 | if (!stringList.isEmpty()) { 90 | jsonObject.add(name, new Gson().fromJson(new Gson().toJson(stringList), JsonArray.class)); 91 | } 92 | } else if (o instanceof StringSetting) { 93 | jsonObject.addProperty(name, ((StringSetting) o).getString()); 94 | } 95 | } 96 | } catch (IllegalAccessException e) { 97 | MessageUtil.error(e); 98 | } 99 | } 100 | try { 101 | Files.write(path.toPath(), new GsonBuilder().setPrettyPrinting().create().toJson(jsonObject).getBytes(StandardCharsets.UTF_8)); 102 | } catch (IOException e) { 103 | MessageUtil.error(e); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/NameObfuscator.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator; 2 | 3 | import cn.enaium.name.obfuscator.ui.MainGUI; 4 | import com.formdev.flatlaf.FlatDarculaLaf; 5 | import com.formdev.flatlaf.FlatIntelliJLaf; 6 | 7 | /** 8 | * @author Enaium 9 | */ 10 | public class NameObfuscator { 11 | 12 | public static MainGUI mainGUI; 13 | 14 | public static void main(String[] args) { 15 | Config.load(); 16 | FlatDarculaLaf.setup(); 17 | mainGUI = new MainGUI(); 18 | mainGUI.setVisible(true); 19 | Runtime.getRuntime().addShutdownHook(new Thread(Config::save)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/StringPool.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator; 2 | 3 | import org.apache.commons.lang3.RandomStringUtils; 4 | import org.apache.commons.lang3.RandomUtils; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.LinkedHashSet; 9 | import java.util.List; 10 | 11 | /** 12 | * @author Enaium 13 | */ 14 | public class StringPool { 15 | private final List strings = new ArrayList<>(); 16 | private int index = 0; 17 | 18 | public StringPool(List strings) { 19 | this.strings.addAll(new LinkedHashSet<>(strings)); 20 | after(); 21 | } 22 | 23 | public StringPool(String[] strings) { 24 | final ArrayList arrayList = new ArrayList(); 25 | Collections.addAll(arrayList, strings); 26 | this.strings.addAll(new LinkedHashSet<>(arrayList)); 27 | after(); 28 | } 29 | 30 | private void after() { 31 | strings.removeIf(String::isEmpty); 32 | } 33 | 34 | public boolean re = false; 35 | 36 | public String next() { 37 | if (index == strings.size()) { 38 | index = 0; 39 | re = true; 40 | } 41 | 42 | String s = strings.get(index); 43 | 44 | if (re) { 45 | s += RandomStringUtils.randomAlphabetic(10); 46 | } 47 | 48 | index++; 49 | return s; 50 | } 51 | 52 | public List getStrings() { 53 | return strings; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/annotation/ExcludeUI.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Enaium 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.FIELD) 13 | public @interface ExcludeUI { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/dialog/Dialog.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.dialog; 2 | 3 | import cn.enaium.name.obfuscator.NameObfuscator; 4 | 5 | import javax.swing.*; 6 | 7 | public class Dialog extends JFrame { 8 | public Dialog(String title) { 9 | super(title); 10 | setLocation(NameObfuscator.mainGUI.getLocation()); 11 | setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 12 | setSize(600, 400); 13 | setVisible(true); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/dialog/StringListSettingDialog.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.dialog; 2 | 3 | import cn.enaium.name.obfuscator.setting.StringListSetting; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | 8 | /** 9 | * @author Enaium 10 | */ 11 | public class StringListSettingDialog extends Dialog { 12 | public StringListSettingDialog(StringListSetting setting) { 13 | super(setting.getName() + " | " + setting.getDescription()); 14 | JPanel content = new JPanel(); 15 | content.setLayout(new BorderLayout()); 16 | var stringDefaultListModel = new DefaultListModel(); 17 | var jList = new JList<>(stringDefaultListModel); 18 | setting.getStringList().forEach(stringDefaultListModel::addElement); 19 | content.add(new JScrollPane(jList), BorderLayout.CENTER); 20 | JPanel control = new JPanel(); 21 | control.setLayout(new GridLayout(1, 3)); 22 | JTextField jTextField = new JTextField(); 23 | control.add(jTextField); 24 | JButton add = new JButton("Add"); 25 | add.addActionListener(e -> { 26 | if (!jTextField.getText().replace(" ", "").isEmpty()) { 27 | stringDefaultListModel.addElement(jTextField.getText()); 28 | setting.getStringList().add(jTextField.getText()); 29 | } 30 | }); 31 | control.add(add); 32 | JButton remove = new JButton("Remove"); 33 | remove.addActionListener(e -> { 34 | stringDefaultListModel.removeElement(jList.getSelectedValue()); 35 | setting.getStringList().clear(); 36 | for (Object o : stringDefaultListModel.toArray()) { 37 | setting.getStringList().add((String) o); 38 | } 39 | 40 | }); 41 | control.add(remove); 42 | content.add(control, BorderLayout.NORTH); 43 | setContentPane(content); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/setting/EnableSetting.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.setting; 2 | 3 | /** 4 | * @author Enaium 5 | */ 6 | public class EnableSetting extends Setting { 7 | private boolean enable; 8 | 9 | public EnableSetting(String name, String description, boolean enable) { 10 | super(name, description); 11 | this.enable = enable; 12 | } 13 | 14 | public boolean getEnable() { 15 | return enable; 16 | } 17 | 18 | public void setEnable(boolean enable) { 19 | this.enable = enable; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/setting/Setting.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.setting; 2 | 3 | /** 4 | * @author Enaium 5 | */ 6 | public class Setting { 7 | private final String name; 8 | private final String description; 9 | 10 | public Setting(String name, String description) { 11 | this.name = name; 12 | this.description = description; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public String getDescription() { 20 | return description; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/setting/StringListSetting.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.setting; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Enaium 7 | */ 8 | public class StringListSetting extends Setting { 9 | private List stringList; 10 | 11 | public StringListSetting(String name, String description, List stringList) { 12 | super(name, description); 13 | this.stringList = stringList; 14 | } 15 | 16 | public List getStringList() { 17 | return stringList; 18 | } 19 | 20 | public void setStringList(List stringList) { 21 | this.stringList = stringList; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/setting/StringSetting.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.setting; 2 | 3 | /** 4 | * @author Enaium 5 | */ 6 | public class StringSetting extends Setting{ 7 | private String string; 8 | 9 | public StringSetting(String name, String description, String string) { 10 | super(name, description); 11 | this.string = string; 12 | } 13 | 14 | public String getString() { 15 | return string; 16 | } 17 | 18 | public void setString(String string) { 19 | this.string = string; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/MainGUI.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui; 2 | 3 | import cn.enaium.name.obfuscator.ui.layout.bottom.BottomLayout; 4 | import cn.enaium.name.obfuscator.ui.layout.bottom.StatusPanel; 5 | import cn.enaium.name.obfuscator.ui.layout.center.CenterLayout; 6 | import cn.enaium.name.obfuscator.util.MessageUtil; 7 | 8 | import javax.swing.*; 9 | import java.awt.*; 10 | import java.io.IOException; 11 | import java.net.URI; 12 | import java.net.URISyntaxException; 13 | 14 | /** 15 | * @author Enaium 16 | */ 17 | public class MainGUI extends JFrame { 18 | 19 | public static final String NAME = "NameObfuscator"; 20 | public static final String VERSION = MainGUI.class.getPackage().getImplementationVersion(); 21 | 22 | public MainGUI() throws HeadlessException { 23 | setTitle(MainGUI.NAME + " | " + MainGUI.VERSION + " | By Enaium"); 24 | setSize(700, 400); 25 | setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 26 | setLocationRelativeTo(getOwner()); 27 | setLayout(new BorderLayout()); 28 | add(new CenterLayout(), BorderLayout.CENTER); 29 | add(new BottomLayout(), BorderLayout.SOUTH); 30 | JMenuBar jMenuBar = new JMenuBar(); 31 | JMenu help = new JMenu("Help"); 32 | JMenuItem contact = new JMenuItem("Contact"); 33 | contact.addActionListener(e -> { 34 | try { 35 | Desktop.getDesktop().browse(new URI("https://github.com/Enaium/NameObfuscator")); 36 | } catch (IOException | URISyntaxException ioException) { 37 | MessageUtil.error(ioException); 38 | } 39 | }); 40 | help.add(contact); 41 | jMenuBar.add(help); 42 | setJMenuBar(jMenuBar); 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/layout/bottom/BottomLayout.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui.layout.bottom; 2 | 3 | import cn.enaium.name.obfuscator.Config; 4 | import cn.enaium.name.obfuscator.StringPool; 5 | import cn.enaium.name.obfuscator.ui.layout.center.panel.SelectFilePanel; 6 | import cn.enaium.name.obfuscator.ui.layout.center.panel.control.StringPoolPanel; 7 | import cn.enaium.name.obfuscator.util.MessageUtil; 8 | import cn.enaium.name.obfuscator.util.StringUtil; 9 | import org.apache.commons.lang3.RandomStringUtils; 10 | import org.apache.commons.lang3.RandomUtils; 11 | import org.objectweb.asm.*; 12 | import org.objectweb.asm.commons.ClassRemapper; 13 | import org.objectweb.asm.commons.SimpleRemapper; 14 | import org.objectweb.asm.tree.*; 15 | 16 | import javax.swing.*; 17 | import java.awt.*; 18 | import java.io.BufferedOutputStream; 19 | import java.io.File; 20 | import java.io.FileOutputStream; 21 | import java.io.IOException; 22 | import java.nio.file.Files; 23 | import java.util.*; 24 | import java.util.List; 25 | import java.util.jar.JarEntry; 26 | import java.util.jar.JarFile; 27 | import java.util.zip.ZipEntry; 28 | import java.util.zip.ZipFile; 29 | import java.util.zip.ZipOutputStream; 30 | 31 | import static org.objectweb.asm.Opcodes.*; 32 | 33 | /** 34 | * @author Enaium 35 | */ 36 | public class BottomLayout extends JPanel { 37 | 38 | private static final HashMap> superHashMap = new HashMap<>(); 39 | 40 | public BottomLayout() { 41 | setLayout(new BorderLayout()); 42 | final var obfuscate = new JButton("Obfuscate"); 43 | add(obfuscate, BorderLayout.CENTER); 44 | add(new StatusPanel(), BorderLayout.SOUTH); 45 | obfuscate.addActionListener(e -> { 46 | new Thread(() -> { 47 | try { 48 | start(new File(SelectFilePanel.INPUT_JAR_TEXT_FIELD.getText()), new File(SelectFilePanel.OUTPUT_JAR_TEXT_FIELD.getText())); 49 | } catch (IOException exception) { 50 | MessageUtil.error(exception); 51 | } 52 | }).start(); 53 | }); 54 | } 55 | 56 | 57 | private final HashMap readerHashMap = new HashMap<>(); 58 | private final HashMap map = new HashMap<>(); 59 | private final HashMap libraryHashMap = new HashMap<>(); 60 | 61 | private void start(File input, File output) throws IOException { 62 | readerHashMap.clear(); 63 | map.clear(); 64 | libraryHashMap.clear(); 65 | //Read all libraries 66 | StatusPanel.STATUS_LABEL.setText("Loading libraries..."); 67 | for (String s : Config.LIBRARIES.getStringList()) { 68 | final var file = new File(s); 69 | var files = new ArrayList(); 70 | if (file.isDirectory()) { 71 | listFiles(file, files); 72 | } else if (file.isFile()) { 73 | files.add(file); 74 | } 75 | 76 | for (File f : files) { 77 | final var zipFile = new ZipFile(f); 78 | final var entries = zipFile.entries(); 79 | while (entries.hasMoreElements()) { 80 | final ZipEntry zipEntry = entries.nextElement(); 81 | if (zipEntry.isDirectory()) continue; 82 | if (zipEntry.getName().endsWith(".class")) 83 | libraryHashMap.put(zipEntry.getName(), zipFile.getInputStream(zipEntry).readAllBytes()); 84 | } 85 | zipFile.close(); 86 | } 87 | } 88 | 89 | //Read all classes 90 | StatusPanel.STATUS_LABEL.setText("Loading class..."); 91 | analyzeJar(input); 92 | final var outputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(output))); 93 | ZipFile zipFile = new ZipFile(input); 94 | final var entries = zipFile.entries(); 95 | while (entries.hasMoreElements()) { 96 | final ZipEntry zipEntry = entries.nextElement(); 97 | if (zipEntry.isDirectory()) { 98 | continue; 99 | } else if (!zipEntry.getName().endsWith(".class")) { 100 | outputStream.putNextEntry(new JarEntry(zipEntry.getName())); 101 | outputStream.write(zipFile.getInputStream(zipEntry).readAllBytes()); 102 | continue; 103 | } 104 | 105 | readerHashMap.put(zipEntry.getName(), new ClassReader(zipFile.getInputStream(zipEntry))); 106 | } 107 | zipFile.close(); 108 | 109 | 110 | var pool = new StringPool(StringPoolPanel.POOL.getText().split("\n")); 111 | 112 | if (StringPoolPanel.POOL.getText().isEmpty()) { 113 | var size = readerHashMap.size(); 114 | 115 | for (Map.Entry stringClassReaderEntry : readerHashMap.entrySet()) { 116 | ClassNode classNode = new ClassNode(); 117 | stringClassReaderEntry.getValue().accept(classNode, 0); 118 | size += classNode.fields.size(); 119 | size += classNode.methods.size(); 120 | } 121 | 122 | for (int i = 0; i < size; i++) { 123 | pool.getStrings().add(RandomStringUtils.random(RandomUtils.nextInt(10, Byte.MAX_VALUE), StringUtil.cha[RandomUtils.nextInt(0, StringUtil.cha.length - 1)])); 124 | } 125 | } 126 | 127 | 128 | StatusPanel.STATUS_LABEL.setText("Building mapping..."); 129 | //class mapping 130 | for (Map.Entry stringClassReaderEntry : readerHashMap.entrySet()) { 131 | final var value = stringClassReaderEntry.getValue(); 132 | ClassNode classNode = new ClassNode(); 133 | value.accept(classNode, 0); 134 | 135 | var classObf = pool.next(); 136 | if (classNode.name.contains("/")) { 137 | classObf = classNode.name.substring(0, classNode.name.lastIndexOf("/")) + "/" + classObf; 138 | } 139 | 140 | var filter = false; 141 | for (String s : Config.FILTER_CLASS_NAME.getStringList()) { 142 | if (Config.ENABLE_FILTER_CLASS_NAME.getEnable() && (classNode.name.startsWith(s.replace(".", "/")) || classNode.name.endsWith(s.replace(".", "/")))) { 143 | filter = true; 144 | break; 145 | } 146 | } 147 | 148 | if (Config.CLASS_NAME.getEnable()) { 149 | if (!filter) { 150 | map.put(classNode.name, classObf); 151 | } 152 | } 153 | } 154 | 155 | //member mapping 156 | for (Map.Entry stringClassReaderEntry : readerHashMap.entrySet()) { 157 | ClassNode classNode = new ClassNode(); 158 | stringClassReaderEntry.getValue().accept(classNode, 0); 159 | for (FieldNode field : classNode.fields) { 160 | if (Config.FIELD_NAME.getEnable()) { 161 | map.put(classNode.name + "." + field.name, pool.next()); 162 | } 163 | } 164 | 165 | for (MethodNode method : classNode.methods) { 166 | if (!(method.name.equals("") || 167 | method.name.equals("") || 168 | (method.access == Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC && method.name.equals("main") && method.desc.equals("([Ljava/lang/String;)V")))) { 169 | if (Config.METHOD_NAME.getEnable()) { 170 | if (!isOverride(classNode.name, method)) { 171 | map.put(classNode.name + "." + method.name + method.desc, pool.next()); 172 | } 173 | } 174 | } 175 | } 176 | } 177 | 178 | StatusPanel.STATUS_LABEL.setText("Outputting..."); 179 | //Output 180 | for (Map.Entry stringClassReaderEntry : readerHashMap.entrySet()) { 181 | var name = stringClassReaderEntry.getKey(); 182 | 183 | var fileName = name.substring(0, name.lastIndexOf(".")); 184 | if (map.containsKey(fileName)) { 185 | name = map.get(fileName) + ".class"; 186 | } 187 | 188 | outputStream.putNextEntry(new ZipEntry(name)); 189 | ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); 190 | stringClassReaderEntry.getValue().accept(new ClassRemapper(classWriter, new SimpleRemapper(map) { 191 | @Override 192 | public String mapFieldName(String owner, String name, String descriptor) { 193 | String remappedName = map(owner + '.' + name); 194 | if (remappedName == null) { 195 | if (superHashMap.containsKey(owner)) { 196 | for (String s : superHashMap.get(owner)) { 197 | String rn = mapFieldName(s, name, descriptor); 198 | if (rn != null) { 199 | return rn; 200 | } 201 | } 202 | } 203 | } 204 | return remappedName == null ? name : remappedName; 205 | } 206 | 207 | @Override 208 | public String mapMethodName(String owner, String name, String descriptor) { 209 | String remappedName = map(owner + '.' + name + descriptor); 210 | if (remappedName == null) { 211 | if (superHashMap.get(owner) != null) { 212 | for (String s : superHashMap.get(owner)) { 213 | String rn = mapMethodName(s, name, descriptor); 214 | if (rn != null) { 215 | return rn; 216 | } 217 | } 218 | } 219 | } 220 | return remappedName == null ? name : remappedName; 221 | } 222 | }), 0); 223 | final var classReader = new ClassReader(classWriter.toByteArray()); 224 | final var classNode = new ClassNode(); 225 | classReader.accept(classNode, 0); 226 | 227 | classNode.version = V11; 228 | 229 | if (Config.REMOVE_SOURCE.getEnable()) { 230 | classNode.visitSource(null, null); 231 | } 232 | 233 | for (MethodNode method : classNode.methods) { 234 | if (Config.LOCAL_VARIABLE_NAME.getEnable()) { 235 | if (method.parameters != null) { 236 | for (ParameterNode parameter : method.parameters) { 237 | parameter.name = pool.next(); 238 | } 239 | } 240 | 241 | if (method.localVariables != null) { 242 | for (LocalVariableNode localVariable : method.localVariables) { 243 | localVariable.name = pool.next(); 244 | } 245 | } 246 | } 247 | 248 | if (Config.REMOVE_LINE_NUMBER.getEnable()) { 249 | for (AbstractInsnNode instruction : method.instructions) { 250 | if (instruction instanceof LineNumberNode) { 251 | method.instructions.remove(instruction); 252 | } 253 | } 254 | } 255 | } 256 | 257 | final var finalClassWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); 258 | classNode.accept(finalClassWriter); 259 | outputStream.write(finalClassWriter.toByteArray()); 260 | } 261 | outputStream.closeEntry(); 262 | outputStream.close(); 263 | StatusPanel.reset(); 264 | } 265 | 266 | private boolean isOverride(String name, MethodNode methodNode) { 267 | var list = new ArrayList(); 268 | find(name, list); 269 | for (String s : list) { 270 | ClassNode cn = null; 271 | if (readerHashMap.containsKey(s + ".class")) { 272 | final var classReader = readerHashMap.get(s + ".class"); 273 | ClassNode classNode = new ClassNode(); 274 | classReader.accept(classNode, 0); 275 | cn = classNode; 276 | } else { 277 | try { 278 | var classNode = new ClassNode(); 279 | ClassReader classReader = new ClassReader(s); 280 | classReader.accept(classNode, 0); 281 | cn = classNode; 282 | } catch (IOException e) { 283 | if (libraryHashMap.containsKey(s + ".class")) { 284 | var classNode = new ClassNode(); 285 | ClassReader classReader = new ClassReader(libraryHashMap.get(s + ".class")); 286 | classReader.accept(classNode, 0); 287 | cn = classNode; 288 | } else { 289 | // MessageUtil.error(new IOException("Class no found " + s)); 290 | return true; 291 | } 292 | } 293 | } 294 | 295 | for (MethodNode method : cn.methods) { 296 | if ((method.name + method.desc).equals(methodNode.name + methodNode.desc)) { 297 | return true; 298 | } 299 | } 300 | } 301 | return false; 302 | } 303 | 304 | private void find(String name, List classes) { 305 | if (superHashMap.containsKey(name)) { 306 | final var list = superHashMap.get(name); 307 | for (String s : list) { 308 | classes.add(s); 309 | find(s, classes); 310 | } 311 | } 312 | } 313 | 314 | private void analyzeJar(File inputFile) throws IOException { 315 | superHashMap.put("java/lang/Object", Collections.emptyList()); 316 | JarFile jarFile = new JarFile(inputFile); 317 | Enumeration entries = jarFile.entries(); 318 | while (entries.hasMoreElements()) { 319 | JarEntry jarEntry = entries.nextElement(); 320 | if (jarEntry.isDirectory()) 321 | continue; 322 | if (!jarEntry.getName().endsWith(".class")) 323 | continue; 324 | 325 | analyze(jarFile.getInputStream(jarEntry).readAllBytes()); 326 | 327 | } 328 | jarFile.close(); 329 | } 330 | 331 | private void analyze(byte[] bytes) { 332 | ClassReader classReader = new ClassReader(bytes); 333 | classReader.accept(new ClassVisitor(ASM9) { 334 | @Override 335 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 336 | ArrayList strings = new ArrayList<>(); 337 | if (superHashMap.containsKey(name)) { 338 | if (superName != null) { 339 | if (!superHashMap.get(name).contains(superName)) { 340 | strings.add(superName); 341 | } 342 | } 343 | 344 | if (interfaces != null) { 345 | for (String inter : interfaces) { 346 | if (!superHashMap.get(name).contains(inter)) { 347 | strings.add(inter); 348 | } 349 | } 350 | } 351 | superHashMap.get(name).addAll(strings); 352 | } else { 353 | if (superName != null) { 354 | strings.add(superName); 355 | } 356 | 357 | if (interfaces != null) { 358 | Collections.addAll(strings, interfaces); 359 | } 360 | superHashMap.put(name, strings); 361 | } 362 | super.visit(version, access, name, signature, superName, interfaces); 363 | } 364 | }, 0); 365 | } 366 | 367 | private void listFiles(File file, List list) { 368 | File[] listFiles = file.listFiles(); 369 | if (listFiles == null) { 370 | return; 371 | } 372 | 373 | for (File listFile : listFiles) { 374 | if (listFile.isFile() && listFile.getName().endsWith(".zip") || listFile.getName().endsWith(".jar")) { 375 | list.add(listFile); 376 | } else if (file.isDirectory()) { 377 | listFiles(listFile.getAbsoluteFile(), list); 378 | } 379 | } 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/layout/bottom/StatusPanel.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui.layout.bottom; 2 | 3 | import cn.enaium.name.obfuscator.ui.MainGUI; 4 | 5 | import javax.swing.*; 6 | 7 | /** 8 | * @author Enaium 9 | */ 10 | public class StatusPanel extends JPanel { 11 | 12 | public static final JLabel STATUS_LABEL = new JLabel(MainGUI.NAME + " | " + MainGUI.VERSION + " | By Enaium"); 13 | 14 | public static void reset() { 15 | STATUS_LABEL.setText(MainGUI.NAME + " | " + MainGUI.VERSION + " | By Enaium"); 16 | } 17 | 18 | public StatusPanel() { 19 | setBorder(BorderFactory.createLoweredBevelBorder()); 20 | add(STATUS_LABEL); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/layout/center/CenterLayout.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui.layout.center; 2 | 3 | import cn.enaium.name.obfuscator.ui.layout.center.panel.ControlPanel; 4 | import cn.enaium.name.obfuscator.ui.layout.center.panel.SelectFilePanel; 5 | 6 | import javax.swing.*; 7 | 8 | /** 9 | * @author Enaium 10 | */ 11 | public class CenterLayout extends JSplitPane { 12 | public CenterLayout() { 13 | super(JSplitPane.VERTICAL_SPLIT, new SelectFilePanel(), new ControlPanel()); 14 | setContinuousLayout(true); 15 | setOneTouchExpandable(true); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/layout/center/panel/ControlPanel.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui.layout.center.panel; 2 | 3 | import cn.enaium.name.obfuscator.ui.layout.center.panel.control.LibrariesPanel; 4 | import cn.enaium.name.obfuscator.ui.layout.center.panel.control.SettingPanel; 5 | import cn.enaium.name.obfuscator.ui.layout.center.panel.control.StringPoolPanel; 6 | 7 | import javax.swing.*; 8 | import java.awt.*; 9 | 10 | /** 11 | * @author Enaium 12 | */ 13 | public class ControlPanel extends JPanel { 14 | public ControlPanel() { 15 | final var jTabbedPane = new JTabbedPane(); 16 | jTabbedPane.addTab("Setting", new SettingPanel()); 17 | jTabbedPane.addTab("String pool", new StringPoolPanel()); 18 | jTabbedPane.addTab("Libraries", new LibrariesPanel()); 19 | setLayout(new BorderLayout()); 20 | add(jTabbedPane, BorderLayout.CENTER); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/layout/center/panel/SelectFilePanel.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui.layout.center.panel; 2 | 3 | import cn.enaium.name.obfuscator.Config; 4 | import cn.enaium.name.obfuscator.util.JFileChooserUtil; 5 | 6 | import javax.swing.*; 7 | import javax.swing.event.AncestorEvent; 8 | import javax.swing.event.AncestorListener; 9 | import java.awt.*; 10 | import java.awt.event.*; 11 | import java.io.File; 12 | 13 | /** 14 | * @author Enaium 15 | */ 16 | public class SelectFilePanel extends JPanel { 17 | 18 | private static final JLabel INPUT_JAR_LABEL = new JLabel("Input Jar:"); 19 | private static final JLabel OUTPUT_JAR_LABEL = new JLabel("Output Jar:"); 20 | public static final JTextField INPUT_JAR_TEXT_FIELD = new JTextField(); 21 | public static final JTextField OUTPUT_JAR_TEXT_FIELD = new JTextField(); 22 | private static final JButton INPUT_JAR_BUTTON = new JButton("..."); 23 | private static final JButton OUTPUT_JAR_BUTTON = new JButton("..."); 24 | 25 | public SelectFilePanel() { 26 | final GridBagLayout gridBagLayout = new GridBagLayout(); 27 | gridBagLayout.columnWeights = new double[]{0.0, 1.0, 0.0, Double.MIN_VALUE}; 28 | gridBagLayout.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE}; 29 | setLayout(gridBagLayout); 30 | 31 | INPUT_JAR_TEXT_FIELD.setText(Config.INPUT_JAR.getString()); 32 | OUTPUT_JAR_TEXT_FIELD.setText(Config.OUTPUT_JAR.getString()); 33 | 34 | 35 | INPUT_JAR_TEXT_FIELD.addKeyListener(new KeyAdapter() { 36 | @Override 37 | public void keyTyped(KeyEvent e) { 38 | Config.INPUT_JAR.setString(INPUT_JAR_TEXT_FIELD.getText()); 39 | } 40 | }); 41 | 42 | OUTPUT_JAR_TEXT_FIELD.addKeyListener(new KeyAdapter() { 43 | @Override 44 | public void keyTyped(KeyEvent e) { 45 | Config.OUTPUT_JAR.setString(INPUT_JAR_TEXT_FIELD.getText()); 46 | } 47 | }); 48 | 49 | INPUT_JAR_BUTTON.addActionListener(e -> { 50 | final File show = JFileChooserUtil.show(JFileChooserUtil.Type.OPEN); 51 | if (show != null) { 52 | final var input = show.getAbsoluteFile().getPath(); 53 | final var output = show.getParent() + File.separator + show.getName().substring(0, show.getName().lastIndexOf(".")) + "-Obf" + show.getName().substring(show.getName().lastIndexOf(".")); 54 | INPUT_JAR_TEXT_FIELD.setText(input); 55 | Config.INPUT_JAR.setString(input); 56 | 57 | if (OUTPUT_JAR_TEXT_FIELD.getText().isEmpty()) { 58 | Config.OUTPUT_JAR.setString(output); 59 | OUTPUT_JAR_TEXT_FIELD.setText(output); 60 | } 61 | } 62 | }); 63 | 64 | OUTPUT_JAR_BUTTON.addActionListener(e -> { 65 | final File show = JFileChooserUtil.show(JFileChooserUtil.Type.SAVE); 66 | if (show != null) { 67 | OUTPUT_JAR_TEXT_FIELD.setText(show.getAbsoluteFile().getPath()); 68 | Config.OUTPUT_JAR.setString(show.getAbsoluteFile().getPath()); 69 | } 70 | }); 71 | 72 | GridBagConstraints inputLabelGBC = new GridBagConstraints(); 73 | inputLabelGBC.gridx = 0; 74 | inputLabelGBC.gridy = 0; 75 | add(INPUT_JAR_LABEL, inputLabelGBC); 76 | 77 | GridBagConstraints inputFieldTextGBC = new GridBagConstraints(); 78 | inputFieldTextGBC.fill = GridBagConstraints.HORIZONTAL; 79 | inputFieldTextGBC.gridx = 1; 80 | inputFieldTextGBC.gridy = 0; 81 | add(INPUT_JAR_TEXT_FIELD, inputFieldTextGBC); 82 | 83 | GridBagConstraints inputButtonTextGBC = new GridBagConstraints(); 84 | inputButtonTextGBC.gridx = 2; 85 | inputButtonTextGBC.gridy = 0; 86 | add(INPUT_JAR_BUTTON, inputButtonTextGBC); 87 | 88 | GridBagConstraints outputLabelGBC = new GridBagConstraints(); 89 | outputLabelGBC.gridx = 0; 90 | outputLabelGBC.gridy = 1; 91 | add(OUTPUT_JAR_LABEL, outputLabelGBC); 92 | 93 | GridBagConstraints outputFieldTextGBC = new GridBagConstraints(); 94 | outputFieldTextGBC.fill = GridBagConstraints.HORIZONTAL; 95 | outputFieldTextGBC.gridx = 1; 96 | outputFieldTextGBC.gridy = 1; 97 | add(OUTPUT_JAR_TEXT_FIELD, outputFieldTextGBC); 98 | 99 | GridBagConstraints outputButtonTextGBC = new GridBagConstraints(); 100 | outputButtonTextGBC.gridx = 2; 101 | outputButtonTextGBC.gridy = 1; 102 | add(OUTPUT_JAR_BUTTON, outputButtonTextGBC); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/layout/center/panel/control/LibrariesPanel.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui.layout.center.panel.control; 2 | 3 | import cn.enaium.name.obfuscator.Config; 4 | import cn.enaium.name.obfuscator.util.JFileChooserUtil; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.util.ArrayList; 9 | 10 | /** 11 | * @author Enaium 12 | */ 13 | public class LibrariesPanel extends JPanel { 14 | public LibrariesPanel() { 15 | setLayout(new BorderLayout()); 16 | var stringDefaultListModel = new DefaultListModel(); 17 | var list = new JList<>(stringDefaultListModel); 18 | add(new JScrollPane(list), BorderLayout.CENTER); 19 | final var jPanel = new JPanel(new BorderLayout()); 20 | final var add = new JButton("Add"); 21 | final var remove = new JButton("Remove"); 22 | jPanel.add(add, BorderLayout.NORTH); 23 | jPanel.add(remove, BorderLayout.SOUTH); 24 | add(jPanel, BorderLayout.EAST); 25 | 26 | Config.LIBRARIES.getStringList().forEach(stringDefaultListModel::addElement); 27 | 28 | add.addActionListener(e -> { 29 | final var show = JFileChooserUtil.show(JFileChooserUtil.Type.OPEN, JFileChooser.FILES_AND_DIRECTORIES); 30 | if (show != null) { 31 | stringDefaultListModel.addElement(show.getAbsolutePath()); 32 | Config.LIBRARIES.getStringList().add(show.getAbsolutePath()); 33 | } 34 | }); 35 | 36 | remove.addActionListener(e -> { 37 | if (list.getSelectedValue() != null) { 38 | stringDefaultListModel.removeElement(list.getSelectedValue()); 39 | var l = new ArrayList(); 40 | for (Object o : stringDefaultListModel.toArray()) { 41 | l.add((String) o); 42 | } 43 | Config.LIBRARIES.setStringList(l); 44 | } 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/layout/center/panel/control/SettingPanel.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui.layout.center.panel.control; 2 | 3 | import cn.enaium.name.obfuscator.Config; 4 | import cn.enaium.name.obfuscator.annotation.ExcludeUI; 5 | import cn.enaium.name.obfuscator.dialog.StringListSettingDialog; 6 | import cn.enaium.name.obfuscator.setting.EnableSetting; 7 | import cn.enaium.name.obfuscator.setting.Setting; 8 | import cn.enaium.name.obfuscator.setting.StringListSetting; 9 | 10 | import javax.swing.*; 11 | import java.awt.*; 12 | import java.lang.reflect.Field; 13 | 14 | /** 15 | * @author Enaium 16 | */ 17 | public class SettingPanel extends JPanel { 18 | public SettingPanel() { 19 | setLayout(new BorderLayout()); 20 | final var jPanel = new JPanel(); 21 | final var gridLayout = new GridLayout(0, 2); 22 | jPanel.setLayout(gridLayout); 23 | jPanel.setPreferredSize(new Dimension(512, 256)); 24 | for (Field field : Config.class.getFields()) { 25 | if (field.isAnnotationPresent(ExcludeUI.class)) continue; 26 | try { 27 | final var o = field.get(null); 28 | if (o instanceof Setting) { 29 | var name = ((Setting) o).getName(); 30 | var description = ((Setting) o).getDescription(); 31 | if (o instanceof EnableSetting) { 32 | final var jCheckBox = new JCheckBox(name); 33 | jCheckBox.setSelected(((EnableSetting) o).getEnable()); 34 | jCheckBox.addActionListener(e -> ((EnableSetting) o).setEnable(jCheckBox.isSelected())); 35 | jPanel.add(jCheckBox); 36 | jPanel.add(new JLabel(description)); 37 | } else if (o instanceof StringListSetting) { 38 | JButton set = new JButton("Set"); 39 | set.addActionListener(e -> { 40 | new StringListSettingDialog((StringListSetting) o); 41 | }); 42 | jPanel.add(set); 43 | jPanel.add(new JLabel(description)); 44 | } 45 | } 46 | } catch (IllegalAccessException e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | final var jScrollPane = new JScrollPane(jPanel); 51 | add(jScrollPane, BorderLayout.CENTER); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/ui/layout/center/panel/control/StringPoolPanel.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.ui.layout.center.panel.control; 2 | 3 | import cn.enaium.name.obfuscator.util.JFileChooserUtil; 4 | import cn.enaium.name.obfuscator.util.MessageUtil; 5 | import cn.enaium.name.obfuscator.util.StringUtil; 6 | 7 | import javax.swing.*; 8 | import javax.swing.filechooser.FileFilter; 9 | import java.awt.*; 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.nio.file.Files; 13 | import java.util.ArrayList; 14 | 15 | /** 16 | * @author Enaium 17 | */ 18 | public class StringPoolPanel extends JPanel { 19 | 20 | public static final JTextArea POOL = new JTextArea(); 21 | 22 | public StringPoolPanel() { 23 | setLayout(new BorderLayout()); 24 | add(new JScrollPane(POOL), BorderLayout.CENTER); 25 | final var inputButton = new JButton("Input"); 26 | add(inputButton, BorderLayout.EAST); 27 | 28 | inputButton.addActionListener(e -> { 29 | try { 30 | final var show = JFileChooserUtil.show(JFileChooserUtil.Type.OPEN, new FileFilter() { 31 | @Override 32 | public boolean accept(File file) { 33 | return file.getName().endsWith(".txt") || file.getName().endsWith(".srt") || file.getName().endsWith(".lrc") || file.isDirectory(); 34 | } 35 | 36 | @Override 37 | public String getDescription() { 38 | return "String Pool(*.txt,*.srt,*.lrc)"; 39 | } 40 | }); 41 | 42 | final var strings = new ArrayList(); 43 | 44 | if (show != null) { 45 | for (String readAllLine : Files.readAllLines(new File(show.getAbsolutePath()).toPath())) { 46 | if (!readAllLine.isEmpty()) { 47 | strings.add(readAllLine.replace(" ", "").replace("\\", "").replaceAll("[\\s\\p{P}\\n\\r=+$<>^`~|0-9.*!@#%&()\",]", "")); 48 | } 49 | } 50 | 51 | if (show.getName().endsWith(".txt")) { 52 | strings.forEach(it -> POOL.append(it + "\n")); 53 | } else if (show.getName().endsWith(".srt")) { 54 | StringUtil.parseSrt(strings).forEach(POOL::append); 55 | } else if (show.getName().endsWith(".lrc")) { 56 | StringUtil.parseLrc(strings).forEach(POOL::append); 57 | } 58 | } 59 | } catch (IOException exception) { 60 | MessageUtil.error(exception); 61 | } 62 | }); 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/util/JFileChooserUtil.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.util; 2 | 3 | import cn.enaium.name.obfuscator.NameObfuscator; 4 | 5 | import javax.swing.*; 6 | import javax.swing.filechooser.FileFilter; 7 | import javax.swing.filechooser.FileSystemView; 8 | import java.io.File; 9 | 10 | /** 11 | * @author Enaium 12 | */ 13 | public class JFileChooserUtil { 14 | 15 | private JFileChooserUtil() { 16 | throw new IllegalAccessError("Utility"); 17 | } 18 | 19 | public static File show(Type type) { 20 | return show(type, JFileChooser.FILES_ONLY); 21 | } 22 | 23 | public static File show(Type type, int mode) { 24 | return show(type, new FileFilter() { 25 | @Override 26 | public boolean accept(File file) { 27 | return file.getName().endsWith(".zip") || file.getName().endsWith(".jar") || file.isDirectory(); 28 | } 29 | 30 | @Override 31 | public String getDescription() { 32 | return "Zip File(*.zip,*.jar)"; 33 | } 34 | }, mode); 35 | } 36 | 37 | public static File show(Type type, FileFilter fileFilter) { 38 | return show(type, fileFilter, JFileChooser.FILES_ONLY); 39 | } 40 | 41 | public static File show(Type type, FileFilter fileFilter, int mode) { 42 | JFileChooser jFileChooser = new JFileChooser(); 43 | jFileChooser.setCurrentDirectory(FileSystemView.getFileSystemView().getHomeDirectory()); 44 | jFileChooser.setFileSelectionMode(mode); 45 | jFileChooser.removeChoosableFileFilter(jFileChooser.getAcceptAllFileFilter()); 46 | jFileChooser.addChoosableFileFilter(fileFilter); 47 | 48 | if (type.equals(Type.OPEN)) { 49 | jFileChooser.showOpenDialog(NameObfuscator.mainGUI); 50 | } else if (type.equals(Type.SAVE)) { 51 | jFileChooser.showSaveDialog(NameObfuscator.mainGUI); 52 | } 53 | 54 | return jFileChooser.getSelectedFile(); 55 | } 56 | 57 | public enum Type { 58 | OPEN, 59 | SAVE 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/util/MessageUtil.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.util; 2 | 3 | import cn.enaium.name.obfuscator.ui.layout.bottom.StatusPanel; 4 | 5 | import javax.swing.*; 6 | 7 | /** 8 | * @author Enaium 9 | */ 10 | public class MessageUtil { 11 | 12 | private MessageUtil() { 13 | throw new IllegalAccessError("Utility"); 14 | } 15 | 16 | public static void error(Throwable e, String message) { 17 | e.printStackTrace(); 18 | StatusPanel.reset(); 19 | JOptionPane.showMessageDialog(null, message.isEmpty() ? e : e + " " + message, "ERROR", JOptionPane.ERROR_MESSAGE); 20 | Thread.currentThread().interrupt(); 21 | } 22 | 23 | public static void error(Throwable e) { 24 | error(e, ""); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/cn/enaium/name/obfuscator/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package cn.enaium.name.obfuscator.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Enaium 8 | */ 9 | public class StringUtil { 10 | public static final char[][] cha = new char[][] 11 | { 12 | {'i', 'l', 'I', 'L', 'j', 'J'}, 13 | {'o', 'O', '〇'}, 14 | {'q', 'p', 'Q', 'P'}, 15 | {'s', 'S'}, 16 | {'ラ', 'う'}, 17 | {'よ', 'ょ'}, 18 | {'ゆ', 'ゅ'}, 19 | {'ㄙ', 'ム'}, 20 | {'ㄑ', 'く'}, 21 | {'一', '二', '三', '亖'}, 22 | {'ぃ', 'い', 'り', 'リ'}, 23 | {'シ', 'ツ', 'ソ', 'ン', 'ジ', 'ヅ', 'ゾ'}, 24 | {'へ', 'ㇸ', '乀'}, 25 | {'回', '茴', '佪', '徊'}, 26 | {'桂', '佳', '洼', '烓', '茥', '垚', '眭', '晆', '㤬', '䞨'}, 27 | {'水', '沝', '淼', '㵘'}, 28 | {'木', '林', '森'}, 29 | {'火', '炏', '炎', '焱', '欻', '燚'}, 30 | {'土', '圭', '茥', '洼', '桂', '烓', '垚', '㙓', '澆'}, 31 | {'鹅', '鵞'}, 32 | {'あ', 'お'}, 33 | {'メ', 'ノ'}, 34 | {'㬺', '幐'}, 35 | {'墫', '壿'}, 36 | {'鬬', '鬭'}, 37 | {'晚', '晩'}, 38 | {'凉', '凉'} 39 | }; 40 | 41 | public static List parseSrt(ArrayList strings) { 42 | ArrayList list = new ArrayList(); 43 | for (String string : strings) { 44 | if (string.matches("[0-9]+")) { 45 | continue; 46 | } 47 | 48 | if (string.contains("-->")) { 49 | continue; 50 | } 51 | 52 | if (string.contains("}")) { 53 | string = string.substring(string.lastIndexOf("}") + 1); 54 | } 55 | list.add(string.replace(" ", "") + "\n"); 56 | } 57 | return list; 58 | } 59 | 60 | public static List parseLrc(ArrayList strings) { 61 | ArrayList list = new ArrayList(); 62 | for (String string : strings) { 63 | list.add(string.substring(string.lastIndexOf("]") + 1) + "\n"); 64 | } 65 | return list; 66 | } 67 | } 68 | --------------------------------------------------------------------------------