1,使用背景
最近工作中对公司接口进行抓包,发现接口路径和返回都是经过加密的,对于查看接口路径及接口返回结果带来了不便,于是想到了对Charles进行小改造,在Charles上增加一个按钮对加密的请求、响应结果解密,本质是执行一个Java方法,然后将解密结果通过文本框显示出来,效果如下
2,相关环境
Charles版本:4.6.2,界面是基于JDK11版本开发的
JDK版本:所以一定要用jdk11,不然会有坑
3,开发过程
3.1,新建普通工程Custom-Decrypt,引入Charles.jar
3.2,新建CustomDecrypt类,TransactionViewerPopupMenu类,代码如下
CustomDecrypt类中decrypt方法是解密方法,根据需要编写,代码注重实现可能有点low
package com.xk72.charles.gui.transaction.actions;
import com.xk72.charles.model.Transaction;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.spec.KeySpec;
import java.util.logging.Logger;
/**
* @author: create by libin
* @date:2023/4/9
*/
public class CustomDecrypt extends AbstractAction {
public final Transaction transaction;
private static final Logger logger = Logger.getLogger("CustomDecryptLog");
public CustomDecrypt(Transaction transaction) {
super("CustomDecrypt");
this.transaction = transaction;
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
String requestString = transaction.getDecodedRequestBodyAsString();
String responseString = transaction.getDecodedResponseBodyAsString();
logger.warning("__________________________________");
logger.info("request" + requestString);
logger.info("response" + responseString);
logger.warning("__________________________________");
try {
String request;
if (requestString == null || requestString.length() < 1) {
request = "空";
} else {
request = decrypt(requestString, DES_REQUEST_KEY);
}
String respnse;
if (responseString == null || responseString.length() < 1) {
respnse = "空";
} else {
respnse = decrypt(responseString, DES_RESPONSE_KEY);
}
String method = transaction.getMethod();
String host = transaction.getHost() + ":" + transaction.getPort();
String path = transaction.getPath();
String file = transaction.getFile();
String query = transaction.getQuery();
String content = "method:" + method + "\n" +
"host:" + host + "\n" +
"path:" + path + "\n" +
"file:" + file + "\n" +
"query:" + query + "\n";
if ("GET".equals(method)) {
String url = host + file;
content += "url:" + url + "\n";
}
WaringDialog("request", content);
WaringDialog("response", respnse);
} catch (Exception e) {
logger.warning("CustomDecrypt Exception" + e.getMessage());
}
}
public static void WaringDialog(String title, String content) {
JFrame JFrame = new JFrame(title);
JFrame.setPreferredSize(new Dimension(800, 500));
JTextArea textArea = new JTextArea();
textArea.setText(content + "\n");
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane jScrollPane = new JScrollPane(textArea);
jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jScrollPane.setAutoscrolls(false);
JFrame.setContentPane(jScrollPane);
JFrame.pack();
JFrame.setVisible(true);
}
@Override
public boolean accept(Object sender) {
return false;
}
}
package com.xk72.charles.gui.transaction.popups;
import com.xk72.charles.gui.session.popups.TransactionPopupMenu;
import com.xk72.charles.gui.transaction.actions.Base64DecodeAction$Text;
import com.xk72.charles.gui.transaction.actions.Base64DecodeAction$TextComponent;
import com.xk72.charles.gui.transaction.actions.CopyToClipboardAction$Text;
import com.xk72.charles.gui.transaction.actions.CopyToClipboardAction$TextComponent;
import com.xk72.charles.gui.transaction.actions.CustomDecrypt;
import com.xk72.charles.model.Transaction;
import javax.swing.*;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.MouseEvent;
public class TransactionViewerPopupMenu extends TransactionPopupMenu {
// 定义 Transaction
private final Transaction transaction;
public TransactionViewerPopupMenu(Transaction paramTransaction) {
super(paramTransaction, null, null, null);
// 接收
this.transaction = paramTransaction;
}
@Override
protected void prepare(MouseEvent paramMouseEvent) {
Component component = (Component)paramMouseEvent.getSource();
if (component instanceof JTable) {
JTable jTable = (JTable)component;
Point point = paramMouseEvent.getPoint();
int i = jTable.rowAtPoint(point);
int j = jTable.columnAtPoint(point);
if (i >= 0 && j >= 0) {
Object object = jTable.getValueAt(i, j);
if (object != null) {
add((Action)new CopyToClipboardAction$Text(object.toString()));
if (object instanceof String)
add((Action)new Base64DecodeAction$Text((String)object, component));
addSeparator();
}
}
} else if (component instanceof JTextComponent) {
add((Action)new CopyToClipboardAction$TextComponent((JTextComponent)component));
add((Action)new Base64DecodeAction$TextComponent((JTextComponent)component));
// 新增一个按钮,执行按钮的时候会调用CustomDecrypt的actionPerformed方法
add((Action)new CustomDecrypt(this.transaction));
addSeparator();
}
prepare(false);
}
}
3.3,将上面的CustomDecrypt类和TransactionViewerPopupMenu类,编译成class
点击Build --> Build Project
3.4,执行命令前进入到outproductioncustom-decrypt路径
在custom-decrypt右键点击 选择 Open in Terminal
执行如下命令,意思是将这两个类的class加到charles.java包里面
jar -uvf D:\charles.jar com\xk72\charles\gui\transaction\actions\CustomDecrypt.class
jar -uvf D:\charles.jar com\xk72\charles\gui\transaction\actions\AESUtil.class
jar -uvf D:\charles.jar com\xk72\charles\gui\transaction\popups\TransactionViewerPopupMenu.class
3.5,将项目中libs下的charles.jar替换到charles的安装路径下的lib目录,例如:D:charleslocationlib
4.测试
替换后,打开charles软件,例如编写一个测试接口(根据需要自己编写),抓包如下
5.问题
5.1 写入现有的 jar 文件时出错
"jar -uvf" 写入现有的 jar 文件时出错 at sun.tools.jar.Main.run(Main.java:286)
原因: 在jar包已经被当前应用加载了,不能再去修改。重新copy一个文件 在新的jar文件里修改。不要修改idea里依赖的目录文件
5.2 编译jdk版本不对
has been compiled by a more recent version of the Java Runtime (class file version 59.0), this version of the Java Runtime only recognizes class file versions up to 55.0
charles用的java11 。而那三个文件编译的时候用的java 15。
9 = Java 5
50 = Java 6
51 = Java 7
52 = Java 8
53 = Java 9
54 = Java 10
55 = Java 11
56 = Java 12
57 = Java 13
58 = Java 14
59 = Java 15
60 = Java 16
61 = Java 17
62 = Java 18
63 = Java 19
没有评论