APK-逆向2--C#Socket编程

(如上图)主要代码也就这些,只要实现一个服务端的socket监听,就可以获取flag。涉及的就是C#socket编程
流程和函数介绍

socket()
int socket(int domain, int type, int protocol);
- domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
- type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等
- protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议
bind()函数
bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket。bind()函数就是将给这个描述字绑定一个名字。
- addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同
- addrlen:对应的是地址的长度。
listen()、connect()函数
如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
int listen(int sockfd, int backlog);
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。
connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。客户端通过调用connect函数来建立与TCP服务器的连接。
accept()函数
TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept函数的第一个参数为服务器的socket描述字,第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。
TcpClient类
为 TCP 网络服务提供客户端连接。
建立tcpclient连接
static void Connect(String server, String message)//服务器的IP地址或主机名,要发送给服务器的消息
{
try
{
Int32 port = 13000;//要连接的服务器端口号
using TcpClient client = new TcpClient(server, port);//使用using声明创建TcpClient实例,确保使用后自动释放资源
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);//将发送的消息转换为ASCII编码的字节数组
NetworkStream stream = client.GetStream();// 获取客户端的网络流(用于读写数据)
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent: {0}", message);
data = new Byte[256];//存储响应数据的缓冲区
String responseData = String.Empty;//存储转换后的响应字符串
Int32 bytes = stream.Read(data, 0, data.Length);//读取服务器响应
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);//将字节数据转换为ASCII字符串
Console.WriteLine("Received: {0}", responseData);
}
catch (ArgumentNullException e)
{
Console.WriteLine("ArgumentNullException: {0}", e);
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
Console.WriteLine("\n Press Enter to continue...");//等待用户输入后再继续,防止控制台窗口直接关闭
Console.Read();
}
属性方法
| 属性 | 描述 |
|---|---|
| Active | 获取或设置一个值,它指示是否已建立连接。 |
| Available | 获取已经从网络接收且可供读取的数据量。 |
| Client | 获取或设置基础 Socket。 |
| Connected | 获取一个值,该值指示 Socket 的基础 TcpClient 是否已连接到远程主机。 |
| ExclusiveAddressUse | 获取或设置 Boolean 值,指定 TcpClient 是否只允许一个客户端使用端口。 |
| LingerState | 获取或设置有关关联的套接字的延迟状态的信息。 |
| NoDelay | 获取或设置一个值,该值在发送或接收缓冲区未满时禁用延迟。 |
| ReceiveBufferSize | 获取或设置接收缓冲区的大小。 |
| ReceiveTimeout | 获取或设置在初始化一个读取操作以后 TcpClient 等待接收数据的时间量。 |
| SendBufferSize | 获取或设置发送缓冲区的大小。 |
| SendTimeout | 获取或设置 TcpClient 等待发送操作成功完成的时间量。 |
根据上述我们就可以编写出服务端的代码
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class TcpServer
{
static void Main(string[] args)
{
int port = 6000;
string host = "127.0.0.1";
// 解析IP地址并创建网络端点
IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);
// 创建并配置TCP套接字
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
// 绑定端点并开始监听
listenSocket.Bind(ipe);
listenSocket.Listen(10); // 允许最多10个挂起连接
Console.WriteLine($"服务器已启动,在 {host}:{port} 监听客户端连接...");
// 等待客户端连接
Socket clientSocket = listenSocket.Accept();
Console.WriteLine($"客户端 {clientSocket.RemoteEndPoint} 已连接");
// 用于接收数据的缓冲区
byte[] recBuffer = new byte[4096];
bool isRunning = true;
// 持续接收客户端消息的循环
while (isRunning)
{
try
{
// 接收客户端发送的数据
int bytesReceived = clientSocket.Receive(recBuffer, recBuffer.Length, 0);
// 客户端断开连接(接收字节数为0)
if (bytesReceived == 0)
{
Console.WriteLine("客户端已断开连接");
isRunning = false;
break;
}
// 解析接收的消息
string recStr = Encoding.ASCII.GetString(recBuffer, 0, bytesReceived);
Console.WriteLine($"收到客户端消息: {recStr}");
// 准备响应消息
string response = $"服务器已接收: {recStr}";
byte[] sendBuffer = Encoding.ASCII.GetBytes(response);
// 发送响应给客户端
clientSocket.Send(sendBuffer, sendBuffer.Length, 0);
Console.WriteLine($"已发送响应: {response}");
}
catch (SocketException ex)
{
Console.WriteLine($"通信错误: {ex.Message}");
isRunning = false;
}
}
// 关闭与客户端的连接
clientSocket.Close();
Console.WriteLine("客户端连接已关闭");
}
catch (Exception ex)
{
Console.WriteLine($"服务器错误: {ex.Message}");
}
finally
{
// 关闭监听套接字
listenSocket.Close();
Console.WriteLine("服务器已停止");
}
Console.WriteLine("按任意键退出...");
Console.ReadKey();
}
}
接着就在vsstudio上执行服务端代码,运行题目程序即可在服务端cmd窗口获取flag。

浙公网安备 33010602011771号