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

image
(如上图)主要代码也就这些,只要实现一个服务端的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。

posted @ 2025-07-27 19:40  MillionMind  阅读(0)  评论(0)    收藏  举报