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;
    }

    @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;
    }
}

 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 {
    // 定义 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 

 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.class

jar -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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值