jason903 发表于 2019-9-8 15:11

mitmproxy与charles的抓包应用 - 自动生成代码

本帖最后由 jason903 于 2019-11-17 23:35 编辑


## 问题
mitmproxy是命令行界面,不太方便查看,自己遇到的问题有:
* 在Flow Details界面不知道用哪个快捷键查看下一条或上一条网络请求详情
* json中的中文显示为 \ua9b4 或 ?不能看清是哪个中文
* 不知道怎么复制界面中显示的内容

Charles的编程能力弱

把Charles和mitmproxy结合起来使用,可以查看方便、编程扩展

## 环境

电脑和手机都连接到同一个Wi-Fi, 比如TP_LINK_629F
电脑: ip=192.168.1.100; 运行着Charles、mitmproxy
Charles: 192.168.1.100:8888
mitmproxy: 192.168.1.100:8080
手机: 设置代{过}{滤}理地址为Charles的地址192.168.1.100:8888

Charles - External Proxy Settings功能开启:
* Web Proxy(HTTP) - Web Proxy Server设置为mitmproxy的地址192.168.1.100:8080
* Secure Web Proxy(HTTPS) - Secure Web Proxy Server设置为mitmproxy的地址192.168.1.100:8080

| 手机 |
| :-: |
| ![](https://tva1.sinaimg.cn/large/006y8mN6ly1g6s2bq3vglj30u01hcaak.jpg) |
| |
| Charles - External Proxy Settings|
| |
| ![](https://tva1.sinaimg.cn/large/006y8mN6ly1g6s2ks0wauj31am0qe76x.jpg) |


## 应用
应用:自动生成接口的python代码

以`趣头条App`为例:
阅读得积分的接口为: `https://api.1sapp.com/readtimer/report`
自动生成的代码大约如下:

```
def readtimer_report(self):

    headers = {
                'User-Agent': 'qukan_android;retrofit/2.4.0 okhttp/3.11.0;os/7.0 M5 Note Meizu;device/862546036581345;version/3.9.41.000.0904.1121;channel/012',
                'Host': 'api.1sapp.com',
                'Accept-Encoding': 'gzip',
                'Connection': 'keep-alive',
      }

    params = {
                'qdata': 'NzVFNkE3Mjc0RjEzRkYwRTM5OTEzNjAyRUZBMDMzQTAuY0dGeVlXMGZPR0kyTldKalltTXRNVGczT1MwME9EZGlMVGszT0RBdE1EUmlOVEV3TWpOak9UazRIblpsY25OcGIyNGZNVEVlY0d4aGRHWnZjbTBmWVc1a2NtOXBaQjVsWXg4eC46LxvyIvgD62/T93SlANmywpigTwlOwcfCHe0iZ1D8mH1zpslt2JCRPdiHOj1M20bU0zDX0odUOBig6Kt51mheNJuQYeDvp15R8RSGTT3LR9s55nBCGvWyTLq+3pjEvkyERElR9E2I384/nHQR4iqxqv7LKQ4rBA0R6bNG8sksHqNl1izSbF87G/4/Qw5vVYcuNUfU0BM6vvIbsy2CTPWlJ51YCzadQZZLONuaYTpyhuOiUV4vnx6qkvpYDNp9XpPPjbXxJAb7fikqjWSdyx167hXDPzUkNZGndjZsv7kQANDkIk2Dm+g5YW1I49xnkOzJkmxvyrLevnsSb9S5fSEUEyfq0GlPHE0RRBeSjFxVltH1zdZraTtk13Z+MvA7HBYQONz/0OwyMnujc1Ety91uKh6YCCVEDvBO+RTOzoRDa3nlRo3FTo9OeRBsyL20qIP24977MMYXEoxinTuwNonipCjnjSYIrhOu6cyv7uxuLd6FxtmTsydawNGMPI/K+habIKXNUFsQMCUcAGhYpoKQJvkQqHEq6lPyZZzXDot1EsN6bsGj56xQdiuJZLMFyZaGNR6E9FmVlI0LAVT8ttVpOvs+5f08T0iMxMNb0VQk6DOySpYHp7EVjc9YFpPcVxj8aXvuTjoPkaNGhSKQ0fgBd8HVRLslcnzX0QLJkTuU7NQ9aili6m2M2hWvh/q8ghWrvtLT+izCiFNKHE+4GTC9J6jqgyjHsXkAjcOSBAaIXMQKnOd664hdoR2GqV+GAy95fc5zZCJ7EFvzmTbJQrpMOwW+Y2NvYPZtgjw1uJEyU7AR7nVw7VqMjPpCDYeWBWoQ1W4OjlXTqgBR4MIu1sTag6a+my/0hItf91SNa58zCN3YmE2NnsWwwiCC+ZP91moV/KqPwX3vMLKW4/3Vsziqe8gl',
      }

    data = {
      }

    url = 'http://api.1sapp.com/readtimer/report'
    result = self._get(url, headers=headers, params=params, data=data)
    return result
   
```

应用步骤:
1. 手机按上面环境设置好代{过}{滤}理地址
2. 在电脑上启动Charles,Charles按上面环境设置
3. 在电脑上启动mitimproxy, 启动命令如下:`mitmproxy -s gen_code_mitm.py`
4. 文件gen_code_mitm.py内容参考下面
5. 在手机`趣头条App`阅读文章或看视频一定时间
6. 会在`~/Desktop/api/`目录下生成一个叫`readtimer_report.text`
7. 把`readtimer_report.text`的相应代码复制粘帖到`文件qu_tou_tiao.py`中
8. 按需要修改自动生成的代码为希望的样子
9. 运行`qu_tou_tiao.py`

注意:
* `readtimer_report.text`的名字和所在目录是由代码`gen_code_mitm.py`决定的,请自行阅读修改
* `readtimer_report`方法名由代码`gen_code_mitm.py`决定的,请自行阅读修改
* 对body为复杂json格式的代码自动生成会有错误,有能力的自行修改
* `readtimer/report`这个接口自动生成的代码数据是不能重复获取积分的,这里只是演示

![](https://tva1.sinaimg.cn/large/006y8mN6ly1g6s4idpz9gj31fa0u045o.jpg)

## 文件
文件qu_tou_tiao.py:
```
'''
代码模板
'''
import requests
import json
import logging

logging.basicConfig(format='%(asctime)s:%(message)s', datefmt='%m-%d %H:%M:%S', level=logging.INFO)

class User(object):
    def __init__(self):
      pass
      
    def api_need_implement(self):
      pass

    def _header(self):
      return {
            'User-Agent': '',
            'Cookie':self.cookie
      }

    @staticmethod
    def _post(url, data=None, json=None, p=logging.warning, **kwargs):
      res = requests.post(url, data=data, **kwargs)
      result = res.text
      p(res.json())
      logging.info('')
      return result

    @staticmethod
    def _get(url, params=None, p=logging.warning, **kwargs):
      res = requests.get(url, params=params, **kwargs)
      result = res.text
      p(json.loads(result))
      logging.info('')
      return result

def genUsers():
    yield User()

if __name__ == "__main__":
    for user in genUsers():
      user.api_need_implement()
```


文件gen_code_mitm.py
```
import json
import re
from urllib.parse import urlparse

from mitmproxy import ctx
from mitmproxy import flowfilter
from mitmproxy import http

'''
生成接口python代码
'''

class GenCode(object):
    def __init__(self):
      ctx.log.info('__init__')

      # 趣头条
      urls = [
            r'sign/sign'
            r'taskcenter/getListV2',#tab页:任务
      ]
      self.qu_tou_tiao = flowfilter.parse('|'.join(urls))

      
      # 百度 - 全民小视频
      urls = [
            r'mvideo/api', # 每日签到
      ]
      self.quan_ming = flowfilter.parse('|'.join(urls))


      
      self.flowfilters = [
            self.qu_tou_tiao,
            self.quan_ming,
         ]      

    def load(self, loader):
      ctx.log.info('event: load')

    def configure(self, updated):
      ctx.log.info('event: configure')

    def running(self):
      ctx.log.info('event: running')

    def done(self):
      ctx.log.info('event: done')



    def response(self, flow: http.HTTPFlow):
      if any( [ filter(flow) for filter in self.flowfilters ] ):
            request: http.HTTPRequest = flow.request

            parse_result = urlparse(request.url)
            url_path = parse_result.path

            function_name = re.sub(r'[/-]','_', url_path).strip('_')
            headers_code = self.headers_string(flow)
            params_code = self.params_string(flow)
            data_code = self.data_string(flow)

            path = f'''/Users/zhoujie/Desktop/api/{function_name}.text'''
            with open(path, 'a') as f:
                print(f'''# ---------------------''',file=f)

                code = f'''
def {function_name}(self):

    {headers_code}

    {params_code}

    {data_code}

    url = '{request.scheme}://{request.pretty_host}{url_path}'
    result = self._{request.method.lower()}(url, headers=headers, params=params, data=data)
    return result
               
'''
                f.write(code)

                print(f'''Response:''',file=f)
                print(f'''{flow.response.text}''',file=f)
                print(f'''# ---------------------\n\n''',file=f)

    def headers_string(self, flow: http.HTTPFlow):
      lines = ''
      for key,value in flow.request.headers.items():
            lines += f"\n\t\t'{key}': '{value}',"
      s = f'''headers = {{{lines}\n\t}}'''      
      return s


    def params_string(self, flow: http.HTTPFlow):
      lines = ''
      for key,value in flow.request.query.items():
            lines += f"\n\t\t'{key}': '{value}',"
      s = f'''params = {{{lines}\n\t}}'''      
      return s

    def data_string(self, flow: http.HTTPFlow):
      '''
      Content-Type: application/x-www-form-urlencoded
      Content-Type: application/json; charset=utf-8
      Content-Type: text/plain;charset=utf-8
      '''
      lines = ''

      # 取其一
      for key,value in flow.request.urlencoded_form.items():
            lines += f"\n\t\t'{key}': '{value}',"

      for key,value in flow.request.multipart_form.items():
            key = key.decode(encoding='utf-8')
            value = value.decode(encoding='utf-8')
            lines += f"\n\t\t'{key}': '{value}',"

      # Todo:复杂json数据还不能代码化
      if 'application/json' in flow.request.headers.get('content-type',''):
            try:
                d = json.loads(flow.request.text)
                for key,value in d.items():
                  lines += f"\n\t\t'{key}': {value},"
            except Exception as e:
                pass
      
      s = f'''data = {{{lines}\n\t}}'''      
      return s


   

addons = [
    GenCode()
]
```

宇宙魔方 发表于 2019-9-8 15:27

这个好啊,谢谢分享哦

不苦小和尚 发表于 2019-9-8 15:33

太蛮烦了,我还是用fD吧

mikeee 发表于 2019-9-10 14:05

感谢分享,学习一下

searchjack 发表于 2021-1-26 12:28

{:1_907:}      看得我一脸懵逼   , 还是 fd 适合我

jason903 发表于 2021-1-26 12:56

searchjack 发表于 2021-1-26 12:28
看得我一脸懵逼   , 还是 fd 适合我

我没有用过fd, 因为Mac上可能没有fd.
用不用charles无所谓,
不知道fd有没有自己编程的能力[插件]?
如果没有,可以学习下mitmproxy

searchjack 发表于 2021-1-26 13:28

jason903 发表于 2021-1-26 12:56
我没有用过fd, 因为Mac上可能没有fd.
用不用charles无所谓,
不知道fd有没有自己编程的能力[插件]?


感谢   我研究下

bill7740571 发表于 2021-1-26 14:09

FD全名叫什么

jason903 发表于 2021-1-26 15:35

bill7740571 发表于 2021-1-26 14:09
FD全名叫什么

抓包工具 - Fiddler
页: [1]
查看完整版本: mitmproxy与charles的抓包应用 - 自动生成代码