zoukankan      html  css  js  c++  java
  • 记一次:Windows的Socket编程学习和分析过程

    Socket编程依赖于:WS2_32.dll

     

    
    
    --- 服务端 ---
    
    1、导入我们需要的函数
    #incldue <windows.h>  //#include<WinSock2.h>
    #pragma comment(lib,"ws2_32.lib")
    
    
    
    2、初始化(指定要使用的socket版本)
    WSADATA ws = {0};
    /*WSAStartup  微软MSDN:https://docs.microsoft.com/en-us/previous-versions/aa921082(v=msdn.10)?redirectedfrom=MSDN
        参数1:版本号  调用者可以使用的Windows套接字最高支持。高位字节指定次要版本号(修订)。低位字节指定主要版本号。
        参数2:存储socket相关的信息
        返回值;成功返回0/
    WSAStartuo(MAKEWORD(2,2),&ws); //MAKEWORD  是一个宏用于将其拆成2个word ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
    
    
    
    
    
    3、创建socket
    /*socket 微软msdn:https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket
    
        参数1:地址簇类型,ip地址类型
        参数2:socket的类型,数据是以何种方式传输
        参数3:协议类型
        返回值:成功返回新的socket,失败返回INVALID_SOCKET*/
    
    SOCKET sk = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    
    
    
    
    
    4、设置协议地址族信息(要连接或绑定的ip端口信息)
    微软MSDN:https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-sockaddr_in
    SOCKADDR_IN sever_addr = {0};
    sever_addr.sin_family = AF_INET; //地址族类型
    sever_addr.sin_port = htons(8888); //端口
    server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //地址
    
    htons函数:intel cpu存储数据的方式采用的是:Littke-endian方式(高位在右,低位在左),而例如ibm早期cpu采用的则是:Big-endian(高位在左,低位在右),而网络协议一致采取Big-endian的方式存储数据,而htons就是将Littke转化为Big的函数
    inet_addr函数:将字符串地址转化为某一种数字格式
    inet_ntoa函数:将数字格式的地址转化为字符串
    需要注意的是描述地址族(莫名其妙的概念)信息本应使用大小为16字节的sockaddr结构体,但是因为该结构体除了sin.family,其余全是存储在一个数组中的,这样赋值难免麻烦,所以才有了SOCKADDR_IN
    
    sockaddr:  
      struct sockaddr {
        u_short    sa_family;
        char       sa_data[14];};
     
    
    SOCKADDR_IN:
      struct sockaddr_in {
      short sin_family;
      u_short sin_port;
      struct in_addr sin_addr;
      char sin_zero[8];
    };
    
    
    
    
    
    5、绑定(将scocket与地址族联起来
    /*bind
        参数1:未绑定的socket
        参数2:地址族信息地址
        参数3:地址族信息的大小
        返回值:成功返回0,失败返回SOCKET_ERROR*/
    bind(sk,(sockaddr*)&server_addr,sizeof(sockaddr))
    
    
    
    
    6、监听
    /*listen
        参数1:已绑定未监听的socket
        参数2:等待连接的队伍最大长度 SOMAXCONN表示自动设置合理值
        返回值:失败返回SOCKET_ERROR,成功返回0*/
    listen(sk,SOMAXCONN);
    
    
    
    
    7、接收连接(等待连接)
    /*接收连接:accetp
        参数1:已监听的socket
        参数2 out :建立连接的客户端信息
        参数3:传递时包含参数2的大小,返回时包含返回地址的实际长度
        返回值:成功就返回已连接的套接字,否则返回INVALID_SOCKET失败信息*/
    SOCKADDR_IN cline_addr = {0};
    DWORD len = sizeof(SOCKADDR_IN);
    SOCKET _cline_socket = accetp(sk,(sockaddr*)&cline_addr,(int*)&len);
    
    accetp函数:这是一个阻塞函数,在有连接前就会等待于此
    
    
    
    
    
    8、通信
    微软MSDN:https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recv
    
    /*通信recv(接收) send(发送) 
        参数1;建立连接的socket
        参数2: 接数或发送数据的缓冲区
        参数3: 缓冲区长度
        参数4: 发送或接数数据的方式
        返回值:成功返回接数或返回的字节大小,连接正常断开返回0,其他情况返回相应的错误代码*/
    char recvbuff[256] = {0};
    while(true)
    {
      memset(recvbuff,0,256);
      DWORD recvlen = recv(_cline_socket,recvbuff,256,0); //默认为0表示全接收,并结束函数
      if(recvlen > 0)
      {
        printf("%s
    ",recvlen);
      }else
      {
        switch(recvlen)
        {
          case 0:
            closesocket(_cline_socket); //关闭socket连接
            break;
        }
      }
    }
    WSACleanup(); //释放ws2_32.dll
    
    
    --- 客户端 ---
    客户端相较于服务端,只需要连接即可进行通信
    
    1、导入需要的函数
    
    #incldue <windows.h>  //#include<WinSock2.h>
    #pragma comment(lib,"ws2_32.lib")
    
    2、创建scoket
    
    SOCKET sk = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    
    
    3、创建地址族描述信息
    SOCKADDR_IN sever_addr = {0};
    sever_addr.sin_family = AF_INET; //地址族类型
    sever_addr.sin_port = htons(8888); //端口
    server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //地址
    
    4、连接到服务端
    
    /*connect
      参数1:未连接的socket
      参数2:连接的议地址族信息(连接的服务端信息)
      参数3:参数2的长度
      返回值:成功返回0,否则返回SOCKET_ERROR*/
    connect(sk,(sockadd*)&server_addr,sizeof(SOCKADDR_IN));
    
    5、通信
      char sendbuff[256] = "Hello.";
      DWORD Num = send(sk,sendbuff,256,0);   ////如果返回值小于len参数,但是这是一个非阻塞套接字就表示没有发生错误
      if(NUm == SOCKET_ERR)
      {
        printf("%s
    ",“连接断开”);
        closesocket(sk);
        WSACleeanup();
      }
    
    
    
    
    




    软件界面:
      

    根据分析找到了其回调函数:并得到其处理过程函数:

    .text:004010F9                 cmp     [ebp+arg_4], 111h ; 判断是否是WM_COMMADN消息
    .text:00401100                 jnz     short loc_40116E
    .text:00401102                 mov     ecx, [ebp+arg_8]
    .text:00401105                 and     ecx, 0FFFFh     ; 获取wparam参数的低4位,也就是控件id
    .text:0040110B                 mov     [ebp+var_8], ecx
    .text:0040110E                 mov     edx, [ebp+arg_C]
    .text:00401111                 mov     [ebp+hWnd], edx
    .text:00401114                 cmp     [ebp+var_8], 3EAh ; 判断是否登录按钮
    .text:0040111B                 jnz     short loc_40116E
    .text:0040111D                 mov     esi, esp
    .text:0040111F                 push    0               ; bEnable
    .text:00401121                 mov     eax, [ebp+hWnd]
    .text:00401124                 push    eax             ; hWnd
    .text:00401125                 call    ds:EnableWindow
    .text:0040112B                 cmp     esi, esp
    .text:0040112D                 call    __chkesp
    .text:00401132                 call    sub_40100F      ; 处理函数
    .text:00401137                 test    eax, eax
    .text:00401139                 jz      short loc_401159
    .text:0040113B                 xor     ecx, ecx
    .text:0040113D                 mov     cl, byte_41AEB0
    .text:00401143                 cmp     ecx, 77h
    .text:00401146                 jz      short loc_401159 ; 返回值为0就重新恢复button,否则就退出程序
    .text:00401148                 mov     esi, esp
    .text:0040114A                 push    0               ; uExitCode
    .text:0040114C                 call    ds:ExitProcess
    sub_40100F函数内核心代码如下:将计算的随机数和用户名长度,密码长度按每个1字节写入到[ebp-0x348]这块内存,之后将用户名和密码也复制到这一块内存
    0129751D  |.  6A 00         push 0x0
    0129751F  |.  E8 7CFEFFFF   call crackmen.timet_stdio_output::positiona>;  获取时间戳
    01297524  |.  83C4 04       add esp,0x4
    01297527  |.  50            push eax
    01297528  |.  E8 D6B5FFFF   call crackmen.01292B03
    0129752D  |.  83C4 04       add esp,0x4
    01297530  |.  E8 E8A0FFFF   call crackmen.0129161D                      ;  获取随机数
    01297535  |.  25 FF000080   and eax,0x800000FF
    0129753A  |.  79 07         jns short crackmen.01297543
    0129753C  |.  48            dec eax
    0129753D  |.  0D 00FFFFFF   or eax,-0x100
    01297542  |.  40            inc eax
    01297543  |>  8885 A7FCFFFF mov byte ptr ss:[ebp-0x359],al              ;  把随机数给0x359
    01297549  |.  BA 01000000   mov edx,0x1
    0129754E  |.  6BC2 00       imul eax,edx,0x0
    01297551  |.  8A8D B0FCFFFF mov cl,byte ptr ss:[ebp-0x350]
    01297557  |.  888C05 B8FCFF>mov byte ptr ss:[ebp+eax-0x348],cl          ;  用户名的长度给0x348
    0129755E  |.  BA 01000000   mov edx,0x1
    01297563  |.  c1e2 00       shl edx,0x0
    01297566  |.  8A85 ACFCFFFF mov al,byte ptr ss:[ebp-0x354]
    0129756C  |.  888415 B8FCFF>mov byte ptr ss:[ebp+edx-0x348],al          ;  把密码给长度给0x348+0x1
    01297573  |.  B9 01000000   mov ecx,0x1
    01297578  |.  D1E1          shl ecx,1
    0129757A  |.  8A95 A7FCFFFF mov dl,byte ptr ss:[ebp-0x359]
    01297580  |.  88940D B8FCFF>mov byte ptr ss:[ebp+ecx-0x348],dl          ;  把随机数给0x348+0x2
    01297587  |.  8B85 B0FCFFFF mov eax,[local.212]
    0129758D  |.  50            push eax
    0129758E  |.  8D4D C0       lea ecx,[local.16]
    01297591  |.  51            push ecx
    01297592  |.  8D95 BBFCFFFF lea edx,dword ptr ss:[ebp-0x345]
    01297598  |.  52            push edx
    01297599  |.  E8 0DBDFFFF   call crackmen.012932AB                      ;  将用户名复制到 [ebp-0x345]
    0129759E  |.  83C4 0C       add esp,0xC
    012975A1  |.  8B85 ACFCFFFF mov eax,[local.213]
    012975A7  |.  50            push eax
    012975A8  |.  8D4D 84       lea ecx,[local.31]
    012975AB  |.  51            push ecx
    012975AC  |.  8B95 B0FCFFFF mov edx,[local.212]
    012975B2  |.  8D8415 BBFCFF>lea eax,dword ptr ss:[ebp+edx-0x345]
    012975B9  |.  50            push eax
    012975BA  |.  E8 ECBCFFFF   call crackmen.012932AB                      ;  将密码复制到 [ebp+用户名长度-0x345]

    当上面步骤执行完后:从[ebp-0x348]这一块内存,就存储了如下格式的数据:04 03 77 61 61 61 61 66 66 66  前3个字节分别是:随机数,用户名长度,密码长度,后面的就是用户名和密码

    对[ebp-0x348]进行简单的加密

    012975C2  |.  8B8D ACFCFFFF mov ecx,[local.213]  ;获取用户名长度
    012975C8  |.  8B95 B0FCFFFF mov edx,[local.212] ;//获取密码长度
    012975CE  |.  8D440A 03     lea eax,dword ptr ds:[edx+ecx+0x3]  //得到整个[ebp-0x348]内存的长度
    012975D2  |.  8985 A8FCFFFF mov [local.214],eax                         ;  liack0x214存储的就是整个用户名长度+整个密码长度+0x3(随机数,用户名长度值,密码长度值+)
    012975D8  |.  C785 9CFCFFFF>mov [local.217],0x0                         ;  217作为循环变量使用i
    012975E2  |.  EB 0F         jmp short crackmen.012975F3
    012975E4  |>  8B8D 9CFCFFFF /mov ecx,[local.217]
    012975EA  |.  83C1 01       |add ecx,0x1    ;i++
    012975ED  |.  898D 9CFCFFFF |mov [local.217],ecx
    012975F3  |>  8B95 9CFCFFFF  mov edx,[local.217]
    012975F9  |.  3B95 A8FCFFFF |cmp edx,[local.214]                        ;  如果i大于等于214([ebp-0x348]缓冲区的总长度)就跳出循环
    012975FF  |.  7D 23         |jge short crackmen.01297624
    01297601  |.  8B85 9CFCFFFF |mov eax,[local.217]
    01297607  |.  0FBE8C05 B8FC>|movsx ecx,byte ptr ss:[ebp+eax-0x348]      ;  取1字节进行加密
    0129760F  |.  81F1 A6000000 |xor ecx,0xA6                               ;  
    01297615  |.  8B95 9CFCFFFF |mov edx,[local.217]
    0129761B  |.  888C15 B8FCFF>|mov byte ptr ss:[ebp+edx-0x348],cl         ;  将加密后的值写回
    01297622  |.^ EB C0         jmp short crackmen.012975E4

    发送数据到服务端:

    01297624  |> 6A 00         push 0x0                                    ; /Flags = 0
    01297626  |.  8B85 A8FCFFFF mov eax,[local.214]                         ; |
    0129762C  |.  50            push eax                                    ; |DataSize = A (10.)
    0129762D  |.  8D8D B8FCFFFF lea ecx,[local.210]                         ; |
    01297633  |.  51            push ecx                                    ; |Data = 00000003
    01297634  |.  8B95 80FCFFFF mov edx,[local.224]                         ; |
    0129763A  |.  52            push edx                                    ; |Socket = 0x4
    0129763B  |.  E8 84050000   call crackmen.tring_output_adapter<char> ><>; send


    接收服务端返回的数据,并进行解密:

    01297654  |.  6A 00         push 0x0                                    ; /Flags = 0
    01297656  |.  68 F4010000   push 0x1F4                                  ; |BufSize = 1F4 (500.)
    0129765B      8D85 88FDFFFF lea eax,dword ptr ss:[ebp-0x278]            ;  [ebp-0x278]作为接收数据的缓冲区
    01297661  |.  50            push eax                                    ; |Buffer = 0000000A
    01297662  |.  8B8D 80FCFFFF mov ecx,[local.224]                         ; |
    01297668  |.  51            push ecx                                    ; |Socket = 0x3
    01297669  |.  E8 50050000   call crackmen.<char,__crt_stdio_output::str>; 
    ecv
    0129766E  |.  8985 A0FCFFFF mov [local.216],eax                         ;  局部变量:loacal.216是接收的数据长度
    01297674  |.  C785 9CFCFFFF>mov [local.217],0x0                         ;  217作为循环值i
    0129767E  |.  EB 0F         jmp short crackmen.0129768F ;循环开始
    01297680  |>  8B95 9CFCFFFF /mov edx,[local.217]
    01297686  |.  83C2 01       |add edx,0x1 ;i++
    01297689  |.  8995 9CFCFFFF |mov [local.217],edx
    0129768F  |>  8B85 9CFCFFFF  mov eax,[local.217]
    01297695  |.  3B85 A0FCFFFF |cmp eax,[local.216]                        ;  i < revc()
    0129769B  |.  7D 1F         |jge short crackmen.012976BC
    0129769D  |.  8B8D 9CFCFFFF |mov ecx,[local.217]
    012976A3  |.  0FB6940D 88FD>|movzx edx,byte ptr ss:[ebp+ecx-0x278]      ;  从[ebp-278]取一个字节,并解密
    012976AB  |.  83F2 6E       |xor edx,0x6E                               ;  解密
    012976AE  |.  8B85 9CFCFFFF |mov eax,[local.217]
    012976B4  |.  8890 F0AE3501 |mov byte ptr ds:[eax+eeam_output_adapter<w>;  0x135AEF0 存储解密的数据内存地址0x135AEF0
    012976BA  |.^ EB C4         jmp short crackmen.01297680

    根据解密后的数据进行验证:
    012976BC  |> B9 01000000   mov ecx,0x1
    012976C1  |.  C1E1 02       shl ecx,0x2                                 ;  ecx = 0x4
    012976C4  |.  0FB691 F0AE35>movzx edx,byte ptr ds:[ecx+eeam_output_adap>;  从解密的数据中+0x4 取1byte 是否为0xd5
    012976CB  |.  81FA D5000000 cmp edx,0xD5
    012976D1  |.  0F85 9E000000 jnz crackmen.01297775 ;1297775结束位置
    012976D7  |.  B8 01000000   mov eax,0x1
    012976DC  |.  6BC8 0E       imul ecx,eax,0xE
    012976DF  |.  0FB691 F0AE35>movzx edx,byte ptr ds:[ecx+eeam_output_adap>;  从解密的数据中+0xe 取1byte
    012976E6  |.  0FB685 A7FCFF>movzx eax,byte ptr ss:[ebp-0x359]           ;  取之前获取的随机数
    012976ED  |.  3BD0          cmp edx,eax                                 ;  判断是否合之前的获取的随机数相等
    012976EF  |.  0F85 80000000 jnz crackmen.01297775
    012976F5  |.  B9 01000000   mov ecx,0x1
    012976FA  |.  6BD1 0A       imul edx,ecx,0xA
    012976FD  |.  0FB682 F0AE35>movzx eax,byte ptr ds:[edx+eeam_output_adap>;  从解密的数据中+0xA 取1byte并+0x3,判断结果是否为0x16
    01297704  |.  83C0 03       add eax,0x3                                 ;  +=3
    01297707  |.  83F8 16       cmp eax,0x16                                ;  判断是否为0x16
    0129770A  |.  75 69         jnz short crackmen.01297775
    0129770C  |.  B9 01000000   mov ecx,0x1
    01297711  |.  6BD1 23       imul edx,ecx,0x23                           ;  从解密的数据中+0x23 取1byte 是否为0bd
    01297714  |.  0FB682 F0AE35>movzx eax,byte ptr ds:[edx+eeam_output_adap>
    0129771B  |.  3D BD000000   cmp eax,0xBD
    01297720  |.  75 53         jnz short crackmen.01297775
    01297722  |.  B9 01000000   mov ecx,0x1
    01297727  |.  6BD1 3C       imul edx,ecx,0x3C
    0129772A  |.  0FB682 F0AE35>movzx eax,byte ptr ds:[edx+eeam_output_adap>;  从解密的数据中+0x3c 取1byte 是否为0x43
    01297731  |.  83F8 43       cmp eax,0x43
    01297734  |.  75 3F         jnz short crackmen.01297775
    01297736  |.  B9 01000000   mov ecx,0x1
    0129773B  |.  6BD1 42       imul edx,ecx,0x42
    0129773E  |.  0FB682 F0AE35>movzx eax,byte ptr ds:[edx+eeam_output_adap>;  从解密的数据中+0x42 取1byte 是否为0xc6
    01297745  |.  3D C6000000   cmp eax,0xC6
    0129774A  |.  75 29         jnz short crackmen.01297775
    0129774C  |.  8BF4          mov esi,esp
    0129774E  |.  6A 00         push 0x0                                    ; /Style = MB_OK|MB_APPLMODAL
    01297750  |.  68 58A03501   push crackmen.0135A058                      ; |Title = "Crackne net-2"
    01297755  |.  68 68A03501   push crackmen.0135A068                      ; |Text = "Registration successful !"
    0129775A  |.  8B0D 80C63501 mov ecx,dword ptr ds:[0xnions'::`2'::_Optio>; |
    01297760  |.  51            push ecx                                    ; |hOwner = 00000003
    01297761  |.  FF15 D0D13501 call dword ptr ds:[<&USER32.MessageBoxA>]   ; MessageBoxA
  • 相关阅读:
    B2. Cat Party (Hard Edition)
    Dubbo集群容错
    Dubbo负载均衡
    Dubbo多协议支持
    Dubbo服务分组
    Dubbo多版本控制
    Dubbo管控平台
    Dubbo应用到web工程
    Dubbo使用Zookeeper注册中心
    Dubbo直连方式
  • 原文地址:https://www.cnblogs.com/Hookcc/p/12547472.html
Copyright © 2011-2022 走看看