美文网首页
人不轻狂枉少年

人不轻狂枉少年

作者: NoviceQAQ | 来源:发表于2018-05-31 15:21 被阅读0次

    大神的辞职,带走了骚豆腐和烤洋芋,带走了星辰大海,也带走了破解的自动打卡。已被懒惰侵蚀的我,早已无法按时起床。为了回到我温暖的被窝,经过python的指引,终于完成了自动打卡的代码。


    抓包分析

    之前使用Burpsuite来抓包,后来嫌窗口切来切去麻烦就在windows上装了Fiddler4,其实还是比较好用的。首先做的第一部就是设置代理了,因为公司打卡使用app实现的。在Fiddler4的菜单选择Tools->options,在下图红色框内打上勾。接下来Ipconfig看下自己电脑的IP,手机和电脑连接到同一局域网,在手机中把电脑IP地址设置为代理地址。就可以抓包了。


    代理.png
    第一个包,打开应用

    打开手机中公司的应用,抓到第一个包,可以看出手机以POST方式像服务器提交了phoneType和userId,两个数据,先将他们存下来,包1-1是http请求头信息。


    包1-1.png

    包1-2是手机客户端主动向服务器发送的数据。


    包1-2.png
    第二个包,客户端登录

    接下来手机模拟登录截到第二个包。包2-1显示的为手机客户端登录请求的地址目录为/mobile/login 。


    包2-1.png

    包2-2为手机客户端向服务器发送的数据:
    system=android
    password=SO1Nc4KbrsEl3KKV1rwY3A%3D%3D
    account=我的账号
    serialNumbe=869949028710182
    version=7
    model=FRD-AL10


    包2-2.png

    登录成功后服务器将会回复如下信息:
    这里比较重要的信息为token,使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
    1、客户端使用用户名跟密码请求登录
    2、服务端收到请求,去验证用户名与密码
    3、验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
    4、客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
    5、客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
    服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据


    包2-2.png
    第三个包,考勤打卡

    最后一个包就是打卡的包了,点击打卡发现打卡请求地址为/mobile/busUserClock/saveOrUpdateNewUserClock,其实头文件都是一样的只有上传的长度不同。


    包3-1.png

    点击打卡后客户端向服务器端发送的数据为:
    1、之前登录成功后获取的token,这里的token和之前的截图不符是因为,我手机打过卡就无法再打,为了提到截图用的是同事的手机;
    2、longitude(精度)、latitude(纬度),中间我省略了几个请求的包,公司打卡的定位是通过调用百度地图API获得定位的,这里的经纬度也是从那里来的;
    3、在第一次打开应用时,客户端主动向服务器发送的userId;
    4、startTime、endTime我们上下班时间=。=#;
    5、position这个是打卡的地址。


    包3-2.png
    服务器返回的数据为签退成功。
    包3-3.png

    python实现

    终于到了激动人心的时刻,使用python模拟上述发包的过程实现客户端与服务器的交互。这里先自己检讨下,我写的代码就跟一坨屎一样,但是一边抓包一边写,最后直接拼在一起的,相当的粗糙,等周末再好好改下代码吧=。=#

    #! /usr/bin/python
    # coding:utf - 8
    
    """
    autho:czy
    仅用于自己使用
    """
    import requests
    
    url_init = 'http://服务器地址:端口号/mobile/person/getNewVersion'
    url_login = 'http://服务器地址:端口号/mobile/login'
    url_clock = "http://服务器地址:端口号/mobile/busUserClock/saveOrUpdateNewUserClock"
    
    #打开应用头请求
    headers_init = {
            "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 7.0; FRD-AL10 Build/HUAWEIFRD-AL10)",
            "Accept-Encoding": "gzip",
            "Content-Length": "52",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Connection": "Keep-Alive"
    }
    
    #登录头请求
    headers_login = {
            "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 7.0; FRD-AL10 Build/HUAWEIFRD-AL10)",
            "Accept-Encoding": "gzip",
            "Content-Length": "129",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Connection": "Keep-Alive"
    }
    
    #打卡头请求
    headers_clock = {
            "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 7.0; FRD-AL10 Build/HUAWEIFRD-AL10)",
            "Accept-Encoding": "gzip",
            "Content-Length": "461",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "Connection": "Keep-Alive"
    }
    
    #打开应用传送的数据
    payload_init = {
            "phoneType": "1",
            "userId": "402880f25c620dd7015c76227a2019da"
    }
    
    #登录传送的数据
    payload_login = {
            "system":"android",
            #注意这里UTF-8编码会将=号转化为%3D,所以发送数据时应使用=号
            "password":"SO1Nc4KbrsEl3KKV1rwY3A==",
            "account":"我的账号,这里就公开了",
            "serialNumber":"869949028710182",
            "version":"7.0",
            "model":"FRD-AL10",
    }
    
    #模拟发送打开应用的包
    r = requests.post(url_init,data = payload_init,headers = headers_init)
    #print r.text  可以用于检查服务器是否正常返回数据
    
    #模拟发送登录数据的包
    r2 = requests.post(url_login,data = payload_login,headers = headers_login)
    #从返回的数据中提取token
    token = str(r2.text[466:654])
    #print token  可以用于检查服务器是否正常返回数据
    
    #打卡发送的数据
    payload_clock = {
            "token": token,
            "longitude": "102.676988",
            "userId":"402880f25c620dd7015c76227a2019da",
            "latitude": "25.053235",
            #注意这里UTF-8编码会将:号转化为%3A,所以发送数据时应使用:号
            "startTime": "09:00",
            "endTime": "18:00",
            #公司打卡分上下班下面注释的是上班发送的数据,没注释的是下班发送的数据。
            #"position": "这里写上打卡的地址",
            #"isStart": "1"
            "position": "这里写上打卡的地址",
            "isStart": "0"
    }
    
    #模拟打卡发送的包
    r3 = requests.post(url_clock,data = payload_clock,headers = headers_clock)
    print r3  #查看是否正常打卡
    
    

    运行结果<Response [200]>http状态表返回成功,查看手机打卡成功。


    运行结果.png

    服务器自动运行python脚本

    脚本已经可以正常使用了接下来就是让机器帮我们运行了,如果天天起来自己点脚本就和用手机打没区别了。在公司的KVM上建个CentOS6.9的服务器(嘘!!!悄悄呢)。
    把脚本拷上去取个帅气的名字

    帅气的名字.png
    这里注意有些同学运行不了会提示缺少模块requests
    安装扩展源EPEL。
    EPEL(http://fedoraproject.org/wiki/EPEL) 是由 Fedora 社区打造,为 RHEL 及衍生发行版如 CentOS、Scientific Linux 等提供高质量软件包的项目。
    ~]# yum -y install epel-release
    然后再安装pip
    ~]# sudo yum -y install python-pip
    最后安装requests模块
    ~]#pip install requests
    crontab

    接下来为服务器设置定时任务
    ~]#crontab -e
    crontab命令格式:
    "* * * * * command"
    M H D m d command
    M: 分(0-59)
    H:时(0-23)
    D:天(1-31)
    m: 月(1-12)
    d: 周(0-6) 0为星期日


    双休定时任务.png

    可以使用如下命令打开邮件查看定时任务执行的情况
    ~]#tail -f /var/spool/mail/root
    这里我测试了一下,执行成功!


    执行成功.png

    后续代码整理

    公司更新后软件重新整理了下代码,更新如下:

    #! /usr/bin/python
    # coding:utf - 8
    
    """
    autho:czy
    """
    import requests
    import json
    import time
    
    #请求和打卡地址
    url_login = 'http://服务器地址:端口号/mobileFrame/login'
    url_clock = "http://服务器地址:端口号/mobile/Hr/userClock"
    
    #伪装头信息
    headers_init = {
            "Accept":"application/json",
            "Accept-Encoding": "gzip,deflate",
            "Accept-Language":"zh-CN,en-US;q=0.8",
            "User-Agent": "Mozilla/5.0 (Linux; Android 7.0; FRD-AL10 Build/HUAWEIFRD-AL10; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36 Html5Plus/1.0 (Immersed/24.0)",
            "X-Requested-With": "XMLHttpRequest",
            "Content-Length": "453",
            "Content-Type": "application/x-www-form-urlencoded",
            "Origin": "file://",
            "Connection": "Keep-Alive"
    }
    
    #伪装登录请求信息
    payload_login = {
            "system":"android",
            "password":"XXXXXX", #这里填写截取到的密码
            "account":"XXXXX",  #这里填写账号
            "serialNumber":"869949028710182%2C869949027256583",
            "version":"7.0",
            "model":"FRD-AL10",
    }
    
    #模拟登录系统抓取token
    server_request_login = requests.post(url_login,data = payload_login,headers = headers_init)
    server_response_login = dict(json.loads(server_request_login.text))
    #相比上次切片截取,使用字典截取更为严谨
    response_token = server_response_login['data'][0]['token']
    
    #获取当前时间
    now_time = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
    
    #判断上下班时间(上次脚本做了两个这里加入判断就避免写两个脚本了)
    if int(time.strftime("%H%M%S"))<85959:
            State = "SIGN"
    else:
            State = "SIGN_OUT"
    
    #伪装打卡请求信息
    payload_clock = {
            "token": response_token,
            "lng": 102.677008,
            "lat": 25.053206,
            "distance": 46.01784908422327,
            "signState": State,
            "nowTime": now_time,
            "position": "打卡的地址",
    }
    
    #模拟打卡
    server_request_clock = requests.post(url_clock,data = payload_clock,headers = headers_init)
    print(server_request_clock)
    

    相关文章

      网友评论

          本文标题:人不轻狂枉少年

          本文链接:https://www.haomeiwen.com/subject/nsmqsftx.html