> 文章列表 > Charles二次开发-接口解密

Charles二次开发-接口解密

Charles二次开发-接口解密

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;}@Overridepublic 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);}@Overridepublic boolean accept(Object sender) {return false;}
}

 TransactionViewerPopupMenu类,通过jd-gui反编译得到,反编译后有错误将.换成$符号即可

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 {// 定义 Transactionprivate final Transaction transaction;public TransactionViewerPopupMenu(Transaction paramTransaction) {super(paramTransaction, null, null, null);// 接收this.transaction = paramTransaction;}@Overrideprotected 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 

 3.4,执行命令前进入到out\\production\\custom-decrypt路径

执行如下命令,意思是将这两个类的class加到charles.java包里面

jar -uvf H:\\learn\\custom-decrypt\\libs\\charles.jar com\\xk72\\charles\\gui\\transaction\\actions\\CustomDecrypt.classjar -uvf H:\\learn\\custom-decrypt\\libs\\charles.jar com\\xk72\\charles\\gui\\transaction\\popups\\TransactionViewerPopupMenu.class

 出现正在添加,表示执行成功 

3.5,将项目中libs下的charles.jar替换到charles的安装路径下的lib目录,例如:D:\\charles\\location\\lib

4,测试

替换后,打开charles软件,例如编写一个测试接口(根据需要自己编写),抓包如下

点击按钮后

 结语:以上笔记已经非常详细,主要给自己做个记录,然后也能分享一下技术,整体来看需要花点时间,如果有问题,不负责任,仅供参考,毕竟能做程序员的都不笨,别跟个别人一样白嫖了文章,自己不会还要骂人,我真是擦了尼玛

参考了以下文章:charles 增加 自定义解密功能 · TesterHome