zoukankan      html  css  js  c++  java
  • DNS解析

    //****************************************************************************************/
    //获取DNS
     
    #include "DNS.h"
    
    
    
    //全局变量
    PDNSADDRANDURL global_pwsadata;
    
    NTSTATUS
    DriverEntry(
        PDRIVER_OBJECT pDriverObj,
        PUNICODE_STRING pRegistryString
    )
    {
        NTSTATUS status = STATUS_SUCCESS;
        UNICODE_STRING ustrLinkName;
        UNICODE_STRING ustrDevName;
        PDEVICE_OBJECT pDevObj;
    
        int s_dns = 0;
    
        unsigned char hostname[100] = { "www.debugman.com" };
    
        //if (DBG)
        {
            //    __asm int 3 
        }
    
    
    
        dprintf("[hello] DriverEntry
    ");
    
        pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
        pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
        pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
        pDriverObj->DriverUnload = DriverUnload;
    
    
        RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
        status = IoCreateDevice(pDriverObj,
            0,
            &ustrDevName,
            FILE_DEVICE_UNKNOWN,
            0,
            FALSE,
            &pDevObj);
    
        if (!NT_SUCCESS(status)) {
            dprintf("[hello] IoCreateDevice = 0x%x
    ", status);
            return status;
        }
    
        RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
         
        if (!NT_SUCCESS(status)) {
            dprintf("[hello] IoCreateSymbolicLink = 0x%x
    ", status);
            IoDeleteDevice(pDevObj);
            return status;
        }
    
        global_pwsadata = (PDNSADDRANDURL)ExAllocatePool(0, sizeof(DNSADDRANDURL));
    
        s_dns = ReadDnsServerFromRegistry();  //返回网络字节顺序
        global_pwsadata->serveur_dns = s_dns;
        gethostbyname(hostname);
        dprintf(" remote ip address is %x
    ", global_pwsadata->urladdr);
    
        return STATUS_SUCCESS;
    }
    
    
    VOID
    DriverUnload(
        PDRIVER_OBJECT pDriverObj
    )
    {
        UNICODE_STRING strLink;
        RtlInitUnicodeString(&strLink, LINK_NAME);
    
        //
        // 添加卸载代码
        //
    
    
    
        IoDeleteSymbolicLink(&strLink);
        IoDeleteDevice(pDriverObj->DeviceObject);
        dprintf("[hello] Unloaded
    ");
    }
    
    
    NTSTATUS
    DispatchCreate(
        PDEVICE_OBJECT pDevObj,
        PIRP pIrp
    )
    {
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = 0;
    
        dprintf("[hello] IRP_MJ_CREATE
    ");
    
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
        return STATUS_SUCCESS;
    }
    
    
    NTSTATUS
    DispatchClose(
        PDEVICE_OBJECT pDevObj,
        PIRP pIrp
    )
    {
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = 0;
    
        dprintf("[hello] IRP_MJ_CLOSE
    ");
    
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
        return STATUS_SUCCESS;
    }
    
    
    NTSTATUS
    DispatchIoctl(
        PDEVICE_OBJECT pDevObj,
        PIRP pIrp
    )
    {
        NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
        PIO_STACK_LOCATION pIrpStack;
        ULONG uIoControlCode;
        PVOID pIoBuffer;
        ULONG uInSize;
        ULONG uOutSize;
    
        pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
        uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
        pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
        uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
        uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
    
        switch (uIoControlCode) {
    
        case IOCTL_HELLO: {
    
            dprintf("[hello] Hello
    ");
            status = STATUS_SUCCESS;
        }
                          break;
        }
    
        if (status == STATUS_SUCCESS)
            pIrp->IoStatus.Information = uOutSize;
        else
            pIrp->IoStatus.Information = 0;
    
        /////////////////////////////////////
        pIrp->IoStatus.Status = status;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    
        return status;
    }
    
    /*
    返回网络字节顺序
    */
    int ReadDnsServerFromRegistry()
    {
        //Variables locales
        NTSTATUS       status = STATUS_UNSUCCESSFUL;
    
        WCHAR       ChaineRegistre[] = L"\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces";
        UNICODE_STRING     usRegistryKey = { 0 };
        OBJECT_ATTRIBUTES     obNomClefRegistre = { 0 };
        HANDLE        RegHandle = 0;
    
        UNICODE_STRING     usRegistryKeySub = { 0 };
        OBJECT_ATTRIBUTES     obNomClefRegistreSub = { 0 };
        HANDLE        RegHandleSub = 0;
    
        WCHAR       ChaineEnableDHCP[] = L"EnableDHCP";
        WCHAR       ChaineNameServer[] = L"NameServer";
        WCHAR       ChaineDhcpNameServer[] = L"DhcpNameServer";    //有问题这个,注册表里好像没有   Win10下DhcpServer
                                                                //DhcpServer
        char        informations_lues[256];
        ULONG       size_lue = 0;
    
        KEY_VALUE_FULL_INFORMATION *KeyValue = NULL;
        char        adresses_ips_dns[40];
    
        int         compteur_subkey = 0;
        unsigned int       adresse = 0;
    
        ANSI_STRING AnsiString;
        UNICODE_STRING CurrentName;
    
    
        RtlInitUnicodeString(&usRegistryKey, ChaineRegistre);
    
        InitializeObjectAttributes(&obNomClefRegistre,
            &usRegistryKey,
            OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
            NULL,
            NULL);
    
        status = ZwOpenKey(&RegHandle, KEY_READ, &obNomClefRegistre);    
        //打开 L"\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces"
    
        if (status != STATUS_SUCCESS)
        {
            return -1;
        }
    
        compteur_subkey = 0;
        status = STATUS_SUCCESS;
        while (TRUE)
        {
            memset(informations_lues, 0, 256);
            status = ZwEnumerateKey(RegHandle,
                compteur_subkey,
                KeyBasicInformation,
                &informations_lues,
                256,
                &size_lue);
    
    
            if (status != STATUS_SUCCESS)
                break;
    
    
            RtlInitUnicodeString(&usRegistryKeySub,
                ((*(KEY_BASIC_INFORMATION*)&informations_lues).Name));
    
            InitializeObjectAttributes(&obNomClefRegistreSub,
                &usRegistryKeySub,
                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                NULL, NULL);
    
    
            obNomClefRegistreSub.RootDirectory = RegHandle;
    
    
            status = ZwOpenKey(&RegHandleSub,
                KEY_READ,
                &obNomClefRegistreSub);
    
    
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
    
                continue;
            }
    
    
            memset(informations_lues, 0, 256);
    
            RtlInitUnicodeString(&usRegistryKey,
                ChaineEnableDHCP);
    
            status = ZwQueryValueKey(RegHandleSub,
                &usRegistryKey,
                KeyValueFullInformation,
                &informations_lues,
                256,
                &size_lue);
    
    
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
                ZwClose(RegHandleSub);
                continue;
            }
    
    
            KeyValue = (KEY_VALUE_FULL_INFORMATION *)informations_lues;
            if (*(int*)(informations_lues + KeyValue->DataOffset))
            {
    
                RtlInitUnicodeString(&usRegistryKey,
                    ChaineDhcpNameServer);
            }
            else
            {
    
                RtlInitUnicodeString(&usRegistryKey,
                    ChaineNameServer);
            }
    
    
            memset(informations_lues, 0, 256);
            status = ZwQueryValueKey(RegHandleSub,
                &usRegistryKey,
                KeyValueFullInformation,
                &informations_lues,
                256,
                &size_lue);
    
    
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
    
                ZwClose(RegHandleSub);
                continue;
            }
    
    
            RtlZeroMemory(adresses_ips_dns, 40);
    
            RtlInitUnicodeString(&CurrentName, informations_lues + KeyValue->DataOffset);
            RtlUnicodeStringToAnsiString(&AnsiString, &CurrentName, TRUE);
            RtlCopyMemory(adresses_ips_dns, AnsiString.Buffer, 40);
    
            dprintf("DNS SERVICE IP %s
    ", adresses_ips_dns);
    
            ZwClose(RegHandleSub);
    
            adresse = inet_addr(adresses_ips_dns);
            if (adresse == 0)
            {
                compteur_subkey++;
                continue;
            }
    
            ZwClose(RegHandle);
            return adresse;
    
            compteur_subkey++;
        }
        ZwClose(RegHandle);
        return -1;
    }
    
    
    
    //获取了DNS的ip后问题就容易处理,剩下构造dns请求包和udp的相关东西~~
    //因为dns请求的协议要求获得本机地址,要去取本机地址,代码如下
    
    /*
    返回网络字节顺序
    */
    int ReadHostIPsFromRegistry()
    {
        NTSTATUS        status = STATUS_UNSUCCESSFUL;
        int*            pHostentArray = NULL;
        char*            pHostentData = NULL;
    
        WCHAR            ChaineRegistre[] = L"\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces";
    
        UNICODE_STRING  usRegistryKey = { 0 };
        OBJECT_ATTRIBUTES        obNomClefRegistre = { 0 };
        HANDLE            RegHandle = 0;
    
        UNICODE_STRING     usRegistryKeySub = { 0 };
        OBJECT_ATTRIBUTES  obNomClefRegistreSub = { 0 };
        HANDLE               RegHandleSub = 0;
    
        WCHAR       ChaineEnableDHCP[] = L"EnableDHCP";
        WCHAR       ChaineIPAddress[] = L"IPAddress";
        WCHAR       ChaineDhcpIPAddress[] = L"DhcpIPAddress";
    
        char        informations_lues[256];
        ULONG       size_lue = 0;
    
        KEY_VALUE_FULL_INFORMATION *KeyValue = NULL;
        char        adresse_ip[20];
    
        int          compteur_subkey = 0;
        unsigned int adresse = 0;
    
        ANSI_STRING AnsiString;
        UNICODE_STRING CurrentName;
    
        RtlInitUnicodeString(&usRegistryKey,
            ChaineRegistre);
    
        InitializeObjectAttributes(&obNomClefRegistre,
            &usRegistryKey,
            OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
            NULL, NULL);
    
        status = ZwOpenKey(&RegHandle,//打开主键
            KEY_READ,
            &obNomClefRegistre);
        if (status != STATUS_SUCCESS)
        {
            return -1;
        }
    
        compteur_subkey = 0;//子键的个数
        status = STATUS_SUCCESS;
        while (TRUE)
        {
            memset(informations_lues, 0, 256);
            status = ZwEnumerateKey(RegHandle,
                compteur_subkey,
                KeyBasicInformation,
                &informations_lues,
                256,
                &size_lue);
    
            if (status != STATUS_SUCCESS)
                break;
    
            RtlInitUnicodeString(&usRegistryKeySub,
                ((*(KEY_BASIC_INFORMATION*)&informations_lues).Name));
            DbgPrint("subkey is  %ws", usRegistryKeySub.Buffer);
    
            InitializeObjectAttributes(&obNomClefRegistreSub,
                &usRegistryKeySub,
                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                NULL,
                NULL);
    
            obNomClefRegistreSub.RootDirectory = RegHandle;
    
            status = ZwOpenKey(&RegHandleSub,
                KEY_READ,
                &obNomClefRegistreSub);
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
                dprintf("[niveau socket] !! ReadHostIPsFromRegistry : Echec d'ouverture du registre sur sous-clef
    ");
                continue;
            }
    
            memset(informations_lues, 0, 256);
            RtlInitUnicodeString(&usRegistryKey, ChaineEnableDHCP);
    
            status = ZwQueryValueKey(RegHandleSub,
                &usRegistryKey,
                KeyValueFullInformation,
                &informations_lues,
                256,
                &size_lue);
    
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
                dprintf("[niveau socket] !! ReadHostIPsFromRegistry : Echec lecture valeur EnableDHCP
    ");
                ZwClose(RegHandleSub);
                continue;
            }
    
            KeyValue = (KEY_VALUE_FULL_INFORMATION *)informations_lues;
            if (*(int*)(informations_lues + KeyValue->DataOffset))
            {
                RtlInitUnicodeString(&usRegistryKey, ChaineDhcpIPAddress);
            }
            else
            {
                RtlInitUnicodeString(&usRegistryKey, ChaineIPAddress);
            }
    
            memset(informations_lues, 0, 256);
            status = ZwQueryValueKey(RegHandleSub,
                &usRegistryKey,
                KeyValueFullInformation,
                &informations_lues,
                256,
                &size_lue);
            if (status != STATUS_SUCCESS)
            {
                compteur_subkey++;
                ZwClose(RegHandleSub);
                continue;
            }
    
            RtlZeroMemory(adresse_ip, 20);
            RtlInitUnicodeString(&CurrentName, informations_lues + KeyValue->DataOffset);
            RtlUnicodeStringToAnsiString(&AnsiString, &CurrentName, TRUE);
            RtlCopyMemory(adresse_ip, AnsiString.Buffer, 20);
    
            dprintf("HOST IP %s", adresse_ip);
    
            ZwClose(RegHandleSub);
    
            adresse = inet_addr(adresse_ip);
            if (adresse == 0)
            {
                compteur_subkey++;
                continue;
            }
            else
            {
                return adresse;
            }
        }
        ZwClose(RegHandle);
    
        return adresse;
    }
    
    //下面开始贴具体DNS请求过程的代码了
    //已经获取得到网络字节顺序
    PHOSTENT gethostbyname(IN char *name)
    {
        struct sockaddr_in  sockaddr_dns = { 0 };
        unsigned char* phostent_buf = NULL;
    
        if (global_pwsadata->serveur_dns == 0)
        {
            return NULL;
        }
    
        phostent_buf = ExAllocatePoolWithTag(0, 2048, 'doki');
        if (phostent_buf == NULL)
        {
            return NULL;
        }
        RtlZeroMemory(phostent_buf, 2048);
    
        sockaddr_dns.sin_family = AF_INET;
        sockaddr_dns.sin_addr.s_addr = global_pwsadata->serveur_dns;//DNS的主机地址
        sockaddr_dns.sin_port = HTONS(53);//dns 服务器固定端口
    
        if (query_dns(sockaddr_dns, name, phostent_buf, FALSE) != -1)
        {
            return (PHOSTENT)phostent_buf;
        }
        else
        {
            ExFreePool(phostent_buf);
            return NULL;
        }
    }
    
    int query_dns(IN  struct sockaddr_in sockaddr_dns,    
        IN  char* URL,    //www.DebugMan.com
        OUT char *hostent_buf,//返回的值
        IN  int rdns)//rdns 是否反向查询
    {
        struct sockaddr_in    sockaddr_bind = { 0 }; //干什么用的?
        int            com_socket = 0;
        NTSTATUS    status = STATUS_UNSUCCESSFUL;
    
        int size_string_requete_format_dns = 0;
        int size_string_requete = 0;
    
        unsigned char * buf = NULL;//需要构造的缓冲区
        unsigned char * reader;  //读取的位置指针
        DNS_HEADER      *    dns = NULL;
        int                size_buffer_dns = 0;// sendto must be know length of databuf
    
        char *                res_record_crawler = NULL;
        CUSTOM_RES_RECORD * res_record = NULL;
        unsigned int *        adresse_ip = NULL;
        int                    compteur_reponses = 0;
    
        PHOSTENT    hostent = NULL;
        char*        hostent_content = NULL;
        char**        hostent_array = NULL;//指向指针的指针
    
        unsigned char * qname = NULL;
        QUESTION *   qinfo = NULL;
    
        int lock = 0, i, j, k;
        int stop, lenthqname;
    
        struct sockaddr_in a;//便于记录读取的IP 
        struct RES_RECORD answers[20], auth[20], addit[20];  //the replies from the DNS server
    
        PUCHAR returnaddr;//指针
    
        int lenth = sizeof(DNS_HEADER);
    
        buf = ExAllocatePoolWithTag(0, 2048, 'doki');
        if (buf == NULL)
        {
            return NULL;
        }
        RtlZeroMemory(buf, 2048);
    
        /*
        +---------------------+
        | Header              |
        +---------------------+
        | Question            | the question for the name server
        +---------------------+
        | Answer              | RRs answering the question
        +---------------------+
        | Authority           | RRs pointing toward an authority
        +---------------------+
        | Additional          | RRs holding additional information
        +---------------------+
    
    
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        | ID                                            |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |QR| Opcode    |AA|TC|RD|RA| Z      |  RCODE    |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   QDCOUNT                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   ANCOUNT                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   NSCOUNT                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
        |                   ARCOUNT                     |
        +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    
        */
        //1 Construction du message DNS 
        //buffer : DNS_HEADER | nom modifi?| QUESTION
        dns = (DNS_HEADER*)buf;
    
        dns->id = 1234;
    
        //Flags DNS
        dns->qr = 0; //This is a query
        dns->opcode = 0; //This is a standard query
        dns->aa = 0; //Not Authoritative
        dns->tc = 0; //This message is not truncated
        dns->rd = 1; //Recursion Desired
        dns->ra = 0; //Recursion not available! hey we dont have it (lol)
        dns->z = 0;
        dns->ad = 0;
        dns->cd = 0;
        dns->rcode = 0;
    
        dns->q_count = HTONS(1); //we have only 1 question
        dns->ans_count = 0;
        dns->auth_count = 0;
        dns->add_count = 0;
    
        //point to the query portion
        qname = (unsigned char*)&buf[sizeof(DNS_HEADER)];
        //www.google.com ==>> 3www6google3com  
        ChangetoDnsNameFormat(qname, URL);
    
        qinfo = (struct QUESTION*)&buf[sizeof(DNS_HEADER) + (strlen((const char*)qname) + 1)]; //fill it
    
        qinfo->qtype = HTONS(1);  //we are requesting the ipv4 address
        qinfo->qclass = HTONS(1); //its internet always is 1 
    
        size_buffer_dns = sizeof(DNS_HEADER) + strlen(qname) + 1 + sizeof(QUESTION);//33
    
        //com_socket = socket(AF_INET, SOCK_DGRAM ,IPPROTO_UDP);
        //udp 数据报查询
        com_socket = socket(2, 2, 17);
        if (com_socket == -1)
        {
            ExFreePool(buf);
            return -1;
        }
    
        status = sendto(com_socket, buf, size_buffer_dns, 0, &sockaddr_dns, sizeof(sockaddr_dns));
        if (status == -1)
        {
    
            ExFreePool(buf);
            status = close(com_socket);
            if (status == -1)
            {
                ;
            }
            return -1;
        }
    
        k = sizeof(sockaddr_dns);
    
        status = recvfrom(com_socket, buf, 1024 * 2, 0, &sockaddr_dns, &k);
        if (status == -1)
        {
            ExFreePool(buf);
            status = close(com_socket);
            if (status == -1)
            {
                ;
            }
            return -1;
        }
        dprintf("received ok 
     ");
    
        status = close(com_socket);
        if (status == -1)
        {
            return -1;
        }
    
    
        dns = (struct DNS_HEADER*)buf;
    
        if (dns->ans_count == 0)
        {
            ExFreePool(buf);
            return -1;
        }
        else
        {
            //http://www.codeproject.com/KB/IP/dns_query.aspx  如果你还不知道返回数据格式,可以参考这篇文章
            //move ahead of the dns header and the query field
            //从返回的数据开始读取,也就是去除自己的构造部分
            reader = &buf[sizeof(DNS_HEADER) + (strlen((const char*)qname) + 1) + sizeof(QUESTION)];
            dprintf("The response contains : 
    ");
            dprintf("%d Questions.
    ", ntohs(dns->q_count));
            dprintf("%d Answers.
    ", ntohs(dns->ans_count));
            dprintf("%d Authoritative Servers.
    ", ntohs(dns->auth_count));
            dprintf("%d Additional records.
    ", ntohs(dns->add_count));
    
            //reading answers
            stop = 0;
    
            for (i = 0;i<ntohs(dns->ans_count);i++)
            {
                answers[i].name = ReadName(reader, buf, &stop);
                reader = reader + stop;
                answers[i].resource = (struct R_DATA*)(reader);
                reader = reader + sizeof(struct R_DATA);
                if (ntohs(answers[i].resource->type) == 1) //if its an ipv4 address
                {
                    answers[i].rdata = (unsigned char*)malloc(ntohs(answers[i].resource->data_len));
                    for (j = 0; j<ntohs(answers[i].resource->data_len); j++)
                        answers[i].rdata[j] = reader[j];
                    answers[i].rdata[ntohs(answers[i].resource->data_len)] = '';
                    reader = reader + ntohs(answers[i].resource->data_len);
                }
                else
                {
                    answers[i].rdata = ReadName(reader, buf, &stop);
                    reader = reader + stop;
                }
            }
    
            //read authorities
            for (i = 0;i<ntohs(dns->auth_count);i++)
            {
                auth[i].name = ReadName(reader, buf, &stop);
                reader += stop;
    
                auth[i].resource = (struct R_DATA*)(reader);
                reader += sizeof(struct R_DATA);
    
                auth[i].rdata = ReadName(reader, buf, &stop);
                reader += stop;
            }
    
            //read additional
            for (i = 0;i<ntohs(dns->add_count);i++)
            {
                addit[i].name = ReadName(reader, buf, &stop);
                reader += stop;
    
                addit[i].resource = (struct R_DATA*)(reader);
                reader += sizeof(struct R_DATA);
    
                if (ntohs(addit[i].resource->type) == 1)
                {
                    addit[i].rdata = (unsigned char*)malloc(ntohs(addit[i].resource->data_len));
                    for (j = 0;j<ntohs(addit[i].resource->data_len);j++)
                        addit[i].rdata[j] = reader[j];
    
                    addit[i].rdata[ntohs(addit[i].resource->data_len)] = '';
                    reader += ntohs(addit[i].resource->data_len);
    
                }
                else
                {
                    addit[i].rdata = ReadName(reader, buf, &stop);
                    reader += stop;
                }
            }
    
    
            //print answers
            for (i = 0;i<ntohs(dns->ans_count);i++)
            {
                //printf("
    Answer : %d",i+1);
                dprintf("Name  :  %s ", answers[i].name);
    
                if (ntohs(answers[i].resource->type) == 1)   //IPv4 address
                {
                    long *p;
                    p = (long*)answers[i].rdata;
                    a.sin_addr.s_addr = (*p);    //working without ntohl
                    dprintf("has IPv4 address :  %x
    ", *p);
    
                    RtlCopyMemory(&(global_pwsadata->urladdr), p, 4); //保存在全局变量中
    
                    returnaddr = ExAllocatePoolWithTag(0, 16, 'doki');
                    if (returnaddr == NULL)
                    {
                        return NULL;
                    }
    
                    RtlZeroMemory(returnaddr, 16);
                    RtlCopyMemory(returnaddr, inet_ntoa(a.sin_addr), 16);
                    dprintf("has IPv4 address :  %s
    ", returnaddr[i]);
    
                    ExFreePool(returnaddr);
                }
                if (ntohs(answers[i].resource->type) == 5)   //Canonical name for an alias
                    dprintf("has alias name : %s
    ", answers[i].rdata);
                dprintf("
    ");
            }
    
            //print authorities
            for (i = 0;i<ntohs(dns->auth_count);i++)
            {
                //printf("
    Authorities : %d",i+1);
                dprintf("Name  :  %s ", auth[i].name);
                if (ntohs(auth[i].resource->type) == 2)
                    dprintf("has authoritative nameserver : %s", auth[i].rdata);
                dprintf("
    ");
            }
    
            //print additional resource records
            for (i = 0;i<ntohs(dns->add_count);i++)
            {
                //printf("
    Additional : %d",i+1);
                dprintf("Name  :  %s ", addit[i].name);
                if (ntohs(addit[i].resource->type) == 1)
                {
                    long *p;
                    p = (long*)addit[i].rdata;
                    a.sin_addr.s_addr = (*p);    //working without ntohl
                    dprintf("has IPv4 address :  %s", inet_ntoa(a.sin_addr));
                }
                dprintf("
    ");
            }
    
    
        }
    
        ExFreePool(buf);
    
        return 0;
    }
    
    
    unsigned char* ReadName(unsigned char* reader, unsigned char* buffer, int* count)
    {
        unsigned char *name;
        unsigned int p = 0, jumped = 0, offset;
        int i, j;
    
        *count = 1;
        name = (unsigned char*)malloc(256);
    
        name[0] = '';
    
        //read the names in 3www6google3com format
        while (*reader != 0)
        {
            if (*reader >= 192)
            {
                offset = (*reader) * 256 + *(reader + 1) - 49152; //49152 = 11000000 00000000  ;)
                reader = buffer + offset - 1;
                jumped = 1;  //we have jumped to another location so counting wont go up!
            }
            else
                name[p++] = *reader;
    
            reader = reader + 1;
    
            if (jumped == 0) *count = *count + 1; //if we havent jumped to another location then we can count up
        }
    
        name[p] = '';    //string complete
        if (jumped == 1) *count = *count + 1;  //number of steps we actually moved forward in the packet
    
        ChangefromDnsNameFormat(name);
    
        return name;
    }
    PVOID malloc(int size)
    {
        return ExAllocatePoolWithTag(0, size, 'doki');//分配内部缓冲区
    }
    
    //this will convert www.google.com to 3www6google3com ;got it :)
    void ChangetoDnsNameFormat(unsigned char* dns, unsigned char* host)
    {
        int lock = 0, i;
    
        strcat((char*)host, ".");
    
        for (i = 0;i<(int)strlen((char*)host);i++)
        {
            if (host[i] == '.')
            {
                *dns++ = i - lock;
                for (;lock<i;lock++)
                {
                    *dns++ = host[lock];
                }
                lock++; //or lock=i+1;
            }
        }
        *dns++ = '';
    }
    //this will convert 3www6google3com to www.google.com ;got it :)
    void ChangefromDnsNameFormat(unsigned char* name)
    {
        int i, j;
        char p;
    
        //now convert 3www6google3com0 to www.google.com
        for (i = 0;i<(int)strlen((const char*)name);i++)
        {
            p = name[i];
            for (j = 0;j<(int)p;j++)
            {
                name[i] = name[i + 1];
                i = i + 1;
            }
            name[i] = '.';
        }
        name[i - 1] = '';      //remove the last dot
    }
    
    int __cdecl bind(int socket, const struct sockaddr *addr, int addrlen)
    {
        PSOCKET s = (PSOCKET)-socket;
        const struct sockaddr_in* localAddr = (const struct sockaddr_in*) addr;
        UNICODE_STRING devName;
        NTSTATUS status;
    
        if (s->isBound || addr == NULL || addrlen < sizeof(struct sockaddr_in))
        {
            return -1;
        }
    
        if (s->type == SOCK_DGRAM)
        {
            RtlInitUnicodeString(&devName, L"\Device\Udp");
        }
        else if (s->type == SOCK_STREAM)
        {
            RtlInitUnicodeString(&devName, L"\Device\Tcp");
        }
        else
        {
            return -1;
        }
    
        status = tdi_open_transport_address(
            &devName,
            localAddr->sin_addr.s_addr,
            localAddr->sin_port,
            s->isShared,
            &s->addressHandle,
            &s->addressFileObject
        );  
    
        if (!NT_SUCCESS(status))
        {
            s->addressFileObject = NULL;
            s->addressHandle = (HANDLE)-1;
            return status;
        }
    
        if (s->type == SOCK_STREAM)
        {
            tdi_set_event_handler(s->addressFileObject, TDI_EVENT_DISCONNECT, event_disconnect, s);
        }
    
        s->isBound = TRUE;
    
        return 0;
    }
    NTSTATUS event_disconnect(PVOID TdiEventContext, CONNECTION_CONTEXT ConnectionContext, LONG DisconnectDataLength,
        PVOID DisconnectData, LONG DisconnectInformationLength, PVOID DisconnectInformation,
        ULONG DisconnectFlags)
    {
        PSOCKET s = (PSOCKET)TdiEventContext;
        PSTREAM_SOCKET streamSocket = (PSTREAM_SOCKET)ConnectionContext;
        KeSetEvent(&streamSocket->disconnectEvent, 0, FALSE);
        return STATUS_SUCCESS;
    }
    
    NTSTATUS tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext)
    {
        PDEVICE_OBJECT  devObj;
        KEVENT          event;
        PIRP            irp;
        IO_STATUS_BLOCK iosb;
        NTSTATUS        status;
    
        devObj = IoGetRelatedDeviceObject(addressFileObject);
    
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, devObj, addressFileObject, &event, &iosb);
    
        if (irp == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        TdiBuildSetEventHandler(irp, devObj, addressFileObject, NULL, NULL, eventType, eventHandler, eventContext);
    
        status = IoCallDriver(devObj, irp);
    
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = iosb.Status;
        }
    
        return status;
    }
    
    
    int __cdecl close(int socket)
    {
        PSOCKET s = (PSOCKET)-socket;
    
        if (s->isBound)
        {
            if (s->type == SOCK_STREAM && s->streamSocket)
            {
                if (s->isConnected)
                {
                    if (!s->isShuttingdown)
                    {
                        tdi_disconnect(s->streamSocket->connectionFileObject, TDI_DISCONNECT_RELEASE);
                    }
                    KeWaitForSingleObject(&s->streamSocket->disconnectEvent, Executive, KernelMode, FALSE, NULL);
                }
                if (s->streamSocket->connectionFileObject)
                {
                    tdi_disassociate_address(s->streamSocket->connectionFileObject);
                    ObDereferenceObject(s->streamSocket->connectionFileObject);
                }
                if (s->streamSocket->connectionHandle != (HANDLE)-1)
                {
                    ZwClose(s->streamSocket->connectionHandle);
                }
                ExFreePool(s->streamSocket);
            }
    
            if (s->type == SOCK_DGRAM || s->type == SOCK_STREAM)
            {
                ObDereferenceObject(s->addressFileObject);
                if (s->addressHandle != (HANDLE)-1)
                {
                    ZwClose(s->addressHandle);
                }
            }
        }
    
        ExFreePool(s);
    
        return 0;
    }
    
    NTSTATUS tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags)
    {
        PDEVICE_OBJECT  devObj;
        KEVENT          event;
        PIRP            irp;
        IO_STATUS_BLOCK iosb;
        NTSTATUS        status;
    
        devObj = IoGetRelatedDeviceObject(connectionFileObject);
    
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        irp = TdiBuildInternalDeviceControlIrp(TDI_DISCONNECT, devObj, connectionFileObject, &event, &iosb);
    
        if (irp == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        TdiBuildDisconnect(irp, devObj, connectionFileObject, NULL, NULL, NULL, flags, NULL, NULL);
    
        status = IoCallDriver(devObj, irp);
    
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = iosb.Status;
        }
    
        return status;
    }
    NTSTATUS tdi_disassociate_address(PFILE_OBJECT connectionFileObject)
    {
        PDEVICE_OBJECT  devObj;
        KEVENT          event;
        PIRP            irp;
        IO_STATUS_BLOCK iosb;
        NTSTATUS        status;
    
        devObj = IoGetRelatedDeviceObject(connectionFileObject);
    
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        irp = TdiBuildInternalDeviceControlIrp(TDI_DISASSOCIATE_ADDRESS, devObj, connectionFileObject, &event, &iosb);
    
        if (irp == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        TdiBuildDisassociateAddress(irp, devObj, connectionFileObject, NULL, NULL);
    
        status = IoCallDriver(devObj, irp);
    
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = iosb.Status;
        }
    
        return status;
    }
    
    NTSTATUS tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, int shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject)
    {
        OBJECT_ATTRIBUTES           attr;
        PFILE_FULL_EA_INFORMATION   eaBuffer;
        ULONG                       eaSize;
        PTA_IP_ADDRESS              localAddr;
        IO_STATUS_BLOCK             iosb;
        NTSTATUS                    status;
    
    #if (VER_PRODUCTBUILD >= 2195)
        InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    #else
        InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE, NULL, NULL);
    #endif
    
        eaSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
            TDI_TRANSPORT_ADDRESS_LENGTH +
            1 +
            sizeof(TA_IP_ADDRESS);
    
        eaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(PagedPool, eaSize);
    
        if (eaBuffer == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        eaBuffer->NextEntryOffset = 0;
        eaBuffer->Flags = 0;
        eaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
        eaBuffer->EaValueLength = sizeof(TA_IP_ADDRESS);
    
        RtlCopyMemory(eaBuffer->EaName, TdiTransportAddress, eaBuffer->EaNameLength + 1);
    
        localAddr = (PTA_IP_ADDRESS)(eaBuffer->EaName + eaBuffer->EaNameLength + 1);
    
        localAddr->TAAddressCount = 1;
        localAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
        localAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
        localAddr->Address[0].Address[0].sin_port = port;
        localAddr->Address[0].Address[0].in_addr = addr;
    
        RtlZeroMemory(localAddr->Address[0].Address[0].sin_zero, sizeof(localAddr->Address[0].Address[0].sin_zero));
    
        status = ZwCreateFile(
            addressHandle,
            GENERIC_READ | GENERIC_WRITE,
            &attr,
            &iosb,
            NULL,
            FILE_ATTRIBUTE_NORMAL,
            shared ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
            FILE_OPEN,
            0,
            eaBuffer,
            eaSize
        );
    
        ExFreePool(eaBuffer);
    
        if (!NT_SUCCESS(status))
        {
            return status;
        }
    
        status = ObReferenceObjectByHandle(*addressHandle, FILE_ALL_ACCESS, NULL, KernelMode, addressFileObject, NULL);
    
        if (!NT_SUCCESS(status))
        {
            ZwClose(*addressHandle);
            return status;
        }
    
        return STATUS_SUCCESS;
    }
    NTSTATUS tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len)
    {
        PDEVICE_OBJECT              devObj;
        KEVENT                      event;
        PTDI_CONNECTION_INFORMATION remoteInfo;
        PTA_IP_ADDRESS              remoteAddr;
        PIRP                        irp;
        PMDL                        mdl;
        IO_STATUS_BLOCK             iosb;
        NTSTATUS                    status;
    
        devObj = IoGetRelatedDeviceObject(addressFileObject);
    
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        remoteInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePool(NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
    
        if (remoteInfo == NULL)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        RtlZeroMemory(remoteInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
    
        remoteInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
        remoteInfo->RemoteAddress = (PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION);
    
        remoteAddr = (PTA_IP_ADDRESS)remoteInfo->RemoteAddress;
    
        remoteAddr->TAAddressCount = 1;
        remoteAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
        remoteAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
        remoteAddr->Address[0].Address[0].sin_port = port;
        remoteAddr->Address[0].Address[0].in_addr = addr;
    
        irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, devObj, addressFileObject, &event, &iosb);
    
        if (irp == NULL)
        {
            ExFreePool(remoteInfo);
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    
        if (len)
        {
            mdl = IoAllocateMdl((void*)buf, len, FALSE, FALSE, NULL);
    
            if (mdl == NULL)
            {
                IoFreeIrp(irp);
                ExFreePool(remoteInfo);
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            __try
            {
                MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
                status = STATUS_SUCCESS;
            }
            __except (EXCEPTION_EXECUTE_HANDLER)
            {
                IoFreeMdl(mdl);
                IoFreeIrp(irp);
                ExFreePool(remoteInfo);
                status = STATUS_INVALID_USER_BUFFER;
            }
    
            if (!NT_SUCCESS(status))
            {
                return status;
            }
        }
    
        TdiBuildSendDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo);
    
        status = IoCallDriver(devObj, irp);
    
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = iosb.Status;
        }
    
        ExFreePool(remoteInfo);
    
        return NT_SUCCESS(status) ? iosb.Information : status;
    }
    int __cdecl sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen)
    {
        {
            PSOCKET s = (PSOCKET)-socket;
            const struct sockaddr_in* remoteAddr = (const struct sockaddr_in*) addr;
            struct  sockaddr_in localAddr;
            NTSTATUS status;
    
            /*
            if (s->type == SOCK_STREAM)
            {
            return send(socket, buf, len, flags);
            }
            */
            // else 
            if (s->type == SOCK_DGRAM)
            {
                if (addr == NULL || addrlen < sizeof(struct sockaddr_in))
                {
                    return -1;
                }
    
                if (!s->isBound)
                {
                    struct sockaddr_in localAddr;
                    NTSTATUS status;  //定义在前面
    
                    localAddr.sin_family = AF_INET;//2
                    localAddr.sin_port = 0;
                    localAddr.sin_addr.s_addr = ReadHostIPsFromRegistry();
    
                    status = bind(socket, (struct sockaddr*) &localAddr, sizeof(localAddr));
    
                    if (!NT_SUCCESS(status))
                    {
                        return status;
                    }
                }
    
                return tdi_send_dgram(
                    s->addressFileObject,
                    remoteAddr->sin_addr.s_addr,
                    remoteAddr->sin_port,
                    buf,
                    len);
            }
            else
            {
                return -1;
            }
        }
    
    }
    
    
        char * inet_ntoa(IN  struct in_addr  in)
        {
            PUCHAR p;
            UCHAR buffer[20];
            PUCHAR b;
    
            //
            // A number of applications apparently depend on calling inet_ntoa()
            // without first calling WSAStartup(). Because of this, we must perform
            // our own explicit thread initialization check here.
            //
    
            b = buffer;
    
            //
            // In an unrolled loop, calculate the string value for each of the four
            // bytes in an IP address.  Note that for values less than 100 we will
            // do one or two extra assignments, but we save a test/jump with this
            // algorithm.
            //
    
            p = (PUCHAR)&in;
    
            *b = NToACharStrings[*p][0];
            *(b + 1) = NToACharStrings[*p][1];
            *(b + 2) = NToACharStrings[*p][2];
            b += NToACharStrings[*p][3];
            *b++ = '.';
    
            p++;
            *b = NToACharStrings[*p][0];
            *(b + 1) = NToACharStrings[*p][1];
            *(b + 2) = NToACharStrings[*p][2];
            b += NToACharStrings[*p][3];
            *b++ = '.';
    
            p++;
            *b = NToACharStrings[*p][0];
            *(b + 1) = NToACharStrings[*p][1];
            *(b + 2) = NToACharStrings[*p][2];
            b += NToACharStrings[*p][3];
            *b++ = '.';
    
            p++;
            *b = NToACharStrings[*p][0];
            *(b + 1) = NToACharStrings[*p][1];
            *(b + 2) = NToACharStrings[*p][2];
            b += NToACharStrings[*p][3];
            *b = '';
            dprintf("buffer %s 
    ", buffer);//注意打印buffer
            return(buffer);
        }
    
        /*
        * Internet address interpretation routine.
        * All the network library routines call this
        * routine to interpret entries in the data bases
        * which are expected to be an address.
        * The value returned is in network order.
        */
        unsigned long
            inet_addr(
                IN const char *cp
            )
        {
            register unsigned long val, base, n;
            register char c;
            unsigned long parts[4], *pp = parts;
    
            // WS_ENTER( "inet_addr", (PVOID)cp, NULL, NULL, NULL );
        again:
            /*
            * Collect number up to ``.''.
            * Values are specified as for C:
            * 0x=hex, 0=octal, other=decimal.
            */
            val = 0; base = 10;
            if (*cp == '0') {
                base = 8, cp++;
                if (*cp == 'x' || *cp == 'X')
                    base = 16, cp++;
            }
    
            while (c = *cp) {
                if (isdigit(c)) {
                    val = (val * base) + (c - '0');
                    cp++;
                    continue;
                }
                if (base == 16 && isxdigit(c)) {
                    val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
                    cp++;
                    continue;
                }
                break;
            }
            if (*cp == '.') {
                /*
                * Internet format:
                *      a.b.c.d
                *      a.b.c   (with c treated as 16-bits)
                *      a.b     (with b treated as 24 bits)
                */
                /* GSS - next line was corrected on 8/5/89, was 'parts + 4' */
                if (pp >= parts + 3) {
                    //WS_EXIT( "inet_addr", -1, TRUE );
                    return ((unsigned long)-1);
                }
                *pp++ = val, cp++;
                goto again;
            }
            /*
            * Check for trailing characters.
            */
            if (*cp && !isspace(*cp)) {
                // WS_EXIT( "inet_addr", -1, TRUE );
                return (INADDR_NONE);
            }
            *pp++ = val;
            /*
            * Concoct the address according to
            * the number of parts specified.
            */
            n = (unsigned long)(pp - parts);
            switch ((int)n) {
    
            case 1:                         /* a -- 32 bits */
                val = parts[0];
                break;
    
            case 2:                         /* a.b -- 8.24 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xffffff)) {
                    //WS_EXIT( "inet_addr", -1, TRUE );
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | (parts[1] & 0xffffff);
                break;
    
            case 3:                         /* a.b.c -- 8.8.16 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
                    (parts[2] > 0xffff)) {
                    //WS_EXIT( "inet_addr", -1, TRUE );
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
                    (parts[2] & 0xffff);
                break;
    
            case 4:                         /* a.b.c.d -- 8.8.8.8 bits */
                if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
                    (parts[2] > 0xff) || (parts[3] > 0xff)) {
                    // WS_EXIT( "inet_addr", -1, TRUE );
                    return(INADDR_NONE);
                }
                val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
                    ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
                break;
    
            default:
                //WS_EXIT( "inet_addr", -1, TRUE );
                return (INADDR_NONE);
            }
            val = htonl(val);
            // WS_EXIT( "inet_addr", val, FALSE );
            return (val);
        }
    
    
        //com_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);//udp 数据报查询
        int __cdecl socket(int af, int type, int protocol)
        {
            PSOCKET s;
    
            if (af != AF_INET ||
                (type != SOCK_DGRAM && type != SOCK_STREAM) ||
                (type == SOCK_DGRAM && protocol != IPPROTO_UDP && protocol != 0) ||
                (type == SOCK_STREAM && protocol != IPPROTO_TCP && protocol != 0)
                )
            {
                return STATUS_INVALID_PARAMETER;
            }
    
            s = (PSOCKET)ExAllocatePool(NonPagedPool, sizeof(SOCKET));
    
            if (!s)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            RtlZeroMemory(s, sizeof(SOCKET));
    
            s->type = type;
            s->addressHandle = (HANDLE)-1;
            //自己添加一行
            s->isBound = FALSE;
            return -(int)s;
        }
    
    
    
        int __cdecl recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen)
        {
            PSOCKET s = (PSOCKET)-socket;
            struct sockaddr_in* returnAddr = (struct sockaddr_in*) addr;
            /*
            if (s->type == SOCK_STREAM)
            {
            return recv(socket, buf, len, flags);
            }
            */
            //    else
            if (s->type == SOCK_DGRAM)
            {
                u_long* sin_addr = 0;
                u_short* sin_port = 0;
    
                if (!s->isBound)
                {
                    return -1;
                }
    
                if (addr != NULL && addrlen != NULL && *addrlen >= sizeof(struct sockaddr_in))
                {
                    sin_addr = &returnAddr->sin_addr.s_addr;
                    sin_port = &returnAddr->sin_port;
                    *addrlen = sizeof(struct sockaddr_in);
                }
    
                return tdi_recv_dgram(
                    s->addressFileObject,
                    sin_addr,
                    sin_port,
                    buf,
                    len,
                    TDI_RECEIVE_NORMAL
                );
            }
            else
            {
                return -1;
            }
        }
    
        NTSTATUS tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags)
        {
            PDEVICE_OBJECT              devObj;
            KEVENT                      event;
            PTDI_CONNECTION_INFORMATION remoteInfo;
            PTDI_CONNECTION_INFORMATION returnInfo;
            PTA_IP_ADDRESS              returnAddr;
            PIRP                        irp;
            PMDL                        mdl;
            IO_STATUS_BLOCK             iosb;
            NTSTATUS                    status;
    
            devObj = IoGetRelatedDeviceObject(addressFileObject);
    
            KeInitializeEvent(&event, NotificationEvent, FALSE);
    
            remoteInfo = (PTDI_CONNECTION_INFORMATION)ExAllocatePool(NonPagedPool, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
    
            if (remoteInfo == NULL)
            {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            RtlZeroMemory(remoteInfo, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
    
            remoteInfo->RemoteAddressLength = 0;
            remoteInfo->RemoteAddress = NULL;
    
            returnInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION));
    
            returnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
            returnInfo->RemoteAddress = (PUCHAR)returnInfo + sizeof(TDI_CONNECTION_INFORMATION);
    
            returnAddr = (PTA_IP_ADDRESS)returnInfo->RemoteAddress;
    
            returnAddr->TAAddressCount = 1;
            returnAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
            returnAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
    
            irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, devObj, addressFileObject, &event, &iosb);
    
            if (irp == NULL)
            {
                ExFreePool(remoteInfo);
                return STATUS_INSUFFICIENT_RESOURCES;
            }
    
            if (len)
            {
                mdl = IoAllocateMdl((void*)buf, len, FALSE, FALSE, NULL);
    
                if (mdl == NULL)
                {
                    IoFreeIrp(irp);
                    ExFreePool(remoteInfo);
                    return STATUS_INSUFFICIENT_RESOURCES;
                }
    
                __try
                {
                    MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
                    status = STATUS_SUCCESS;
                }
                __except (EXCEPTION_EXECUTE_HANDLER)
                {
                    IoFreeMdl(mdl);
                    IoFreeIrp(irp);
                    ExFreePool(remoteInfo);
                    status = STATUS_INVALID_USER_BUFFER;
                }
    
                if (!NT_SUCCESS(status))
                {
                    return status;
                }
            }
    
            TdiBuildReceiveDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo, returnInfo, flags);
    
            status = IoCallDriver(devObj, irp);
    
            if (status == STATUS_PENDING)
            {
                KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
                status = iosb.Status;
            }
    
            if (addr)
            {
                *addr = returnAddr->Address[0].Address[0].in_addr;
            }
    
            if (port)
            {
                *port = returnAddr->Address[0].Address[0].sin_port;
            }
    
            ExFreePool(remoteInfo);
    
            return NT_SUCCESS(status) ? iosb.Information : status;
        }
    
        ///////////////////////////////   END OF FILE   ///////////////////////////////
    
    
    
    
    
    
    
    
    
    
    #pragma once
    
    
    
    #ifndef _HELLO_H
    #define _HELLO_H 1
    
    
    #include <ntifs.h>
    
    #include <ntddk.h>
    #include <tdikrnl.h>
    //#define PF_INET   TDI_ADDRESS_TYPE_IP
    #define AF_INET   2
    
    #define SOCK_STREAM 1 //TCP
    #define SOCK_DGRAM  2 //UDP
    #define SOCK_RAW   3 //RAW  是winsock.h中定义的
    
    #define IPPROTO_ICMP        1
    #define IPPROTO_TCP         6
    #define IPPROTO_UDP         17
    
    
    #define TDI_MAX_SOCKET   256
    #define TDI_MAX_BACKLOG 20
    
    #define TDI_TCP_DEVICE_NAME_W   L"\Device\Tcp"
    #define TDI_UDP_DEVICE_NAME_W L"\Device\Udp"
    #define TDI_RAW_DEVICE_NAME_W L"\Device\RawIp"
    
    #define TDI_TIMEOUT_CONNECT_SEC   60
    #define TDI_TIMEOUT_DISCONNECT_SEC 60
    #define TDI_TIMEOUT_COMMUNICATION 60
    
    
    #define SOCKET_STATUS_CLEAR     0
    #define SOCKET_STATUS_ALLOCATED    1
    #define SOCKET_STATUS_TRANSPORT    2
    #define SOCKET_STATUS_CONNECTION    3
    #define SOCKET_STATUS_CON_AND_TRANS   4
    #define SOCKET_STATUS_ASSOCIATED    5
    #define SOCKET_STATUS_LISTEN     6
    #define SOCKET_STATUS_WAITING_INBOUND 7 
    #define SOCKET_STATUS_DISCONNECTED   8
    #define SOCKET_STATUS_CONNECTED    9
    #define SOCKET_STATUS_CHANGING    10
    
    
    #define WSA_NOT_ENOUGH_MEMORY     8
    #define WSAEMFILE        10024 
    #define WSAEPROTOTYPE       10041 
    #define WSAEPROTONOSUPPORT     10043 
    #define WSAESHUTDOWN       10058
    #define WSANO_DATA        11004
    
    unsigned char NToACharStrings[][4] = {
        '0', 'x', 'x', 1,
        '1', 'x', 'x', 1,
        '2', 'x', 'x', 1,
        '3', 'x', 'x', 1,
        '4', 'x', 'x', 1,
        '5', 'x', 'x', 1,
        '6', 'x', 'x', 1,
        '7', 'x', 'x', 1,
        '8', 'x', 'x', 1,
        '9', 'x', 'x', 1,
        '1', '0', 'x', 2,
        '1', '1', 'x', 2,
        '1', '2', 'x', 2,
        '1', '3', 'x', 2,
        '1', '4', 'x', 2,
        '1', '5', 'x', 2,
        '1', '6', 'x', 2,
        '1', '7', 'x', 2,
        '1', '8', 'x', 2,
        '1', '9', 'x', 2,
        '2', '0', 'x', 2,
        '2', '1', 'x', 2,
        '2', '2', 'x', 2,
        '2', '3', 'x', 2,
        '2', '4', 'x', 2,
        '2', '5', 'x', 2,
        '2', '6', 'x', 2,
        '2', '7', 'x', 2,
        '2', '8', 'x', 2,
        '2', '9', 'x', 2,
        '3', '0', 'x', 2,
        '3', '1', 'x', 2,
        '3', '2', 'x', 2,
        '3', '3', 'x', 2,
        '3', '4', 'x', 2,
        '3', '5', 'x', 2,
        '3', '6', 'x', 2,
        '3', '7', 'x', 2,
        '3', '8', 'x', 2,
        '3', '9', 'x', 2,
        '4', '0', 'x', 2,
        '4', '1', 'x', 2,
        '4', '2', 'x', 2,
        '4', '3', 'x', 2,
        '4', '4', 'x', 2,
        '4', '5', 'x', 2,
        '4', '6', 'x', 2,
        '4', '7', 'x', 2,
        '4', '8', 'x', 2,
        '4', '9', 'x', 2,
        '5', '0', 'x', 2,
        '5', '1', 'x', 2,
        '5', '2', 'x', 2,
        '5', '3', 'x', 2,
        '5', '4', 'x', 2,
        '5', '5', 'x', 2,
        '5', '6', 'x', 2,
        '5', '7', 'x', 2,
        '5', '8', 'x', 2,
        '5', '9', 'x', 2,
        '6', '0', 'x', 2,
        '6', '1', 'x', 2,
        '6', '2', 'x', 2,
        '6', '3', 'x', 2,
        '6', '4', 'x', 2,
        '6', '5', 'x', 2,
        '6', '6', 'x', 2,
        '6', '7', 'x', 2,
        '6', '8', 'x', 2,
        '6', '9', 'x', 2,
        '7', '0', 'x', 2,
        '7', '1', 'x', 2,
        '7', '2', 'x', 2,
        '7', '3', 'x', 2,
        '7', '4', 'x', 2,
        '7', '5', 'x', 2,
        '7', '6', 'x', 2,
        '7', '7', 'x', 2,
        '7', '8', 'x', 2,
        '7', '9', 'x', 2,
        '8', '0', 'x', 2,
        '8', '1', 'x', 2,
        '8', '2', 'x', 2,
        '8', '3', 'x', 2,
        '8', '4', 'x', 2,
        '8', '5', 'x', 2,
        '8', '6', 'x', 2,
        '8', '7', 'x', 2,
        '8', '8', 'x', 2,
        '8', '9', 'x', 2,
        '9', '0', 'x', 2,
        '9', '1', 'x', 2,
        '9', '2', 'x', 2,
        '9', '3', 'x', 2,
        '9', '4', 'x', 2,
        '9', '5', 'x', 2,
        '9', '6', 'x', 2,
        '9', '7', 'x', 2,
        '9', '8', 'x', 2,
        '9', '9', 'x', 2,
        '1', '0', '0', 3,
        '1', '0', '1', 3,
        '1', '0', '2', 3,
        '1', '0', '3', 3,
        '1', '0', '4', 3,
        '1', '0', '5', 3,
        '1', '0', '6', 3,
        '1', '0', '7', 3,
        '1', '0', '8', 3,
        '1', '0', '9', 3,
        '1', '1', '0', 3,
        '1', '1', '1', 3,
        '1', '1', '2', 3,
        '1', '1', '3', 3,
        '1', '1', '4', 3,
        '1', '1', '5', 3,
        '1', '1', '6', 3,
        '1', '1', '7', 3,
        '1', '1', '8', 3,
        '1', '1', '9', 3,
        '1', '2', '0', 3,
        '1', '2', '1', 3,
        '1', '2', '2', 3,
        '1', '2', '3', 3,
        '1', '2', '4', 3,
        '1', '2', '5', 3,
        '1', '2', '6', 3,
        '1', '2', '7', 3,
        '1', '2', '8', 3,
        '1', '2', '9', 3,
        '1', '3', '0', 3,
        '1', '3', '1', 3,
        '1', '3', '2', 3,
        '1', '3', '3', 3,
        '1', '3', '4', 3,
        '1', '3', '5', 3,
        '1', '3', '6', 3,
        '1', '3', '7', 3,
        '1', '3', '8', 3,
        '1', '3', '9', 3,
        '1', '4', '0', 3,
        '1', '4', '1', 3,
        '1', '4', '2', 3,
        '1', '4', '3', 3,
        '1', '4', '4', 3,
        '1', '4', '5', 3,
        '1', '4', '6', 3,
        '1', '4', '7', 3,
        '1', '4', '8', 3,
        '1', '4', '9', 3,
        '1', '5', '0', 3,
        '1', '5', '1', 3,
        '1', '5', '2', 3,
        '1', '5', '3', 3,
        '1', '5', '4', 3,
        '1', '5', '5', 3,
        '1', '5', '6', 3,
        '1', '5', '7', 3,
        '1', '5', '8', 3,
        '1', '5', '9', 3,
        '1', '6', '0', 3,
        '1', '6', '1', 3,
        '1', '6', '2', 3,
        '1', '6', '3', 3,
        '1', '6', '4', 3,
        '1', '6', '5', 3,
        '1', '6', '6', 3,
        '1', '6', '7', 3,
        '1', '6', '8', 3,
        '1', '6', '9', 3,
        '1', '7', '0', 3,
        '1', '7', '1', 3,
        '1', '7', '2', 3,
        '1', '7', '3', 3,
        '1', '7', '4', 3,
        '1', '7', '5', 3,
        '1', '7', '6', 3,
        '1', '7', '7', 3,
        '1', '7', '8', 3,
        '1', '7', '9', 3,
        '1', '8', '0', 3,
        '1', '8', '1', 3,
        '1', '8', '2', 3,
        '1', '8', '3', 3,
        '1', '8', '4', 3,
        '1', '8', '5', 3,
        '1', '8', '6', 3,
        '1', '8', '7', 3,
        '1', '8', '8', 3,
        '1', '8', '9', 3,
        '1', '9', '0', 3,
        '1', '9', '1', 3,
        '1', '9', '2', 3,
        '1', '9', '3', 3,
        '1', '9', '4', 3,
        '1', '9', '5', 3,
        '1', '9', '6', 3,
        '1', '9', '7', 3,
        '1', '9', '8', 3,
        '1', '9', '9', 3,
        '2', '0', '0', 3,
        '2', '0', '1', 3,
        '2', '0', '2', 3,
        '2', '0', '3', 3,
        '2', '0', '4', 3,
        '2', '0', '5', 3,
        '2', '0', '6', 3,
        '2', '0', '7', 3,
        '2', '0', '8', 3,
        '2', '0', '9', 3,
        '2', '1', '0', 3,
        '2', '1', '1', 3,
        '2', '1', '2', 3,
        '2', '1', '3', 3,
        '2', '1', '4', 3,
        '2', '1', '5', 3,
        '2', '1', '6', 3,
        '2', '1', '7', 3,
        '2', '1', '8', 3,
        '2', '1', '9', 3,
        '2', '2', '0', 3,
        '2', '2', '1', 3,
        '2', '2', '2', 3,
        '2', '2', '3', 3,
        '2', '2', '4', 3,
        '2', '2', '5', 3,
        '2', '2', '6', 3,
        '2', '2', '7', 3,
        '2', '2', '8', 3,
        '2', '2', '9', 3,
        '2', '3', '0', 3,
        '2', '3', '1', 3,
        '2', '3', '2', 3,
        '2', '3', '3', 3,
        '2', '3', '4', 3,
        '2', '3', '5', 3,
        '2', '3', '6', 3,
        '2', '3', '7', 3,
        '2', '3', '8', 3,
        '2', '3', '9', 3,
        '2', '4', '0', 3,
        '2', '4', '1', 3,
        '2', '4', '2', 3,
        '2', '4', '3', 3,
        '2', '4', '4', 3,
        '2', '4', '5', 3,
        '2', '4', '6', 3,
        '2', '4', '7', 3,
        '2', '4', '8', 3,
        '2', '4', '9', 3,
        '2', '5', '0', 3,
        '2', '5', '1', 3,
        '2', '5', '2', 3,
        '2', '5', '3', 3,
        '2', '5', '4', 3,
        '2', '5', '5', 3
    };
    
    typedef unsigned char   u_char;
    typedef unsigned short  u_short;
    typedef unsigned int    u_int;
    typedef unsigned long   u_long;
    
    struct in_addr {
        union {
            struct { u_char s_b1, s_b2, s_b3, s_b4; }   S_un_b;
            struct { u_short s_w1, s_w2; }              S_un_w;
            u_long                                      S_addr;
        } S_un;
    };
    #define s_addr S_un.S_addr
    
    struct sockaddr_in {
        short           sin_family;
        unsigned short  sin_port;
        struct in_addr  sin_addr;
        char            sin_zero[8];
    }sockaddr;
    #define h_addr h_addr_list[0]
    
    //Constant sized fields of the resource record structure
    #pragma pack(push, 1)
    struct  R_DATA
    {
        unsigned short type;
        unsigned short _class;
        unsigned int   ttl;
        unsigned short data_len;
    };
    #pragma pack(pop)
    
    //Pointers to resource record contents
    struct RES_RECORD
    {
        unsigned char  *name;
        struct R_DATA  *resource;
        unsigned char  *rdata;
    };
    
    typedef struct {
        char * h_name;
        char ** h_aliases;
        short h_addrtype;
        short h_length;
        unsigned int ** h_addr_list;
    } HOSTENT, *PHOSTENT;  //定义一样的
    
    typedef struct _DNSADDRANDURL
    {
        int serveur_dns;//
        int urladdr;//已解析的
    } DNSADDRANDURL, *PDNSADDRANDURL;
    
    typedef struct
    {
        unsigned short id;       // identification number 
        unsigned char rd : 1;     // recursion desired 
        unsigned char tc : 1;     // truncated message 
        unsigned char aa : 1;     // authoritive answer 
        unsigned char opcode : 4; // purpose of message 
        unsigned char qr : 1;     // query/response flag 
        unsigned char rcode : 4; // response code 
        unsigned char cd : 1;     // checking disabled 
        unsigned char ad : 1;     // authenticated data 
        unsigned char z : 1;      // its z! reserved 
        unsigned char ra : 1;     // recursion available 
        unsigned short q_count; // number of question entries
        unsigned short ans_count; // number of answer entries 
        unsigned short auth_count; // number of authority entries 
        unsigned short add_count; // number of resource entries
    } DNS_HEADER;
    
    //DNS Question
    typedef struct
    {
        unsigned short qtype;
        unsigned short qclass;
    } QUESTION;
    
    
    typedef struct {
        unsigned short name;
        unsigned short type;
        unsigned short _class;
        unsigned short ttl_hi;
        unsigned short ttl_low;
        unsigned short data_len;
        unsigned char rdata[1];
    }CUSTOM_RES_RECORD;
    
    typedef struct _STREAM_SOCKET {
        HANDLE              connectionHandle;
        PFILE_OBJECT        connectionFileObject;
        KEVENT              disconnectEvent;
    } STREAM_SOCKET, *PSTREAM_SOCKET;
    
    typedef struct _SOCKET {
        int                 type;
        BOOLEAN             isBound;
        BOOLEAN             isConnected;
        BOOLEAN             isListening;
        BOOLEAN             isShuttingdown;
        BOOLEAN             isShared;
        HANDLE              addressHandle;
        PFILE_OBJECT        addressFileObject;
        PSTREAM_SOCKET      streamSocket;
        struct sockaddr_in     peer;
    } SOCKET, *PSOCKET;
    
    #define INADDR_NONE             0xffffffff
    
    #define htonl(l)                                
        ( ( ((l) >> 24) & 0x000000FFL ) |       
        ( ((l) >>  8) & 0x0000FF00L ) |       
        ( ((l) <<  8) & 0x00FF0000L ) |       
                  ( ((l) << 24) & 0xFF000000L ) )
    
    #define ntohs(s)                            
        ( ( ((s) >> 8) & 0x00FF ) |             
                  ( ((s) << 8) & 0xFF00 ) )
    
    
    #define HTONS(a) (((0xFF&a)<<8) + ((0xFF00&a)>>8))
    #define NTOHS(s) ((((s)>> 8) & 0x00FF)|(((s)<<8)&0xFF00)) //找了好久哦,其实也很简单
    
    #define dprintf if (DBG) DbgPrint
    #define nprintf DbgPrint
    
    #define DEVICE_NAME L"\Device\devhello" // Driver Name
    #define LINK_NAME L"\DosDevices\hello"  // Link Name
    
    //
    // The device driver IOCTLs
    //
    
    #define IOCTL_BASE    0x800
    #define MY_CTL_CODE(i) 
        CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_BASE+i, METHOD_BUFFERED, FILE_ANY_ACCESS)
    
    
    #define IOCTL_HELLO    MY_CTL_CODE(0)
    
    
    /////////////////////////////////////////////////////////////////////
    
    NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString);
    NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    VOID     DriverUnload(PDRIVER_OBJECT pDriverObj);
    NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
    
    /////////////////////////////////////////////////////////////////////
    //函数声明
    char*            inet_ntoa(struct in_addr  in);
    unsigned long    inet_addr(const char *cp);
    PVOID            malloc(int size);
    int                ReadDnsServerFromRegistry();
    int                ReadHostIPsFromRegistry();
    PHOSTENT        gethostbyname(char *name);
    int                query_dns(struct sockaddr_in sockaddr_dns,
        char* nom_a_resoudre,
        char *hostent_buf,
        int rdns);
    int                build_dns_query(char* URL, int* taille_buffer_dns, int rdns);
    void            ChangetoDnsNameFormat(unsigned char* dns, unsigned char* host);
    void            ChangefromDnsNameFormat(unsigned char* name);
    int __cdecl        bind(int socket, const struct sockaddr *addr, int addrlen);
    NTSTATUS        tdi_open_transport_address(PUNICODE_STRING devName,
        ULONG addr,
        USHORT port,
        int shared,
        PHANDLE addressHandle,
        PFILE_OBJECT *addressFileObject);
    NTSTATUS        tdi_set_event_handler(PFILE_OBJECT addressFileObject,
        LONG eventType,
        PVOID eventHandler,
        PVOID eventContext);
    int __cdecl        sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen);
    int __cdecl        send(int socket, const char *buf, int len, int flags);
    NTSTATUS        tdi_send_dgram(PFILE_OBJECT addressFileObject,
        ULONG addr,
        USHORT port,
        const char *buf,
        int len);
    int __cdecl        socket(int af, int type, int protocol);
    NTSTATUS        tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags);
    NTSTATUS        tdi_disassociate_address(PFILE_OBJECT connectionFileObject);
    int __cdecl        close(int socket);
    int __cdecl        recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen);
    unsigned char*    ReadName(unsigned char* reader, unsigned char* buffer, int* count);
    NTSTATUS        tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags);
    NTSTATUS        event_disconnect(PVOID TdiEventContext, CONNECTION_CONTEXT ConnectionContext, LONG DisconnectDataLength,
        PVOID DisconnectData, LONG DisconnectInformationLength, PVOID DisconnectInformation,
        ULONG DisconnectFlags);
    int __cdecl        recv(int socket, char *buf, int len, int flags);
    NTSTATUS        tdi_recv_stream(PFILE_OBJECT connectionFileObject, char *buf, int len, ULONG flags);
    int __cdecl        socket(int af, int type, int protocol);
    NTSTATUS        tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext);
    NTSTATUS        tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len);
    NTSTATUS        tdi_send_stream(PFILE_OBJECT connectionFileObject, const char *buf, int len, ULONG flags);
    NTSTATUS        tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, int shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject);
    
    
    #endif
    
    ///////////////////////////////   END OF FILE   ///////////////////////////////
  • 相关阅读:
    vuex 简单理解
    es2015(es6)学习总结
    工作资源知识点总结收集
    margin-top使用需要注意的地方
    关于用display:table让元素居中的小结
    display:table-cell
    margin:0 auto;不居中
    css选择器总结
    css 选择器优先级
    给行内元素加上绝对定位之后,元素属性的变化
  • 原文地址:https://www.cnblogs.com/yifi/p/6527916.html
Copyright © 2011-2022 走看看