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
  • 相关阅读:
    HDU 1358 Period (KMP)
    POJ 1042 Gone Fishing
    Csharp,Javascript 获取显示器的大小的几种方式
    css text 自动换行的实现方法 Internet Explorer,Firefox,Opera,Safar
    Dynamic Fonts动态设置字体大小存入Cookie
    CSS Image Rollovers翻转效果Image Sprites图片精灵
    CSS three column layout
    css 自定义字体 Internet Explorer,Firefox,Opera,Safari
    颜色选择器 Color Picker,Internet Explorer,Firefox,Opera,Safar
    CSS TextShadow in Safari, Opera, Firefox and more
  • 原文地址:https://www.cnblogs.com/Hookcc/p/12547472.html
Copyright © 2011-2022 走看看