├── .gitignore
├── README.assets
├── image-20220116100055765.png
└── image-20220116101431188.png
├── README.md
├── img
├── origin.png
└── u2cTab.png
├── pom.xml
└── src
├── U2C
├── CharSetHelper.java
└── U2CTab.java
└── burp
└── BurpExtender.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.class
2 | /burp/*.class
3 | /U2C/*.class
4 | .project
5 | .classpath
6 | /target/
7 | *.class
8 | *.prefs
9 | .fatjar
10 |
--------------------------------------------------------------------------------
/README.assets/image-20220116100055765.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bit4woo/u2c/6d1f0d1ac8770128d82b03500c372fa3cb501674/README.assets/image-20220116100055765.png
--------------------------------------------------------------------------------
/README.assets/image-20220116101431188.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bit4woo/u2c/6d1f0d1ac8770128d82b03500c372fa3cb501674/README.assets/image-20220116101431188.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ###################################################
4 |
5 |
6 |
7 |
8 |
9 | # 该项目不再维护,功能已经合并到[knife](https://github.com/bit4woo/knife)
10 |
11 |
12 |
13 |
14 |
15 | #########################################################
16 |
17 | ## U2C = Unicode To Chinese
18 |
19 |
20 | A burpsuite Extender That Convert Unicode To Chinese
21 |
22 | Unicode 转中文 的burp suite插件
23 |
24 | GitHub: https://github.com/bit4woo/u2c
25 |
26 | Download: https://github.com/bit4woo/u2c/releases
27 |
28 | ### version 0.1-0.5
29 |
30 | 前五个版本使用自定义的图形界面,是在原始请求响应的基础上修改数据包,然后进行展示。
31 |
32 | 这样有个坏处就是可能破坏响应包在浏览器等终端的展示,可能出现乱码。虽然设计了图像界面进行控制,但是也不够灵活简洁。
33 |
34 | 前五个版本算是走了冤枉路,但也是由于有前五个版本,才有了下面的第六版。
35 |
36 | ### version 0.6
37 |
38 | 完全重写,使用新的tab来展示转码后的响应数据包,不影响原始的响应数据包,更加简洁实用!
39 |
40 | 值得注意的是:U2C中的显示情况与burp中User options---Display--- HTTP Message Display & Character Sets有关,目前burp的API无法完全控制。只能自行设置。
41 |
42 | 
43 |
44 |
45 |
46 | 
47 |
48 | ### version 0.9
49 |
50 | 将【Unicode转中文】+【切换中文显示的编码】融合。
51 |
52 | 
53 |
54 |
55 |
56 | 
57 |
58 |
59 |
60 | ### Unicode测试URL
61 |
62 | https://passport.baidu.com/v2/api/getqrcode
63 |
64 | https://aiqicha.baidu.com/index/getCPlaceAjax
--------------------------------------------------------------------------------
/img/origin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bit4woo/u2c/6d1f0d1ac8770128d82b03500c372fa3cb501674/img/origin.png
--------------------------------------------------------------------------------
/img/u2cTab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bit4woo/u2c/6d1f0d1ac8770128d82b03500c372fa3cb501674/img/u2cTab.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 | com.bit4woo.burp
6 | u2c
7 | 0.9
8 |
9 | src
10 |
11 |
12 | maven-compiler-plugin
13 | 3.7.0
14 |
15 | 1.8
16 | 1.8
17 | UTF-8
18 |
19 |
20 |
21 |
22 | maven-assembly-plugin
23 | 3.1.0
24 |
25 |
26 | jar-with-dependencies
27 |
28 |
29 |
30 |
31 | true
32 |
33 |
34 |
35 |
36 |
37 |
38 | make-assembly
39 | package
40 |
41 | single
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | net.portswigger.burp.extender
52 | burp-extender-api
53 | [1.7.22,)
54 |
55 |
56 |
57 |
58 | com.github.bit4woo
59 | burp-api-common
60 | [0.1.3,)
61 |
62 |
63 |
64 |
65 | com.ibm.icu
66 | icu4j
67 | [70.1,)
68 |
69 |
70 |
71 |
72 | org.apache.commons
73 | commons-text
74 | [1.6,)
75 |
76 |
77 |
78 |
79 | com.google.code.gson
80 | gson
81 | [2.3.1,)
82 |
83 |
84 |
85 |
86 | org.beanshell
87 | bsh
88 | [2.0b5,)
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/U2C/CharSetHelper.java:
--------------------------------------------------------------------------------
1 | package U2C;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.nio.charset.Charset;
5 |
6 | import com.ibm.icu.text.CharsetDetector;
7 | import com.ibm.icu.text.CharsetMatch;
8 |
9 | import burp.BurpExtender;
10 | import burp.Getter;
11 | import burp.IExtensionHelpers;
12 |
13 | public class CharSetHelper {
14 |
15 | public static String getSystemCharSet() {
16 | return Charset.defaultCharset().toString();
17 | }
18 |
19 | /**
20 | * 进行响应包的编码转换。
21 | * @param response
22 | * @return 转换后的格式的byte[]
23 | */
24 | public static byte[] covertCharSet(byte[] response,String originalCharset,String newCharset) {
25 | if (originalCharset == null) {
26 | return response;
27 | }else {
28 | byte[] newResponse;
29 | try {
30 | newResponse = new String(response,originalCharset).getBytes(newCharset);
31 | return newResponse;
32 | } catch (UnsupportedEncodingException e) {
33 | e.printStackTrace(BurpExtender.getStderr());
34 | return response;
35 | }
36 | }
37 | }
38 |
39 | /**
40 | * utf8 utf-8都是可以的。
41 | * @param requestOrResponse
42 | * @return
43 | */
44 | public static String detectCharset(byte[] requestOrResponse){
45 | IExtensionHelpers helpers = BurpExtender.getCallbacks().getHelpers();
46 | Getter getter = new Getter(helpers);
47 | boolean isRequest = true;
48 | if (new String(requestOrResponse).startsWith("HTTP/")) {//response
49 | isRequest = false;
50 | }
51 |
52 | String contentType = getter.getHeaderValueOf(isRequest,requestOrResponse,"Content-Type");
53 |
54 | //1、尝试从contentTpye中获取
55 | if (contentType != null){
56 | if (contentType.toLowerCase().contains("charset=")) {
57 | String tmpcharSet = contentType.toLowerCase().split("charset=")[1];
58 | if (tmpcharSet != null && tmpcharSet.length() >0) {
59 | return tmpcharSet;
60 | }
61 | }
62 | }
63 |
64 | //2、尝试使用ICU4J进行编码的检测
65 | CharsetDetector detector = new CharsetDetector();
66 | detector.setText(requestOrResponse);
67 | CharsetMatch cm = detector.detect();
68 | if (cm != null) {
69 | return cm.getName();
70 | }
71 |
72 | //3、http post的默认编码
73 | return "ISO-8859-1";
74 | }
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/src/U2C/U2CTab.java:
--------------------------------------------------------------------------------
1 | package U2C;
2 |
3 | import java.awt.BorderLayout;
4 | import java.awt.Component;
5 | import java.awt.event.ActionEvent;
6 | import java.awt.event.ActionListener;
7 | import java.io.UnsupportedEncodingException;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.regex.Matcher;
11 | import java.util.regex.Pattern;
12 |
13 | import javax.swing.JButton;
14 | import javax.swing.JPanel;
15 | import javax.swing.border.EmptyBorder;
16 |
17 | import org.apache.commons.text.StringEscapeUtils;
18 |
19 | import com.google.gson.Gson;
20 | import com.google.gson.GsonBuilder;
21 | import com.google.gson.JsonElement;
22 | import com.google.gson.JsonParser;
23 |
24 | import burp.Getter;
25 | import burp.IBurpExtenderCallbacks;
26 | import burp.IExtensionHelpers;
27 | import burp.IMessageEditorController;
28 | import burp.IMessageEditorTab;
29 | import burp.IRequestInfo;
30 | import burp.IResponseInfo;
31 | import burp.ITextEditor;
32 |
33 | /**
34 | * @author bit4woo
35 | * @github https://github.com/bit4woo
36 | * @version CreateTime:2022年1月15日 下午11:07:59
37 | *
38 | * 想要正确显示中文内容,有三个编码设置会影响结果:
39 | * 1、原始编码,通过代码尝试自动获取,但是结果可能不准确,极端情况下需要手动设置。
40 | * 2、转换后的编码,手动设置。
41 | * 3、burp设置的显示编码,显示时时用的编码,应该和转换后的编码一致。
42 | *
43 | * 原始数据是byte[],但也是文本内容的某种编码的byte[].
44 | *
45 | */
46 | public class U2CTab implements IMessageEditorTab{
47 | private ITextEditor txtInput;
48 | private JPanel panel;
49 | private JButton btnNewButton;
50 |
51 | private byte[] originContent;
52 | private byte[] displayContent = "Nothing to show".getBytes();
53 |
54 | private List allPossibleCharset;
55 | private int charSetIndex = 0;
56 |
57 | private static IExtensionHelpers helpers;
58 |
59 | public U2CTab(IMessageEditorController controller, boolean editable, IExtensionHelpers helpers, IBurpExtenderCallbacks callbacks)
60 | {
61 | txtInput = callbacks.createTextEditor();
62 | panel = createpanel();
63 | txtInput.setEditable(editable);
64 | U2CTab.helpers = helpers;
65 | }
66 |
67 | public String getCurrentCharSet() {
68 | return allPossibleCharset.get(charSetIndex);
69 | }
70 |
71 | public String getNextCharSet() {
72 | if (charSetIndex < allPossibleCharset.size()-1) {
73 | charSetIndex++;
74 | }else {
75 | charSetIndex =0;
76 | }
77 | return allPossibleCharset.get(charSetIndex);
78 | }
79 |
80 | public JPanel createpanel() {
81 |
82 | JPanel contentPane = new JPanel();
83 | contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
84 | contentPane.setLayout(new BorderLayout(0, 0));
85 |
86 | btnNewButton = new JButton("Change Encoding");
87 | contentPane.add(btnNewButton, BorderLayout.NORTH);
88 | contentPane.add(txtInput.getComponent(), BorderLayout.CENTER);
89 |
90 | btnNewButton.addActionListener(new ActionListener() {
91 | public void actionPerformed(ActionEvent e) {
92 | getNextCharSet();
93 | display();
94 | }
95 | });
96 |
97 | return contentPane;
98 | }
99 |
100 | @Override
101 | public String getTabCaption()
102 | {
103 | return "U2C";
104 | }
105 |
106 | @Override
107 | public Component getUiComponent()
108 | {
109 | return panel;
110 | }
111 |
112 | @Override
113 | public boolean isEnabled(byte[] content, boolean isRequest)
114 | {
115 | return true;
116 | }
117 |
118 | @Override
119 | public void setMessage(byte[] content, boolean isRequest)
120 | {
121 | String coding = "GBK,GB2312,UTF-8,GB18030,Big5,Big5-HKSCS,UNICODE";
122 | coding = CharSetHelper.detectCharset(content)+","+coding;//检测到的编码+一些常用编码!
123 | allPossibleCharset = Arrays.asList(coding.split(","));
124 |
125 | if(content==null) {
126 | txtInput.setText(displayContent);
127 | return;
128 | }else {
129 | originContent = content;//存储原始数据
130 | displayContent = preHandle(content,isRequest,getCurrentCharSet());
131 | display();
132 | }
133 | }
134 |
135 | /**
136 | * 使用特定编码显示内容,变化原始编码。
137 | * @param currentCharSet
138 | */
139 | public void display() {
140 | try {
141 | displayContent = CharSetHelper.covertCharSet(displayContent,getCurrentCharSet(),CharSetHelper.getSystemCharSet());
142 | txtInput.setText(displayContent);
143 |
144 | String text = String.format("Change Encoding: (Using %s)", getCurrentCharSet());
145 | btnNewButton.setText(text);
146 | } catch (Exception e) {
147 | e.printStackTrace();
148 | }
149 | }
150 |
151 | /**
152 | * 中文下的编辑还是有问题,暂不支持。
153 | * 始终返回原始内容。
154 | */
155 | @Override
156 | public byte[] getMessage()
157 | {
158 | /*
159 | try {
160 | byte[] text = txtInput.getText();//这个时候应该是当前编码对应的byte[]
161 | byte[] result = new String(text,currentCharSet).getBytes(originalCharSet);
162 | return result;
163 | } catch (UnsupportedEncodingException e) {
164 | e.printStackTrace();
165 | return originContent;
166 | }*/
167 | return originContent;
168 | }
169 |
170 | @Override
171 | public boolean isModified()
172 | {
173 | return false;
174 | //return txtInput.isTextModified();
175 | }
176 |
177 | @Override
178 | public byte[] getSelectedData()
179 | {
180 | return txtInput.getSelectedText();
181 | }
182 |
183 | public static boolean needtoconvert(String str) {
184 | Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
185 | Matcher matcher = pattern.matcher(str.toLowerCase());
186 |
187 | if (matcher.find() ){
188 | return true;
189 | }else {
190 | return false;
191 | }
192 | }
193 |
194 | public static boolean isJSON(byte[] content,boolean isRequest) {
195 | if (isRequest) {
196 | IRequestInfo requestInfo = helpers.analyzeRequest(content);
197 | return requestInfo.getContentType() == IRequestInfo.CONTENT_TYPE_JSON;
198 | } else {
199 | IResponseInfo responseInfo = helpers.analyzeResponse(content);
200 | return responseInfo.getInferredMimeType().equals("JSON");
201 | }
202 | }
203 |
204 | /**
205 | * JSON美化,会自动转换Unicode
206 | * @param inputJson
207 | * @return
208 | */
209 | public static String beauty(String inputJson) {
210 | //Take the input, determine request/response, parse as json, then print prettily.
211 | Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().serializeNulls().create();
212 | JsonParser jp = new JsonParser();
213 | JsonElement je = jp.parse(inputJson);
214 | return gson.toJson(je);
215 | }
216 |
217 | /**
218 | * 如果有Unicode编码的内容,就进行escape操作,否则内容和原始内容一致。
219 | * @param content
220 | * @param isRequest
221 | * @return
222 | */
223 | public static byte[] preHandle(byte[] content,boolean isRequest,String originalCharSet) {
224 |
225 | byte[] displayContent = content;
226 |
227 | try {
228 | String contentStr = new String(content,originalCharSet);
229 | if (needtoconvert(contentStr)){
230 | //先尝试进行JSON格式的美化,如果其中有Unicode编码也会自动完成转换
231 | if (isJSON(content, isRequest)) {
232 | try {
233 | Getter getter = new Getter(helpers);
234 | byte[] body = getter.getBody(isRequest, content);
235 | List headers = getter.getHeaderList(isRequest, content);
236 |
237 | byte[] newBody = beauty(new String(body,originalCharSet)).getBytes(originalCharSet);
238 |
239 | displayContent = helpers.buildHttpMessage(headers,newBody);
240 | return displayContent;//如果JSON美化成功,主动返回。
241 | }catch(Exception e) {
242 |
243 | }
244 | }
245 |
246 | int i=0;
247 | do {
248 | contentStr = StringEscapeUtils.unescapeJava(contentStr);
249 | i++;
250 | }while(needtoconvert(contentStr) && i<3);
251 |
252 | displayContent = contentStr.getBytes(originalCharSet);
253 | }
254 | } catch (UnsupportedEncodingException e1) {
255 |
256 | }
257 | return displayContent;
258 | }
259 |
260 | public static void main(String[] args) {
261 | String aaa = "STK_7411642209636022({\"errno\":1003,\"errmsg\":\"\\u7528\\u6237\\u672a\\u767b\\u5f55\",\"errmsg_lang\":{\"zh\":\"\\u7528\\u6237\\u672a\\u767b\\u5f55\",\"en\":\"User is not logged in.\",\"zh-HK\":\"\\u7528\\u6236\\u672a\\u767b\\u9304\"},\"data\":null});";
262 | System.out.println(StringEscapeUtils.unescapeJava(aaa));
263 | }
264 | }
--------------------------------------------------------------------------------
/src/burp/BurpExtender.java:
--------------------------------------------------------------------------------
1 | package burp;
2 |
3 | import java.io.PrintWriter;
4 |
5 | import U2C.U2CTab;
6 |
7 | public class BurpExtender implements IBurpExtender,IMessageEditorTabFactory
8 | {
9 | private static IBurpExtenderCallbacks callbacks;
10 | private IExtensionHelpers helpers;
11 |
12 | public static String Version = bsh.This.class.getPackage().getImplementationVersion();
13 | private static PrintWriter stdout;
14 | private static PrintWriter stderr;
15 | public static String ExtensionName = "U2C";
16 | public static String Author = "by bit4woo";
17 | public String github = "https://github.com/bit4woo/U2C";
18 |
19 | @Override
20 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks)
21 | {
22 | BurpExtender.callbacks = callbacks;
23 | callbacks.printOutput(getFullExtensionName());
24 | callbacks.printOutput(github);
25 | helpers = callbacks.getHelpers();
26 | callbacks.setExtensionName(getFullExtensionName());
27 | callbacks.registerMessageEditorTabFactory(this);
28 | }
29 |
30 | @Override
31 | public IMessageEditorTab createNewInstance(IMessageEditorController controller, boolean editable) {
32 | return new U2CTab(controller, false, helpers, callbacks);
33 | }
34 |
35 | private static void flushStd(){
36 | try{
37 | stdout = new PrintWriter(callbacks.getStdout(), true);
38 | stderr = new PrintWriter(callbacks.getStderr(), true);
39 | }catch (Exception e){
40 | stdout = new PrintWriter(System.out, true);
41 | stderr = new PrintWriter(System.out, true);
42 | }
43 | }
44 |
45 | public static PrintWriter getStdout() {
46 | flushStd();//不同的时候调用这个参数,可能得到不同的值
47 | return stdout;
48 | }
49 |
50 | public static PrintWriter getStderr() {
51 | flushStd();
52 | return stderr;
53 | }
54 |
55 | //name+version+author
56 | public static String getFullExtensionName(){
57 | return ExtensionName+" "+Version+" "+Author;
58 | }
59 |
60 | public static IBurpExtenderCallbacks getCallbacks() {
61 | return callbacks;
62 | }
63 | }
--------------------------------------------------------------------------------