记一次:Windows的Socket编程学习和分析过程
Socket编程依赖于:WS2_32.dll

--- 服务端 --- 、导入我们需要的函数
#incldue <windows.h> //#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib") 、初始化(指定要使用的socket版本)
WSADATA ws = {};
/*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); 、设置协议地址族信息(要连接或绑定的ip端口信息)
微软MSDN:https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-sockaddr_in
SOCKADDR_IN sever_addr = {};
sever_addr.sin_family = AF_INET; //地址族类型
sever_addr.sin_port = htons(); //端口
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[];}; SOCKADDR_IN:
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[];
}; 、绑定(将scocket与地址族联起来
/*bind
参数1:未绑定的socket
参数2:地址族信息地址
参数3:地址族信息的大小
返回值:成功返回0,失败返回SOCKET_ERROR*/
bind(sk,(sockaddr*)&server_addr,sizeof(sockaddr)) 、监听
/*listen
参数1:已绑定未监听的socket
参数2:等待连接的队伍最大长度 SOMAXCONN表示自动设置合理值
返回值:失败返回SOCKET_ERROR,成功返回0*/
listen(sk,SOMAXCONN); 、接收连接(等待连接)
/*接收连接:accetp
参数1:已监听的socket
参数2 out :建立连接的客户端信息
参数3:传递时包含参数2的大小,返回时包含返回地址的实际长度
返回值:成功就返回已连接的套接字,否则返回INVALID_SOCKET失败信息*/
SOCKADDR_IN cline_addr = {};
DWORD len = sizeof(SOCKADDR_IN);
SOCKET _cline_socket = accetp(sk,(sockaddr*)&cline_addr,(int*)&len); accetp函数:这是一个阻塞函数,在有连接前就会等待于此 、通信
微软MSDN:https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-recv /*通信recv(接收) send(发送)
参数1;建立连接的socket
参数2: 接数或发送数据的缓冲区
参数3: 缓冲区长度
参数4: 发送或接数数据的方式
返回值:成功返回接数或返回的字节大小,连接正常断开返回0,其他情况返回相应的错误代码*/
char recvbuff[] = {};
while(true)
{
memset(recvbuff,,);
DWORD recvlen = recv(_cline_socket,recvbuff,,); //默认为0表示全接收,并结束函数
if(recvlen > )
{
printf("%s\r\n",recvlen);
}else
{
switch(recvlen)
{
case :
closesocket(_cline_socket); //关闭socket连接
break;
}
}
}
WSACleanup(); //释放ws2_32.dll --- 客户端 ---
客户端相较于服务端,只需要连接即可进行通信 、导入需要的函数 #incldue <windows.h> //#include<WinSock2.h>
#pragma comment(lib,"ws2_32.lib") 、创建scoket SOCKET sk = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 、创建地址族描述信息
SOCKADDR_IN sever_addr = {};
sever_addr.sin_family = AF_INET; //地址族类型
sever_addr.sin_port = htons(); //端口
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //地址 、连接到服务端 /*connect
参数1:未连接的socket
参数2:连接的议地址族信息(连接的服务端信息)
参数3:参数2的长度
返回值:成功返回0,否则返回SOCKET_ERROR*/
connect(sk,(sockadd*)&server_addr,sizeof(SOCKADDR_IN)); 、通信
char sendbuff[] = "Hello.";
DWORD Num = send(sk,sendbuff,,); ////如果返回值小于len参数,但是这是一个非阻塞套接字就表示没有发生错误
if(NUm == SOCKET_ERR)
{
printf("%s\r\n",“连接断开”);
closesocket(sk);
WSACleeanup();
}
软件界面:

