├── .DS_Store ├── .idea ├── .gitignore ├── inspectionProfiles │ └── profiles_settings.xml ├── material_theme_project_new.xml ├── misc.xml ├── mitmproxy-gui.iml ├── modules.xml └── vcs.xml ├── __pycache__ └── mitmproxy_gui.cpython-39.pyc ├── readme.md ├── requirements.txt ├── resource ├── icon │ ├── 开关-关.png │ └── 开关-开.png ├── logo │ └── img.png └── themes │ ├── dark.qss │ └── light.qss └── src ├── .idea ├── .gitignore ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── material_theme_project_new.xml ├── misc.xml ├── modules.xml └── src.iml ├── __init__.py ├── __pycache__ ├── __init__.cpython-39.pyc └── main.cpython-39.pyc ├── button ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ └── button.cpython-39.pyc └── button.py ├── constants ├── __pycache__ │ ├── encryption_constants.cpython-39.pyc │ ├── error_messages.cpython-39.pyc │ ├── message_constants.cpython-39.pyc │ ├── mode_constants.cpython-39.pyc │ └── ui_constants.cpython-39.pyc ├── encryption_constants.py ├── error_messages.py ├── message_constants.py ├── mode_constants.py └── ui_constants.py ├── highlighter ├── __pycache__ │ ├── log_highlighter.cpython-39.pyc │ └── python_highlighter.cpython-39.pyc ├── log_highlighter.py └── python_highlighter.py ├── log ├── __init__.py └── logging_config.py ├── main.py ├── main_table ├── __init__.py └── intercept_table.py ├── mode ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ └── mode.cpython-39.pyc └── mode.py ├── network ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ ├── mitmproxy_packet_capture.cpython-39.pyc │ └── shard.cpython-39.pyc ├── mitmproxy_packet_capture.py └── shard.py ├── otherTools ├── QueryStringParser.py ├── __init__.py ├── __pycache__ │ ├── QueryStringParser.cpython-39.pyc │ ├── __init__.cpython-39.pyc │ ├── rsa_handler.cpython-39.pyc │ └── script_loader.cpython-39.pyc ├── rsa_handler.py └── script_loader.py ├── scripts ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ └── script_config.cpython-39.pyc ├── bothTools │ ├── __pycache__ │ │ ├── aes_cbc.cpython-39.pyc │ │ ├── base64.cpython-39.pyc │ │ ├── des_cbc.cpython-39.pyc │ │ └── rsa.cpython-39.pyc │ ├── aes_cbc.py │ ├── aes_ecb.py │ ├── aes_gcm.py │ ├── base64.py │ ├── des3_cbc.py │ ├── des_cbc.py │ └── rsa.py ├── decryptTools │ ├── __init__.py │ ├── __pycache__ │ │ ├── aes_cbc.cpython-39.pyc │ │ ├── aes_ecb.cpython-39.pyc │ │ ├── aes_gcm.cpython-39.pyc │ │ ├── base64.cpython-39.pyc │ │ ├── des3_cbc.cpython-39.pyc │ │ ├── des_cbc.cpython-39.pyc │ │ └── rsa.cpython-39.pyc │ ├── aes_cbc.py │ ├── aes_ecb.py │ ├── aes_gcm.py │ ├── base64.py │ ├── des3_cbc.py │ ├── des_cbc.py │ ├── private.pem │ ├── rsa.py │ ├── rsa_private_key.pem │ └── rsa_public_key.pem ├── encryptTools │ ├── __init__.py │ ├── __pycache__ │ │ ├── aes.cpython-39.pyc │ │ ├── aes_cbc.cpython-39.pyc │ │ ├── aes_ecb.cpython-39.pyc │ │ ├── base64.cpython-39.pyc │ │ ├── des3_cbc.cpython-39.pyc │ │ ├── des_cbc.cpython-39.pyc │ │ ├── md5.cpython-39.pyc │ │ ├── rsa.cpython-39.pyc │ │ ├── sha1.cpython-39.pyc │ │ ├── sha256.cpython-39.pyc │ │ ├── sha384.cpython-39.pyc │ │ └── sha512.cpython-39.pyc │ ├── aes_cbc.py │ ├── aes_ecb.py │ ├── base64.py │ ├── des3_cbc.py │ ├── des_cbc.py │ ├── md5.py │ ├── rsa.py │ ├── rsa_private_key.pem │ ├── rsa_public_key.pem │ ├── sha1.py │ ├── sha256.py │ ├── sha384.py │ └── sha512.py ├── hookTools │ ├── __init__.py │ └── test.py └── test │ ├── des3_cbc_test.py │ └── des_cbc_test.py ├── themes ├── __pycache__ │ └── theme.cpython-39.pyc └── theme.py ├── thread ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-39.pyc │ └── mitmproxy_thread.cpython-39.pyc └── mitmproxy_thread.py ├── ui ├── __init__.py ├── __pycache__ │ └── __init__.cpython-39.pyc └── mitmproxy_gui.ui └── validator ├── KeyValidator.py ├── PortValidator.py ├── __init__.py └── __pycache__ ├── KeyValidator.cpython-39.pyc ├── PortValidator.cpython-39.pyc └── __init__.cpython-39.pyc /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/.DS_Store -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/material_theme_project_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/mitmproxy-gui.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 17 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /__pycache__/mitmproxy_gui.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/__pycache__/mitmproxy_gui.cpython-39.pyc -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Mitmproxy GUI 2 | 3 | 一个基于 Mitmproxy 的 GUI 工具,支持多种加密算法的请求拦截和修改。 4 | 5 | ## 功能特点 6 | 7 | - 图形化界面,操作简单直观 8 | - 支持多种加密算法: 9 | - RSA 10 | - DES (ECB/CBC) 11 | - AES (ECB/CBC) 12 | - Base64 13 | - 支持三种工作模式: 14 | - 加密模式 15 | - 解密模式 16 | - 双向模式(同时支持加密和解密) 17 | - 支持 JSON 和表单数据的处理 18 | - 实时显示请求详情和日志 19 | - 支持多字段同时加解密 20 | - 支持自定义上游代理 21 | 22 | ## 安装要求 23 | 24 | - Python 3.8+ 25 | - PyQt6 26 | - mitmproxy 9.0+ 27 | - pycryptodome 28 | 29 | ## 快速开始 30 | 31 | 1. 安装依赖: 32 | 33 | bash 34 | 35 | pip install -r requirements.txt 36 | 37 | 38 | 39 | ## 使用说明 40 | 41 | 42 | 43 | 进入 src 目录 44 | 45 | ```python 46 | python main.py 47 | ``` 48 | 49 | 50 | 51 | ### 基本设置 52 | 53 | 1. 选择工作模式(加密/解密/双向) 54 | 2. 选择加密算法 55 | 3. 设置监听端口(默认 8888) 56 | 4. 设置上游代理端口(默认 8080) 57 | 5. 输入需要处理的字段名(多个字段用逗号分隔) 58 | 6. 输入密钥和 IV(如果需要) 59 | image 60 | image 61 | 62 | 63 | ### 加密模式 64 | 65 | - 监听指定端口 66 | - 对请求数据进行加密处理 67 | - 支持的数据格式: 68 | - application/json 69 | - application/x-www-form-urlencoded 70 | 71 | ### 解密模式 72 | 73 | - 监听指定端口 74 | - 对请求数据进行解密处理 75 | - 自动转发到上游代理 76 | 77 | ### 双向模式 78 | 79 | - 同时启动加密和解密代理 80 | - 支持请求数据的实时加解密 81 | - 自动处理上下游代理转发 82 | 83 | ## 支持的加密算法 84 | 85 | ### RSA 86 | 87 | - 支持公钥加密/私钥解密 88 | - 支持 .pem 格式密钥文件 89 | - 支持 Base64 格式密钥 90 | 91 | ### DES 92 | 93 | - 支持 ECB/CBC 模式 94 | - 支持自定义 IV(CBC 模式) 95 | - 支持 PKCS7 填充 96 | 97 | ### AES 98 | 99 | - 支持 ECB/CBC 模式 100 | - 支持自定义 IV(CBC 模式) 101 | - 支持 PKCS7 填充 102 | 103 | ### Base64 104 | 105 | - 支持标准 Base64 编码/解码 106 | - 支持 URL 安全的 Base64 编码/解码 107 | 108 | ## 项目结构 109 | 110 | ## 使用说明 111 | 112 | ### 基本设置 113 | 114 | 1. 选择工作模式(加密/解密/双向) 115 | 2. 选择加密算法 116 | 3. 设置监听端口(默认 8888) 117 | 4. 设置上游代理端口(默认 8080) 118 | 5. 输入需要处理的字段名(多个字段用逗号分隔) 119 | 6. 输入密钥和 IV(如果需要) 120 | 121 | ### 加密模式 122 | 123 | - 监听指定端口 124 | - 对请求数据进行加密处理 125 | - 支持的数据格式: 126 | - application/json 127 | - application/x-www-form-urlencoded 128 | 129 | ### 解密模式 130 | 131 | - 监听指定端口 132 | - 对请求数据进行解密处理 133 | - 自动转发到上游代理 134 | 135 | ### 双向模式 136 | 137 | - 同时启动加密和解密代理 138 | - 支持请求数据的实时加解密 139 | - 自动处理上下游代理转发 140 | 141 | ## 支持的加密算法 142 | 143 | ### RSA 144 | 145 | - 支持公钥加密/私钥解密 146 | - 支持 .pem 格式密钥文件 147 | - 支持 Base64 格式密钥 148 | 149 | ### DES 150 | 151 | - 支持 ECB/CBC 模式 152 | - 支持自定义 IV(CBC 模式) 153 | - 支持 PKCS7 填充 154 | 155 | ### AES 156 | 157 | - 支持 ECB/CBC 模式 158 | - 支持自定义 IV(CBC 模式) 159 | - 支持 PKCS7 填充 160 | 161 | ### Base64 162 | 163 | - 支持标准 Base64 编码/解码 164 | - 支持 URL 安全的 Base64 编码/解码 165 | 166 | ## 项目结构 167 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/requirements.txt -------------------------------------------------------------------------------- /resource/icon/开关-关.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/resource/icon/开关-关.png -------------------------------------------------------------------------------- /resource/icon/开关-开.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/resource/icon/开关-开.png -------------------------------------------------------------------------------- /resource/logo/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/resource/logo/img.png -------------------------------------------------------------------------------- /resource/themes/dark.qss: -------------------------------------------------------------------------------- 1 | /* Modern Dark Theme - Mitmproxy GUI Pro */ 2 | /*****************************************/ 3 | 4 | QMainWindow, QWidget { 5 | background-color: #2b2b2b; 6 | color: #e0e0e0; 7 | font-family: 'Segoe UI', sans-serif; 8 | font-size: 13px; 9 | } 10 | 11 | /* ========== Global Text Styles ========== */ 12 | QLabel { 13 | color: #a0a0a0; 14 | font-weight: 500; 15 | } 16 | 17 | QGroupBox { 18 | border: 1px solid #424647; 19 | border-radius: 4px; 20 | margin-top: 20px; 21 | padding-top: 15px; 22 | } 23 | 24 | QGroupBox::title { 25 | subcontrol-origin: margin; 26 | left: 10px; 27 | color: #7f8c8d; 28 | font-weight: bold; 29 | } 30 | 31 | /* ========== Input Fields ========== */ 32 | QLineEdit, QTextEdit, QComboBox { 33 | background-color: #353535; 34 | border: 1px solid #404040; 35 | border-radius: 3px; 36 | padding: 5px 8px; 37 | min-height: 25px; 38 | selection-background-color: #3d8ec9; 39 | } 40 | 41 | QLineEdit:hover, QTextEdit:hover, QComboBox:hover { 42 | border-color: #4a4a4a; 43 | } 44 | 45 | QLineEdit:focus, QTextEdit:focus, QComboBox:focus { 46 | border-color: #3d8ec9; 47 | background-color: #424647; 48 | } 49 | 50 | /* ========== Buttons ========== */ 51 | QPushButton { 52 | background-color: #424647; 53 | border: 1px solid #404040; 54 | border-radius: 4px; 55 | color: #e0e0e0; 56 | padding: 6px 15px; 57 | min-width: 80px; 58 | transition: all 0.3s ease; 59 | } 60 | 61 | QPushButton:hover { 62 | background-color: #444; 63 | border-color: #4a4a4a; 64 | } 65 | 66 | QPushButton:pressed { 67 | background-color: #333; 68 | border-color: #383838; 69 | } 70 | 71 | QPushButton[text="Start Proxy"] { 72 | background-color: #3d8ec9; /* 使用你指定的蓝色 */ 73 | border-color: #1d8348; /* 边框颜色保持不变 */ 74 | color: white; 75 | font-weight: bold; 76 | } 77 | 78 | QPushButton[text="Intercept Off"] { 79 | background: #424647; 80 | 81 | } 82 | 83 | /* ========== Tab Widget ========== */ 84 | QTabWidget::pane { 85 | border: 1px solid #424647; 86 | top: -1px; 87 | background: #323232; 88 | } 89 | 90 | QTabBar::tab { 91 | background: #424647; 92 | border: 1px solid #404040; 93 | color: #a0a0a0; 94 | padding: 8px 20px; 95 | margin-right: 2px; 96 | border-top-left-radius: 4px; 97 | border-top-right-radius: 4px; 98 | } 99 | 100 | QTabBar::tab:selected { 101 | background: #323232; 102 | border-bottom-color: #323232; 103 | color: #e0e0e0; 104 | } 105 | 106 | QTabBar::tab:hover { 107 | background: #424242; 108 | } 109 | 110 | /* ========== Table Widget ========== */ 111 | QTableWidget { 112 | background: #323334; 113 | gridline-color: #424647; 114 | border: none; 115 | alternate-background-color: #2a2a2a; 116 | } 117 | 118 | QHeaderView::section { 119 | background-color: #353535; 120 | color: #e0e0e0; 121 | padding: 6px; 122 | border: none; 123 | border-bottom: 2px solid #3d8ec9; 124 | } 125 | 126 | QTableWidget::item { 127 | padding: 5px; 128 | border-bottom: 1px solid #383838; 129 | } 130 | 131 | QTableWidget::item:selected { 132 | background-color: #3d8ec9; 133 | color: white; 134 | } 135 | 136 | /* ========== Scrollbars ========== */ 137 | QScrollBar:vertical { 138 | background: #353535; 139 | width: 12px; 140 | } 141 | 142 | QScrollBar::handle:vertical { 143 | background: #4a4a4a; 144 | min-height: 20px; 145 | border-radius: 6px; 146 | } 147 | 148 | QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { 149 | background: none; 150 | } 151 | 152 | QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { 153 | background: none; 154 | } 155 | 156 | /* ========== ComboBox ========== */ 157 | QComboBox::drop-down { 158 | subcontrol-origin: padding; 159 | subcontrol-position: top right; 160 | width: 20px; 161 | border-left: 1px solid #404040; 162 | } 163 | 164 | QComboBox QAbstractItemView { 165 | background: #353535; 166 | border: 1px solid #404040; 167 | color: #e0e0e0; 168 | selection-background-color: #3d8ec9; 169 | } 170 | 171 | /* ========== Progress Bars ========== */ 172 | QProgressBar { 173 | border: 1px solid #404040; 174 | border-radius: 3px; 175 | text-align: center; 176 | background: #353535; 177 | } 178 | 179 | QProgressBar::chunk { 180 | background: qlineargradient(x1:0, y1:0, x2:0, y2:1, 181 | stop:0 #3d8ec9, stop:1 #2b6ca3); 182 | border-radius: 2px; 183 | } 184 | 185 | /* ========== Checkboxes/Radios ========== */ 186 | QCheckBox::indicator, QRadioButton::indicator { 187 | width: 16px; 188 | height: 16px; 189 | border: 1px solid #4a4a4a; 190 | } 191 | 192 | QCheckBox::indicator:checked { 193 | background-color: #3d8ec9; 194 | image: url(:/icons/check_light.svg); 195 | } 196 | 197 | QRadioButton::indicator:checked { 198 | background-color: #3d8ec9; 199 | border: 4px solid #424647; 200 | } 201 | 202 | /* ========== Tooltips ========== */ 203 | QToolTip { 204 | background-color: #353535; 205 | color: #e0e0e0; 206 | border: 1px solid #404040; 207 | border-radius: 3px; 208 | padding: 5px; 209 | } 210 | 211 | /* ========== Splitter ========== */ 212 | QSplitter::handle { 213 | background: #424647; 214 | height: 5px; 215 | } 216 | 217 | QSplitter::handle:hover { 218 | background: #3d8ec9; 219 | } 220 | 221 | /* ========== Menu Bar ========== */ 222 | QMenuBar { 223 | background-color: #353535; 224 | border-bottom: 1px solid #404040; 225 | } 226 | 227 | QMenuBar::item { 228 | padding: 5px 15px; 229 | color: #a0a0a0; 230 | } 231 | 232 | QMenuBar::item:selected { 233 | background: #444; 234 | } 235 | 236 | QMenu { 237 | background-color: #353535; 238 | border: 1px solid #404040; 239 | padding: 5px; 240 | } 241 | 242 | QMenu::item { 243 | padding: 5px 25px; 244 | } 245 | 246 | QMenu::item:selected { 247 | background-color: #3d8ec9; 248 | color: white; 249 | } 250 | 251 | /* ========== Status Bar ========== */ 252 | QStatusBar { 253 | background: #353535; 254 | border-top: 1px solid #404040; 255 | } 256 | 257 | QStatusBar::item { 258 | border: none; 259 | } 260 | 261 | /* 为水平布局中的QLineEdit添加弹性布局 */ 262 | QHBoxLayout QLineEdit { 263 | flex: 1; 264 | } 265 | 266 | /* 调整FormLayout中标签和输入框的间距 */ 267 | QFormLayout { 268 | spacing: 8px; 269 | } 270 | 271 | /* 优化输入框组的样式 */ 272 | QLineEdit { 273 | margin-right: 4px; 274 | } 275 | 276 | QLineEdit:last-child { 277 | margin-right: 0; 278 | } 279 | 280 | QTextEdit { 281 | background-color: #353535; 282 | border: 1px solid #404040; 283 | border-radius: 3px; 284 | padding: 5px 8px; 285 | min-height: 25px; 286 | selection-background-color: #3d8ec9; 287 | font-size: 14pt; 288 | } -------------------------------------------------------------------------------- /resource/themes/light.qss: -------------------------------------------------------------------------------- 1 | /* Modern Light Theme - Mitmproxy GUI Pro */ 2 | /******************************************/ 3 | 4 | QMainWindow, QWidget { 5 | background-color: #f5f6fa; 6 | color: #2d3436; 7 | font-family: 'Segoe UI', sans-serif; 8 | font-size: 13px; 9 | } 10 | 11 | /* ========== Global Text Styles ========== */ 12 | QLabel { 13 | color: #636e72; 14 | font-weight: 500; 15 | } 16 | 17 | QGroupBox { 18 | border: 1px solid #dcdde1; 19 | border-radius: 4px; 20 | margin-top: 20px; 21 | padding-top: 15px; 22 | } 23 | 24 | QGroupBox::title { 25 | subcontrol-origin: margin; 26 | left: 10px; 27 | color: #747d8c; 28 | font-weight: bold; 29 | } 30 | 31 | /* ========== Input Fields ========== */ 32 | QLineEdit, QTextEdit, QComboBox { 33 | background-color: white; 34 | border: 1px solid #dcdde1; 35 | border-radius: 3px; 36 | padding: 5px 8px; 37 | min-height: 25px; 38 | selection-background-color: #74b9ff; 39 | } 40 | 41 | QLineEdit:hover, QTextEdit:hover, QComboBox:hover { 42 | border-color: #a4b0be; 43 | } 44 | 45 | QLineEdit:focus, QTextEdit:focus, QComboBox:focus { 46 | border-color: #74b9ff; 47 | background-color: white; 48 | } 49 | 50 | /* ========== Buttons ========== */ 51 | QPushButton { 52 | background-color: white; 53 | border: 1px solid #dcdde1; 54 | border-radius: 4px; 55 | color: #2d3436; 56 | padding: 6px 15px; 57 | min-width: 80px; 58 | transition: all 0.3s ease; 59 | } 60 | 61 | QPushButton:hover { 62 | background-color: #f8f9fa; 63 | border-color: #a4b0be; 64 | } 65 | 66 | QPushButton:pressed { 67 | background-color: #f1f2f6; 68 | border-color: #ced6e0; 69 | } 70 | 71 | QPushButton[text="Start Proxy"] { 72 | background: qlineargradient(x1:0, y1:0, x2:0, y2:1, 73 | stop:0 #2ecc71, stop:1 #27ae60); 74 | border-color: #219a52; 75 | color: white; 76 | font-weight: bold; 77 | } 78 | 79 | QPushButton[text="Intercept"] { 80 | background: qlineargradient(x1:0, y1:0, x2:0, y2:1, 81 | stop:0 #3498db, stop:1 #2980b9); 82 | border-color: #2472a4; 83 | } 84 | 85 | /* ========== Tab Widget ========== */ 86 | QTabWidget::pane { 87 | border: 1px solid #dcdde1; 88 | top: -1px; 89 | background: white; 90 | } 91 | 92 | QTabBar::tab { 93 | background: #f8f9fa; 94 | border: 1px solid #dcdde1; 95 | color: #747d8c; 96 | padding: 8px 20px; 97 | margin-right: 2px; 98 | border-top-left-radius: 4px; 99 | border-top-right-radius: 4px; 100 | } 101 | 102 | QTabBar::tab:selected { 103 | background: white; 104 | border-bottom-color: white; 105 | color: #2d3436; 106 | } 107 | 108 | QTabBar::tab:hover { 109 | background: #f1f2f6; 110 | } 111 | 112 | /* ========== Table Widget ========== */ 113 | QTableWidget { 114 | background: white; 115 | gridline-color: #dcdde1; 116 | border: none; 117 | alternate-background-color: #f8f9fa; 118 | } 119 | 120 | QHeaderView::section { 121 | background-color: #f8f9fa; 122 | color: #2d3436; 123 | padding: 6px; 124 | border: none; 125 | border-bottom: 2px solid #74b9ff; 126 | } 127 | 128 | QTableWidget::item { 129 | padding: 5px; 130 | border-bottom: 1px solid #f1f2f6; 131 | } 132 | 133 | QTableWidget::item:selected { 134 | background-color: #74b9ff; 135 | color: white; 136 | } 137 | 138 | /* ========== Scrollbars ========== */ 139 | QScrollBar:vertical { 140 | background: #f8f9fa; 141 | width: 12px; 142 | } 143 | 144 | QScrollBar::handle:vertical { 145 | background: #ced6e0; 146 | min-height: 20px; 147 | border-radius: 6px; 148 | } 149 | 150 | QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { 151 | background: none; 152 | } 153 | 154 | QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { 155 | background: none; 156 | } 157 | 158 | /* ========== ComboBox ========== */ 159 | QComboBox::drop-down { 160 | subcontrol-origin: padding; 161 | subcontrol-position: top right; 162 | width: 20px; 163 | border-left: 1px solid #dcdde1; 164 | } 165 | 166 | QComboBox QAbstractItemView { 167 | background: white; 168 | border: 1px solid #dcdde1; 169 | color: #2d3436; 170 | selection-background-color: #74b9ff; 171 | } 172 | 173 | /* ========== Progress Bars ========== */ 174 | QProgressBar { 175 | border: 1px solid #dcdde1; 176 | border-radius: 3px; 177 | text-align: center; 178 | background: white; 179 | } 180 | 181 | QProgressBar::chunk { 182 | background: qlineargradient(x1:0, y1:0, x2:0, y2:1, 183 | stop:0 #74b9ff, stop:1 #4a95d6); 184 | border-radius: 2px; 185 | } 186 | 187 | /* ========== Checkboxes/Radios ========== */ 188 | QCheckBox::indicator, QRadioButton::indicator { 189 | width: 16px; 190 | height: 16px; 191 | border: 1px solid #a4b0be; 192 | } 193 | 194 | QCheckBox::indicator:checked { 195 | background-color: #74b9ff; 196 | image: url(:/icons/check_dark.svg); 197 | } 198 | 199 | QRadioButton::indicator:checked { 200 | background-color: #74b9ff; 201 | border: 4px solid white; 202 | } 203 | 204 | /* ========== Tooltips ========== */ 205 | QToolTip { 206 | background-color: white; 207 | color: #2d3436; 208 | border: 1px solid #dcdde1; 209 | border-radius: 3px; 210 | padding: 5px; 211 | } 212 | 213 | /* ========== Splitter ========== */ 214 | QSplitter::handle { 215 | background: #dcdde1; 216 | height: 5px; 217 | } 218 | 219 | QSplitter::handle:hover { 220 | background: #74b9ff; 221 | } 222 | 223 | /* ========== Menu Bar ========== */ 224 | QMenuBar { 225 | background-color: white; 226 | border-bottom: 1px solid #dcdde1; 227 | } 228 | 229 | QMenuBar::item { 230 | padding: 5px 15px; 231 | } 232 | 233 | QTextEdit { 234 | background-color: white; 235 | border: 1px solid #dcdde1; 236 | border-radius: 3px; 237 | padding: 5px 8px; 238 | min-height: 25px; 239 | selection-background-color: #74b9ff; 240 | font-size: 14pt; /* 改为14pt */ 241 | } 242 | -------------------------------------------------------------------------------- /src/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /src/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | -------------------------------------------------------------------------------- /src/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /src/.idea/material_theme_project_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /src/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /src/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/.idea/src.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- 1 | # 空文件,仅用于标记这是一个 Python 包 -------------------------------------------------------------------------------- /src/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /src/__pycache__/main.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/__pycache__/main.cpython-39.pyc -------------------------------------------------------------------------------- /src/button/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/button/__init__.py -------------------------------------------------------------------------------- /src/button/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/button/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /src/button/__pycache__/button.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/button/__pycache__/button.cpython-39.pyc -------------------------------------------------------------------------------- /src/constants/__pycache__/encryption_constants.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/constants/__pycache__/encryption_constants.cpython-39.pyc -------------------------------------------------------------------------------- /src/constants/__pycache__/error_messages.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/constants/__pycache__/error_messages.cpython-39.pyc -------------------------------------------------------------------------------- /src/constants/__pycache__/message_constants.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/constants/__pycache__/message_constants.cpython-39.pyc -------------------------------------------------------------------------------- /src/constants/__pycache__/mode_constants.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/constants/__pycache__/mode_constants.cpython-39.pyc -------------------------------------------------------------------------------- /src/constants/__pycache__/ui_constants.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/constants/__pycache__/ui_constants.cpython-39.pyc -------------------------------------------------------------------------------- /src/constants/encryption_constants.py: -------------------------------------------------------------------------------- 1 | class EncryptionConstants: 2 | AES_ALGORITHMS = ['aes_cbc.py', 'aes_ecb.py', 'aes_cfb.py', 'aes_ofb.py', 'aes_ctr.py', 'aes_gcm.py', 'aes_ccm.py', 'aes_xts.py', 'aes_xts_128.py', 'aes_xts_256.py'] # 添加所有 AES 脚本 3 | DES_ALGORITHMS = ['des_cbc.py', 'des3_cbc','des_ecb.py', 'des_cfb.py', 'des_ofb.py', 'des_ctr.py', 'des_gcm.py', 'des_ccm.py', 'des_xts.py', 'des_xts_128.py', 'des_xts_256.py'] # 添加所有 DES 脚本 4 | HASH_ALGORITHMS = ['md5.py', 'sha1.py', 'sha256.py', 'sha512.py', 'hmac.py', 'hmac_md5.py', 'hmac_sha1.py', 'hmac_sha256.py', 'hmac_sha512.py'] # 添加所有哈希算法 5 | NO_KEY_ALGORITHMS = ['base64.py', 'md5.py','sha1.py','sha256.py','sha512.py','hmac.py','hmac_md5.py','hmac_sha1.py','hmac_sha256.py','hmac_sha512.py'] # 不需要密钥的算法 6 | AES_KEY_LENGTHS = [16, 24, 32] # AES 密钥长度 7 | DES_KEY_LENGTH = [8,16,24] # DES 密钥长度,3DES 秘钥长度 8 | IV_LENGTH = 16 # IV 长度 9 | 10 | # 不需要密钥的加密算法列表 11 | NO_KEY_ALGORITHMS = ['base64.py', 'md5.py','sha1.py','sha256.py','sha512.py','hmac.py','hmac_md5.py','hmac_sha1.py','hmac_sha256.py','hmac_sha512.py'] # 添加其他不需要密钥的算法 -------------------------------------------------------------------------------- /src/constants/error_messages.py: -------------------------------------------------------------------------------- 1 | class ErrorMessages: 2 | 3 | # 启动代理错误消息 4 | PROXY_START_ERROR = "❌ 启动代理失败: {}" 5 | 6 | # 秘钥错误消息 7 | EMPTY_KEY = "❌ 错误: 解密密钥不能为空" 8 | INVALID_MODE = "❌ 错误: 无效的模式" 9 | AES_KEY_LENGTH_ERROR = "❌ 错误: AES 密钥长度必须是 16、24 或 32 字节" 10 | DES_KEY_LENGTH_ERROR = "❌ 错误: DES 密钥长度必须是 8 字节,3DES 密钥长度必须是 16 或 24 字节" 11 | IV_LENGTH_ERROR = "❌ 错误: IV 必须是 16 字节长度" 12 | KEY_REQUIRED = "❌ 错误: 当前加密算法需要密钥" 13 | # 端口错误消息 14 | PORT_ERROR = "❌ 端口错误: {}" 15 | 16 | -------------------------------------------------------------------------------- /src/constants/message_constants.py: -------------------------------------------------------------------------------- 1 | class MessageConstants: 2 | # 状态消息 3 | PROXY_STARTED = "✅ {} 模式抓包已启动" 4 | PROXY_STOPPED = "❌ 代理已停止" 5 | INTERCEPT_STARTED = "拦截已开启, Default Listen Port Is 8888" 6 | INTERCEPT_STOPPED = "拦截已停止" 7 | LOG_CLEARED = "✅ 日志已清空" 8 | 9 | # 秘钥消息 10 | DECRYPT_KEY_SAVED = "✅ 解密密钥保存成功: {}" 11 | -------------------------------------------------------------------------------- /src/constants/mode_constants.py: -------------------------------------------------------------------------------- 1 | class ModeConstants: 2 | ENCRYPT = "Encrypt" 3 | DECRYPT = "Decrypt" 4 | BOTH = "Both" 5 | DEFAULT = "Default" -------------------------------------------------------------------------------- /src/constants/ui_constants.py: -------------------------------------------------------------------------------- 1 | class UIConstants: 2 | # 链接 3 | GITHUB_URL = "https://github.com/blackguest007/" 4 | 5 | # 按钮文本 6 | BTN_START_PROXY = "Start Proxy" 7 | BTN_STOP_PROXY = "Stop Proxy" 8 | BTN_INTERCEPT_ON = "Intercept On" 9 | BTN_INTERCEPT_OFF = "Intercept Off" 10 | 11 | # 提示文本 12 | TOOLTIP_GITHUB = "访问项目 GitHub 页面" 13 | TOOLTIP_MENU = "访问 GitHub" 14 | 15 | -------------------------------------------------------------------------------- /src/highlighter/__pycache__/log_highlighter.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/highlighter/__pycache__/log_highlighter.cpython-39.pyc -------------------------------------------------------------------------------- /src/highlighter/__pycache__/python_highlighter.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/highlighter/__pycache__/python_highlighter.cpython-39.pyc -------------------------------------------------------------------------------- /src/highlighter/log_highlighter.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from PyQt6.QtCore import Qt 4 | from PyQt6.QtGui import QSyntaxHighlighter, QTextCharFormat, QColor, QFont 5 | 6 | 7 | class LogHighlighter(QSyntaxHighlighter): 8 | def __init__(self, parent=None): 9 | super().__init__(parent) 10 | 11 | self.highlighting_rules = [] 12 | 13 | # 成功信息格式(绿色) 14 | success_format = QTextCharFormat() 15 | success_format.setForeground(QColor("#98C379")) # 绿色 16 | success_format.setFontWeight(QFont.Weight.Bold) 17 | self.highlighting_rules.append(( 18 | r"✅.*$", success_format 19 | )) 20 | 21 | # 错误信息格式(红色) 22 | error_format = QTextCharFormat() 23 | error_format.setForeground(QColor("#E06C75")) # 红色 24 | error_format.setFontWeight(QFont.Weight.Bold) 25 | self.highlighting_rules.append(( 26 | r"❌.*$", error_format 27 | )) 28 | 29 | # 警告信息格式(黄色) 30 | warning_format = QTextCharFormat() 31 | warning_format.setForeground(QColor("#E5C07B")) # 黄色 32 | warning_format.setFontWeight(QFont.Weight.Bold) 33 | self.highlighting_rules.append(( 34 | r"⚠.*$", warning_format 35 | )) 36 | 37 | # 加载脚本信息格式(蓝色) 38 | loading_format = QTextCharFormat() 39 | loading_format.setForeground(QColor("#61AFEF")) # 蓝色 40 | self.highlighting_rules.append(( 41 | r"Loading script.*$", loading_format 42 | )) 43 | 44 | # 时间戳格式(灰色) 45 | timestamp_format = QTextCharFormat() 46 | timestamp_format.setForeground(QColor("#5C6370")) # 灰色 47 | self.highlighting_rules.append(( 48 | r"\[\d{2}:\d{2}:\d{2}\.\d{3}\]", timestamp_format 49 | )) 50 | 51 | # 命令执行格式(青色) 52 | command_format = QTextCharFormat() 53 | command_format.setForeground(QColor("#56B6C2")) # 青色 54 | self.highlighting_rules.append(( 55 | r"执行命令:.*$", command_format 56 | )) 57 | 58 | # 普通日志格式(白色) 59 | info_format = QTextCharFormat() 60 | info_format.setForeground(QColor("#ABB2BF")) # 浅灰白色 61 | self.highlighting_rules.append(( 62 | r"^(?!✅|❌|⚠|\[|Loading|执行命令).*$", info_format 63 | )) 64 | 65 | def highlightBlock(self, text): 66 | """高亮文本块""" 67 | for pattern, format in self.highlighting_rules: 68 | for match in re.finditer(pattern, text): 69 | self.setFormat(match.start(), match.end() - match.start(), format) -------------------------------------------------------------------------------- /src/highlighter/python_highlighter.py: -------------------------------------------------------------------------------- 1 | from PyQt6.QtCore import Qt 2 | from PyQt6.QtGui import QSyntaxHighlighter, QTextCharFormat, QColor, QFont 3 | import re 4 | 5 | class PythonHighlighter(QSyntaxHighlighter): 6 | def __init__(self, parent=None): 7 | super().__init__(parent) 8 | 9 | self.highlighting_rules = [] 10 | 11 | # 关键字格式 12 | keyword_format = QTextCharFormat() 13 | keyword_format.setForeground(QColor("#FF6B6B")) 14 | keyword_format.setFontWeight(QFont.Weight.Bold) 15 | keywords = [ 16 | # 基础关键字 17 | "and", "as", "assert", "break", "class", "continue", "def", 18 | "del", "elif", "else", "except", "False", "finally", "for", 19 | "from", "global", "if", "import", "in", "is", "lambda", "None", 20 | "nonlocal", "not", "or", "pass", "raise", "return", "True", 21 | "try", "while", "with", "yield", 22 | # 扩展关键字 23 | "self", "cls", "async", "await", "match", "case" 24 | ] 25 | for word in keywords: 26 | self.highlighting_rules.append(( 27 | f"\\b{word}\\b", keyword_format 28 | )) 29 | 30 | # 内置函数格式 31 | builtin_format = QTextCharFormat() 32 | builtin_format.setForeground(QColor("#C678DD")) 33 | builtins = [ 34 | "abs", "all", "any", "bin", "bool", "bytes", "callable", "chr", 35 | "classmethod", "compile", "complex", "delattr", "dict", "dir", 36 | "divmod", "enumerate", "eval", "exec", "filter", "float", "format", 37 | "frozenset", "getattr", "globals", "hasattr", "hash", "help", "hex", 38 | "id", "input", "int", "isinstance", "issubclass", "iter", "len", 39 | "list", "locals", "map", "max", "min", "next", "object", "oct", 40 | "open", "ord", "pow", "print", "property", "range", "repr", 41 | "reversed", "round", "set", "setattr", "slice", "sorted", 42 | "staticmethod", "str", "sum", "super", "tuple", "type", "vars", 43 | "zip", "__import__" 44 | ] 45 | for word in builtins: 46 | self.highlighting_rules.append(( 47 | f"\\b{word}\\b", builtin_format 48 | )) 49 | 50 | # 装饰器格式 51 | decorator_format = QTextCharFormat() 52 | decorator_format.setForeground(QColor("#E5C07B")) 53 | self.highlighting_rules.append(( 54 | r"@\w+", decorator_format 55 | )) 56 | 57 | # 字符串格式(包括三引号字符串) 58 | string_format = QTextCharFormat() 59 | string_format.setForeground(QColor("#98C379")) 60 | self.highlighting_rules.extend([ 61 | (r'"[^"\\]*(\\.[^"\\]*)*"', string_format), 62 | (r"'[^'\\]*(\\.[^'\\]*)*'", string_format), 63 | (r'""".*?"""', string_format), 64 | (r"'''.*?'''", string_format) 65 | ]) 66 | 67 | # 注释格式 68 | comment_format = QTextCharFormat() 69 | comment_format.setForeground(QColor("#5C6370")) 70 | comment_format.setFontItalic(True) 71 | self.highlighting_rules.append(( 72 | r"#[^\n]*", comment_format 73 | )) 74 | 75 | # 函数定义格式 76 | function_format = QTextCharFormat() 77 | function_format.setForeground(QColor("#61AFEF")) 78 | self.highlighting_rules.append(( 79 | r"\bdef\s+(\w+)", function_format 80 | )) 81 | 82 | # 类定义格式 83 | class_format = QTextCharFormat() 84 | class_format.setForeground(QColor("#E5C07B")) 85 | class_format.setFontWeight(QFont.Weight.Bold) 86 | self.highlighting_rules.append(( 87 | r"\bclass\s+(\w+)", class_format 88 | )) 89 | 90 | # 数字格式 91 | number_format = QTextCharFormat() 92 | number_format.setForeground(QColor("#D19A66")) 93 | self.highlighting_rules.extend([ 94 | (r"\b[0-9]+\b", number_format), 95 | (r"\b0[xX][0-9a-fA-F]+\b", number_format), # 十六进制 96 | (r"\b0[oO][0-7]+\b", number_format), # 八进制 97 | (r"\b0[bB][01]+\b", number_format), # 二进制 98 | (r"\b\d*\.\d+\b", number_format), # 浮点数 99 | ]) 100 | 101 | # 特殊方法格式(魔术方法) 102 | magic_format = QTextCharFormat() 103 | magic_format.setForeground(QColor("#56B6C2")) 104 | self.highlighting_rules.append(( 105 | r"__\w+__", magic_format 106 | )) 107 | 108 | def highlightBlock(self, text): 109 | for pattern, format in self.highlighting_rules: 110 | for match in re.finditer(pattern, text): 111 | self.setFormat(match.start(), match.end() - match.start(), format) -------------------------------------------------------------------------------- /src/log/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | -------------------------------------------------------------------------------- /src/log/logging_config.py: -------------------------------------------------------------------------------- 1 | # src/log/logger.py 2 | import logging 3 | 4 | def setup_logging(): 5 | logging.basicConfig(level=logging.INFO, 6 | format='%(asctime)s - %(levelname)s - %(message)s') 7 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | # path: /src/main.py 2 | 3 | # 主程序 4 | 5 | import warnings 6 | import os 7 | import sys 8 | from PyQt6.QtWidgets import QApplication, QMainWindow 9 | from PyQt6.uic import loadUi 10 | from PyQt6.QtGui import QFont, QIcon 11 | from PyQt6.QtWidgets import QTextEdit 12 | from PyQt6.QtCore import Qt 13 | 14 | # 过滤掉 Qt 的 transition 属性警告 15 | warnings.filterwarnings("ignore", "Unknown property transition") 16 | # 过滤掉 sip 的废弃警告 17 | warnings.filterwarnings("ignore", "sipPyTypeDict() is deprecated") 18 | 19 | from button.button import setup_buttons 20 | from highlighter.python_highlighter import PythonHighlighter 21 | from mode.mode import setup_mode_connections, update_mode 22 | 23 | from otherTools.script_loader import ScriptLoader 24 | 25 | from themes.theme import get_themes, init_themes 26 | from highlighter.log_highlighter import LogHighlighter 27 | 28 | 29 | class MainWindow(QMainWindow): 30 | def __init__(self): 31 | super().__init__() 32 | 33 | # 设置窗口标题 34 | self.setWindowTitle("mitmproxy-gui V1.0.0 Created by @LingDu") 35 | 36 | # 初始化属性 37 | self.mitm_threads = [] # 用于存储当前运行的线程 38 | 39 | # 首先加载UI 40 | self.load_ui() # 移到最前面 41 | 42 | # 设置窗口图标 43 | icon_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resource", "logo", "img.png") 44 | if os.path.exists(icon_path): 45 | self.setWindowIcon(QIcon(icon_path)) 46 | else: 47 | print(f"Warning: Icon file not found at {icon_path}") 48 | 49 | # 其他初始化 50 | self.initialize_script_loader() 51 | self.initialize_highlighters() 52 | self.setup_buttons() 53 | self.setup_themes() 54 | 55 | # 调用初始化函数 56 | self.initialize() 57 | 58 | def initialize_ui(self): 59 | """加载用户界面""" 60 | try: 61 | self.load_ui() 62 | except Exception as e: 63 | print(f"Error loading UI: {e}") 64 | 65 | def initialize_script_loader(self): 66 | """初始化脚本加载器""" 67 | try: 68 | self.script_loader = ScriptLoader(self) 69 | except Exception as e: 70 | print(f"Error initializing script loader: {e}") 71 | 72 | def initialize_highlighters(self): 73 | """初始化代码和日志高亮器""" 74 | try: 75 | self.init_code_highlighter() 76 | self.log_highlighter = LogHighlighter(self.packet_detail.document()) 77 | except Exception as e: 78 | print(f"Error initializing highlighters: {e}") 79 | 80 | def setup_buttons(self): 81 | """设置按钮的信号连接""" 82 | setup_buttons(self) 83 | 84 | def setup_themes(self): 85 | """设置主题""" 86 | get_themes(self) 87 | init_themes(self) 88 | 89 | def setup_mode_connections(self): 90 | """设置模式连接""" 91 | setup_mode_connections(self) 92 | 93 | def load_ui(self): 94 | """ 加载 .ui 文件 """ 95 | # 获取当前文件所在目录 96 | current_dir = os.path.dirname(os.path.abspath(__file__)) 97 | # 构建 UI 文件的绝对路径 98 | ui_path = os.path.join(current_dir, "ui", "mitmproxy_gui.ui") 99 | 100 | if not os.path.exists(ui_path): 101 | raise FileNotFoundError(f"UI file not found: {ui_path}") 102 | 103 | loadUi(ui_path, self) 104 | 105 | def init_code_highlighter(self): 106 | """初始化代码高亮器""" 107 | # 设置代码编辑器字体 108 | font = QFont("Consolas") 109 | font.setPointSize(14) # 改为14pt 110 | 111 | # 修改为正确的控件名称 112 | self.encrypt_script_content.setFont(font) 113 | self.decrypt_script_content.setFont(font) 114 | self.both_script_content.setFont(font) 115 | 116 | # 启用Ctrl+滚轮缩放 117 | for editor in [self.encrypt_script_content, self.decrypt_script_content, self.both_script_content]: 118 | editor.setAcceptRichText(False) # 禁用富文本以确保正确的字体缩放 119 | editor.wheelEvent = lambda event, ed=editor: self._handle_wheel_event(event, ed) 120 | 121 | # 初始化高亮器 122 | self.highlighter_encrypt = PythonHighlighter(self.encrypt_script_content.document()) 123 | self.highlighter_decrypt = PythonHighlighter(self.decrypt_script_content.document()) 124 | self.highlighter_both = PythonHighlighter(self.both_script_content.document()) 125 | 126 | def _handle_wheel_event(self, event, editor): 127 | """处理滚轮事件,实现Ctrl+滚轮缩放字体""" 128 | if event.modifiers() & Qt.KeyboardModifier.ControlModifier: 129 | delta = event.angleDelta().y() 130 | if delta > 0: 131 | editor.zoomIn() 132 | else: 133 | editor.zoomOut() 134 | else: 135 | # 调用原始的滚轮事件处理 136 | QTextEdit.wheelEvent(editor, event) 137 | 138 | def initialize(self): 139 | """初始化窗口设置""" 140 | # 设置默认模式 141 | self.mode_combo.setCurrentText("Default") 142 | 143 | # 更新UI状态 144 | update_mode(self) # 确保在显示窗口之前更新UI状态 145 | 146 | 147 | # 主程序入口 148 | if __name__ == "__main__": 149 | app = QApplication(sys.argv) 150 | window = MainWindow() 151 | window.show() 152 | sys.exit(app.exec()) 153 | -------------------------------------------------------------------------------- /src/main_table/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/main_table/__init__.py -------------------------------------------------------------------------------- /src/main_table/intercept_table.py: -------------------------------------------------------------------------------- 1 | # path: /src/main_table/intercept_table.py 2 | 3 | 4 | from PyQt6.QtCore import QDateTime 5 | from PyQt6.QtWidgets import QTableWidgetItem 6 | 7 | class PacketTableUpdater: 8 | def __init__(self, window): 9 | self.window = window # 保存窗口对象,以便后续更新表格 10 | 11 | # 更新 intercept_table 中的字段 12 | def update_packet_table(self, data): 13 | """ 更新 QTableWidget 中的数据显示 """ 14 | current_time = QDateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss") 15 | 16 | row_position = self.window.packet_table.rowCount() # 获取当前表格的行数 17 | self.window.packet_table.insertRow(row_position) # 插入新的一行 18 | 19 | # 填充数据 20 | self.window.packet_table.setItem(row_position, 0, QTableWidgetItem(current_time)) 21 | self.window.packet_table.setItem(row_position, 1, QTableWidgetItem(data['type'])) 22 | self.window.packet_table.setItem(row_position, 2, QTableWidgetItem(data['direction'])) # 显示方向 23 | self.window.packet_table.setItem(row_position, 3, QTableWidgetItem(data['method'])) 24 | self.window.packet_table.setItem(row_position, 4, QTableWidgetItem(data['url'])) 25 | self.window.packet_table.setItem(row_position, 5, QTableWidgetItem(str(data['status_code']))) 26 | self.window.packet_table.setItem(row_position, 6, QTableWidgetItem(str(data['length']))) 27 | -------------------------------------------------------------------------------- /src/mode/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/mode/__init__.py -------------------------------------------------------------------------------- /src/mode/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/mode/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /src/mode/__pycache__/mode.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/mode/__pycache__/mode.cpython-39.pyc -------------------------------------------------------------------------------- /src/mode/mode.py: -------------------------------------------------------------------------------- 1 | # path:/src/mode/mode.py 2 | 3 | # 初始化加密模式,并调整按钮更新 4 | def init_mode(window): 5 | """初始化模式相关的UI元素""" 6 | 7 | # 初始化显示状态 8 | update_mode(window) 9 | 10 | # 初始化Default模式的命令 11 | if hasattr(window, 'script_loader'): 12 | command = window.script_loader.generate_command(window) 13 | if command and hasattr(window, 'proxy_thread'): 14 | window.proxy_thread.command = command 15 | 16 | 17 | def update_mode(window): 18 | """根据当前模式更新UI状态""" 19 | current_mode = window.mode_combo.currentText() 20 | 21 | # 基础控制按钮只在Default模式显示 22 | control_buttons = [window.intercept_btn, window.forward_btn, window.drop_btn] 23 | 24 | if current_mode == "Default": 25 | window.start_btn.hide() # 在Default模式下隐藏Start Proxy按钮 26 | for btn in control_buttons: 27 | btn.show() # 显示基础控制按钮 28 | else: 29 | window.start_btn.show() # 在其他模式下显示Start Proxy按钮 30 | for btn in control_buttons: 31 | btn.hide() # 隐藏基础控制按钮 32 | 33 | # 更新加密参数输入框显示状态 34 | encrypt_params_label = window.encrypt_params_label 35 | encrypt_params_input = window.encrypt_params_input 36 | 37 | # 获取所有key和iv相关控件 38 | dec_key_label = window.dec_key_label 39 | dec_key_input = window.dec_key_input 40 | dec_iv_label = window.dec_iv_label 41 | dec_iv_input = window.dec_iv_input 42 | enc_key_label = window.enc_key_label 43 | enc_key_input = window.enc_key_input 44 | enc_iv_label = window.enc_iv_label 45 | enc_iv_input = window.enc_iv_input 46 | 47 | # 获取端口相关控件 48 | dec_port_label = window.label # dec_Listen Port label 49 | dec_port_input = window.lineEdit # dec_Listen Port input 50 | enc_port_label = window.listen_port_label # enc_Listen Port label 51 | enc_port_input = window.listen_port_input # enc_Listen Port input 52 | 53 | if current_mode == "Default": 54 | # 只显示监听端口 55 | dec_port_label.show() 56 | dec_port_input.show() 57 | dec_port_label.setText('Listen Port:') # 默认模式显示为 Listen Port 58 | 59 | # 隐藏其他所有控件 60 | encrypt_params_label.hide() 61 | encrypt_params_input.hide() 62 | dec_key_label.hide() 63 | dec_key_input.hide() 64 | dec_iv_label.hide() 65 | dec_iv_input.hide() 66 | enc_key_label.hide() 67 | enc_key_input.hide() 68 | enc_iv_label.hide() 69 | enc_iv_input.hide() 70 | window.upstream_label.hide() 71 | window.upstream_input.hide() 72 | enc_port_label.hide() 73 | enc_port_input.hide() 74 | 75 | elif current_mode == "Encrypt": 76 | # 显示加密相关控件 77 | encrypt_params_label.show() 78 | encrypt_params_input.show() 79 | enc_key_label.show() 80 | enc_key_input.show() 81 | enc_iv_label.show() 82 | enc_iv_input.show() 83 | enc_port_label.show() 84 | enc_port_input.show() 85 | enc_port_label.setText('Enc Listen Port:') # 加密模式显示为 Enc Listen Port 86 | 87 | # 隐藏解密相关控件 88 | dec_key_label.hide() 89 | dec_key_input.hide() 90 | dec_iv_label.hide() 91 | dec_iv_input.hide() 92 | window.upstream_label.hide() 93 | window.upstream_input.hide() 94 | dec_port_label.hide() 95 | dec_port_input.hide() 96 | 97 | elif current_mode == "Decrypt": 98 | # 显示解密相关控件 99 | encrypt_params_label.show() 100 | encrypt_params_input.show() 101 | dec_key_label.show() 102 | dec_key_input.show() 103 | dec_iv_label.show() 104 | dec_iv_input.show() 105 | dec_port_label.show() 106 | dec_port_input.show() 107 | dec_port_label.setText('Dec Listen Port:') # 解密模式显示为 Dec Listen Port 108 | window.upstream_label.show() 109 | window.upstream_input.show() 110 | 111 | # 隐藏加密相关控件 112 | enc_key_label.hide() 113 | enc_key_input.hide() 114 | enc_iv_label.hide() 115 | enc_iv_input.hide() 116 | enc_port_label.hide() 117 | enc_port_input.hide() 118 | 119 | elif current_mode == "Both": 120 | # 显示所有控件 121 | encrypt_params_label.show() 122 | encrypt_params_input.show() 123 | dec_key_label.show() 124 | dec_key_input.show() 125 | dec_iv_label.show() 126 | dec_iv_input.show() 127 | enc_key_label.show() 128 | enc_key_input.show() 129 | enc_iv_label.show() 130 | enc_iv_input.show() 131 | window.upstream_label.show() 132 | window.upstream_input.show() 133 | dec_port_label.show() 134 | dec_port_input.show() 135 | enc_port_label.show() 136 | enc_port_input.show() 137 | 138 | # Both模式下更新端口标签 139 | dec_port_label.setText('Dec Listen Port:') # 解密端口显示为 Dec Listen Port 140 | enc_port_label.setText('Enc Listen Port:') # 加密端口显示为 Enc Listen Port 141 | 142 | def setup_mode_connections(window): 143 | """设置模式相关的信号连接""" 144 | window.mode_combo.currentTextChanged.connect(lambda: update_mode(window)) 145 | -------------------------------------------------------------------------------- /src/network/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/network/__init__.py -------------------------------------------------------------------------------- /src/network/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/network/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /src/network/__pycache__/mitmproxy_packet_capture.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/network/__pycache__/mitmproxy_packet_capture.cpython-39.pyc -------------------------------------------------------------------------------- /src/network/__pycache__/shard.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/network/__pycache__/shard.cpython-39.pyc -------------------------------------------------------------------------------- /src/network/mitmproxy_packet_capture.py: -------------------------------------------------------------------------------- 1 | # path:/src/network/mitmproxy_packet_capture.py 2 | 3 | 4 | import logging 5 | from mitmproxy import http 6 | from shard import * # 假设你已经正确配置了共享数据结构,如 packet_queue 7 | 8 | logging.basicConfig(level=logging.INFO) 9 | 10 | 11 | class MyAddon(): 12 | def __init__(self): 13 | self.active_flows = {} 14 | 15 | def request(self, flow: http.HTTPFlow) -> None: 16 | try: 17 | # 在MyAddon的request方法首行添加 18 | print(f"🔥 Intercepted: {flow.request.url}") 19 | 20 | # 构建类似Burp的请求格式 21 | raw_request = ( 22 | f"{flow.request.method} {flow.request.url} {flow.request.http_version}\n" 23 | f"{self.format_headers(flow.request.headers)}\n\n" # 格式化请求头 24 | f"{flow.request.text}" # 请求体(如果有的话) 25 | ) 26 | 27 | # 只传递必要元数据,不要传递flow对象 28 | packet_queue.put({ 29 | "flow_id": id(flow), 30 | "raw": raw_request, 31 | "meta": { # 添加可序列化元数据 32 | "host": flow.request.host, 33 | "port": flow.request.port, 34 | "scheme": flow.request.scheme 35 | } 36 | }) 37 | # 输出队列信息 38 | logging.info(f"flow_start\n{packet_queue.get()}\nflow_end") # 格式化输出抓到的请求 39 | 40 | except Exception as e: 41 | logging.error(f"Error capturing request: {str(e)}") 42 | 43 | def format_headers(self, headers): 44 | """格式化请求头为类似Burp的格式""" 45 | formatted_headers = "" 46 | for header, value in headers.items(): 47 | formatted_headers += f"{header}: {value}\n" 48 | return formatted_headers 49 | 50 | 51 | # 注册插件 52 | addons = [MyAddon()] 53 | -------------------------------------------------------------------------------- /src/network/shard.py: -------------------------------------------------------------------------------- 1 | # path:/src/network/shared.py 2 | from multiprocessing import Queue 3 | 4 | 5 | packet_queue = Queue() 6 | -------------------------------------------------------------------------------- /src/otherTools/QueryStringParser.py: -------------------------------------------------------------------------------- 1 | # path: src/otherTools/QueryStringParser.py 2 | 3 | import re 4 | 5 | 6 | class QueryStringParser: 7 | def __init__(self, query_string: str): 8 | self.query_string = query_string 9 | 10 | # 将请求参数解析成为字典形式 11 | def parse_request_params(self): 12 | """使用正则表达式解析查询字符串""" 13 | params = {} 14 | # 使用正则解析查询参数(包括空值的参数) 15 | pattern = re.compile(r'([^&=]+)=?([^&]*)') 16 | for match in pattern.finditer(self.query_string): 17 | key = match.group(1) 18 | value = match.group(2) or '' # 如果没有值,设置为空字符串 19 | if key in params: 20 | params[key].append(value) 21 | else: 22 | params[key] = [value] 23 | return params 24 | -------------------------------------------------------------------------------- /src/otherTools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/otherTools/__init__.py -------------------------------------------------------------------------------- /src/otherTools/__pycache__/QueryStringParser.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/otherTools/__pycache__/QueryStringParser.cpython-39.pyc -------------------------------------------------------------------------------- /src/otherTools/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/otherTools/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /src/otherTools/__pycache__/rsa_handler.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/otherTools/__pycache__/rsa_handler.cpython-39.pyc -------------------------------------------------------------------------------- /src/otherTools/__pycache__/script_loader.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/otherTools/__pycache__/script_loader.cpython-39.pyc -------------------------------------------------------------------------------- /src/otherTools/rsa_handler.py: -------------------------------------------------------------------------------- 1 | import os 2 | import textwrap 3 | 4 | 5 | def handle_rsa_keys(window, mode, key): 6 | """处理RSA密钥并将其保存为本地文件 7 | 8 | 此函数根据用户输入的RSA密钥,将其保存为PEM格式的文件。 9 | 根据模式(加密或解密),选择保存公钥或私钥。 10 | 11 | 参数: 12 | window: 窗口对象,用于访问脚本加载器 13 | mode: 模式,'Encrypt' 或 'Decrypt' 14 | key: RSA密钥内容 15 | 16 | 返回: 17 | tuple: 包含密钥路径和错误信息的元组 18 | """ 19 | try: 20 | if not key: # 添加空值检查 21 | return None, "密钥不能为空" 22 | 23 | # 获取正确的目录路径 - 注意这里改为 decryptTools 24 | script_dir = os.path.join(window.script_loader.root_path, "src", "scripts", "decryptTools") 25 | # 根据模式选择保存的文件名 26 | pem_file_path = os.path.join(script_dir, "rsa_public_key.pem" if mode == "Encrypt" else "rsa_private_key.pem") 27 | 28 | # 确保密钥内容是正确的PEM格式 29 | key_content = key.strip() 30 | if mode == "Encrypt": 31 | if "-----BEGIN PUBLIC KEY-----" not in key_content: 32 | key_content = ("-----BEGIN PUBLIC KEY-----\n" + 33 | "\n".join(textwrap.wrap(key_content, 64)) + 34 | "\n-----END PUBLIC KEY-----") 35 | elif mode == "Decrypt": 36 | if "-----BEGIN RSA PRIVATE KEY-----" not in key_content: 37 | key_content = ("-----BEGIN RSA PRIVATE KEY-----\n" + 38 | "\n".join(textwrap.wrap(key_content, 64)) + 39 | "\n-----END RSA PRIVATE KEY-----") 40 | 41 | # 保存PEM格式的密钥到文件 42 | with open(pem_file_path, "w") as f: 43 | f.write(key_content) 44 | 45 | # 使用正斜杠路径,确保兼容性 46 | pem_file_path = pem_file_path.replace('\\', '/') 47 | print(f"密钥已保存到: {pem_file_path}") # 添加调试信息 48 | return pem_file_path, "" 49 | 50 | except Exception as e: 51 | error_msg = f"保存RSA密钥失败: {str(e)}" 52 | print(error_msg) # 打印错误信息 53 | window.packet_detail.append(f"❌ {error_msg}") 54 | return None, error_msg 55 | -------------------------------------------------------------------------------- /src/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/__init__.py -------------------------------------------------------------------------------- /src/scripts/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/__pycache__/script_config.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/__pycache__/script_config.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/bothTools/__pycache__/aes_cbc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/bothTools/__pycache__/aes_cbc.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/bothTools/__pycache__/base64.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/bothTools/__pycache__/base64.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/bothTools/__pycache__/des_cbc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/bothTools/__pycache__/des_cbc.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/bothTools/__pycache__/rsa.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/bothTools/__pycache__/rsa.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/bothTools/aes_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | AES CBC 双向加解密脚本 3 | 4 | 使用方法: 5 | 加密: mitmdump -p 9999 -s aes_cbc.py --ssl-insecure field=password key=your_key iv=your_iv 6 | 解密: mitmdump -p 8888 -s aes_cbc.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=password key=your_key iv=your_iv 7 | 8 | 参数说明: 9 | field: 需要处理的字段,多个字段用逗号分隔 10 | key: AES密钥 11 | iv: 初始化向量(CBC模式需要) 12 | """ 13 | import base64 14 | import sys 15 | from mitmproxy import http 16 | import logging 17 | from Crypto.Cipher import AES 18 | from Crypto.Util.Padding import pad, unpad 19 | import json 20 | from urllib.parse import parse_qs, urlencode 21 | 22 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 23 | 24 | def get_fields(): 25 | """获取需要处理的字段""" 26 | all_args = sys.argv 27 | fields = [] 28 | for arg in all_args: 29 | if arg.startswith('field='): 30 | fields = [field.strip() for field in arg.replace('field=', '').split(',') if field.strip()] 31 | break 32 | return fields or ['password'] 33 | 34 | def get_key_iv(): 35 | """获取密钥和IV""" 36 | all_args = sys.argv 37 | key = None 38 | iv = None 39 | for arg in all_args: 40 | if arg.startswith('key='): 41 | key = arg.replace('key=', '').strip().encode('utf-8') 42 | elif arg.startswith('iv='): 43 | iv = arg.replace('iv=', '').strip().encode('utf-8') 44 | return key, iv 45 | 46 | def is_encrypt_mode(): 47 | """判断是加密还是解密模式""" 48 | return '--mode' not in ' '.join(sys.argv) 49 | 50 | class AESCBCProcessor: 51 | def __init__(self, fields): 52 | self.fields = fields 53 | self.is_encrypt = is_encrypt_mode() 54 | logging.info(f"初始化 AES CBC {'加密' if self.is_encrypt else '解密'}处理器") 55 | 56 | def process_value(self, value: str) -> str: 57 | """处理单个值""" 58 | key, iv = get_key_iv() 59 | cipher = AES.new(key, AES.MODE_CBC, iv) 60 | if self.is_encrypt: 61 | return base64.b64encode(cipher.encrypt(pad(value.encode('utf-8'), AES.block_size))).decode('utf-8') 62 | else: 63 | return unpad(cipher.decrypt(base64.b64decode(value)), AES.block_size).decode('utf-8') 64 | 65 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 66 | """处理JSON数据""" 67 | modified = False 68 | for field in self.fields: 69 | if field in json_data: 70 | json_data[field] = self.process_value(json_data[field]) 71 | modified = True 72 | return json_data, modified 73 | 74 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 75 | """处理表单数据""" 76 | params = parse_qs(form_data, keep_blank_values=True) 77 | modified = False 78 | for field in self.fields: 79 | if field in params: 80 | params[field] = [self.process_value(value) for value in params[field]] 81 | modified = True 82 | return urlencode(params), modified 83 | 84 | def request(self, flow: http.HTTPFlow) -> None: 85 | """处理请求""" 86 | # 处理请求逻辑... 87 | pass 88 | 89 | # 获取配置并注册插件 90 | fields = get_fields() 91 | addons = [AESCBCProcessor(fields)] -------------------------------------------------------------------------------- /src/scripts/bothTools/aes_ecb.py: -------------------------------------------------------------------------------- 1 | """ 2 | AES ECB 双向加解密脚本 3 | 4 | 使用方法: 5 | 加密: mitmdump -p 9999 -s aes_ecb.py --ssl-insecure field=password key=your_key 6 | 解密: mitmdump -p 8888 -s aes_ecb.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=password key=your_key 7 | 8 | 参数说明: 9 | field: 需要处理的字段,多个字段用逗号分隔 10 | key: AES密钥(必须为16、24或32字节) 11 | 12 | 注意事项: 13 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 14 | 2. 支持单个或多个字段处理 15 | 3. 自动检测运行模式(加密/解密) 16 | """ 17 | 18 | import sys 19 | import logging 20 | import json 21 | from mitmproxy import http 22 | from Crypto.Cipher import AES 23 | from Crypto.Util.Padding import pad, unpad 24 | import base64 25 | from urllib.parse import parse_qs, urlencode 26 | 27 | # 配置日志记录 28 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 29 | 30 | def get_fields_and_key(): 31 | """获取需要处理的字段和密钥""" 32 | all_args = sys.argv 33 | fields = [] 34 | key = None 35 | 36 | for arg in all_args: 37 | if arg.startswith('field='): 38 | fields = [field.strip() for field in arg.replace('field=', '').split(',') if field.strip()] 39 | elif arg.startswith('key='): 40 | key = arg.split('=', 1)[1].strip() 41 | 42 | if not fields: 43 | fields = ['password'] # 默认字段 44 | 45 | if not key or len(key) not in (16, 24, 32): 46 | logging.error("请提供有效的 AES 密钥(16、24 或 32 字节)") 47 | sys.exit(1) 48 | 49 | logging.info(f"需要处理的字段: {fields}") 50 | return fields, key 51 | 52 | def is_encrypt_mode(): 53 | """判断是加密还是解密模式""" 54 | return '--mode' not in ' '.join(sys.argv) 55 | 56 | class AESECBProcessor: 57 | def __init__(self, fields, key): 58 | self.fields = fields 59 | self.is_encrypt = is_encrypt_mode() 60 | self.key = key.encode('utf-8') 61 | mode = "加密" if self.is_encrypt else "解密" 62 | logging.info(f"初始化 AES ECB {mode}处理器") 63 | 64 | def process_value(self, value: str) -> str: 65 | """处理单个值""" 66 | cipher = AES.new(self.key, AES.MODE_ECB) 67 | if self.is_encrypt: 68 | padded_value = pad(value.encode('utf-8'), AES.block_size) 69 | return base64.b64encode(cipher.encrypt(padded_value)).decode('utf-8') 70 | else: 71 | decrypted_value = unpad(cipher.decrypt(base64.b64decode(value)), AES.block_size) 72 | return decrypted_value.decode('utf-8') 73 | 74 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 75 | """处理JSON数据""" 76 | modified = False 77 | for field in self.fields: 78 | if field in json_data: 79 | json_data[field] = self.process_value(json_data[field]) 80 | modified = True 81 | return json_data, modified 82 | 83 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 84 | """处理表单数据""" 85 | params = parse_qs(form_data, keep_blank_values=True) 86 | modified = False 87 | for field in self.fields: 88 | if field in params: 89 | params[field] = [self.process_value(value) for value in params[field]] 90 | modified = True 91 | return urlencode(params), modified 92 | 93 | def request(self, flow: http.HTTPFlow) -> None: 94 | """处理请求""" 95 | content_type = flow.request.headers.get("Content-Type", "") 96 | logging.info("=" * 50) 97 | logging.info(f"请求URL: {flow.request.pretty_url}") 98 | logging.info(f"请求方法: {flow.request.method}") 99 | logging.info(f"Content-Type: {content_type}") 100 | 101 | modified = False 102 | if "application/json" in content_type: 103 | json_data = json.loads(flow.request.content) 104 | json_data, modified = self.process_json_data(json_data) 105 | if modified: 106 | flow.request.content = json.dumps(json_data).encode('utf-8') 107 | 108 | elif "application/x-www-form-urlencoded" in content_type: 109 | form_data = flow.request.content.decode('utf-8') 110 | new_content, modified = self.process_form_data(form_data) 111 | if modified: 112 | flow.request.content = new_content.encode('utf-8') 113 | 114 | if modified: 115 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 116 | logging.info(f"处理后的请求数据: {flow.request.content.decode('utf-8')}") 117 | 118 | logging.info("=" * 50) 119 | 120 | # 获取配置并注册插件 121 | fields, key = get_fields_and_key() 122 | addons = [AESECBProcessor(fields, key)] -------------------------------------------------------------------------------- /src/scripts/bothTools/aes_gcm.py: -------------------------------------------------------------------------------- 1 | """ 2 | AES GCM 双向加解密脚本 3 | 4 | 使用方法: 5 | 加密: mitmdump -p 9999 -s aes_gcm.py --ssl-insecure field=password key=your_key 6 | 解密: mitmdump -p 8888 -s aes_gcm.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=password key=your_key 7 | 8 | 参数说明: 9 | field: 需要处理的字段,多个字段用逗号分隔 10 | key: AES密钥(必须为16、24或32字节) 11 | 12 | 注意事项: 13 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 14 | 2. 支持单个或多个字段处理 15 | 3. 自动检测运行模式(加密/解密) 16 | """ 17 | 18 | import sys 19 | from mitmproxy import http 20 | import logging 21 | from Crypto.Cipher import AES 22 | from Crypto.Util import Counter 23 | import base64 24 | import json 25 | from urllib.parse import parse_qs, urlencode 26 | 27 | # 配置日志记录 28 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 29 | 30 | def get_fields(): 31 | """获取需要处理的字段""" 32 | all_args = sys.argv 33 | fields = [] 34 | for arg in all_args: 35 | if arg.startswith('field='): 36 | fields = [field.strip() for field in arg.replace('field=', '').split(',') if field.strip()] 37 | break 38 | return fields or ['password'] 39 | 40 | def get_key(): 41 | """获取密钥""" 42 | all_args = sys.argv 43 | key = None 44 | for arg in all_args: 45 | if arg.startswith('key='): 46 | key = arg.split('=', 1)[1].strip() 47 | if not key or len(key) not in (16, 24, 32): 48 | logging.error("请提供有效的 AES 密钥(16、24 或 32 字节)") 49 | sys.exit(1) 50 | return key.encode('utf-8') 51 | 52 | def is_encrypt_mode(): 53 | """判断是加密还是解密模式""" 54 | return '--mode' not in ' '.join(sys.argv) 55 | 56 | class AesGCMProcessor: 57 | def __init__(self, fields, key): 58 | self.fields = fields 59 | self.is_encrypt = is_encrypt_mode() 60 | self.key = key 61 | mode = "加密" if self.is_encrypt else "解密" 62 | logging.info(f"初始化 AES GCM {mode}处理器") 63 | 64 | def process_value(self, value: str) -> str: 65 | """处理单个值""" 66 | cipher = AES.new(self.key, AES.MODE_GCM) 67 | if self.is_encrypt: 68 | nonce = cipher.nonce 69 | ciphertext, tag = cipher.encrypt_and_digest(value.encode('utf-8')) 70 | return base64.b64encode(nonce + tag + ciphertext).decode('utf-8') 71 | else: 72 | data = base64.b64decode(value) 73 | nonce, tag, ciphertext = data[:16], data[16:32], data[32:] 74 | cipher = AES.new(self.key, AES.MODE_GCM, nonce=nonce) 75 | return cipher.decrypt_and_verify(ciphertext, tag).decode('utf-8') 76 | 77 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 78 | """处理JSON数据""" 79 | modified = False 80 | for field in self.fields: 81 | if field in json_data: 82 | json_data[field] = self.process_value(json_data[field]) 83 | modified = True 84 | return json_data, modified 85 | 86 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 87 | """处理表单数据""" 88 | params = parse_qs(form_data, keep_blank_values=True) 89 | modified = False 90 | for field in self.fields: 91 | if field in params: 92 | params[field] = [self.process_value(value) for value in params[field]] 93 | modified = True 94 | return urlencode(params), modified 95 | 96 | def request(self, flow: http.HTTPFlow) -> None: 97 | """处理请求""" 98 | content_type = flow.request.headers.get("Content-Type", "") 99 | logging.info("=" * 50) 100 | logging.info(f"请求URL: {flow.request.pretty_url}") 101 | logging.info(f"请求方法: {flow.request.method}") 102 | logging.info(f"Content-Type: {content_type}") 103 | 104 | modified = False 105 | if "application/json" in content_type: 106 | json_data = json.loads(flow.request.content) 107 | json_data, modified = self.process_json_data(json_data) 108 | if modified: 109 | flow.request.content = json.dumps(json_data).encode('utf-8') 110 | 111 | elif "application/x-www-form-urlencoded" in content_type: 112 | form_data = flow.request.content.decode('utf-8') 113 | new_content, modified = self.process_form_data(form_data) 114 | if modified: 115 | flow.request.content = new_content.encode('utf-8') 116 | 117 | if modified: 118 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 119 | logging.info(f"处理后的请求数据: {flow.request.content.decode('utf-8')}") 120 | 121 | logging.info("=" * 50) 122 | 123 | # 获取配置并注册插件 124 | fields = get_fields() 125 | key = get_key() 126 | addons = [AesGCMProcessor(fields, key)] -------------------------------------------------------------------------------- /src/scripts/bothTools/base64.py: -------------------------------------------------------------------------------- 1 | """ 2 | Base64 双向加解密脚本 3 | 4 | 使用方法: 5 | 加密: mitmdump -p 9999 -s base64.py --ssl-insecure field=password 6 | 解密: mitmdump -p 8888 -s base64.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=password 7 | 8 | 参数说明: 9 | field=password: 需要处理的字段,多个字段用逗号分隔 10 | 11 | 注意事项: 12 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 13 | 2. 支持单个或多个字段处理 14 | 3. 自动检测运行模式(加密/解密) 15 | """ 16 | 17 | import sys 18 | from mitmproxy import http 19 | import base64 20 | import logging 21 | import json 22 | from urllib.parse import parse_qs, urlencode 23 | 24 | # 配置日志记录 25 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 26 | 27 | def get_fields(): 28 | """获取需要处理的字段""" 29 | all_args = sys.argv 30 | fields = [] 31 | 32 | for arg in all_args: 33 | if arg.startswith('field='): 34 | fields = [field.strip() for field in arg.replace('field=', '').split(',') if field.strip()] 35 | break 36 | 37 | if not fields: 38 | fields = ['password'] # 默认字段 39 | 40 | logging.info(f"需要处理的字段: {fields}") 41 | return fields 42 | 43 | def is_encrypt_mode(): 44 | """判断是加密还是解密模式""" 45 | return '--mode' not in ' '.join(sys.argv) 46 | 47 | class Base64Processor: 48 | def __init__(self, fields): 49 | self.fields = fields 50 | self.is_encrypt = is_encrypt_mode() 51 | mode = "加密" if self.is_encrypt else "解密" 52 | logging.info(f"初始化 Base64 {mode}处理器") 53 | 54 | def process_value(self, value: str) -> str: 55 | """处理单个值""" 56 | try: 57 | if self.is_encrypt: 58 | return base64.b64encode(value.encode('utf-8')).decode('utf-8') 59 | else: 60 | return base64.b64decode(value).decode('utf-8') 61 | except Exception as e: 62 | logging.error(f"处理失败: {e}") 63 | return value 64 | 65 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 66 | """处理JSON数据""" 67 | modified = False 68 | for field in self.fields: 69 | if field in json_data: 70 | try: 71 | value = str(json_data[field]) 72 | mode = "加密" if self.is_encrypt else "解密" 73 | logging.info(f"JSON字段 {field} 待{mode}值: {value}") 74 | json_data[field] = self.process_value(value) 75 | modified = True 76 | logging.info(f"JSON字段 {field} {mode}完成") 77 | except Exception as e: 78 | logging.error(f"处理字段 {field} 失败: {e}") 79 | return json_data, modified 80 | 81 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 82 | """处理表单数据""" 83 | params = parse_qs(form_data, keep_blank_values=True) 84 | modified = False 85 | 86 | for field in self.fields: 87 | if field in params: 88 | try: 89 | values = params[field] 90 | mode = "加密" if self.is_encrypt else "解密" 91 | if isinstance(values, list): 92 | processed_values = [] 93 | for value in values: 94 | logging.info(f"表单字段 {field} 待{mode}值: {value}") 95 | processed_values.append(self.process_value(value)) 96 | params[field] = processed_values 97 | else: 98 | logging.info(f"表单字段 {field} 待{mode}值: {values}") 99 | params[field] = self.process_value(values) 100 | modified = True 101 | logging.info(f"表单字段 {field} {mode}完成") 102 | except Exception as e: 103 | logging.error(f"处理字段 {field} 失败: {e}") 104 | 105 | for key in params: 106 | if isinstance(params[key], list) and len(params[key]) == 1: 107 | params[key] = params[key][0] 108 | 109 | return urlencode(params), modified 110 | 111 | def request(self, flow: http.HTTPFlow) -> None: 112 | """处理请求""" 113 | try: 114 | content_type = flow.request.headers.get("Content-Type", "") 115 | mode = "加密" if self.is_encrypt else "解密" 116 | logging.info("=" * 50) 117 | logging.info(f"请求URL: {flow.request.pretty_url}") 118 | logging.info(f"请求方法: {flow.request.method}") 119 | logging.info(f"Content-Type: {content_type}") 120 | logging.info(f"运行模式: {mode}") 121 | 122 | modified = False 123 | if "application/json" in content_type: 124 | json_data = json.loads(flow.request.content) 125 | json_data, modified = self.process_json_data(json_data) 126 | if modified: 127 | new_content = json.dumps(json_data, separators=(',', ':')) 128 | flow.request.content = new_content.encode('utf-8') 129 | 130 | elif "application/x-www-form-urlencoded" in content_type: 131 | form_data = flow.request.content.decode('utf-8') 132 | new_content, modified = self.process_form_data(form_data) 133 | if modified: 134 | flow.request.content = new_content.encode('utf-8') 135 | 136 | if modified: 137 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 138 | logging.info(f"{mode}后的请求数据: {flow.request.content.decode('utf-8')}") 139 | 140 | logging.info("=" * 50) 141 | 142 | except Exception as e: 143 | logging.error(f"处理请求失败: {e}") 144 | import traceback 145 | logging.error(traceback.format_exc()) 146 | 147 | # 获取配置并注册插件 148 | fields = get_fields() 149 | addons = [Base64Processor(fields)] -------------------------------------------------------------------------------- /src/scripts/bothTools/des3_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3DES CBC 双向加解密脚本 3 | 4 | 使用方法: 5 | 加密: mitmdump -p 9999 -s des3_cbc.py --ssl-insecure field=password key=your_key iv=your_iv 6 | 解密: mitmdump -p 8888 -s des3_cbc.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=password key=your_key iv=your_iv 7 | 8 | 参数说明: 9 | field: 需要处理的字段,多个字段用逗号分隔 10 | key: 3DES密钥(必须为24字节) 11 | iv: 初始化向量(CBC模式需要) 12 | 13 | 注意事项: 14 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 15 | 2. 支持单个或多个字段处理 16 | 3. 自动检测运行模式(加密/解密) 17 | """ 18 | 19 | import sys 20 | from mitmproxy import http 21 | import logging 22 | from Crypto.Cipher import DES3 23 | from Crypto.Util.Padding import pad, unpad 24 | import base64 25 | import json 26 | from urllib.parse import parse_qs, urlencode 27 | 28 | # 配置日志记录 29 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 30 | 31 | def get_fields(): 32 | """获取需要处理的字段""" 33 | all_args = sys.argv 34 | fields = [] 35 | for arg in all_args: 36 | if arg.startswith('field='): 37 | fields = [field.strip() for field in arg.replace('field=', '').split(',') if field.strip()] 38 | break 39 | return fields or ['password'] 40 | 41 | def get_key_iv(): 42 | """获取密钥和IV""" 43 | all_args = sys.argv 44 | key = None 45 | iv = None 46 | for arg in all_args: 47 | if arg.startswith('key='): 48 | key = arg.replace('key=', '').strip().encode('utf-8') 49 | elif arg.startswith('iv='): 50 | iv = arg.replace('iv=', '').strip().encode('utf-8') 51 | return key, iv 52 | 53 | def is_encrypt_mode(): 54 | """判断是加密还是解密模式""" 55 | return '--mode' not in ' '.join(sys.argv) 56 | 57 | class DES3CBCProcessor: 58 | def __init__(self, fields): 59 | self.fields = fields 60 | self.is_encrypt = is_encrypt_mode() 61 | logging.info(f"初始化 3DES CBC {'加密' if self.is_encrypt else '解密'}处理器") 62 | 63 | def process_value(self, value: str) -> str: 64 | """处理单个值""" 65 | key, iv = get_key_iv() 66 | cipher = DES3.new(key, DES3.MODE_CBC, iv) 67 | if self.is_encrypt: 68 | return base64.b64encode(cipher.encrypt(pad(value.encode('utf-8'), DES3.block_size))).decode('utf-8') 69 | else: 70 | return unpad(cipher.decrypt(base64.b64decode(value)), DES3.block_size).decode('utf-8') 71 | 72 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 73 | """处理JSON数据""" 74 | modified = False 75 | for field in self.fields: 76 | if field in json_data: 77 | json_data[field] = self.process_value(json_data[field]) 78 | modified = True 79 | return json_data, modified 80 | 81 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 82 | """处理表单数据""" 83 | params = parse_qs(form_data, keep_blank_values=True) 84 | modified = False 85 | for field in self.fields: 86 | if field in params: 87 | params[field] = [self.process_value(value) for value in params[field]] 88 | modified = True 89 | return urlencode(params), modified 90 | 91 | def request(self, flow: http.HTTPFlow) -> None: 92 | """处理请求""" 93 | content_type = flow.request.headers.get("Content-Type", "") 94 | logging.info("=" * 50) 95 | logging.info(f"请求URL: {flow.request.pretty_url}") 96 | logging.info(f"请求方法: {flow.request.method}") 97 | logging.info(f"Content-Type: {content_type}") 98 | 99 | modified = False 100 | if "application/json" in content_type: 101 | json_data = json.loads(flow.request.content) 102 | json_data, modified = self.process_json_data(json_data) 103 | if modified: 104 | flow.request.content = json.dumps(json_data).encode('utf-8') 105 | 106 | elif "application/x-www-form-urlencoded" in content_type: 107 | form_data = flow.request.content.decode('utf-8') 108 | new_content, modified = self.process_form_data(form_data) 109 | if modified: 110 | flow.request.content = new_content.encode('utf-8') 111 | 112 | if modified: 113 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 114 | logging.info(f"处理后的请求数据: {flow.request.content.decode('utf-8')}") 115 | 116 | logging.info("=" * 50) 117 | 118 | # 获取配置并注册插件 119 | fields = get_fields() 120 | addons = [DES3CBCProcessor(fields)] -------------------------------------------------------------------------------- /src/scripts/bothTools/des_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | DES CBC 双向加解密脚本 3 | 4 | 使用方法: 5 | 加密: mitmdump -p 9999 -s des_cbc.py --ssl-insecure field=password key=your_key iv=your_iv 6 | 解密: mitmdump -p 8888 -s des_cbc.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=password key=your_key iv=your_iv 7 | """ 8 | import base64 9 | import sys 10 | from mitmproxy import http 11 | import logging 12 | from Crypto.Cipher import DES 13 | from Crypto.Util.Padding import pad, unpad 14 | import json 15 | from urllib.parse import parse_qs, urlencode 16 | 17 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 18 | 19 | def get_fields(): 20 | """获取需要处理的字段""" 21 | all_args = sys.argv 22 | fields = [] 23 | for arg in all_args: 24 | if arg.startswith('field='): 25 | fields = [field.strip() for field in arg.replace('field=', '').split(',') if field.strip()] 26 | break 27 | return fields or ['password'] 28 | 29 | def get_key_iv(): 30 | """获取密钥和IV""" 31 | all_args = sys.argv 32 | key = None 33 | iv = None 34 | for arg in all_args: 35 | if arg.startswith('key='): 36 | key = arg.replace('key=', '').strip().encode('utf-8') 37 | elif arg.startswith('iv='): 38 | iv = arg.replace('iv=', '').strip().encode('utf-8') 39 | return key, iv 40 | 41 | def is_encrypt_mode(): 42 | """判断是加密还是解密模式""" 43 | return '--mode' not in ' '.join(sys.argv) 44 | 45 | class DESCBCProcessor: 46 | def __init__(self, fields): 47 | self.fields = fields 48 | self.is_encrypt = is_encrypt_mode() 49 | logging.info(f"初始化 DES CBC {'加密' if self.is_encrypt else '解密'}处理器") 50 | 51 | def process_value(self, value: str) -> str: 52 | """处理单个值""" 53 | key, iv = get_key_iv() 54 | cipher = DES.new(key, DES.MODE_CBC, iv) 55 | if self.is_encrypt: 56 | return base64.b64encode(cipher.encrypt(pad(value.encode('utf-8'), DES.block_size))).decode('utf-8') 57 | else: 58 | return unpad(cipher.decrypt(base64.b64decode(value)), DES.block_size).decode('utf-8') 59 | 60 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 61 | """处理JSON数据""" 62 | modified = False 63 | for field in self.fields: 64 | if field in json_data: 65 | json_data[field] = self.process_value(json_data[field]) 66 | modified = True 67 | return json_data, modified 68 | 69 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 70 | """处理表单数据""" 71 | params = parse_qs(form_data, keep_blank_values=True) 72 | modified = False 73 | for field in self.fields: 74 | if field in params: 75 | params[field] = [self.process_value(value) for value in params[field]] 76 | modified = True 77 | return urlencode(params), modified 78 | 79 | def request(self, flow: http.HTTPFlow) -> None: 80 | """处理请求""" 81 | # 处理请求逻辑... 82 | pass 83 | 84 | # 获取配置并注册插件 85 | fields = get_fields() 86 | addons = [DESCBCProcessor(fields)] -------------------------------------------------------------------------------- /src/scripts/decryptTools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/decryptTools/__init__.py -------------------------------------------------------------------------------- /src/scripts/decryptTools/__pycache__/aes_cbc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/decryptTools/__pycache__/aes_cbc.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/decryptTools/__pycache__/aes_ecb.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/decryptTools/__pycache__/aes_ecb.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/decryptTools/__pycache__/aes_gcm.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/decryptTools/__pycache__/aes_gcm.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/decryptTools/__pycache__/base64.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/decryptTools/__pycache__/base64.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/decryptTools/__pycache__/des3_cbc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/decryptTools/__pycache__/des3_cbc.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/decryptTools/__pycache__/des_cbc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/decryptTools/__pycache__/des_cbc.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/decryptTools/__pycache__/rsa.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/decryptTools/__pycache__/rsa.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/decryptTools/aes_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | AES-CBC 解密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s aes_cbc.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=data key=1234567890123456 iv=1234567890123456 6 | 7 | 参数说明: 8 | -p 8888: 监听端口 9 | -s aes_cbc.py: 指定脚本文件 10 | --mode upstream:http://127.0.0.1:8080: 指定代理服务器 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field: 需要解密的字段名称,多个字段用逗号分隔 13 | key: AES密钥,必须是16字节(128位)、24字节(192位)或32字节(256位) 14 | iv: 初始化向量,必须是16字节 15 | """ 16 | 17 | import sys 18 | from mitmproxy import http 19 | from Crypto.Cipher import AES 20 | from Crypto.Util.Padding import unpad 21 | import base64 22 | import logging 23 | import json 24 | from urllib.parse import parse_qs, urlencode 25 | 26 | # 配置日志记录 27 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 28 | 29 | def get_decryption_fields(): 30 | """获取解密配置""" 31 | all_args = sys.argv[1:] 32 | decryption_fields = [] 33 | key = None 34 | iv = None 35 | 36 | for arg in all_args: 37 | if not arg.startswith('-'): 38 | if 'key=' in arg: 39 | key = arg.split('=')[1] 40 | elif 'iv=' in arg: 41 | iv = arg.split('=')[1] 42 | elif 'field=' in arg: 43 | fields = arg.split('=', 1)[1].strip().split(',') 44 | decryption_fields.extend([field.strip() for field in fields if field.strip()]) 45 | 46 | if not key or not iv: 47 | raise ValueError("必须提供key和iv参数") 48 | if len(key) not in [16, 24, 32]: 49 | raise ValueError("AES密钥必须是16/24/32字节长度") 50 | if len(iv) != 16: 51 | raise ValueError("IV必须是16字节长度") 52 | 53 | logging.info(f"需要解密的字段: {decryption_fields}") 54 | return decryption_fields, key, iv 55 | 56 | class AesCbcDecryptInterceptor: 57 | def __init__(self, decryption_fields, key, iv): 58 | self.decryption_fields = decryption_fields 59 | self.key = key.encode('utf-8') 60 | self.iv = iv.encode('utf-8') 61 | 62 | def decrypt_value(self, encrypted_text: str) -> str: 63 | """解密单个值""" 64 | try: 65 | encrypted_data = base64.b64decode(encrypted_text) 66 | cipher = AES.new(self.key, AES.MODE_CBC, self.iv) 67 | decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size) 68 | return decrypted_data.decode('utf-8') 69 | except Exception as e: 70 | logging.error(f"解密失败: {e}") 71 | return encrypted_text 72 | 73 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 74 | """处理JSON数据""" 75 | modified = False 76 | for field in self.decryption_fields: 77 | if field in json_data: 78 | try: 79 | encrypted_value = json_data[field] 80 | logging.info(f"JSON字段 {field} 待解密值: {encrypted_value}") 81 | decrypted_value = self.decrypt_value(encrypted_value) 82 | 83 | try: 84 | # 尝试将解密后的字符串解析为 JSON 对象 85 | json_data[field] = json.loads(decrypted_value) 86 | except json.JSONDecodeError: 87 | # 如果不是有效的 JSON,则保持为字符串 88 | json_data[field] = decrypted_value 89 | 90 | modified = True 91 | logging.info(f"JSON字段 {field} 解密完成") 92 | except Exception as e: 93 | logging.error(f"解密字段 {field} 失败: {e}") 94 | return json_data, modified 95 | 96 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 97 | """处理表单数据""" 98 | params = parse_qs(form_data, keep_blank_values=True) 99 | modified = False 100 | 101 | for field in self.decryption_fields: 102 | if field in params: 103 | try: 104 | values = params[field] 105 | if isinstance(values, list): 106 | decrypted_values = [] 107 | for value in values: 108 | logging.info(f"表单字段 {field} 待解密值: {value}") 109 | decrypted_values.append(self.decrypt_value(value)) 110 | params[field] = decrypted_values 111 | else: 112 | logging.info(f"表单字段 {field} 待解密值: {values}") 113 | params[field] = self.decrypt_value(values) 114 | modified = True 115 | logging.info(f"表单字段 {field} 解密完成") 116 | except Exception as e: 117 | logging.error(f"解密字段 {field} 失败: {e}") 118 | 119 | for key in params: 120 | if isinstance(params[key], list) and len(params[key]) == 1: 121 | params[key] = params[key][0] 122 | 123 | return urlencode(params), modified 124 | 125 | def request(self, flow: http.HTTPFlow) -> None: 126 | """处理请求""" 127 | try: 128 | content_type = flow.request.headers.get("Content-Type", "") 129 | logging.info("=" * 50) 130 | logging.info(f"请求URL: {flow.request.pretty_url}") 131 | logging.info(f"请求方法: {flow.request.method}") 132 | logging.info(f"Content-Type: {content_type}") 133 | 134 | modified = False 135 | if "application/json" in content_type: 136 | json_data = json.loads(flow.request.content) 137 | json_data, modified = self.process_json_data(json_data) 138 | if modified: 139 | new_content = json.dumps(json_data, separators=(',', ':')) 140 | flow.request.content = new_content.encode('utf-8') 141 | 142 | elif "application/x-www-form-urlencoded" in content_type: 143 | form_data = flow.request.content.decode('utf-8') 144 | new_content, modified = self.process_form_data(form_data) 145 | if modified: 146 | flow.request.content = new_content.encode('utf-8') 147 | 148 | if modified: 149 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 150 | logging.info(f"解密后的请求数据: {flow.request.content.decode('utf-8')}") 151 | 152 | logging.info("=" * 50) 153 | 154 | except Exception as e: 155 | logging.error(f"处理请求失败: {e}") 156 | import traceback 157 | logging.error(traceback.format_exc()) 158 | 159 | # 获取解密配置 160 | decryption_fields, key, iv = get_decryption_fields() 161 | 162 | # 注册插件 163 | addons = [AesCbcDecryptInterceptor(decryption_fields, key, iv)] -------------------------------------------------------------------------------- /src/scripts/decryptTools/aes_ecb.py: -------------------------------------------------------------------------------- 1 | """ 2 | AES-ECB 解密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 9090 -s aes_ecb.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=data key=1234567890123456 6 | 7 | 参数说明: 8 | -p 9090: 监听端口 9 | -s aes_ecb.py: 指定脚本文件 10 | --mode upstream:http://127.0.0.1:8080: 指定代理服务器 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field: 需要解密的字段名称,多个字段用逗号分隔 13 | key: AES密钥,必须是16字节(128位)、24字节(192位)或32字节(256位) 14 | 15 | 注意:ECB模式不需要IV,但安全性较低,建议使用CBC或GCM模式 16 | """ 17 | 18 | import sys 19 | from mitmproxy import http 20 | from Crypto.Cipher import AES 21 | from Crypto.Util.Padding import unpad 22 | import base64 23 | import logging 24 | import json 25 | from urllib.parse import parse_qs, urlencode 26 | 27 | # 配置日志记录 28 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 29 | 30 | def get_decryption_fields(): 31 | """获取解密配置""" 32 | all_args = sys.argv[1:] 33 | decryption_fields = [] 34 | key = None 35 | 36 | for arg in all_args: 37 | if not arg.startswith('-'): 38 | if 'key=' in arg: 39 | key = arg.split('=')[1] 40 | elif 'field=' in arg: # 明确检查 field= 前缀 41 | fields = arg.split('=')[1] 42 | decryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 43 | 44 | if not key: 45 | raise ValueError("必须提供key参数") 46 | if len(key) not in [16, 24, 32]: 47 | raise ValueError("AES密钥必须是16/24/32字节长度") 48 | 49 | logging.info(f"需要解密的字段: {decryption_fields}") 50 | return decryption_fields, key 51 | 52 | class AesEcbDecryptInterceptor: 53 | def __init__(self, decryption_fields, key): 54 | self.decryption_fields = decryption_fields 55 | self.key = key.encode('utf-8') 56 | 57 | def decrypt_value(self, encrypted_text: str) -> str: 58 | """解密单个值""" 59 | try: 60 | encrypted_data = base64.b64decode(encrypted_text) 61 | cipher = AES.new(self.key, AES.MODE_ECB) 62 | decrypted_data = unpad(cipher.decrypt(encrypted_data), AES.block_size) 63 | return decrypted_data.decode('utf-8') 64 | except Exception as e: 65 | logging.error(f"解密失败: {e}") 66 | return encrypted_text 67 | 68 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 69 | """处理JSON数据""" 70 | modified = False 71 | for field in self.decryption_fields: 72 | if field in json_data: 73 | try: 74 | encrypted_value = json_data[field] 75 | logging.info(f"JSON字段 {field} 待解密值: {encrypted_value}") 76 | decrypted_value = self.decrypt_value(encrypted_value) 77 | 78 | try: 79 | # 尝试将解密后的字符串解析为 JSON 对象 80 | json_data[field] = json.loads(decrypted_value) 81 | except json.JSONDecodeError: 82 | # 如果不是有效的 JSON,则保持为字符串 83 | json_data[field] = decrypted_value 84 | 85 | modified = True 86 | logging.info(f"JSON字段 {field} 解密完成") 87 | except Exception as e: 88 | logging.error(f"解密字段 {field} 失败: {e}") 89 | return json_data, modified 90 | 91 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 92 | """处理表单数据""" 93 | params = parse_qs(form_data, keep_blank_values=True) 94 | modified = False 95 | 96 | for field in self.decryption_fields: 97 | if field in params: 98 | try: 99 | values = params[field] 100 | if isinstance(values, list): 101 | decrypted_values = [] 102 | for value in values: 103 | logging.info(f"表单字段 {field} 待解密值: {value}") 104 | decrypted_values.append(self.decrypt_value(value)) 105 | params[field] = decrypted_values 106 | else: 107 | logging.info(f"表单字段 {field} 待解密值: {values}") 108 | params[field] = self.decrypt_value(values) 109 | modified = True 110 | logging.info(f"表单字段 {field} 解密完成") 111 | except Exception as e: 112 | logging.error(f"解密字段 {field} 失败: {e}") 113 | 114 | for key in params: 115 | if isinstance(params[key], list) and len(params[key]) == 1: 116 | params[key] = params[key][0] 117 | 118 | return urlencode(params), modified 119 | 120 | def request(self, flow: http.HTTPFlow) -> None: 121 | """处理请求""" 122 | try: 123 | content_type = flow.request.headers.get("Content-Type", "") 124 | logging.info("=" * 50) 125 | logging.info(f"请求URL: {flow.request.pretty_url}") 126 | logging.info(f"请求方法: {flow.request.method}") 127 | logging.info(f"Content-Type: {content_type}") 128 | 129 | # 显示原始请求数据包 130 | logging.info(f"原始请求数据包: {flow.request.content.decode('utf-8')}") 131 | 132 | modified = False 133 | if "application/json" in content_type: 134 | json_data = json.loads(flow.request.content) 135 | json_data, modified = self.process_json_data(json_data) 136 | if modified: 137 | flow.request.content = json.dumps(json_data).encode('utf-8') 138 | 139 | elif "application/x-www-form-urlencoded" in content_type: 140 | form_data = flow.request.content.decode('utf-8') 141 | new_content, modified = self.process_form_data(form_data) 142 | if modified: 143 | flow.request.content = new_content.encode('utf-8') 144 | 145 | if modified: 146 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 147 | logging.info("\n解密后的请求数据包:") 148 | logging.info(f"{flow.request.content.decode('utf-8')}") 149 | 150 | logging.info("=" * 50) 151 | 152 | except Exception as e: 153 | logging.error(f"处理请求失败: {e}") 154 | import traceback 155 | logging.error(traceback.format_exc()) 156 | 157 | # 获取解密配置 158 | decryption_fields, key = get_decryption_fields() 159 | 160 | # 注册插件 161 | addons = [AesEcbDecryptInterceptor(decryption_fields, key)] -------------------------------------------------------------------------------- /src/scripts/decryptTools/aes_gcm.py: -------------------------------------------------------------------------------- 1 | """ 2 | AES-GCM 解密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s aes_gcm.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=data key=32byteslongsecretkeyforaes256!aa iv=16byteslongiv456 6 | 7 | 参数说明: 8 | -p 8888: 监听端口 9 | -s aes_gcm.py: 指定脚本文件 10 | --mode upstream:http://127.0.0.1:8080: 指定代理服务器 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field: 需要解密的字段名称,多个字段用逗号分隔 13 | key: AES密钥,必须是16字节(128位)、24字节(192位)或32字节(256位) 14 | iv: GCM模式的初始化向量,必须是16字节长度(与客户端保持一致) 15 | """ 16 | 17 | import sys 18 | import os 19 | from mitmproxy import http 20 | from Crypto.Cipher import AES 21 | import base64 22 | import logging 23 | import json 24 | from urllib.parse import parse_qs, urlencode 25 | 26 | # 配置日志记录 27 | logging.basicConfig( 28 | level=logging.INFO, 29 | format='%(asctime)s - %(levelname)s - %(message)s' 30 | ) 31 | 32 | def get_decryption_fields(): 33 | """获取解密配置""" 34 | all_args = sys.argv[1:] 35 | decryption_fields = [] 36 | key = None 37 | iv = None 38 | 39 | for arg in all_args: 40 | if not arg.startswith('-'): 41 | if 'key=' in arg: 42 | key = arg.split('=')[1] 43 | elif 'iv=' in arg: 44 | iv = arg.split('=')[1] 45 | elif 'field=' in arg: # 明确检查 field= 前缀 46 | fields = arg.split('=')[1] 47 | decryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 48 | 49 | if not key or not iv: 50 | raise ValueError("必须提供key和iv参数") 51 | if len(key) not in [16, 24, 32]: 52 | raise ValueError("AES密钥必须是16/24/32字节长度") 53 | if len(iv) != 16: # 修改为16字节,与客户端保持一致 54 | raise ValueError("IV必须是16字节长度") 55 | 56 | logging.info(f"需要解密的字段: {decryption_fields}") 57 | return decryption_fields, key, iv 58 | 59 | def get_fields(): 60 | """获取需要处理的字段""" 61 | all_args = sys.argv 62 | fields = [] 63 | for arg in all_args: 64 | if arg.startswith('field='): 65 | fields = [field.strip() for field in arg.replace('field=', '').split(',') if field.strip()] 66 | break 67 | return fields or ['password'] # 默认字段 68 | 69 | # 获取所有参数 70 | try: 71 | decryption_fields, key, iv = get_decryption_fields() 72 | except Exception as e: 73 | logging.error(f"参数错误: {e}") 74 | sys.exit(1) 75 | 76 | class AesGcmDecryptInterceptor: 77 | def __init__(self, decryption_fields, key, iv): 78 | self.decryption_fields = decryption_fields 79 | self.key = key.encode('utf-8') 80 | self.iv = iv.encode('utf-8') 81 | self.tag_length = 16 # GCM认证标签长度(字节) 82 | 83 | def decrypt_value(self, encrypted_text: str) -> str: 84 | """解密单个值""" 85 | try: 86 | # Base64解码 87 | encrypted_data = base64.b64decode(encrypted_text) 88 | 89 | # 分离密文和认证标签(与客户端一致) 90 | ciphertext = encrypted_data[:-self.tag_length] 91 | tag = encrypted_data[-self.tag_length:] 92 | 93 | # 创建解密器 94 | cipher = AES.new(self.key, AES.MODE_GCM, nonce=self.iv) 95 | 96 | # 解密并验证 97 | decrypted_data = cipher.decrypt_and_verify(ciphertext, tag) 98 | return decrypted_data.decode('utf-8') 99 | except Exception as e: 100 | logging.error(f"解密失败: {e}") 101 | logging.error(f"密钥长度: {len(self.key)}") 102 | logging.error(f"IV长度: {len(self.iv)}") 103 | logging.error(f"加密数据长度: {len(encrypted_data)}") 104 | return encrypted_text 105 | 106 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 107 | """处理JSON数据""" 108 | modified = False 109 | for field in self.decryption_fields: 110 | if field in json_data: 111 | try: 112 | encrypted_value = json_data[field] 113 | logging.info(f"JSON字段 {field} 待解密值: {encrypted_value}") 114 | decrypted_value = self.decrypt_value(encrypted_value) 115 | 116 | try: 117 | # 尝试将解密后的字符串解析为 JSON 对象 118 | json_data[field] = json.loads(decrypted_value) 119 | except json.JSONDecodeError: 120 | # 如果不是有效的 JSON,则保持为字符串 121 | json_data[field] = decrypted_value 122 | 123 | modified = True 124 | logging.info(f"JSON字段 {field} 解密完成") 125 | except Exception as e: 126 | logging.error(f"解密字段 {field} 失败: {e}") 127 | return json_data, modified 128 | 129 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 130 | """处理表单数据""" 131 | params = parse_qs(form_data, keep_blank_values=True) 132 | modified = False 133 | 134 | for field in self.decryption_fields: 135 | if field in params: 136 | try: 137 | values = params[field] 138 | if isinstance(values, list): 139 | decrypted_values = [] 140 | for value in values: 141 | logging.info(f"表单字段 {field} 待解密值: {value}") 142 | decrypted_values.append(self.decrypt_value(value)) 143 | params[field] = decrypted_values 144 | else: 145 | logging.info(f"表单字段 {field} 待解密值: {values}") 146 | params[field] = self.decrypt_value(values) 147 | modified = True 148 | logging.info(f"表单字段 {field} 解密完成") 149 | except Exception as e: 150 | logging.error(f"解密字段 {field} 失败: {e}") 151 | 152 | for key in params: 153 | if isinstance(params[key], list) and len(params[key]) == 1: 154 | params[key] = params[key][0] 155 | 156 | return urlencode(params), modified 157 | 158 | def request(self, flow: http.HTTPFlow) -> None: 159 | """处理请求""" 160 | try: 161 | content_type = flow.request.headers.get("Content-Type", "") 162 | logging.info("=" * 50) 163 | logging.info(f"原始请求数据包:\n{flow.request.method} {flow.request.pretty_url}") 164 | logging.info(f"Content-Type: {content_type}") 165 | logging.info(f"{flow.request.content.decode('utf-8')}") 166 | 167 | modified = False 168 | if "application/json" in content_type: 169 | json_data = json.loads(flow.request.content) 170 | json_data, modified = self.process_json_data(json_data) 171 | if modified: 172 | new_content = json.dumps(json_data, separators=(',', ':')) 173 | flow.request.content = new_content.encode('utf-8') 174 | 175 | elif "application/x-www-form-urlencoded" in content_type: 176 | form_data = flow.request.content.decode('utf-8') 177 | new_content, modified = self.process_form_data(form_data) 178 | if modified: 179 | flow.request.content = new_content.encode('utf-8') 180 | 181 | if modified: 182 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 183 | logging.info("\n解密后的请求数据包:") 184 | logging.info(f"{flow.request.content.decode('utf-8')}") 185 | 186 | logging.info("=" * 50) 187 | 188 | except Exception as e: 189 | logging.error(f"处理请求失败: {e}") 190 | import traceback 191 | logging.error(traceback.format_exc()) 192 | 193 | # 注册插件 194 | addons = [AesGcmDecryptInterceptor(decryption_fields, key, iv)] -------------------------------------------------------------------------------- /src/scripts/decryptTools/base64.py: -------------------------------------------------------------------------------- 1 | """ 2 | Base64 解密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s base64.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=password 6 | mitmdump -p 8888 -s base64.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=password,username 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s base64.py: 指定脚本文件 11 | --mode upstream:http://127.0.0.1:8080: 指定代理服务器 12 | --ssl-insecure: 忽略 SSL 证书验证 13 | field=password: 单个解密字段 14 | field=password,username: 多个解密字段,用逗号分隔 15 | """ 16 | 17 | import sys 18 | from mitmproxy import http 19 | import base64 20 | import logging 21 | import json 22 | from urllib.parse import parse_qs, urlencode 23 | 24 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 25 | 26 | def get_decryption_fields(): 27 | """ 28 | 从命令行参数获取解密配置 29 | 30 | Returns: 31 | list: 需要解密的字段名称列表 32 | """ 33 | all_args = sys.argv 34 | decryption_fields = [] 35 | 36 | # 遍历所有参数 37 | for arg in all_args: 38 | if arg.startswith('field='): 39 | # 提取 field= 后面的值 40 | fields = arg.replace('field=', '') 41 | decryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 42 | break 43 | 44 | if not decryption_fields: 45 | decryption_fields = ['password'] # 默认解密字段 46 | 47 | logging.info(f"需要解密的字段: {decryption_fields}") 48 | return decryption_fields 49 | 50 | class Base64DecodeInterceptor: 51 | def __init__(self, decryption_fields): 52 | self.decryption_fields = decryption_fields 53 | logging.info("成功初始化Base64解密器") 54 | 55 | def decode_value(self, encoded_text: str) -> str: 56 | """Base64解码""" 57 | try: 58 | decoded_bytes = base64.b64decode(encoded_text) 59 | return decoded_bytes.decode('utf-8') 60 | except Exception as e: 61 | logging.error(f"解码失败: {e}") 62 | return encoded_text 63 | 64 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 65 | """处理JSON数据""" 66 | modified = False 67 | for field in self.decryption_fields: 68 | if field in json_data: 69 | try: 70 | encoded_value = json_data[field] 71 | logging.info(f"JSON字段 {field} 待解码值: {encoded_value}") 72 | decoded_value = self.decode_value(encoded_value) 73 | 74 | try: 75 | json_data[field] = json.loads(decoded_value) 76 | except json.JSONDecodeError: 77 | json_data[field] = decoded_value 78 | 79 | modified = True 80 | logging.info(f"JSON字段 {field} 解码完成") 81 | except Exception as e: 82 | logging.error(f"解码字段 {field} 失败: {e}") 83 | return json_data, modified 84 | 85 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 86 | """处理表单数据""" 87 | params = parse_qs(form_data, keep_blank_values=True) 88 | modified = False 89 | 90 | for field in self.decryption_fields: 91 | if field in params: 92 | try: 93 | values = params[field] 94 | if isinstance(values, list): 95 | decoded_values = [] 96 | for value in values: 97 | logging.info(f"表单字段 {field} 待解码值: {value}") 98 | decoded_values.append(self.decode_value(value)) 99 | params[field] = decoded_values 100 | else: 101 | logging.info(f"表单字段 {field} 待解码值: {values}") 102 | params[field] = self.decode_value(values) 103 | modified = True 104 | logging.info(f"表单字段 {field} 解码完成") 105 | except Exception as e: 106 | logging.error(f"解码字段 {field} 失败: {e}") 107 | 108 | for key in params: 109 | if isinstance(params[key], list) and len(params[key]) == 1: 110 | params[key] = params[key][0] 111 | 112 | return urlencode(params), modified 113 | 114 | def request(self, flow: http.HTTPFlow) -> None: 115 | """处理请求""" 116 | try: 117 | content_type = flow.request.headers.get("Content-Type", "") 118 | logging.info("=" * 50) 119 | logging.info(f"原始请求数据包:\n{flow.request.method} {flow.request.pretty_url}") 120 | logging.info(f"Content-Type: {content_type}") 121 | logging.info(f"{flow.request.content.decode('utf-8')}") 122 | 123 | modified = False 124 | if "application/json" in content_type: 125 | json_data = json.loads(flow.request.content) 126 | json_data, modified = self.process_json_data(json_data) 127 | if modified: 128 | new_content = json.dumps(json_data, separators=(',', ':')) 129 | flow.request.content = new_content.encode('utf-8') 130 | 131 | elif "application/x-www-form-urlencoded" in content_type: 132 | form_data = flow.request.content.decode('utf-8') 133 | new_content, modified = self.process_form_data(form_data) 134 | if modified: 135 | flow.request.content = new_content.encode('utf-8') 136 | 137 | if modified: 138 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 139 | logging.info("\n解码后的请求数据包:") 140 | logging.info(f"{flow.request.content.decode('utf-8')}") 141 | 142 | logging.info("=" * 50) 143 | 144 | except Exception as e: 145 | logging.error(f"处理请求失败: {e}") 146 | import traceback 147 | logging.error(traceback.format_exc()) 148 | 149 | # 获取解密配置 150 | decryption_fields = get_decryption_fields() 151 | 152 | # 注册插件 153 | addons = [Base64DecodeInterceptor(decryption_fields)] -------------------------------------------------------------------------------- /src/scripts/decryptTools/des3_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3DES-CBC 解密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s des3_cbc.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=data key=12345678 iv=12345678 6 | 7 | 参数说明: 8 | -p 8888: 监听端口 9 | -s des3_cbc.py: 指定脚本文件 10 | --mode upstream:http://127.0.0.1:8080: 指定代理服务器 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field: 需要解密的字段名称,多个字段用逗号分隔 13 | key: 3DES密钥,必须是24字节长度 14 | iv: 初始化向量,必须是8字节长度 15 | 16 | 注意事项: 17 | 1. 3DES密钥必须是24字节长度,IV必须是8字节长度 18 | 2. 支持 application/json 和 application/x-www-form-urlencoded 格式 19 | 3. 解密前数据需为 Base64 编码 20 | """ 21 | 22 | import sys 23 | from mitmproxy import http 24 | from Crypto.Cipher import DES3 25 | from Crypto.Util.Padding import unpad 26 | import base64 27 | import logging 28 | import json 29 | from urllib.parse import parse_qs, urlencode 30 | 31 | # 配置日志记录 32 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 33 | 34 | 35 | def get_decryption_fields(): 36 | """获取解密配置""" 37 | all_args = sys.argv[1:] 38 | decryption_fields = [] 39 | key = None 40 | iv = None 41 | 42 | for arg in all_args: 43 | if not arg.startswith('-'): 44 | if 'key=' in arg: 45 | key = arg.split('=')[1] 46 | elif 'iv=' in arg: 47 | iv = arg.split('=')[1] 48 | elif 'field=' in arg: # 明确检查 field= 前缀 49 | fields = arg.split('=')[1] 50 | decryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 51 | 52 | logging.info(f"需要解密的字段: {decryption_fields}") 53 | return decryption_fields, key, iv 54 | 55 | 56 | class Des3DecryptInterceptor: 57 | def __init__(self, decryption_fields, key, iv): 58 | self.decryption_fields = decryption_fields 59 | self.key = key.encode('utf-8') 60 | self.iv = iv.encode('utf-8') 61 | 62 | def decrypt_value(self, encrypted_text: str) -> str: 63 | """解密单个值""" 64 | try: 65 | # 确保数据是 Base64 编码的 66 | encrypted_data = base64.b64decode(encrypted_text) 67 | cipher = DES3.new(self.key, DES3.MODE_CBC, self.iv) 68 | decrypted_data = unpad(cipher.decrypt(encrypted_data), DES3.block_size) 69 | return decrypted_data.decode('utf-8') 70 | except Exception as e: 71 | logging.error(f"解密失败: {e}") 72 | return encrypted_text 73 | 74 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 75 | """处理JSON数据""" 76 | modified = False 77 | for field in self.decryption_fields: 78 | if field in json_data: 79 | try: 80 | encrypted_value = json_data[field] 81 | logging.info(f"JSON字段 {field} 待解密值: {encrypted_value}") 82 | decrypted_value = self.decrypt_value(encrypted_value) 83 | 84 | # 解析解密后的字符串为 JSON 对象 85 | json_data[field] = json.loads(decrypted_value) # 确保将解密后的字符串解析为 JSON 对象 86 | modified = True 87 | logging.info(f"JSON字段 {field} 解密完成") 88 | except Exception as e: 89 | logging.error(f"解密字段 {field} 失败: {e}") 90 | return json_data, modified 91 | 92 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 93 | """处理表单数据""" 94 | params = parse_qs(form_data, keep_blank_values=True) 95 | modified = False 96 | 97 | for field in self.decryption_fields: 98 | if field in params: 99 | try: 100 | values = params[field] 101 | if isinstance(values, list): 102 | decrypted_values = [] 103 | for value in values: 104 | logging.info(f"表单字段 {field} 待解密值: {value}") 105 | decrypted_values.append(self.decrypt_value(value)) 106 | params[field] = decrypted_values 107 | else: 108 | logging.info(f"表单字段 {field} 待解密值: {values}") 109 | params[field] = self.decrypt_value(values) 110 | modified = True 111 | logging.info(f"表单字段 {field} 解密完成") 112 | except Exception as e: 113 | logging.error(f"解密字段 {field} 失败: {e}") 114 | 115 | for key in params: 116 | if isinstance(params[key], list) and len(params[key]) == 1: 117 | params[key] = params[key][0] 118 | 119 | return urlencode(params), modified 120 | 121 | def request(self, flow: http.HTTPFlow) -> None: 122 | """处理请求""" 123 | try: 124 | content_type = flow.request.headers.get("Content-Type", "") 125 | logging.info("=" * 50) 126 | logging.info(f"请求URL: {flow.request.pretty_url}") 127 | logging.info(f"请求方法: {flow.request.method}") 128 | logging.info(f"Content-Type: {content_type}") 129 | 130 | # 显示原始请求数据包 131 | logging.info(f"原始请求数据包: {flow.request.content.decode('utf-8')}") 132 | 133 | modified = False 134 | if "application/json" in content_type: 135 | json_data = json.loads(flow.request.content) 136 | json_data, modified = self.process_json_data(json_data) 137 | if modified: 138 | flow.request.content = json.dumps(json_data).encode('utf-8') 139 | 140 | elif "application/x-www-form-urlencoded" in content_type: 141 | form_data = flow.request.content.decode('utf-8') 142 | new_content, modified = self.process_form_data(form_data) 143 | if modified: 144 | flow.request.content = new_content.encode('utf-8') 145 | 146 | if modified: 147 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 148 | logging.info("\n解密后的请求数据包:") 149 | logging.info(f"{flow.request.content.decode('utf-8')}") 150 | 151 | logging.info("=" * 50) 152 | 153 | except Exception as e: 154 | logging.error(f"处理请求失败: {e}") 155 | import traceback 156 | logging.error(traceback.format_exc()) 157 | 158 | 159 | # 获取解密配置 160 | decryption_fields, key, iv = get_decryption_fields() 161 | 162 | # 注册插件 163 | addons = [Des3DecryptInterceptor(decryption_fields, key, iv)] 164 | -------------------------------------------------------------------------------- /src/scripts/decryptTools/des_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | DES-CBC 解密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s des_cbc.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure field=data key=12345678 iv=12345678 6 | 7 | 参数说明: 8 | -p 8888: 监听端口 9 | -s des_cbc.py: 指定脚本文件 10 | --mode upstream:http://127.0.0.1:8080: 指定代理服务器 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field: 需要解密的字段名称,多个字段用逗号分隔 13 | key: DES密钥,必须是8字节长度 14 | iv: 初始化向量,必须是8字节长度 15 | 16 | 注意事项: 17 | 1. DES密钥和IV必须是8字节长度 18 | 2. 支持 application/json 和 application/x-www-form-urlencoded 格式 19 | 3. 解密前数据需为 Base64 编码 20 | """ 21 | 22 | import sys 23 | from mitmproxy import http 24 | from Crypto.Cipher import DES 25 | from Crypto.Util.Padding import unpad 26 | import base64 27 | import logging 28 | import json 29 | from urllib.parse import parse_qs, urlencode 30 | 31 | # 配置日志记录 32 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 33 | 34 | 35 | def get_decryption_fields(): 36 | """获取解密配置""" 37 | all_args = sys.argv[1:] 38 | decryption_fields = [] 39 | key = None 40 | iv = None 41 | 42 | for arg in all_args: 43 | if not arg.startswith('-'): 44 | if 'key=' in arg: 45 | key = arg.split('=')[1] 46 | elif 'iv=' in arg: 47 | iv = arg.split('=')[1] 48 | elif 'field=' in arg: # 修改这里,明确检查 field= 前缀 49 | fields = arg.split('=')[1] 50 | decryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 51 | 52 | logging.info(f"需要解密的字段: {decryption_fields}") 53 | return decryption_fields, key, iv 54 | 55 | 56 | class DesDecryptInterceptor: 57 | def __init__(self, decryption_fields, key, iv): 58 | self.decryption_fields = decryption_fields 59 | self.key = key.encode('utf-8') 60 | self.iv = iv.encode('utf-8') 61 | 62 | def decrypt_value(self, encrypted_text: str) -> str: 63 | """解密单个值""" 64 | try: 65 | # 确保数据是 Base64 编码的 66 | encrypted_data = base64.b64decode(encrypted_text) 67 | cipher = DES.new(self.key, DES.MODE_CBC, self.iv) 68 | decrypted_data = unpad(cipher.decrypt(encrypted_data), DES.block_size) 69 | return decrypted_data.decode('utf-8') 70 | except Exception as e: 71 | logging.error(f"解密失败: {e}") 72 | return encrypted_text 73 | 74 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 75 | """处理JSON数据""" 76 | modified = False 77 | for field in self.decryption_fields: 78 | if field in json_data: 79 | try: 80 | encrypted_value = json_data[field] 81 | logging.info(f"JSON字段 {field} 待解密值: {encrypted_value}") 82 | decrypted_value = self.decrypt_value(encrypted_value) 83 | 84 | # 解析解密后的字符串为 JSON 对象 85 | json_data[field] = json.loads(decrypted_value) # 确保将解密后的字符串解析为 JSON 对象 86 | modified = True 87 | logging.info(f"JSON字段 {field} 解密完成") 88 | except Exception as e: 89 | logging.error(f"解密字段 {field} 失败: {e}") 90 | return json_data, modified 91 | 92 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 93 | """处理表单数据""" 94 | params = parse_qs(form_data, keep_blank_values=True) 95 | modified = False 96 | 97 | for field in self.decryption_fields: 98 | if field in params: 99 | try: 100 | values = params[field] 101 | if isinstance(values, list): 102 | decrypted_values = [] 103 | for value in values: 104 | logging.info(f"表单字段 {field} 待解密值: {value}") 105 | decrypted_values.append(self.decrypt_value(value)) 106 | params[field] = decrypted_values 107 | else: 108 | logging.info(f"表单字段 {field} 待解密值: {values}") 109 | params[field] = self.decrypt_value(values) 110 | modified = True 111 | logging.info(f"表单字段 {field} 解密完成") 112 | except Exception as e: 113 | logging.error(f"解密字段 {field} 失败: {e}") 114 | 115 | for key in params: 116 | if isinstance(params[key], list) and len(params[key]) == 1: 117 | params[key] = params[key][0] 118 | 119 | return urlencode(params), modified 120 | 121 | def request(self, flow: http.HTTPFlow) -> None: 122 | """处理请求""" 123 | try: 124 | content_type = flow.request.headers.get("Content-Type", "") 125 | logging.info("=" * 50) 126 | logging.info(f"请求URL: {flow.request.pretty_url}") 127 | logging.info(f"请求方法: {flow.request.method}") 128 | logging.info(f"Content-Type: {content_type}") 129 | 130 | # 显示原始请求数据包 131 | logging.info(f"原始请求数据包: {flow.request.content.decode('utf-8')}") 132 | 133 | modified = False 134 | if "application/json" in content_type: 135 | json_data = json.loads(flow.request.content) 136 | json_data, modified = self.process_json_data(json_data) 137 | if modified: 138 | flow.request.content = json.dumps(json_data).encode('utf-8') 139 | 140 | elif "application/x-www-form-urlencoded" in content_type: 141 | form_data = flow.request.content.decode('utf-8') 142 | new_content, modified = self.process_form_data(form_data) 143 | if modified: 144 | flow.request.content = new_content.encode('utf-8') 145 | 146 | if modified: 147 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 148 | logging.info("\n解密后的请求数据包:") 149 | logging.info(f"{flow.request.content.decode('utf-8')}") 150 | 151 | logging.info("=" * 50) 152 | 153 | except Exception as e: 154 | logging.error(f"处理请求失败: {e}") 155 | import traceback 156 | logging.error(traceback.format_exc()) 157 | 158 | 159 | # 获取解密配置 160 | decryption_fields, key, iv = get_decryption_fields() 161 | 162 | # 注册插件 163 | addons = [DesDecryptInterceptor(decryption_fields, key, iv)] 164 | -------------------------------------------------------------------------------- /src/scripts/decryptTools/private.pem: -------------------------------------------------------------------------------- 1 | MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKt+pi/bvygO+t6iFl5H5QyI1IkLYUbi7x1I0L+GPzyXDt5QtA6K5Sexnh6Kd54U6q5dySOGSHUAmx3zv43PVlAHrV1jc2ZVHlOT7bAf+Q12JUKhGttQuzb1OazXsjKtllT1ZAVBsHEL+DqfnPCnpJP+yIZF8cDBVVur6JxxB92nAgMBAAECgYAghb2lcNKBGcooo2uDiLXe2SoZLT/O7iVzk8YGtEJUzr7imUJ0SZHoo639U7wYjhXtaFrHMmWWTr2cAggvMAVJi5fZYYJLbYdc8O5QCKi6PzV2J2NxYyuABL5yarvy4Ji0twnDjlqBYqrjOsxJbeMv58CHLKqduIZuxppGGOoRQQJBANTV3JEg6xJdPXsF9ztOf03BNkvpibuUSNbTssTdzEtLMQW7zd5y1qTCwUbf+e2UsRIYPn5DwOlTu8SaE97Zz8ECQQDORm7szA0WL1OTYob0U1NSSFDn8Jg7FyX5md6ndL3KNTKBDBfe3hNpauLi01lTMbO3MoriOWsFiN++6dZAdwdnAkEAq6PcwN1/Ncwj7Lae7yEa4SXUF9w6yx+GrlkDbmhAfOginLEcES0jlLPLEtFFySeEtUb//uu9A24XmzF2nN2jAQJABgL7fJ89ymW6s9LtR/WdugotgXT7ms1D6BBZ8ttuJJSEUkp975rdSfc5gY7TTZ9nM3GfppQx0El66994xQwzBQJAct1HPeCVROxyEHNwsiRH9wqR5P4B59Mo1714R7ozsdTpVx8FWmqi+OQIJt+IizYgRyQ09qORAFei9AHeQtxKiw== -------------------------------------------------------------------------------- /src/scripts/decryptTools/rsa_private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 1 3 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /src/scripts/decryptTools/rsa_public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | 1 3 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /src/scripts/encryptTools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__init__.py -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/aes.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/aes.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/aes_cbc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/aes_cbc.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/aes_ecb.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/aes_ecb.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/base64.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/base64.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/des3_cbc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/des3_cbc.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/des_cbc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/des_cbc.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/md5.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/md5.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/rsa.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/rsa.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/sha1.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/sha1.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/sha256.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/sha256.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/sha384.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/sha384.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/__pycache__/sha512.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/encryptTools/__pycache__/sha512.cpython-39.pyc -------------------------------------------------------------------------------- /src/scripts/encryptTools/aes_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | AES-CBC 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s aes_cbc.py --ssl-insecure field=password key=1234567890123456 iv=1234567890123456 6 | mitmdump -p 8888 -s aes_cbc.py --ssl-insecure field=password,username key=1234567890123456 iv=1234567890123456 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s aes_cbc.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field: 单个加密字段或多个加密字段,用逗号分隔 13 | key: AES密钥,必须是16字节(128位)、24字节(192位)或32字节(256位) 14 | iv: 初始化向量,必须是16字节 15 | 16 | 注意事项: 17 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 18 | 2. 支持单个或多个字段加密 19 | 3. AES密钥必须是16/24/32字节长度 20 | 4. IV必须是16字节长度 21 | 5. 加密结果使用 Base64 编码 22 | """ 23 | 24 | import sys 25 | import os 26 | from mitmproxy import http 27 | from Crypto.Cipher import AES 28 | from Crypto.Util.Padding import pad 29 | import base64 30 | import logging 31 | import json 32 | from urllib.parse import parse_qs, urlencode 33 | 34 | # 配置日志记录 35 | logging.basicConfig( 36 | level=logging.INFO, 37 | format='%(asctime)s - %(levelname)s - %(message)s' 38 | ) 39 | 40 | def get_encryption_fields(): 41 | """从命令行参数获取加密配置""" 42 | all_args = sys.argv 43 | encryption_fields = [] 44 | key = None 45 | iv = None 46 | 47 | for arg in all_args: 48 | if not arg.startswith('-'): 49 | if 'key=' in arg: 50 | key = arg.split('=')[1] 51 | elif 'iv=' in arg: 52 | iv = arg.split('=')[1] 53 | elif 'field=' in arg: 54 | fields = arg.split('=', 1)[1].strip().split(',') 55 | encryption_fields.extend([field.strip() for field in fields if field.strip()]) 56 | else: 57 | try: 58 | float(arg) 59 | except ValueError: 60 | continue 61 | 62 | if not encryption_fields: 63 | encryption_fields = ['password'] 64 | 65 | 66 | logging.info(f"需要加密的字段: {encryption_fields}") 67 | return encryption_fields, key, iv 68 | 69 | # 获取加密配置 70 | encryption_fields, key, iv = get_encryption_fields() 71 | 72 | class AesCbcEncryptInterceptor: 73 | """AES-CBC 加密拦截器""" 74 | 75 | def __init__(self, encryption_fields, key, iv): 76 | self.encryption_fields = encryption_fields 77 | self.key = key.encode('utf-8') 78 | self.iv = iv.encode('utf-8') 79 | logging.info("成功初始化AES-CBC加密器") 80 | 81 | def encrypt_value(self, plain_text: str) -> str: 82 | """加密单个值""" 83 | try: 84 | cipher = AES.new(self.key, AES.MODE_CBC, self.iv) 85 | padded_data = pad(plain_text.encode('utf-8'), AES.block_size) 86 | encrypted_data = cipher.encrypt(padded_data) 87 | return base64.b64encode(encrypted_data).decode('utf-8') 88 | except Exception as e: 89 | logging.error(f"加密失败: {e}") 90 | return plain_text 91 | 92 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 93 | """处理JSON数据""" 94 | modified = False 95 | for field in self.encryption_fields: 96 | if field in json_data: 97 | try: 98 | # 如果是字典,先转换为 JSON 字符串 99 | if isinstance(json_data[field], (dict, list)): 100 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 101 | else: 102 | plain_text = str(json_data[field]) 103 | 104 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 105 | json_data[field] = self.encrypt_value(plain_text) 106 | modified = True 107 | logging.info(f"JSON字段 {field} 加密完成") 108 | except Exception as e: 109 | logging.error(f"加密字段 {field} 失败: {e}") 110 | return json_data, modified 111 | 112 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 113 | """处理表单数据""" 114 | params = parse_qs(form_data, keep_blank_values=True) 115 | modified = False 116 | 117 | for field in self.encryption_fields: 118 | if field in params: 119 | try: 120 | values = params[field] 121 | if isinstance(values, list): 122 | encrypted_values = [] 123 | for value in values: 124 | logging.info(f"表单字段 {field} 待加密值: {value}") 125 | encrypted_values.append(self.encrypt_value(value)) 126 | params[field] = encrypted_values 127 | else: 128 | logging.info(f"表单字段 {field} 待加密值: {values}") 129 | params[field] = self.encrypt_value(values) 130 | modified = True 131 | logging.info(f"表单字段 {field} 加密完成") 132 | except Exception as e: 133 | logging.error(f"加密字段 {field} 失败: {e}") 134 | 135 | for key in params: 136 | if isinstance(params[key], list) and len(params[key]) == 1: 137 | params[key] = params[key][0] 138 | 139 | return urlencode(params), modified 140 | 141 | def request(self, flow: http.HTTPFlow) -> None: 142 | """处理请求""" 143 | try: 144 | content_type = flow.request.headers.get("Content-Type", "") 145 | logging.info("=" * 50) 146 | logging.info(f"请求URL: {flow.request.pretty_url}") 147 | logging.info(f"请求方法: {flow.request.method}") 148 | logging.info(f"Content-Type: {content_type}") 149 | 150 | modified = False 151 | if "application/json" in content_type: 152 | json_data = json.loads(flow.request.content) 153 | json_data, modified = self.process_json_data(json_data) 154 | if modified: 155 | new_content = json.dumps(json_data, separators=(',', ':')) 156 | flow.request.content = new_content.encode('utf-8') 157 | 158 | elif "application/x-www-form-urlencoded" in content_type: 159 | form_data = flow.request.content.decode('utf-8') 160 | new_content, modified = self.process_form_data(form_data) 161 | if modified: 162 | flow.request.content = new_content.encode('utf-8') 163 | 164 | if modified: 165 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 166 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 167 | 168 | logging.info("=" * 50) 169 | 170 | except Exception as e: 171 | logging.error(f"处理请求失败: {e}") 172 | import traceback 173 | logging.error(traceback.format_exc()) 174 | 175 | # 注册插件 176 | addons = [AesCbcEncryptInterceptor(encryption_fields, key, iv)] -------------------------------------------------------------------------------- /src/scripts/encryptTools/aes_ecb.py: -------------------------------------------------------------------------------- 1 | """ 2 | AES-ECB 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s aes_ecb.py --ssl-insecure field=password key=1234567890123456 6 | mitmdump -p 8888 -s aes_ecb.py --ssl-insecure field=password,username key=1234567890123456 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s aes_ecb.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field=password: 单个加密字段 13 | field=password,username: 多个加密字段,用逗号分隔 14 | key=1234567890123456: AES密钥,必须是16/24/32字节 15 | 16 | 注意事项: 17 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 18 | 2. 支持单个或多个字段加密 19 | 3. AES密钥必须是16/24/32字节长度 20 | 4. 加密结果使用 Base64 编码 21 | """ 22 | 23 | import sys 24 | import os 25 | from mitmproxy import http 26 | from Crypto.Cipher import AES 27 | from Crypto.Util.Padding import pad 28 | import base64 29 | import logging 30 | import json 31 | from urllib.parse import parse_qs, urlencode 32 | 33 | # 配置日志记录 34 | logging.basicConfig( 35 | level=logging.INFO, 36 | format='%(asctime)s - %(levelname)s - %(message)s' 37 | ) 38 | 39 | def get_encryption_fields(): 40 | """ 41 | 从命令行参数获取加密配置 42 | 43 | Returns: 44 | tuple: (加密字段列表, 密钥) 45 | """ 46 | all_args = sys.argv 47 | encryption_fields = [] 48 | key = None 49 | 50 | # 遍历所有参数 51 | for arg in all_args: 52 | if arg.startswith('field='): 53 | fields = arg.replace('field=', '') 54 | encryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 55 | elif arg.startswith('key='): 56 | key = arg.replace('key=', '') 57 | 58 | 59 | logging.info(f"需要加密的字段: {encryption_fields}") 60 | return encryption_fields, key 61 | 62 | # 获取加密配置 63 | encryption_fields, key = get_encryption_fields() 64 | 65 | class AesEcbEncryptInterceptor: 66 | """AES-ECB 加密拦截器""" 67 | 68 | def __init__(self, encryption_fields, key): 69 | """ 70 | 初始化加密器 71 | 72 | Args: 73 | encryption_fields (list): 需要加密的字段名称列表 74 | key (str): AES密钥,16/24/32字节 75 | """ 76 | self.encryption_fields = encryption_fields 77 | self.key = key.encode('utf-8') 78 | logging.info("成功初始化AES-ECB加密器") 79 | 80 | def encrypt_value(self, plain_text: str) -> str: 81 | """ 82 | 加密单个值 83 | 84 | Args: 85 | plain_text (str): 待加密的文本 86 | 87 | Returns: 88 | str: Base64编码的加密结果 89 | """ 90 | try: 91 | cipher = AES.new(self.key, AES.MODE_ECB) 92 | padded_data = pad(plain_text.encode('utf-8'), AES.block_size) 93 | encrypted_data = cipher.encrypt(padded_data) 94 | return base64.b64encode(encrypted_data).decode('utf-8') 95 | except Exception as e: 96 | logging.error(f"加密失败: {e}") 97 | return plain_text 98 | 99 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 100 | """处理JSON数据""" 101 | modified = False 102 | for field in self.encryption_fields: 103 | if field in json_data: 104 | try: 105 | # 将字段值转换为标准 JSON 字符串(使用双引号) 106 | if isinstance(json_data[field], (dict, list)): 107 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 108 | else: 109 | plain_text = str(json_data[field]) 110 | 111 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 112 | json_data[field] = self.encrypt_value(plain_text) 113 | modified = True 114 | logging.info(f"JSON字段 {field} 加密完成") 115 | except Exception as e: 116 | logging.error(f"加密字段 {field} 失败: {e}") 117 | return json_data, modified 118 | 119 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 120 | """处理表单数据""" 121 | params = parse_qs(form_data, keep_blank_values=True) 122 | modified = False 123 | 124 | for field in self.encryption_fields: 125 | if field in params: 126 | try: 127 | values = params[field] 128 | if isinstance(values, list): 129 | encrypted_values = [] 130 | for value in values: 131 | logging.info(f"表单字段 {field} 待加密值: {value}") 132 | encrypted_values.append(self.encrypt_value(value)) 133 | params[field] = encrypted_values 134 | else: 135 | logging.info(f"表单字段 {field} 待加密值: {values}") 136 | params[field] = self.encrypt_value(values) 137 | modified = True 138 | logging.info(f"表单字段 {field} 加密完成") 139 | except Exception as e: 140 | logging.error(f"加密字段 {field} 失败: {e}") 141 | 142 | for key in params: 143 | if isinstance(params[key], list) and len(params[key]) == 1: 144 | params[key] = params[key][0] 145 | 146 | return urlencode(params), modified 147 | 148 | def request(self, flow: http.HTTPFlow) -> None: 149 | """ 150 | 处理请求 151 | 152 | Args: 153 | flow: mitmproxy的请求流对象 154 | """ 155 | try: 156 | content_type = flow.request.headers.get("Content-Type", "") 157 | logging.info("=" * 50) 158 | logging.info(f"请求URL: {flow.request.pretty_url}") 159 | logging.info(f"请求方法: {flow.request.method}") 160 | logging.info(f"Content-Type: {content_type}") 161 | 162 | modified = False 163 | if "application/json" in content_type: 164 | json_data = json.loads(flow.request.content) 165 | json_data, modified = self.process_json_data(json_data) 166 | if modified: 167 | new_content = json.dumps(json_data, separators=(',', ':')) 168 | flow.request.content = new_content.encode('utf-8') 169 | 170 | elif "application/x-www-form-urlencoded" in content_type: 171 | form_data = flow.request.content.decode('utf-8') 172 | new_content, modified = self.process_form_data(form_data) 173 | if modified: 174 | flow.request.content = new_content.encode('utf-8') 175 | 176 | if modified: 177 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 178 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 179 | 180 | logging.info("=" * 50) 181 | 182 | except Exception as e: 183 | logging.error(f"处理请求失败: {e}") 184 | import traceback 185 | logging.error(traceback.format_exc()) 186 | 187 | # 注册插件 188 | addons = [AesEcbEncryptInterceptor(encryption_fields, key)] -------------------------------------------------------------------------------- /src/scripts/encryptTools/base64.py: -------------------------------------------------------------------------------- 1 | """ 2 | Base64 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s base64.py --ssl-insecure field=password 6 | mitmdump -p 8888 -s base64.py --ssl-insecure field=password,username 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s base64.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | password: 单个加密字段 13 | password,username: 多个加密字段,用逗号分隔 14 | 15 | 注意事项: 16 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 17 | 2. 支持单个或多个字段加密 18 | 3. 加密结果为标准Base64编码 19 | """ 20 | 21 | import sys 22 | from mitmproxy import http 23 | import base64 24 | import logging 25 | import json 26 | from urllib.parse import parse_qs, urlencode 27 | 28 | # 配置日志记录 29 | logging.basicConfig( 30 | level=logging.INFO, 31 | format='%(asctime)s - %(levelname)s - %(message)s' 32 | ) 33 | 34 | def get_encryption_fields(): 35 | """ 36 | 从命令行参数获取加密配置 37 | 38 | Returns: 39 | list: 需要加密的字段名称列表 40 | """ 41 | all_args = sys.argv 42 | encryption_fields = [] 43 | 44 | # 遍历所有参数 45 | for arg in all_args: 46 | if arg.startswith('field='): 47 | # 提取 field= 后面的值 48 | fields = arg.replace('field=', '') 49 | encryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 50 | break 51 | 52 | logging.info(f"需要加密的字段: {encryption_fields}") 53 | return encryption_fields 54 | 55 | # 获取加密配置 56 | encryption_fields = get_encryption_fields() 57 | 58 | class Base64EncryptInterceptor: 59 | """Base64 加密拦截器""" 60 | 61 | def __init__(self, encryption_fields): 62 | """ 63 | 初始化加密器 64 | 65 | Args: 66 | encryption_fields (list): 需要加密的字段名称列表 67 | """ 68 | self.encryption_fields = encryption_fields 69 | logging.info("成功初始化Base64加密器") 70 | 71 | def encrypt_value(self, plain_text: str) -> str: 72 | """ 73 | 加密单个值 74 | 75 | Args: 76 | plain_text (str): 待加密的文本 77 | 78 | Returns: 79 | str: Base64编码结果 80 | """ 81 | try: 82 | return base64.b64encode(plain_text.encode('utf-8')).decode('utf-8') 83 | except Exception as e: 84 | logging.error(f"加密失败: {e}") 85 | return plain_text 86 | 87 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 88 | """处理JSON数据""" 89 | modified = False 90 | for field in self.encryption_fields: 91 | if field in json_data: 92 | try: 93 | plain_text = str(json_data[field]) 94 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 95 | json_data[field] = self.encrypt_value(plain_text) 96 | modified = True 97 | logging.info(f"JSON字段 {field} 加密完成") 98 | except Exception as e: 99 | logging.error(f"加密字段 {field} 失败: {e}") 100 | return json_data, modified 101 | 102 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 103 | """处理表单数据""" 104 | params = parse_qs(form_data, keep_blank_values=True) 105 | modified = False 106 | 107 | for field in self.encryption_fields: 108 | if field in params: 109 | try: 110 | values = params[field] 111 | if isinstance(values, list): 112 | encrypted_values = [] 113 | for value in values: 114 | logging.info(f"表单字段 {field} 待加密值: {value}") 115 | encrypted_values.append(self.encrypt_value(value)) 116 | params[field] = encrypted_values 117 | else: 118 | logging.info(f"表单字段 {field} 待加密值: {values}") 119 | params[field] = self.encrypt_value(values) 120 | modified = True 121 | logging.info(f"表单字段 {field} 加密完成") 122 | except Exception as e: 123 | logging.error(f"加密字段 {field} 失败: {e}") 124 | 125 | for key in params: 126 | if isinstance(params[key], list) and len(params[key]) == 1: 127 | params[key] = params[key][0] 128 | 129 | return urlencode(params), modified 130 | 131 | def request(self, flow: http.HTTPFlow) -> None: 132 | """ 133 | 处理请求 134 | 135 | Args: 136 | flow: mitmproxy的请求流对象 137 | """ 138 | try: 139 | content_type = flow.request.headers.get("Content-Type", "") 140 | logging.info("=" * 50) 141 | logging.info(f"请求URL: {flow.request.pretty_url}") 142 | logging.info(f"请求方法: {flow.request.method}") 143 | logging.info(f"Content-Type: {content_type}") 144 | 145 | modified = False 146 | if "application/json" in content_type: 147 | json_data = json.loads(flow.request.content) 148 | json_data, modified = self.process_json_data(json_data) 149 | if modified: 150 | new_content = json.dumps(json_data, separators=(',', ':')) 151 | flow.request.content = new_content.encode('utf-8') 152 | 153 | elif "application/x-www-form-urlencoded" in content_type: 154 | form_data = flow.request.content.decode('utf-8') 155 | new_content, modified = self.process_form_data(form_data) 156 | if modified: 157 | flow.request.content = new_content.encode('utf-8') 158 | 159 | if modified: 160 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 161 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 162 | 163 | logging.info("=" * 50) 164 | 165 | except Exception as e: 166 | logging.error(f"处理请求失败: {e}") 167 | import traceback 168 | logging.error(traceback.format_exc()) 169 | 170 | # 注册插件 171 | addons = [Base64EncryptInterceptor(encryption_fields)] 172 | -------------------------------------------------------------------------------- /src/scripts/encryptTools/des3_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3DES-CBC 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s des3_cbc.py --ssl-insecure field=data key=123456789012345678901234 iv=12345678 6 | 7 | 参数说明: 8 | -p 8888: 监听端口 9 | -s des3_cbc.py: 指定脚本文件 10 | --ssl-insecure: 忽略 SSL 证书验证 11 | field: 需要加密的字段名称,多个字段用逗号分隔 12 | key: 3DES密钥,必须是16字节(128位)或24字节(192位) 13 | iv: 初始化向量,必须是8字节长度 14 | 15 | 注意事项: 16 | 1. 3DES密钥必须是16字节或24字节长度 17 | 2. 支持 application/json 和 application/x-www-form-urlencoded 格式 18 | 3. 加密结果使用 Base64 编码 19 | """ 20 | 21 | import sys 22 | from mitmproxy import http 23 | from Crypto.Cipher import DES3 24 | from Crypto.Util.Padding import pad 25 | import base64 26 | import logging 27 | import json 28 | from urllib.parse import parse_qs, urlencode 29 | import traceback 30 | 31 | # 配置日志记录 32 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 33 | 34 | 35 | def get_encryption_fields(): 36 | """从命令行参数获取加密配置""" 37 | all_args = sys.argv 38 | encryption_fields = [] 39 | key = None 40 | iv = None 41 | 42 | for arg in all_args: 43 | if not arg.startswith('-'): 44 | if 'key=' in arg: 45 | key = arg.split('=')[1] 46 | elif 'iv=' in arg: 47 | iv = arg.split('=')[1] 48 | elif 'field=' in arg: 49 | fields = arg.split('=', 1)[1].strip().split(',') 50 | encryption_fields.extend([field.strip() for field in fields if field.strip()]) 51 | else: 52 | try: 53 | float(arg) 54 | except ValueError: 55 | continue 56 | 57 | if not encryption_fields: 58 | encryption_fields = ['data'] 59 | 60 | logging.info(f"需要加密的字段: {encryption_fields}") 61 | return encryption_fields, key, iv 62 | 63 | 64 | # 获取加密配置 65 | encryption_fields, key, iv = get_encryption_fields() 66 | 67 | 68 | class Des3EncryptInterceptor: 69 | """3DES-CBC 加密拦截器""" 70 | 71 | def __init__(self, encryption_fields, key, iv): 72 | self.encryption_fields = encryption_fields 73 | self.key = key.encode('utf-8') 74 | self.iv = iv.encode('utf-8') 75 | logging.info("成功初始化3DES-CBC加密器") 76 | 77 | def encrypt_value(self, plain_text: str) -> str: 78 | """加密单个值""" 79 | try: 80 | # 使用与 CryptoJS.TripleDES 相同的加密方式 81 | cipher = DES3.new( 82 | self.key, 83 | DES3.MODE_CBC, 84 | self.iv, 85 | padmode=None # 使用手动填充 86 | ) 87 | 88 | # 手动实现 PKCS7 填充 89 | block_size = DES3.block_size 90 | padding_length = block_size - (len(plain_text.encode()) % block_size) 91 | padded_data = plain_text.encode() + bytes([padding_length] * padding_length) 92 | 93 | # 加密 94 | encrypted_data = cipher.encrypt(padded_data) 95 | return base64.b64encode(encrypted_data).decode('utf-8') 96 | except Exception as e: 97 | logging.error(f"加密失败: {e}") 98 | return plain_text 99 | 100 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 101 | """处理JSON数据""" 102 | modified = False 103 | for field in self.encryption_fields: 104 | if field in json_data: 105 | try: 106 | # 将字段值转换为标准 JSON 字符串(使用双引号) 107 | if isinstance(json_data[field], (dict, list)): 108 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 109 | else: 110 | plain_text = str(json_data[field]) 111 | 112 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 113 | json_data[field] = self.encrypt_value(plain_text) 114 | modified = True 115 | logging.info(f"JSON字段 {field} 加密完成") 116 | except Exception as e: 117 | logging.error(f"加密字段 {field} 失败: {e}") 118 | logging.error(traceback.format_exc()) 119 | return json_data, modified 120 | 121 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 122 | """处理表单数据""" 123 | params = parse_qs(form_data, keep_blank_values=True) 124 | modified = False 125 | 126 | for field in self.encryption_fields: 127 | if field in params: 128 | try: 129 | values = params[field] 130 | if isinstance(values, list): 131 | encrypted_values = [] 132 | for value in values: 133 | logging.info(f"表单字段 {field} 待加密值: {value}") 134 | encrypted_values.append(self.encrypt_value(value)) 135 | params[field] = encrypted_values 136 | else: 137 | logging.info(f"表单字段 {field} 待加密值: {values}") 138 | params[field] = self.encrypt_value(values) 139 | modified = True 140 | logging.info(f"表单字段 {field} 加密完成") 141 | except Exception as e: 142 | logging.error(f"加密字段 {field} 失败: {e}") 143 | 144 | for key in params: 145 | if isinstance(params[key], list) and len(params[key]) == 1: 146 | params[key] = params[key][0] 147 | 148 | return urlencode(params), modified 149 | 150 | def request(self, flow: http.HTTPFlow) -> None: 151 | """处理请求""" 152 | try: 153 | content_type = flow.request.headers.get("Content-Type", "") 154 | logging.info("=" * 50) 155 | logging.info(f"请求URL: {flow.request.pretty_url}") 156 | logging.info(f"请求方法: {flow.request.method}") 157 | logging.info(f"Content-Type: {content_type}") 158 | 159 | modified = False 160 | if "application/json" in content_type: 161 | json_data = json.loads(flow.request.content) 162 | json_data, modified = self.process_json_data(json_data) 163 | if modified: 164 | new_content = json.dumps(json_data, separators=(',', ':')) 165 | flow.request.content = new_content.encode('utf-8') 166 | 167 | elif "application/x-www-form-urlencoded" in content_type: 168 | form_data = flow.request.content.decode('utf-8') 169 | new_content, modified = self.process_form_data(form_data) 170 | if modified: 171 | flow.request.content = new_content.encode('utf-8') 172 | 173 | if modified: 174 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 175 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 176 | 177 | logging.info("=" * 50) 178 | 179 | except Exception as e: 180 | logging.error(f"处理请求失败: {e}") 181 | import traceback 182 | logging.error(traceback.format_exc()) 183 | 184 | 185 | # 注册插件 186 | addons = [Des3EncryptInterceptor(encryption_fields, key, iv)] 187 | -------------------------------------------------------------------------------- /src/scripts/encryptTools/des_cbc.py: -------------------------------------------------------------------------------- 1 | """ 2 | DES-CBC 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s des_cbc.py --ssl-insecure field=password key=12345678 iv=12345678 6 | mitmdump -p 8888 -s des_cbc.py --ssl-insecure field=password,username key=12345678 iv=12345678 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s des_cbc.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field: 单个加密字段或多个加密字段,用逗号分隔 13 | key: DES密钥,必须是8字节长度 14 | iv: 初始化向量,必须是8字节长度 15 | 16 | 注意事项: 17 | 1. DES密钥和IV必须是8字节长度 18 | 2. 支持 application/json 和 application/x-www-form-urlencoded 格式 19 | 3. 加密结果使用 Base64 编码 20 | """ 21 | 22 | import sys 23 | from mitmproxy import http 24 | from Crypto.Cipher import DES 25 | from Crypto.Util.Padding import pad 26 | import base64 27 | import logging 28 | import json 29 | from urllib.parse import parse_qs, urlencode 30 | 31 | # 配置日志记录 32 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 33 | 34 | def get_encryption_fields(): 35 | """从命令行参数获取加密配置""" 36 | all_args = sys.argv 37 | encryption_fields = [] 38 | key = None 39 | iv = None 40 | 41 | for arg in all_args: 42 | if not arg.startswith('-'): 43 | if 'key=' in arg: 44 | key = arg.split('=')[1] 45 | elif 'iv=' in arg: 46 | iv = arg.split('=')[1] 47 | elif 'field=' in arg: 48 | fields = arg.split('=', 1)[1].strip().split(',') 49 | encryption_fields.extend([field.strip() for field in fields if field.strip()]) 50 | else: 51 | try: 52 | float(arg) 53 | except ValueError: 54 | continue 55 | 56 | if not encryption_fields: 57 | encryption_fields = ['data'] 58 | 59 | logging.info(f"需要加密的字段: {encryption_fields}") 60 | return encryption_fields, key, iv 61 | 62 | # 获取加密配置 63 | encryption_fields, key, iv = get_encryption_fields() 64 | 65 | class DesEncryptInterceptor: 66 | """DES-CBC 加密拦截器""" 67 | 68 | def __init__(self, encryption_fields, key, iv): 69 | self.encryption_fields = encryption_fields 70 | self.key = key.encode('utf-8') 71 | self.iv = iv.encode('utf-8') 72 | logging.info("成功初始化DES-CBC加密器") 73 | 74 | def encrypt_value(self, plain_text: str) -> str: 75 | """加密单个值""" 76 | try: 77 | cipher = DES.new(self.key, DES.MODE_CBC, self.iv) 78 | padded_data = pad(plain_text.encode('utf-8'), DES.block_size) 79 | encrypted_data = cipher.encrypt(padded_data) 80 | return base64.b64encode(encrypted_data).decode('utf-8') 81 | except Exception as e: 82 | logging.error(f"加密失败: {e}") 83 | return plain_text 84 | 85 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 86 | """处理JSON数据""" 87 | modified = False 88 | for field in self.encryption_fields: 89 | if field in json_data: 90 | try: 91 | # 将字段值转换为标准 JSON 字符串(使用双引号) 92 | if isinstance(json_data[field], (dict, list)): 93 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 94 | else: 95 | plain_text = str(json_data[field]) 96 | 97 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 98 | json_data[field] = self.encrypt_value(plain_text) 99 | modified = True 100 | logging.info(f"JSON字段 {field} 加密完成") 101 | except Exception as e: 102 | logging.error(f"加密字段 {field} 失败: {e}") 103 | return json_data, modified 104 | 105 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 106 | """处理表单数据""" 107 | params = parse_qs(form_data, keep_blank_values=True) 108 | modified = False 109 | 110 | for field in self.encryption_fields: 111 | if field in params: 112 | try: 113 | values = params[field] 114 | if isinstance(values, list): 115 | encrypted_values = [] 116 | for value in values: 117 | logging.info(f"表单字段 {field} 待加密值: {value}") 118 | encrypted_values.append(self.encrypt_value(value)) 119 | params[field] = encrypted_values 120 | else: 121 | logging.info(f"表单字段 {field} 待加密值: {values}") 122 | params[field] = self.encrypt_value(values) 123 | modified = True 124 | logging.info(f"表单字段 {field} 加密完成") 125 | except Exception as e: 126 | logging.error(f"加密字段 {field} 失败: {e}") 127 | 128 | for key in params: 129 | if isinstance(params[key], list) and len(params[key]) == 1: 130 | params[key] = params[key][0] 131 | 132 | return urlencode(params), modified 133 | 134 | def request(self, flow: http.HTTPFlow) -> None: 135 | """处理请求""" 136 | try: 137 | content_type = flow.request.headers.get("Content-Type", "") 138 | logging.info("=" * 50) 139 | logging.info(f"请求URL: {flow.request.pretty_url}") 140 | logging.info(f"请求方法: {flow.request.method}") 141 | logging.info(f"Content-Type: {content_type}") 142 | 143 | modified = False 144 | if "application/json" in content_type: 145 | json_data = json.loads(flow.request.content) 146 | json_data, modified = self.process_json_data(json_data) 147 | if modified: 148 | new_content = json.dumps(json_data, separators=(',', ':')) 149 | flow.request.content = new_content.encode('utf-8') 150 | 151 | elif "application/x-www-form-urlencoded" in content_type: 152 | form_data = flow.request.content.decode('utf-8') 153 | new_content, modified = self.process_form_data(form_data) 154 | if modified: 155 | flow.request.content = new_content.encode('utf-8') 156 | 157 | if modified: 158 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 159 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 160 | 161 | logging.info("=" * 50) 162 | 163 | except Exception as e: 164 | logging.error(f"处理请求失败: {e}") 165 | import traceback 166 | logging.error(traceback.format_exc()) 167 | 168 | # 注册插件 169 | addons = [DesEncryptInterceptor(encryption_fields, key, iv)] -------------------------------------------------------------------------------- /src/scripts/encryptTools/md5.py: -------------------------------------------------------------------------------- 1 | """ 2 | MD5 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s md5.py --ssl-insecure password 6 | mitmdump -p 8888 -s md5.py --ssl-insecure password,username,token 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s md5.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | password: 单个加密字段 13 | password,username,token: 多个加密字段,用逗号分隔 14 | 15 | 注意事项: 16 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 17 | 2. 支持单个或多个字段加密 18 | 3. MD5加密结果为32位小写字符串 19 | """ 20 | 21 | import sys 22 | import os 23 | from mitmproxy import http 24 | import hashlib 25 | import logging 26 | import json 27 | from urllib.parse import parse_qs, urlencode 28 | 29 | # 修改导入路径的设置 30 | current_dir = os.path.dirname(os.path.abspath(__file__)) 31 | project_root = os.path.dirname(os.path.dirname(os.path.dirname(current_dir))) 32 | sys.path.insert(0, project_root) 33 | 34 | 35 | # 配置日志记录 36 | logging.basicConfig( 37 | level=logging.INFO, 38 | format='%(asctime)s - %(levelname)s - %(message)s' 39 | ) 40 | 41 | def get_encryption_fields(): 42 | """从命令行参数获取加密配置""" 43 | all_args = sys.argv 44 | encryption_fields = [] 45 | 46 | for arg in all_args: 47 | if not arg.startswith('-'): 48 | if 'field=' in arg: 49 | fields = arg.split('=', 1)[1].strip().split(',') 50 | encryption_fields.extend([field.strip() for field in fields if field.strip()]) 51 | else: 52 | try: 53 | float(arg) 54 | except ValueError: 55 | continue 56 | 57 | if not encryption_fields: 58 | encryption_fields = ['password'] # 默认加密字段 59 | 60 | logging.info(f"需要加密的字段: {encryption_fields}") 61 | return encryption_fields 62 | 63 | encryption_fields = get_encryption_fields() 64 | 65 | class MD5EncryptInterceptor: 66 | """MD5 加密拦截器""" 67 | 68 | def __init__(self, field_names): 69 | """ 70 | 初始化加密器 71 | 72 | Args: 73 | field_names (list): 需要加密的字段名称列表 74 | """ 75 | self.field_names = field_names 76 | logging.info(f"加密目标字段: {self.field_names}") 77 | 78 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 79 | """处理JSON数据""" 80 | modified = False 81 | for field in self.field_names: 82 | if field in json_data: 83 | try: 84 | # 将字段值转换为标准 JSON 字符串(使用双引号) 85 | if isinstance(json_data[field], (dict, list)): 86 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 87 | else: 88 | plain_text = str(json_data[field]) 89 | 90 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 91 | json_data[field] = self.encrypt_value(plain_text) 92 | modified = True 93 | logging.info(f"JSON字段 {field} 加密完成") 94 | except Exception as e: 95 | logging.error(f"加密字段 {field} 失败: {e}") 96 | return json_data, modified 97 | 98 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 99 | """处理表单数据""" 100 | params = parse_qs(form_data, keep_blank_values=True) 101 | modified = False 102 | 103 | for field in self.field_names: 104 | if field in params: 105 | try: 106 | values = params[field] 107 | if isinstance(values, list): 108 | encrypted_values = [] 109 | for value in values: 110 | logging.info(f"表单字段 {field} 待加密值: {value}") 111 | md5_hash = hashlib.md5() 112 | md5_hash.update(value.encode('utf-8')) 113 | encrypted_values.append(md5_hash.hexdigest()) 114 | params[field] = encrypted_values 115 | else: 116 | logging.info(f"表单字段 {field} 待加密值: {values}") 117 | md5_hash = hashlib.md5() 118 | md5_hash.update(values.encode('utf-8')) 119 | params[field] = md5_hash.hexdigest() 120 | modified = True 121 | logging.info(f"表单字段 {field} 加密完成") 122 | except Exception as e: 123 | logging.error(f"加密字段 {field} 失败: {e}") 124 | 125 | for key in params: 126 | if isinstance(params[key], list) and len(params[key]) == 1: 127 | params[key] = params[key][0] 128 | 129 | return urlencode(params), modified 130 | 131 | def request(self, flow: http.HTTPFlow) -> None: 132 | """ 133 | 处理请求 134 | 135 | Args: 136 | flow: mitmproxy的请求流对象 137 | """ 138 | try: 139 | content_type = flow.request.headers.get("Content-Type", "") 140 | logging.info("=" * 50) 141 | logging.info(f"请求URL: {flow.request.pretty_url}") 142 | logging.info(f"请求方法: {flow.request.method}") 143 | logging.info(f"Content-Type: {content_type}") 144 | 145 | modified = False 146 | if "application/json" in content_type: 147 | json_data = json.loads(flow.request.content) 148 | json_data, modified = self.process_json_data(json_data) 149 | if modified: 150 | new_content = json.dumps(json_data, separators=(',', ':')) 151 | flow.request.content = new_content.encode('utf-8') 152 | 153 | elif "application/x-www-form-urlencoded" in content_type: 154 | form_data = flow.request.content.decode('utf-8') 155 | new_content, modified = self.process_form_data(form_data) 156 | if modified: 157 | flow.request.content = new_content.encode('utf-8') 158 | 159 | if modified: 160 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 161 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 162 | 163 | logging.info("=" * 50) 164 | 165 | except Exception as e: 166 | logging.error(f"处理请求失败: {e}") 167 | import traceback 168 | logging.error(traceback.format_exc()) 169 | 170 | # 注册插件 171 | addons = [MD5EncryptInterceptor(encryption_fields)] 172 | -------------------------------------------------------------------------------- /src/scripts/encryptTools/rsa_private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQC0Llg1bVZhnyslfezwfeOkvnXWq59bDtmQyHvxkP/38Fw8QQXB 3 | fROCgzGc+Te6pOPl6Ye+vQ1rAnisBaP3rMk40i3OpallzVkuwRKydek3V9ufPpZE 4 | EH4eBgInMSDiMsggTWxcI/Lvag6eHjkSc67RTrj96oxj0ipVRqjxW4X6HQIDAQAB 5 | AoGAEE2pOZxdFpQ6aTgNum0Jrhx1uSjqUGj1kr4xSNhf8OVU0zbm+G0C2OpaEOQU 6 | ANVusZ0B5WZh0m700EvqXDzMMCsa9QhKPP4z9Nd09RHdcQtysbSXnWc2VKDYxiqy 7 | bIsnnlHRemCqHzQVqLaoKa0OVGFouunSqKFiVbXZ9bb/aMECQQDhYD97TI5CpHxU 8 | 7tW67uphUD4xoND3v5ENE//9mgjjJsxnNarpYQDcZgPN2DNMSVmBzuItiiTBuLBE 9 | uXDSBoGFAkEAzKn7H7Aa9G6hLfvHBfxVYtOuybqQwxsdXpQ6kH14dH2a+2A2tIw9 10 | M2U4/pNz89nLC0pzWaYwCgNXHsmeBjYtuQJAYxT5U6+Ya1v8/Sny9LfMevPYI+Fb 11 | fU/O6Tz9sfRiK9sGyekiNm/a/Qosafa+tq8YlqTpcrPk7PXRKKWOIAeUMQJAZDqO 12 | eBtHaBNRrfJSqnTD4C0ouTQ7tsDtpibTc3Vu6yWkI50fzVWslyHoQow1yeMME9B3 13 | Ix1HA3BVVweH8yTPSQJBAKY6NQgHEonErU0k7KzYQFncUAwp3k/TztZYVe86WNjk 14 | 3Ans1T2Dexf5w8pu0TStXxrBNI0MjP9OstFUSR8v92o= 15 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /src/scripts/encryptTools/rsa_public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | 3 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /src/scripts/encryptTools/sha1.py: -------------------------------------------------------------------------------- 1 | """ 2 | SHA1 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s sha1.py --ssl-insecure field=password 6 | mitmdump -p 8888 -s sha1.py --ssl-insecure field=password,username 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s sha1.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field=password: 单个加密字段 13 | field=password,username: 多个加密字段,用逗号分隔 14 | 15 | 注意事项: 16 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 17 | 2. 支持单个或多个字段加密 18 | 3. SHA1加密结果为40位小写字符串 19 | """ 20 | 21 | import sys 22 | import os 23 | from mitmproxy import http 24 | import hashlib 25 | import logging 26 | import json 27 | from urllib.parse import parse_qs, urlencode 28 | 29 | # 配置日志记录 30 | logging.basicConfig( 31 | level=logging.INFO, 32 | format='%(asctime)s - %(levelname)s - %(message)s' 33 | ) 34 | 35 | def get_encryption_fields(): 36 | """ 37 | 从命令行参数获取加密配置 38 | 39 | Returns: 40 | list: 需要加密的字段名称列表 41 | """ 42 | all_args = sys.argv 43 | encryption_fields = [] 44 | 45 | # 遍历所有参数 46 | for arg in all_args: 47 | if arg.startswith('field='): 48 | # 提取 field= 后面的值 49 | fields = arg.replace('field=', '') 50 | encryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 51 | break 52 | 53 | logging.info(f"需要加密的字段: {encryption_fields}") 54 | return encryption_fields 55 | 56 | # 获取加密配置 57 | encryption_fields = get_encryption_fields() 58 | 59 | class SHA1EncryptInterceptor: 60 | """SHA1 加密拦截器""" 61 | 62 | def __init__(self, encryption_fields): 63 | """ 64 | 初始化加密器 65 | 66 | Args: 67 | encryption_fields (list): 需要加密的字段名称列表 68 | """ 69 | self.encryption_fields = encryption_fields 70 | logging.info("成功初始化SHA1加密器") 71 | 72 | def encrypt_value(self, plain_text: str) -> str: 73 | """ 74 | 加密单个值 75 | 76 | Args: 77 | plain_text (str): 待加密的文本 78 | 79 | Returns: 80 | str: SHA1加密结果 81 | """ 82 | try: 83 | sha1_hash = hashlib.sha1() 84 | sha1_hash.update(plain_text.encode('utf-8')) 85 | return sha1_hash.hexdigest() 86 | except Exception as e: 87 | logging.error(f"加密失败: {e}") 88 | return plain_text 89 | 90 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 91 | """处理JSON数据""" 92 | modified = False 93 | for field in self.encryption_fields: 94 | if field in json_data: 95 | try: 96 | # 将字段值转换为标准 JSON 字符串(使用双引号) 97 | if isinstance(json_data[field], (dict, list)): 98 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 99 | else: 100 | plain_text = str(json_data[field]) 101 | 102 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 103 | json_data[field] = self.encrypt_value(plain_text) 104 | modified = True 105 | logging.info(f"JSON字段 {field} 加密完成") 106 | except Exception as e: 107 | logging.error(f"加密字段 {field} 失败: {e}") 108 | return json_data, modified 109 | 110 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 111 | """处理表单数据""" 112 | params = parse_qs(form_data, keep_blank_values=True) 113 | modified = False 114 | 115 | for field in self.encryption_fields: 116 | if field in params: 117 | try: 118 | values = params[field] 119 | if isinstance(values, list): 120 | encrypted_values = [] 121 | for value in values: 122 | logging.info(f"表单字段 {field} 待加密值: {value}") 123 | encrypted_values.append(self.encrypt_value(value)) 124 | params[field] = encrypted_values 125 | else: 126 | logging.info(f"表单字段 {field} 待加密值: {values}") 127 | params[field] = self.encrypt_value(values) 128 | modified = True 129 | logging.info(f"表单字段 {field} 加密完成") 130 | except Exception as e: 131 | logging.error(f"加密字段 {field} 失败: {e}") 132 | 133 | for key in params: 134 | if isinstance(params[key], list) and len(params[key]) == 1: 135 | params[key] = params[key][0] 136 | 137 | return urlencode(params), modified 138 | 139 | def request(self, flow: http.HTTPFlow) -> None: 140 | """ 141 | 处理请求 142 | 143 | Args: 144 | flow: mitmproxy的请求流对象 145 | """ 146 | try: 147 | content_type = flow.request.headers.get("Content-Type", "") 148 | logging.info("=" * 50) 149 | logging.info(f"请求URL: {flow.request.pretty_url}") 150 | logging.info(f"请求方法: {flow.request.method}") 151 | logging.info(f"Content-Type: {content_type}") 152 | 153 | modified = False 154 | if "application/json" in content_type: 155 | json_data = json.loads(flow.request.content) 156 | json_data, modified = self.process_json_data(json_data) 157 | if modified: 158 | new_content = json.dumps(json_data, separators=(',', ':')) 159 | flow.request.content = new_content.encode('utf-8') 160 | 161 | elif "application/x-www-form-urlencoded" in content_type: 162 | form_data = flow.request.content.decode('utf-8') 163 | new_content, modified = self.process_form_data(form_data) 164 | if modified: 165 | flow.request.content = new_content.encode('utf-8') 166 | 167 | if modified: 168 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 169 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 170 | 171 | logging.info("=" * 50) 172 | 173 | except Exception as e: 174 | logging.error(f"处理请求失败: {e}") 175 | import traceback 176 | logging.error(traceback.format_exc()) 177 | 178 | # 注册插件 179 | addons = [SHA1EncryptInterceptor(encryption_fields)] -------------------------------------------------------------------------------- /src/scripts/encryptTools/sha256.py: -------------------------------------------------------------------------------- 1 | """ 2 | SHA256 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s sha256.py --ssl-insecure field=password 6 | mitmdump -p 8888 -s sha256.py --ssl-insecure field=password,username 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s sha256.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field=password: 单个加密字段 13 | field=password,username: 多个加密字段,用逗号分隔 14 | 15 | 注意事项: 16 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 17 | 2. 支持单个或多个字段加密 18 | 3. SHA256加密结果为64位小写字符串 19 | """ 20 | 21 | import sys 22 | import os 23 | from mitmproxy import http 24 | import hashlib 25 | import logging 26 | import json 27 | from urllib.parse import parse_qs, urlencode 28 | 29 | # 配置日志记录 30 | logging.basicConfig( 31 | level=logging.INFO, 32 | format='%(asctime)s - %(levelname)s - %(message)s' 33 | ) 34 | 35 | def get_encryption_fields(): 36 | """ 37 | 从命令行参数获取加密配置 38 | 39 | Returns: 40 | list: 需要加密的字段名称列表 41 | """ 42 | all_args = sys.argv 43 | encryption_fields = [] 44 | 45 | # 遍历所有参数 46 | for arg in all_args: 47 | if arg.startswith('field='): 48 | # 提取 field= 后面的值 49 | fields = arg.replace('field=', '') 50 | encryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 51 | break 52 | 53 | logging.info(f"需要加密的字段: {encryption_fields}") 54 | return encryption_fields 55 | 56 | # 获取加密配置 57 | encryption_fields = get_encryption_fields() 58 | 59 | class SHA256EncryptInterceptor: 60 | """SHA256 加密拦截器""" 61 | 62 | def __init__(self, encryption_fields): 63 | """ 64 | 初始化加密器 65 | 66 | Args: 67 | encryption_fields (list): 需要加密的字段名称列表 68 | """ 69 | self.encryption_fields = encryption_fields 70 | logging.info("成功初始化SHA256加密器") 71 | 72 | def encrypt_value(self, plain_text: str) -> str: 73 | """ 74 | 加密单个值 75 | 76 | Args: 77 | plain_text (str): 待加密的文本 78 | 79 | Returns: 80 | str: SHA256加密结果 81 | """ 82 | try: 83 | sha256_hash = hashlib.sha256() 84 | sha256_hash.update(plain_text.encode('utf-8')) 85 | return sha256_hash.hexdigest() 86 | except Exception as e: 87 | logging.error(f"加密失败: {e}") 88 | return plain_text 89 | 90 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 91 | """处理JSON数据""" 92 | modified = False 93 | for field in self.encryption_fields: 94 | if field in json_data: 95 | try: 96 | # 将字段值转换为标准 JSON 字符串(使用双引号) 97 | if isinstance(json_data[field], (dict, list)): 98 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 99 | else: 100 | plain_text = str(json_data[field]) 101 | 102 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 103 | json_data[field] = self.encrypt_value(plain_text) 104 | modified = True 105 | logging.info(f"JSON字段 {field} 加密完成") 106 | except Exception as e: 107 | logging.error(f"加密字段 {field} 失败: {e}") 108 | return json_data, modified 109 | 110 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 111 | """处理表单数据""" 112 | params = parse_qs(form_data, keep_blank_values=True) 113 | modified = False 114 | 115 | for field in self.encryption_fields: 116 | if field in params: 117 | try: 118 | values = params[field] 119 | if isinstance(values, list): 120 | encrypted_values = [] 121 | for value in values: 122 | logging.info(f"表单字段 {field} 待加密值: {value}") 123 | encrypted_values.append(self.encrypt_value(value)) 124 | params[field] = encrypted_values 125 | else: 126 | logging.info(f"表单字段 {field} 待加密值: {values}") 127 | params[field] = self.encrypt_value(values) 128 | modified = True 129 | logging.info(f"表单字段 {field} 加密完成") 130 | except Exception as e: 131 | logging.error(f"加密字段 {field} 失败: {e}") 132 | 133 | for key in params: 134 | if isinstance(params[key], list) and len(params[key]) == 1: 135 | params[key] = params[key][0] 136 | 137 | return urlencode(params), modified 138 | 139 | def request(self, flow: http.HTTPFlow) -> None: 140 | """ 141 | 处理请求 142 | 143 | Args: 144 | flow: mitmproxy的请求流对象 145 | """ 146 | try: 147 | content_type = flow.request.headers.get("Content-Type", "") 148 | logging.info("=" * 50) 149 | logging.info(f"请求URL: {flow.request.pretty_url}") 150 | logging.info(f"请求方法: {flow.request.method}") 151 | logging.info(f"Content-Type: {content_type}") 152 | 153 | modified = False 154 | if "application/json" in content_type: 155 | json_data = json.loads(flow.request.content) 156 | json_data, modified = self.process_json_data(json_data) 157 | if modified: 158 | new_content = json.dumps(json_data, separators=(',', ':')) 159 | flow.request.content = new_content.encode('utf-8') 160 | 161 | elif "application/x-www-form-urlencoded" in content_type: 162 | form_data = flow.request.content.decode('utf-8') 163 | new_content, modified = self.process_form_data(form_data) 164 | if modified: 165 | flow.request.content = new_content.encode('utf-8') 166 | 167 | if modified: 168 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 169 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 170 | 171 | logging.info("=" * 50) 172 | 173 | except Exception as e: 174 | logging.error(f"处理请求失败: {e}") 175 | import traceback 176 | logging.error(traceback.format_exc()) 177 | 178 | # 注册插件 179 | addons = [SHA256EncryptInterceptor(encryption_fields)] -------------------------------------------------------------------------------- /src/scripts/encryptTools/sha384.py: -------------------------------------------------------------------------------- 1 | """ 2 | SHA384 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s sha384.py --ssl-insecure field=password 6 | mitmdump -p 8888 -s sha384.py --ssl-insecure field=password,username 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s sha384.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field=password: 单个加密字段 13 | field=password,username: 多个加密字段,用逗号分隔 14 | 15 | 注意事项: 16 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 17 | 2. 支持单个或多个字段加密 18 | 3. SHA384加密结果为96位小写字符串 19 | """ 20 | 21 | import sys 22 | import os 23 | from mitmproxy import http 24 | import hashlib 25 | import logging 26 | import json 27 | from urllib.parse import parse_qs, urlencode 28 | 29 | # 配置日志记录 30 | logging.basicConfig( 31 | level=logging.INFO, 32 | format='%(asctime)s - %(levelname)s - %(message)s' 33 | ) 34 | 35 | def get_encryption_fields(): 36 | """ 37 | 从命令行参数获取加密配置 38 | 39 | Returns: 40 | list: 需要加密的字段名称列表 41 | """ 42 | all_args = sys.argv 43 | encryption_fields = [] 44 | 45 | # 遍历所有参数 46 | for arg in all_args: 47 | if arg.startswith('field='): 48 | # 提取 field= 后面的值 49 | fields = arg.replace('field=', '') 50 | encryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 51 | break 52 | 53 | logging.info(f"需要加密的字段: {encryption_fields}") 54 | return encryption_fields 55 | 56 | # 获取加密配置 57 | encryption_fields = get_encryption_fields() 58 | 59 | class SHA384EncryptInterceptor: 60 | """SHA384 加密拦截器""" 61 | 62 | def __init__(self, encryption_fields): 63 | """ 64 | 初始化加密器 65 | 66 | Args: 67 | encryption_fields (list): 需要加密的字段名称列表 68 | """ 69 | self.encryption_fields = encryption_fields 70 | logging.info("成功初始化SHA384加密器") 71 | 72 | def encrypt_value(self, plain_text: str) -> str: 73 | """ 74 | 加密单个值 75 | 76 | Args: 77 | plain_text (str): 待加密的文本 78 | 79 | Returns: 80 | str: SHA384加密结果 81 | """ 82 | try: 83 | sha384_hash = hashlib.sha384() 84 | sha384_hash.update(plain_text.encode('utf-8')) 85 | return sha384_hash.hexdigest() 86 | except Exception as e: 87 | logging.error(f"加密失败: {e}") 88 | return plain_text 89 | 90 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 91 | """处理JSON数据""" 92 | modified = False 93 | for field in self.encryption_fields: 94 | if field in json_data: 95 | try: 96 | # 将字段值转换为标准 JSON 字符串(使用双引号) 97 | if isinstance(json_data[field], (dict, list)): 98 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 99 | else: 100 | plain_text = str(json_data[field]) 101 | 102 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 103 | json_data[field] = self.encrypt_value(plain_text) 104 | modified = True 105 | logging.info(f"JSON字段 {field} 加密完成") 106 | except Exception as e: 107 | logging.error(f"加密字段 {field} 失败: {e}") 108 | return json_data, modified 109 | 110 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 111 | """处理表单数据""" 112 | params = parse_qs(form_data, keep_blank_values=True) 113 | modified = False 114 | 115 | for field in self.encryption_fields: 116 | if field in params: 117 | try: 118 | values = params[field] 119 | if isinstance(values, list): 120 | encrypted_values = [] 121 | for value in values: 122 | logging.info(f"表单字段 {field} 待加密值: {value}") 123 | encrypted_values.append(self.encrypt_value(value)) 124 | params[field] = encrypted_values 125 | else: 126 | logging.info(f"表单字段 {field} 待加密值: {values}") 127 | params[field] = self.encrypt_value(values) 128 | modified = True 129 | logging.info(f"表单字段 {field} 加密完成") 130 | except Exception as e: 131 | logging.error(f"加密字段 {field} 失败: {e}") 132 | 133 | for key in params: 134 | if isinstance(params[key], list) and len(params[key]) == 1: 135 | params[key] = params[key][0] 136 | 137 | return urlencode(params), modified 138 | 139 | def request(self, flow: http.HTTPFlow) -> None: 140 | """ 141 | 处理请求 142 | 143 | Args: 144 | flow: mitmproxy的请求流对象 145 | """ 146 | try: 147 | content_type = flow.request.headers.get("Content-Type", "") 148 | logging.info("=" * 50) 149 | logging.info(f"请求URL: {flow.request.pretty_url}") 150 | logging.info(f"请求方法: {flow.request.method}") 151 | logging.info(f"Content-Type: {content_type}") 152 | 153 | modified = False 154 | if "application/json" in content_type: 155 | json_data = json.loads(flow.request.content) 156 | json_data, modified = self.process_json_data(json_data) 157 | if modified: 158 | new_content = json.dumps(json_data, separators=(',', ':')) 159 | flow.request.content = new_content.encode('utf-8') 160 | 161 | elif "application/x-www-form-urlencoded" in content_type: 162 | form_data = flow.request.content.decode('utf-8') 163 | new_content, modified = self.process_form_data(form_data) 164 | if modified: 165 | flow.request.content = new_content.encode('utf-8') 166 | 167 | if modified: 168 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 169 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 170 | 171 | logging.info("=" * 50) 172 | 173 | except Exception as e: 174 | logging.error(f"处理请求失败: {e}") 175 | import traceback 176 | logging.error(traceback.format_exc()) 177 | 178 | # 注册插件 179 | addons = [SHA384EncryptInterceptor(encryption_fields)] -------------------------------------------------------------------------------- /src/scripts/encryptTools/sha512.py: -------------------------------------------------------------------------------- 1 | """ 2 | SHA512 加密脚本 3 | 4 | 使用方法: 5 | mitmdump -p 8888 -s sha512.py --ssl-insecure field=password 6 | mitmdump -p 8888 -s sha512.py --ssl-insecure field=password,username 7 | 8 | 参数说明: 9 | -p 8888: 监听端口 10 | -s sha512.py: 指定脚本文件 11 | --ssl-insecure: 忽略 SSL 证书验证 12 | field=password: 单个加密字段 13 | field=password,username: 多个加密字段,用逗号分隔 14 | 15 | 注意事项: 16 | 1. 支持 application/json 和 application/x-www-form-urlencoded 格式 17 | 2. 支持单个或多个字段加密 18 | 3. SHA512加密结果为128位小写字符串 19 | """ 20 | 21 | import sys 22 | import os 23 | from mitmproxy import http 24 | import hashlib 25 | import logging 26 | import json 27 | from urllib.parse import parse_qs, urlencode 28 | 29 | # 配置日志记录 30 | logging.basicConfig( 31 | level=logging.INFO, 32 | format='%(asctime)s - %(levelname)s - %(message)s' 33 | ) 34 | 35 | def get_encryption_fields(): 36 | """ 37 | 从命令行参数获取加密配置 38 | 39 | Returns: 40 | list: 需要加密的字段名称列表 41 | """ 42 | all_args = sys.argv 43 | encryption_fields = [] 44 | 45 | # 遍历所有参数 46 | for arg in all_args: 47 | if arg.startswith('field='): 48 | # 提取 field= 后面的值 49 | fields = arg.replace('field=', '') 50 | encryption_fields = [field.strip() for field in fields.split(',') if field.strip()] 51 | break 52 | 53 | logging.info(f"需要加密的字段: {encryption_fields}") 54 | return encryption_fields 55 | 56 | # 获取加密配置 57 | encryption_fields = get_encryption_fields() 58 | 59 | class SHA512EncryptInterceptor: 60 | """SHA512 加密拦截器""" 61 | 62 | def __init__(self, encryption_fields): 63 | """ 64 | 初始化加密器 65 | 66 | Args: 67 | encryption_fields (list): 需要加密的字段名称列表 68 | """ 69 | self.encryption_fields = encryption_fields 70 | logging.info("成功初始化SHA512加密器") 71 | 72 | def encrypt_value(self, plain_text: str) -> str: 73 | """ 74 | 加密单个值 75 | 76 | Args: 77 | plain_text (str): 待加密的文本 78 | 79 | Returns: 80 | str: SHA512加密结果 81 | """ 82 | try: 83 | sha512_hash = hashlib.sha512() 84 | sha512_hash.update(plain_text.encode('utf-8')) 85 | return sha512_hash.hexdigest() 86 | except Exception as e: 87 | logging.error(f"加密失败: {e}") 88 | return plain_text 89 | 90 | def process_json_data(self, json_data: dict) -> tuple[dict, bool]: 91 | """处理JSON数据""" 92 | modified = False 93 | for field in self.encryption_fields: 94 | if field in json_data: 95 | try: 96 | # 将字段值转换为标准 JSON 字符串(使用双引号) 97 | if isinstance(json_data[field], (dict, list)): 98 | plain_text = json.dumps(json_data[field], ensure_ascii=False) 99 | else: 100 | plain_text = str(json_data[field]) 101 | 102 | logging.info(f"JSON字段 {field} 待加密值: {plain_text}") 103 | json_data[field] = self.encrypt_value(plain_text) 104 | modified = True 105 | logging.info(f"JSON字段 {field} 加密完成") 106 | except Exception as e: 107 | logging.error(f"加密字段 {field} 失败: {e}") 108 | return json_data, modified 109 | 110 | def process_form_data(self, form_data: str) -> tuple[str, bool]: 111 | """处理表单数据""" 112 | params = parse_qs(form_data, keep_blank_values=True) 113 | modified = False 114 | 115 | for field in self.encryption_fields: 116 | if field in params: 117 | try: 118 | values = params[field] 119 | if isinstance(values, list): 120 | encrypted_values = [] 121 | for value in values: 122 | logging.info(f"表单字段 {field} 待加密值: {value}") 123 | encrypted_values.append(self.encrypt_value(value)) 124 | params[field] = encrypted_values 125 | else: 126 | logging.info(f"表单字段 {field} 待加密值: {values}") 127 | params[field] = self.encrypt_value(values) 128 | modified = True 129 | logging.info(f"表单字段 {field} 加密完成") 130 | except Exception as e: 131 | logging.error(f"加密字段 {field} 失败: {e}") 132 | 133 | for key in params: 134 | if isinstance(params[key], list) and len(params[key]) == 1: 135 | params[key] = params[key][0] 136 | 137 | return urlencode(params), modified 138 | 139 | def request(self, flow: http.HTTPFlow) -> None: 140 | """ 141 | 处理请求 142 | 143 | Args: 144 | flow: mitmproxy的请求流对象 145 | """ 146 | try: 147 | content_type = flow.request.headers.get("Content-Type", "") 148 | logging.info("=" * 50) 149 | logging.info(f"请求URL: {flow.request.pretty_url}") 150 | logging.info(f"请求方法: {flow.request.method}") 151 | logging.info(f"Content-Type: {content_type}") 152 | 153 | modified = False 154 | if "application/json" in content_type: 155 | json_data = json.loads(flow.request.content) 156 | json_data, modified = self.process_json_data(json_data) 157 | if modified: 158 | new_content = json.dumps(json_data, separators=(',', ':')) 159 | flow.request.content = new_content.encode('utf-8') 160 | 161 | elif "application/x-www-form-urlencoded" in content_type: 162 | form_data = flow.request.content.decode('utf-8') 163 | new_content, modified = self.process_form_data(form_data) 164 | if modified: 165 | flow.request.content = new_content.encode('utf-8') 166 | 167 | if modified: 168 | flow.request.headers["Content-Length"] = str(len(flow.request.content)) 169 | logging.info(f"加密后的请求数据: {flow.request.content.decode('utf-8')}") 170 | 171 | logging.info("=" * 50) 172 | 173 | except Exception as e: 174 | logging.error(f"处理请求失败: {e}") 175 | import traceback 176 | logging.error(traceback.format_exc()) 177 | 178 | # 注册插件 179 | addons = [SHA512EncryptInterceptor(encryption_fields)] -------------------------------------------------------------------------------- /src/scripts/hookTools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/scripts/hookTools/__init__.py -------------------------------------------------------------------------------- /src/scripts/hookTools/test.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 开发中,敬请期待 -------------------------------------------------------------------------------- /src/scripts/test/des3_cbc_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3DES-CBC 加密/解密测试脚本 3 | 4 | 使用方法: 5 | python des3_cbc_test.py 6 | 7 | 功能: 8 | 1. 使用与前端相同的加密参数 9 | 2. 支持用户输入字符串进行加密测试 10 | 3. 显示加密前后的数据对比 11 | """ 12 | 13 | from Crypto.Cipher import DES3 14 | from Crypto.Util.Padding import pad, unpad 15 | import base64 16 | import json 17 | 18 | def encrypt_des3_cbc(plain_text: str, key: str = "24byteslongKeyfordes3!aa", iv: str = "8bytesIv") -> str: 19 | """3DES-CBC 加密函数""" 20 | try: 21 | # 确保密钥长度为24字节(192位) 22 | if len(key) < 24: 23 | key = key + (24 - len(key)) * '\0' 24 | elif len(key) > 24: 25 | key = key[:24] 26 | 27 | # 确保IV长度为8字节 28 | if len(iv) < 8: 29 | iv = iv + (8 - len(iv)) * '\0' 30 | elif len(iv) > 8: 31 | iv = iv[:8] 32 | 33 | cipher = DES3.new(key.encode('utf-8'), DES3.MODE_CBC, iv.encode('utf-8')) 34 | padded_data = pad(plain_text.encode('utf-8'), DES3.block_size) 35 | encrypted_data = cipher.encrypt(padded_data) 36 | return base64.b64encode(encrypted_data).decode('utf-8') 37 | except Exception as e: 38 | print(f"加密错误: {e}") 39 | return None 40 | 41 | def decrypt_des3_cbc(encrypted_text: str, key: str = "24byteslongKeyfordes3!aa", iv: str = "8bytesIv") -> str: 42 | """3DES-CBC 解密函数""" 43 | try: 44 | # 确保密钥长度为24字节 45 | if len(key) < 24: 46 | key = key + (24 - len(key)) * '\0' 47 | elif len(key) > 24: 48 | key = key[:24] 49 | 50 | # 确保IV长度为8字节 51 | if len(iv) < 8: 52 | iv = iv + (8 - len(iv)) * '\0' 53 | elif len(iv) > 8: 54 | iv = iv[:8] 55 | 56 | encrypted_data = base64.b64decode(encrypted_text) 57 | cipher = DES3.new(key.encode('utf-8'), DES3.MODE_CBC, iv.encode('utf-8')) 58 | decrypted_data = cipher.decrypt(encrypted_data) 59 | unpadded_data = unpad(decrypted_data, DES3.block_size) 60 | return unpadded_data.decode('utf-8') 61 | except Exception as e: 62 | print(f"解密错误: {e}") 63 | return None 64 | 65 | def main(): 66 | print("3DES-CBC 加密/解密测试工具") 67 | print("=" * 50) 68 | print("使用与前端相同的加密参数:") 69 | print("密钥(key): 24byteslongKeyfordes3!aa") 70 | print("初始向量(iv): 8bytesIv") 71 | print("=" * 50) 72 | 73 | while True: 74 | # 获取用户输入 75 | user_input = input("\n请输入要加密的内容 (输入 'q' 退出): ") 76 | if user_input.lower() == 'q': 77 | break 78 | 79 | # 构造与前端相同的数据结构 80 | data = {"username": user_input} 81 | json_data = json.dumps(data, ensure_ascii=False) 82 | 83 | # 加密 84 | encrypted = encrypt_des3_cbc(json_data) 85 | 86 | if encrypted: 87 | print("\n加密结果:") 88 | print("-" * 50) 89 | print(f"原始数据: {json_data}") 90 | print(f"加密后: {encrypted}") 91 | 92 | # 解密验证 93 | decrypted = decrypt_des3_cbc(encrypted) 94 | print(f"\n解密验证:") 95 | print(f"解密后: {decrypted}") 96 | print("-" * 50) 97 | 98 | # 构造完整的请求数据 99 | request_data = {"data": encrypted} 100 | print(f"\n完整的请求数据:") 101 | print(json.dumps(request_data, indent=2, ensure_ascii=False)) 102 | 103 | # 测试前端传来的加密数据 104 | print("\n是否要测试解密前端数据? (y/n)") 105 | test_frontend = input().lower() 106 | if test_frontend == 'y': 107 | frontend_data = input("请输入前端加密的数据: ") 108 | decrypted_frontend = decrypt_des3_cbc(frontend_data) 109 | if decrypted_frontend: 110 | print(f"\n前端数据解密结果:") 111 | print(f"解密后: {decrypted_frontend}") 112 | 113 | if __name__ == "__main__": 114 | main() -------------------------------------------------------------------------------- /src/scripts/test/des_cbc_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | DES-CBC 加密/解密测试脚本 3 | 4 | 使用方法: 5 | python des_cbc_test.py 6 | 7 | 功能: 8 | 1. 使用与前端相同的加密参数 9 | 2. 支持用户输入字符串进行加密测试 10 | 3. 显示加密前后的数据对比 11 | """ 12 | 13 | from Crypto.Cipher import DES 14 | from Crypto.Util.Padding import pad, unpad 15 | import base64 16 | import json 17 | 18 | 19 | def encrypt_des_cbc(plain_text: str, key: str = "12345678", iv: str = "12345678") -> str: 20 | """ 21 | DES-CBC 加密函数 22 | 23 | Args: 24 | plain_text: 待加密的文本 25 | key: 密钥(8字节) 26 | iv: 初始化向量(8字节) 27 | 28 | Returns: 29 | str: Base64编码的加密结果 30 | """ 31 | try: 32 | # 创建 DES-CBC 加密器 33 | cipher = DES.new(key.encode('utf-8'), DES.MODE_CBC, iv.encode('utf-8')) 34 | 35 | # 对数据进行填充和加密 36 | padded_data = pad(plain_text.encode('utf-8'), DES.block_size) 37 | encrypted_data = cipher.encrypt(padded_data) 38 | 39 | # Base64 编码 40 | return base64.b64encode(encrypted_data).decode('utf-8') 41 | except Exception as e: 42 | print(f"加密错误: {e}") 43 | return None 44 | 45 | 46 | def decrypt_des_cbc(encrypted_text: str, key: str = "12345678", iv: str = "12345678") -> str: 47 | """DES-CBC 解密函数""" 48 | try: 49 | encrypted_data = base64.b64decode(encrypted_text) 50 | cipher = DES.new(key.encode('utf-8'), DES.MODE_CBC, iv.encode('utf-8')) 51 | decrypted_data = cipher.decrypt(encrypted_data) 52 | unpadded_data = unpad(decrypted_data, DES.block_size) 53 | return unpadded_data.decode('utf-8') 54 | except Exception as e: 55 | print(f"解密错误: {e}") 56 | return None 57 | 58 | 59 | def main(): 60 | print("DES-CBC 加密/解密测试工具") 61 | print("=" * 50) 62 | print("使用与前端相同的加密参数:") 63 | print("密钥(key): 12345678") 64 | print("初始向量(iv): 12345678") 65 | print("=" * 50) 66 | 67 | while True: 68 | # 获取用户输入 69 | user_input = input("\n请输入要加密的内容 (输入 'q' 退出): ") 70 | if user_input.lower() == 'q': 71 | break 72 | 73 | # 构造与前端相同的数据结构 74 | data = {"username": user_input} 75 | json_data = json.dumps(data) 76 | 77 | # 加密 78 | encrypted = encrypt_des_cbc(json_data) 79 | 80 | if encrypted: 81 | print("\n加密结果:") 82 | print("-" * 50) 83 | print(f"原始数据: {json_data}") 84 | print(f"加密后: {encrypted}") 85 | 86 | # 解密验证 87 | decrypted = decrypt_des_cbc(encrypted) 88 | print(f"\n解密验证:") 89 | print(f"解密后: {decrypted}") 90 | print("-" * 50) 91 | 92 | # 构造完整的请求数据 93 | request_data = {"data": encrypted} 94 | print(f"\n完整的请求数据:") 95 | print(json.dumps(request_data, indent=2)) 96 | 97 | # 测试前端传来的加密数据 98 | print("\n是否要测试解密前端数据? (y/n)") 99 | test_frontend = input().lower() 100 | if test_frontend == 'y': 101 | frontend_data = input("请输入前端加密的数据: ") 102 | decrypted_frontend = decrypt_des_cbc(frontend_data) 103 | if decrypted_frontend: 104 | print(f"\n前端数据解密结果:") 105 | print(f"解密后: {decrypted_frontend}") 106 | 107 | 108 | if __name__ == "__main__": 109 | main() 110 | -------------------------------------------------------------------------------- /src/themes/__pycache__/theme.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/themes/__pycache__/theme.cpython-39.pyc -------------------------------------------------------------------------------- /src/themes/theme.py: -------------------------------------------------------------------------------- 1 | # path: /src/themes/theme.py 2 | import os 3 | 4 | 5 | def get_themes(window): 6 | """ 动态加载 /resources/themes 下的 .qss 文件,并添加到 theme_combo 下拉框中 """ 7 | 8 | # 定义资源目录路径 9 | 10 | theme_dir = os.path.join(os.path.dirname(__file__), '..', '..', 'resource', 'themes') # 使用正确的相对路径 11 | 12 | # 获取所有 .qss 文件 13 | qss_files = [f for f in os.listdir(theme_dir) if f.endswith(".qss")] 14 | 15 | # 清空下拉框并添加主题 16 | window.theme_combo.clear() 17 | 18 | # 将文件名添加到 theme_combo 下拉框 19 | for qss_file in qss_files: 20 | theme_name = qss_file.split('.')[0] # 使用文件名(不包括扩展名)作为主题名 21 | window.theme_combo.addItem(theme_name, userData=qss_file) # 使用 userData 储存文件名 22 | 23 | # 连接下拉框的改变事件,选择后更新主题 24 | window.theme_combo.currentTextChanged.connect(lambda: apply_theme(window)) 25 | 26 | 27 | # 当用户切换 theme 的时候,则更换 qss 样式 28 | def apply_theme(window): 29 | """ 应用选中的主题 """ 30 | selected_theme = window.theme_combo.currentData() # 获取选中的 .qss 文件名 31 | if selected_theme: 32 | # 获取 qss 的路径 33 | theme_file_path = os.path.join(os.path.dirname(__file__), '..', '..', 'resource', 'themes', 34 | selected_theme) # 使用正确的相对路径 35 | try: 36 | # 指定文件编码为 utf-8 37 | with open(theme_file_path, 'r', encoding='utf-8') as f: 38 | qss = f.read() # 读取 qss 文件内容 39 | # print(qss) # 打印 qss 内容调试 40 | window.setStyleSheet(qss) # 应用主题 41 | # print(f"Applied theme: {selected_theme}") 42 | except Exception as e: 43 | pass 44 | # print(f"Error loading theme '{selected_theme}': {e}") 45 | # 你也可以在这里弹出一个提示框,给用户反馈错误信息 46 | 47 | 48 | # 初始化主题为 dark 49 | def init_themes(window): 50 | """ 初始化并加载主题列表 """ 51 | 52 | # 默认选择第一个主题,假设已经有至少一个主题 53 | if window.theme_combo.count() > 0: 54 | window.theme_combo.setCurrentIndex(0) 55 | apply_theme(window) 56 | -------------------------------------------------------------------------------- /src/thread/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/thread/__init__.py -------------------------------------------------------------------------------- /src/thread/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/thread/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /src/thread/__pycache__/mitmproxy_thread.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/thread/__pycache__/mitmproxy_thread.cpython-39.pyc -------------------------------------------------------------------------------- /src/thread/mitmproxy_thread.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import subprocess 4 | import traceback 5 | 6 | from PyQt6.QtCore import QThread, pyqtSignal 7 | 8 | 9 | class MitmProxyThread(QThread): 10 | new_log = pyqtSignal(str) # 用于发送日志消息的信号 11 | new_packet = pyqtSignal(list) # 用于发送数据包字段信息的信号 12 | 13 | def __init__(self, listen_port=None, command=None): 14 | super().__init__() 15 | self.log = '' # 存储日志信息 16 | self.listen_port = listen_port # 监听端口 17 | self.command = command # 自定义命令 18 | self.process = None # 存储子进程 19 | self.running = False # 线程运行状态 20 | self.script_dir = os.path.dirname(os.path.abspath(__file__)) # 获取当前脚本目录 21 | self.script_path = os.path.join(self.script_dir, "..", "network", "mitmproxy_packet_capture.py") # 默认抓包脚本路径 22 | 23 | def parse_http_request(self, raw_request): 24 | """解析HTTP请求,提取需要的信息""" 25 | try: 26 | # 分割请求行和请求头 27 | lines = raw_request.split('\n') 28 | request_line = lines[0].strip() 29 | 30 | # 解析请求行 31 | method, url, _ = request_line.split(' ') 32 | 33 | # 解析请求头 34 | headers = {} 35 | for line in lines[1:]: 36 | line = line.strip() 37 | if ':' in line: 38 | key, value = line.split(':', 1) 39 | headers[key.strip()] = value.strip() 40 | 41 | # 获取当前时间 42 | from datetime import datetime 43 | current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 44 | 45 | # 构造表格行数据 46 | row_data = [ 47 | current_time, # 时间 48 | "Request", # 类型 49 | "->", # 方向 50 | method, # 方法 51 | url, # URL 52 | "200", # 状态码(默认200) 53 | headers.get('Content-Length', '') # 内容长度 54 | ] 55 | 56 | # 添加原始请求数据作为第8个元素 57 | row_data.append(raw_request) 58 | 59 | return row_data 60 | 61 | except Exception as e: 62 | print(f"Error parsing request: {e}") 63 | return None 64 | 65 | def run(self): 66 | """线程运行逻辑""" 67 | try: 68 | # 如果传入命令,则使用自定义命令 69 | if self.command: 70 | print(f"Starting process with command: {self.command}") 71 | self.process = subprocess.Popen( 72 | self.command, 73 | stdout=subprocess.PIPE, 74 | stderr=subprocess.PIPE, 75 | text=True, 76 | encoding="utf-8" 77 | ) 78 | else: 79 | # 使用默认的抓包脚本 80 | command = ["mitmdump", "-p", str(self.listen_port), "-s", self.script_path, "--ssl-insecure"] 81 | print(f"Starting process with command: {command}") 82 | self.process = subprocess.Popen( 83 | command, 84 | stdout=subprocess.PIPE, 85 | stderr=subprocess.PIPE, 86 | text=True, 87 | encoding="utf-8" 88 | ) 89 | 90 | if self.process is None: 91 | self.new_log.emit("❌ 无法启动 mitmdump 进程。") 92 | return 93 | 94 | self.running = True # 设置运行状态为 True 95 | while self.running: 96 | if self.process.poll() is not None: 97 | # 进程已经终止 98 | error = self.process.stderr.read() # 读取错误信息 99 | if error: 100 | self.new_log.emit(f"❌ 进程错误: {error}") 101 | break 102 | 103 | line = self.process.stdout.readline() # 读取标准输出 104 | if line: 105 | if "error while attempting to bind on address" in line: 106 | self.new_log.emit("❌ 端口被占用,请尝试其他端口或关闭占用端口的程序") 107 | self.stop() # 停止线程 108 | break 109 | 110 | self.log += line # 累加日志 111 | self.new_log.emit(line.strip()) # 发送日志消息 112 | 113 | # Default 模式下解析数据包 114 | if not self.command: # 只在 Default 模式下解析数据包 115 | match = re.search(r"flow_start\n(.*?)\nflow_end", self.log, re.DOTALL) 116 | if match: 117 | full_flow_str = match.group(1) 118 | try: 119 | full_flow = eval(full_flow_str) # 解析流数据 120 | raw_request = full_flow.get('raw', '') 121 | 122 | # 解析请求并发送新信号 123 | row_data = self.parse_http_request(raw_request) 124 | if row_data: 125 | print(f"Sending packet data: {row_data}") # 调试输出 126 | self.new_packet.emit(row_data) # 发送数据包信息 127 | 128 | except Exception as e: 129 | print(f"Error processing flow: {e}") 130 | 131 | self.log = '' # 清空日志 132 | 133 | self.msleep(100) # 暂停100毫秒 134 | 135 | except Exception as e: 136 | self.new_log.emit(f"❌ 线程错误: {str(e)}") 137 | traceback.print_exc() # 打印异常堆栈 138 | finally: 139 | self.cleanup() # 清理资源 140 | 141 | def stop(self): 142 | """安全地停止线程和进程""" 143 | self.running = False # 设置运行状态为 False 144 | if self.process: 145 | self.process.terminate() # 尝试正常终止进程 146 | try: 147 | self.process.wait(timeout=3) # 等待进程结束 148 | except subprocess.TimeoutExpired: 149 | self.process.kill() # 强制结束进程 150 | print("Thread stopped.") # 调试信息 151 | self.quit() # 退出线程 152 | 153 | def cleanup(self): 154 | """清理资源""" 155 | try: 156 | if self.process: 157 | # 尝试正常终止进程 158 | self.process.terminate() 159 | try: 160 | self.process.wait(timeout=3) 161 | except subprocess.TimeoutExpired: 162 | # 如果进程没有及时响应,强制结束它 163 | self.process.kill() 164 | self.process.wait() 165 | finally: 166 | self.process = None # 清空进程引用 167 | except Exception as e: 168 | print(f"清理资源时出错: {e}") 169 | finally: 170 | self.quit() # 退出线程 171 | 172 | -------------------------------------------------------------------------------- /src/ui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/ui/__init__.py -------------------------------------------------------------------------------- /src/ui/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/ui/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /src/validator/KeyValidator.py: -------------------------------------------------------------------------------- 1 | from constants.encryption_constants import EncryptionConstants 2 | from constants.error_messages import ErrorMessages 3 | 4 | 5 | def validate_key_length(window, script, key): 6 | """验证密钥长度是否符合要求 7 | 8 | Args: 9 | window: 主窗口实例 10 | script: 选择的加密/解密脚本 11 | key: 输入的密钥 12 | 13 | Returns: 14 | bool: 验证是否通过 15 | """ 16 | # 检查是否需要密钥 17 | if not key and script not in EncryptionConstants.NO_KEY_ALGORITHMS: 18 | window.packet_detail.append(ErrorMessages.KEY_REQUIRED) 19 | return False 20 | print(key,script) 21 | # 根据选择的脚本进行密钥长度检查 22 | if script in EncryptionConstants.AES_ALGORITHMS: 23 | if len(key) not in EncryptionConstants.AES_KEY_LENGTHS: 24 | window.packet_detail.append(ErrorMessages.AES_KEY_LENGTH_ERROR) 25 | return False 26 | elif script in EncryptionConstants.DES_ALGORITHMS: 27 | if len(key) not in EncryptionConstants.DES_KEY_LENGTH: 28 | print(len(key)) 29 | window.packet_detail.append(ErrorMessages.DES_KEY_LENGTH_ERROR) 30 | return False 31 | 32 | return True 33 | -------------------------------------------------------------------------------- /src/validator/PortValidator.py: -------------------------------------------------------------------------------- 1 | # path: src/validator/PortValidator.py 2 | import os 3 | import re 4 | import sys 5 | from typing import Dict, Union 6 | 7 | 8 | class PortValidator: 9 | """端口配置验证器,支持全场景校验""" 10 | 11 | @staticmethod 12 | def validate(port_str: str) -> Dict[str, Union[bool, str, int]]: 13 | """ 14 | 综合验证端口配置 15 | 16 | :return: 包含校验结果的字典 { 17 | "valid": bool, # 是否合法 18 | "value": int, # 转换后的端口号(仅当valid=True时存在) 19 | "warning": str, # 警告信息(如需要root权限) 20 | "error": str # 错误描述(仅当valid=False时存在) 21 | } 22 | """ 23 | # 基础清洗 24 | cleaned = port_str.strip() 25 | if not cleaned: 26 | return {"valid": False, "error": "端口不能为空"} 27 | 28 | # 格式校验 29 | if not re.match(r'^\d+$', cleaned): 30 | return {"valid": False, "error": "必须为纯数字"} 31 | 32 | # 数值转换 33 | try: 34 | port = int(cleaned) 35 | except ValueError: 36 | return {"valid": False, "error": "无效数字格式"} 37 | 38 | # 范围校验 39 | if not (0 <= port <= 65535): 40 | return {"valid": False, "error": "端口范围0-65535"} 41 | 42 | # 特殊端口警告 43 | result = {"valid": True, "value": port} 44 | if 1 <= port <= 1023 and not PortValidator._has_root(): 45 | result["warning"] = "需管理员权限(Linux/Mac需sudo)" 46 | 47 | return result 48 | 49 | @staticmethod 50 | def _has_root() -> bool: 51 | """检查是否具有管理员权限""" 52 | try: 53 | return (sys.platform == 'win32') or (os.geteuid() == 0) 54 | except AttributeError: 55 | # Windows无euid概念 56 | return False 57 | -------------------------------------------------------------------------------- /src/validator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/validator/__init__.py -------------------------------------------------------------------------------- /src/validator/__pycache__/KeyValidator.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/validator/__pycache__/KeyValidator.cpython-39.pyc -------------------------------------------------------------------------------- /src/validator/__pycache__/PortValidator.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/validator/__pycache__/PortValidator.cpython-39.pyc -------------------------------------------------------------------------------- /src/validator/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackguest007/mitmproxy-gui/33f0cd5c63323d6780ad69d883c26f12cd13394b/src/validator/__pycache__/__init__.cpython-39.pyc --------------------------------------------------------------------------------