前言

  贪欲是人类与生俱来的陋习,但正是因为有贪欲,人类才能进步,“贪”才是我们探索精神的领袖。
  在前两篇博文中,我对安朗(安腾)宽带认证客户端(以下统称蝴蝶)进行了简单的爆破,达到了无障碍使用共享Wifi软件的目的,并且分析和试译了Swiftz协议(以下统称蝴蝶协议),但这并不能满足我的贪欲,所以这一篇记录了我如何从零制作一个属于自己的蝴蝶

准备

说明

  在你开始看这一篇博文之前,请务必看懂蝴蝶协议,并在动手制作之间实时查阅,这会让你的编程效率大大提高。
  根据蝴蝶协议的分析,整个蝴蝶客户端,我们需要实现的是四个主要功能:搜索、上线、呼吸、下线。

  • 搜索:构建搜索包,发送搜索包从本机IP:38481.1.1.8:3850,接收返回包。
  • 上线:构建上线包,发送上线包从本机IP:3848服务器IP:3848,接收返回包。
  • 呼吸:构建呼吸包,循环发送呼吸包从本机IP:3848服务器IP:3848(间隔30秒),循环接收返回包。
  • 下线:构建下线包,发送下线包从本机IP:3848服务器IP:3848,接收返回包。

实现

  重点提一下构建数据包,以构建搜索服务器的数据包为例(构建上线、呼吸、下线数据包大同小异),至于发送接收数据包则非常简单,利用Socket发报收报即可,但要注意是基于UDP协议的。
  另外,在发送和接收之前,需要加密和解密数据包。即:

  构建数据包——加密数据包——发送数据包——接收数据包——解密数据包

  构建搜索服务器数据包部分示例代码:

  • [C]
void search_server(int sockfd,struct infoset * const pinfo){
    char md5[0x10] = {0x0};
    int  md5len = 0x10;
    char *pkt, *ppkt, *tmphost;
    struct usrinfoSet *psu = pinfo -> psu;
    struct sockaddr_in *pss = pinfo -> pss;
    int sendbytes = 51;
    
    int iplen = strlen(psu -> local_ip), maclen = 0x6;
    pkt = (char *)calloc(sendbytes, sizeof(char));
    ppkt = pkt;
    *ppkt++ = 0x0c;
    *ppkt++ = sendbytes;
    ppkt += 0x10;
    
    *ppkt++ = 0x08;
    *ppkt++ = 0x07;
    *ppkt++ = 0x00;
    *ppkt++ = 0x01;
    *ppkt++ = 0x02;
    *ppkt++ = 0x03;
    *ppkt++ = 0x04;
    ……
    ……
    ……
  • [Python]
def search_server_ip(ip, mac):
    packet = []
    packet.append(0x0c)
    packet_len = 1 + 1 + 16 + 1 + 1 + 5 + 1 + 1 + 16 + 1 + 1 + 6
    packet.append(packet_len)
    packet.extend([i * 0 for i in range(16)])
    packet.append(0x08)
    packet.append(0x07)
    packet.extend([i * 1 for i in range(5)])
    packet.append(0x09)
    packet.append(0x12)
    packet.extend([ord(i) for i in ip])
    packet.extend([i * 0 for i in range(16 - len(ip))])
    packet.append(0x07)
    ……
    ……
    ……
  • [Java]
private void searchServerIp() {
        byte packet_len = 1 + 1 + 16 + 1 + 1 + 5 + 1 + 1 + 16 + 1 + 1 + 6;
        byte[] packet = new byte[packet_len];
        byte i = -1;
        packet[++i] = 0x0c;
        packet[++i] = packet_len;
        for (; i < 17;) {
            packet[++i] = 0;
        }
        packet[++i] = 0x08;
        packet[++i] = 0x07;
        for (byte j = 0; j < 5; j++) {
            packet[++i] = j;
        }
        packet[++i] = 0x09;
        packet[++i] = 0x12;
        byte[] bytes = LOCAL_IP.getBytes();
        for (byte b : bytes) {
            packet[++i] = b;
        }
        for (int j = 0; j < 16 - bytes.length; j++) {
            packet[++i] = 0;
        }
        packet[++i] = 0x07;
        packet[++i] = 0x08;
        ……
        ……
        ……
  • [C#]
 public class SearchSend
    {
        public byte[] SessionBytes;
        public string IP;
        public string Mac;
        public SearchSend(string ip, string mac)
        {
            IP = ip;
            Mac = mac;
            SessionBytes = new byte[5]
            {
                0,1,2,3,4
            };
        }
        public byte[] ToBytes()
        {
            int offset = 0;
            int iLen = 51;
            byte[] bts = new byte[iLen];
            bts[offset] = 0x0C;
            offset++;
            bts[offset] = 51;
            for (int i = 1; i < 16; i++)
            {
                bts[++offset] = 0;
            }
            offset++;
            offset++;
            bts[offset] = 8;
            ……
            ……
            ……

抓包

  在构建数据包完成后,我们需要利用抓包工具来测试我们构建的数据包是否正确、发送和接收数据包是否正常,而Wireshark这款工具是一个不错的选择。

1.jpg

  我们主要检查的是包的长度、收发端口、以及最重要的Data

2.jpg

  抓包之前,我们要利用蝴蝶协议中提到的3848端口解密算法额外写一个解密程序,用来打印数据包被解密后的数据,以便我们能够更直观地检查。下图以上线数据包为例:

3.jpg

后记

  在编写过程中,一定会遇到许许多多的问题(大神忽略),路漫漫其修远兮,你要上下而求索,要时刻铭记。因为在你想要放弃的时候,其实距离终点只有一步之遥。
  下面说一下当初编写这个程序我的一些经验:

  • 登录确认包可以完全省略。
  • 如果你想节省时间,其实搜索包也可以省略,学校不会频繁更换服务类型和服务器IP地址,记下来填上即可。
  • 服务器是固定三个端口384838493850,但是本地端口是随机的话也能正常认证,绑定同样的端口是为了防止多个认证客户端同时工作,这可能会造成一些错误。
  • 上线包和下线包只发送一次,可以容许一点瑕疵,只要能成功接收到服务器返回的数据包,提取到需要的内容就行。
  • 呼吸包的构建必须完全正确,因为是循环地发送和接收,其过程必须稳定,这关系到你能否顺畅地使用校园网,在调试过程中可以拿学校官方的蝴蝶数据进行比对查错。
  • 呼吸包发送间隔是30秒,也可以小于30秒,如果呼吸包不稳定可以尝试适当调整。
  • 在构建数据包之前要把需要填充的数据整理打包好,例如类型的转换,以及空字符的处理等等,以减少不必要的程序异常。
  • 编写这个程序很简单,但是错误处理和代码优化有点繁琐,将自己当成使用者,并不断测试程序的极限状态,你会发现bug比你头发还多(当然,其根本原因还是我学艺不精)。

  完成程序后,还可以考虑增加一点自己常用的功能,例如集成无线热点,增加NAT穿透等等……

  成品效果图:

4.jpg

如果觉得我的文章对您有用,请我喝一杯咖啡吧~