根据分析找到了其回调函数:并得到其处理过程函数:
.text:004010F9 cmp [ebp+arg_4], 111h ; 判断是否是WM_COMMADN消息
.text: jnz short loc_40116E
.text: mov ecx, [ebp+arg_8]
.text: and ecx, 0FFFFh ; 获取wparam参数的低4位,也就是控件id
.text:0040110B mov [ebp+var_8], ecx
.text:0040110E mov edx, [ebp+arg_C]
.text: mov [ebp+hWnd], edx
.text: cmp [ebp+var_8], 3EAh ; 判断是否登录按钮
.text:0040111B jnz short loc_40116E
.text:0040111D mov esi, esp
.text:0040111F push ; bEnable
.text: mov eax, [ebp+hWnd]
.text: push eax ; hWnd
.text: call ds:EnableWindow
.text:0040112B cmp esi, esp
.text:0040112D call __chkesp
.text: call sub_40100F ; 处理函数
.text: test eax, eax
.text: jz short loc_401159
.text:0040113B xor ecx, ecx
.text:0040113D mov cl, byte_41AEB0
.text: cmp ecx, 77h
.text: jz short loc_401159 ; 返回值为0就重新恢复button,否则就退出程序
.text: mov esi, esp
.text:0040114A push ; uExitCode
.text:0040114C call ds:ExitProcess
sub_40100F函数内核心代码如下:将计算的随机数和用户名长度,密码长度按每个1字节写入到[ebp-0x348]这块内存,之后将用户名和密码也复制到这一块内存
0129751D |. 6A push 0x0
0129751F |. E8 7CFEFFFF call crackmen.timet_stdio_output::positiona>; 获取时间戳
|. 83C4 add esp,0x4
|. push eax
|. E8 D6B5FFFF call crackmen.01292B03
0129752D |. 83C4 add esp,0x4
|. E8 E8A0FFFF call crackmen.0129161D ; 获取随机数
|. FF000080 and eax,0x800000FF
0129753A |. jns short crackmen.
0129753C |. dec eax
0129753D |. 0D 00FFFFFF or eax,-0x100
|. inc eax
|> A7FCFFFF mov byte ptr ss:[ebp-0x359],al ; 把随机数给0x359
|. BA mov edx,0x1
0129754E |. 6BC2 imul eax,edx,0x0
|. 8A8D B0FCFFFF mov cl,byte ptr ss:[ebp-0x350]
|. 888C05 B8FCFF>mov byte ptr ss:[ebp+eax-0x348],cl ; 用户名的长度给0x348
0129755E |. BA mov edx,0x1
|. c1e2 shl edx,0x0
|. 8A85 ACFCFFFF mov al,byte ptr ss:[ebp-0x354]
0129756C |. B8FCFF>mov byte ptr ss:[ebp+edx-0x348],al ; 把密码给长度给0x348+0x1
|. B9 mov ecx,0x1
|. D1E1 shl ecx,
0129757A |. 8A95 A7FCFFFF mov dl,byte ptr ss:[ebp-0x359]
|. 88940D B8FCFF>mov byte ptr ss:[ebp+ecx-0x348],dl ; 把随机数给0x348+0x2
|. 8B85 B0FCFFFF mov eax,[local.]
0129758D |. push eax
0129758E |. 8D4D C0 lea ecx,[local.]
|. push ecx
|. 8D95 BBFCFFFF lea edx,dword ptr ss:[ebp-0x345]
|. push edx
|. E8 0DBDFFFF call crackmen.012932AB ; 将用户名复制到 [ebp-0x345]
0129759E |. 83C4 0C add esp,0xC
012975A1 |. 8B85 ACFCFFFF mov eax,[local.]
012975A7 |. push eax
012975A8 |. 8D4D lea ecx,[local.]
012975AB |. push ecx
012975AC |. 8B95 B0FCFFFF mov edx,[local.]
012975B2 |. 8D8415 BBFCFF>lea eax,dword ptr ss:[ebp+edx-0x345]
012975B9 |. 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.] ;获取用户名长度
012975C8 |. 8B95 B0FCFFFF mov edx,[local.] ;//获取密码长度
012975CE |. 8D440A lea eax,dword ptr ds:[edx+ecx+0x3] //得到整个[ebp-0x348]内存的长度
012975D2 |. A8FCFFFF mov [local.],eax ; liack0x214存储的就是整个用户名长度+整个密码长度+0x3(随机数,用户名长度值,密码长度值+)
012975D8 |. C785 9CFCFFFF>mov [local.],0x0 ; 217作为循环变量使用i
012975E2 |. EB 0F jmp short crackmen.012975F3
012975E4 |> 8B8D 9CFCFFFF /mov ecx,[local.]
012975EA |. 83C1 |add ecx,0x1 ;i++
012975ED |. 898D 9CFCFFFF |mov [local.],ecx
012975F3 |> 8B95 9CFCFFFF mov edx,[local.]
012975F9 |. 3B95 A8FCFFFF |cmp edx,[local.] ; 如果i大于等于214([ebp-0x348]缓冲区的总长度)就跳出循环
012975FF |. 7D |jge short crackmen.
|. 8B85 9CFCFFFF |mov eax,[local.]
|. 0FBE8C05 B8FC>|movsx ecx,byte ptr ss:[ebp+eax-0x348] ; 取1字节进行加密
0129760F |. 81F1 A6000000 |xor ecx,0xA6 ;
|. 8B95 9CFCFFFF |mov edx,[local.]
0129761B |. 888C15 B8FCFF>|mov byte ptr ss:[ebp+edx-0x348],cl ; 将加密后的值写回
|.^ EB C0 \jmp short crackmen.012975E4
发送数据到服务端:
|> \6A push 0x0 ; /Flags =
|. 8B85 A8FCFFFF mov eax,[local.] ; |
0129762C |. push eax ; |DataSize = A (.)
0129762D |. 8D8D B8FCFFFF lea ecx,[local.] ; |
|. push ecx ; |Data =
|. 8B95 80FCFFFF mov edx,[local.] ; |
0129763A |. push edx ; |Socket = 0x4
0129763B |. E8 call crackmen.tring_output_adapter<char> ><>; \send
接收服务端返回的数据,并进行解密:
|. 6A push 0x0 ; /Flags =
|. F4010000 push 0x1F4 ; |BufSize = 1F4 (.)
0129765B 8D85 88FDFFFF lea eax,dword ptr ss:[ebp-0x278] ; [ebp-0x278]作为接收数据的缓冲区
|. push eax ; |Buffer = 0000000A
|. 8B8D 80FCFFFF mov ecx,[local.] ; |
|. push ecx ; |Socket = 0x3
|. E8 call crackmen.<char,__crt_stdio_output::str>; \recv
0129766E |. A0FCFFFF mov [local.],eax ; 局部变量:loacal.216是接收的数据长度
|. C785 9CFCFFFF>mov [local.],0x0 ; 217作为循环值i
0129767E |. EB 0F jmp short crackmen.0129768F ;循环开始
|> 8B95 9CFCFFFF /mov edx,[local.]
|. 83C2 |add edx,0x1 ;i++
|. 9CFCFFFF |mov [local.],edx
0129768F |> 8B85 9CFCFFFF mov eax,[local.]
|. 3B85 A0FCFFFF |cmp eax,[local.] ; i < revc()
0129769B |. 7D 1F |jge short crackmen.012976BC
0129769D |. 8B8D 9CFCFFFF |mov ecx,[local.]
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.]
012976B4 |. F0AE3501 |mov byte ptr ds:[eax+eeam_output_adapter<w>; 0x135AEF0 存储解密的数据内存地址0x135AEF0
012976BA |.^ EB C4 \jmp short crackmen.
根据解密后的数据进行验证:
012976BC |> \B9 mov ecx,0x1
012976C1 |. C1E1 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 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 jnz crackmen.
012976F5 |. B9 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
|. 83C0 add eax,0x3 ; +=
|. 83F8 cmp eax,0x16 ; 判断是否为0x16
0129770A |. jnz short crackmen.
0129770C |. B9 mov ecx,0x1
|. 6BD1 imul edx,ecx,0x23 ; 从解密的数据中+0x23 取1byte 是否为0bd
|. 0FB682 F0AE35>movzx eax,byte ptr ds:[edx+eeam_output_adap>
0129771B |. 3D BD000000 cmp eax,0xBD
|. jnz short crackmen.
|. B9 mov ecx,0x1
|. 6BD1 3C imul edx,ecx,0x3C
0129772A |. 0FB682 F0AE35>movzx eax,byte ptr ds:[edx+eeam_output_adap>; 从解密的数据中+0x3c 取1byte 是否为0x43
|. 83F8 cmp eax,0x43
|. 3F jnz short crackmen.
|. B9 mov ecx,0x1
0129773B |. 6BD1 imul edx,ecx,0x42
0129773E |. 0FB682 F0AE35>movzx eax,byte ptr ds:[edx+eeam_output_adap>; 从解密的数据中+0x42 取1byte 是否为0xc6
|. 3D C6000000 cmp eax,0xC6
0129774A |. jnz short crackmen.
0129774C |. 8BF4 mov esi,esp
0129774E |. 6A push 0x0 ; /Style = MB_OK|MB_APPLMODAL
|. 58A03501 push crackmen.0135A058 ; |Title = "Crackne net-2"
|. 68A03501 push crackmen.0135A068 ; |Text = "Registration successful !"
0129775A |. 8B0D 80C63501 mov ecx,dword ptr ds:[0xnions'::`2'::_Optio>; |
|. push ecx ; |hOwner =
|. FF15 D0D13501 call dword ptr ds:[<&USER32.MessageBoxA>] ; \MessageBoxA
记一次:Windows的Socket编程学习和分析过程的更多相关文章
- socket编程学习step1
socket学习参考链接,赞一个:http://blog.csdn.net/hguisu/article/details/7445768 sockets(套接字)编程有三种,流式套接字(SOCK_ST ...
- [补] windows C socket编程——大物实验预约
注 : 心血来潮,想着把这两年没能记录下来的经历,写一波回忆杀.诚然,有些经历十分复杂繁琐,希望能耐下性子,写出好文章来,可惜一时不能全想起来这两年来的种种,就想起来什么便写什么吧. 时间估摸着是大一 ...
- JAVA Socket 编程学习笔记(二)
在上一篇中,使用了 java Socket+Tcp/IP 协议来实现应用程序或客户端--服务器间的实时双向通信,本篇中,将使用 UDP 协议来实现 Socket 的通信. 1. 关于UDP UDP协 ...
- JAVA Socket 编程学习笔记(一)
1. Socket 通信简介及模型 Java Socket 可实现客户端--服务器间的双向实时通信.java.net包中定义的两个类socket和ServerSocket,分别用来实现双向连接的cli ...
- Socket编程学习之道:揭开Socket编程的面纱
对TCP/IP.UDP.Socket编程这些词你不会非常陌生吧?随着网络技术的发展.这些词充斥着我们的耳朵. 那么我想问: 1. 什么是TCP/IP.UDP? 2. S ...
- LInux下socket编程学习笔记
1.socket套接字: socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模 ...
- socket编程头文件分析
在socket网络编程中经常用到一些宏定义.结构和函数,这些经常包含在相关的头文件中,使用时直接include相关头文件即可.下面简单描述下相关的一些结构及头文件. 1. sockaddr / bi ...
- Android Socket编程学习笔记
http://blog.csdn.net/eyu8874521/article/details/8847173 度娘给出的描述:通常也称作"套接字",用于描述IP地址和端口,是一个 ...
- windows下socket编程:区分shutdown()及closesocket()
以下描述主要是针对windows平台下的TCP socket而言. 首先需要区分一下关闭socket和关闭TCP连接的区别,关闭TCP连接是指TCP协议层的东西,就是两个TCP端之间交换了一些协议包( ...
随机推荐
- 吴裕雄--天生自然python学习笔记:Python3 数据结构
列表 Python中列表是可变的,这是它区别于字符串和元组的最重要的特点,一句话概括即:列表可以修改,而字符串和元组不能. list.append(x) 把一个元素添加到列表的结尾,相当于 a[len ...
- React中key的讲解
通过阅读React的文档我们知道React这个框架的核心思想是,将页面分割成一个个组件,一个组件还可能嵌套更小的组件,每个组件有自己的数据(属性/状态);当某个组件的数据发生变化时,更新该组件部分的视 ...
- Autotestplat体验中心
web端 移动端 可戳[阅读原文]进行体验
- react ReactDOMServer
此文章是翻译ReactDOMServer这篇React(版本v15.4.0)官方文档. ReactDOMServer 如果你用script 标签来使用React,这些顶级APIs 将会在全局React ...
- 关于struct stat
需要使用struct stat 类型时如果编译不过,修改Makefile: ##CFG_INC := -I$(MPI_DIR)/api/so/##CFG_INC += -I$(BASE_DIR)/pu ...
- create view and switch view
pageView扩展backbone cAbstractApp定义view加载.切换.回退.跳转-webApp/cWebViewApp/hybirdApp为其子类 1.cWebApp扩展了父类的bin ...
- C++走向远洋——36(数组做数据成员,工资)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:salarly.cpp * 作者:常轩 * 微信公众号:Worl ...
- 10分钟进阶SpringBoot - 05. 数据访问之JDBC(附加源码分析+代码下载)
10分钟进阶SpringBoot - 05. 数据访问之JDBC 代码下载:https://github.com/Jackson0714/study-spring-boot.git 一.JDBC是什么 ...
- idea通过maven打jar包不成功或无法加载主类或打成功也找不到jar包
这个问题纠结了我一天,在网上也搜了一些方法,现在把我自己的处理过程记录一下,以方便遇到此类问题的小伙伴参考: 第一步:查看idea的jdk版本与Windows安装的jdk是不是同一个版本,如下图 第二 ...
- 7-46 jmu-python-求单词长度 (10 分)
输入n个单词,计算每个单词长度.对单词长度排序,分行输出单词长度及其单词. 输入格式: 行1:单词个数n 分行输入n个单词 输出格式: 分行输出单词长度及其单词.(单词长度,单词)用元组表示 输入样例 ...