网络通信类程序(Client-Server)

这是最常见的需要两个程序交互的形式:

  • 客户端(client.exe):向服务端(如 server.exe、远程服务)发送请求。

  • 服务端(server.exe):接收请求、处理、返回响应。

常见逆向任务

  • 找出客户端与服务端的协议和通信方式(TCP/UDP / custom protocol)。

  • 反向分析通信数据(如请求/响应格式、加密方式、反序列化方法)。

  • 检查是否对认证信息、数据做了加密/混淆处理。

  • 分析客户端的行为以发现服务器的弱点或隐藏逻辑。

2026软件系统安全赛

在这里刚好拿之前的一道题过一遍。

当时调试的时候很疑惑:为什么两个独立的.exe 文件可以像QQ一样“相互交流”?而且调试的时候需要启动两个.exe文件才可以正常通信

1. 服务器启动与监听
首先,需要运行 server.exe 。程序启动后,它会在计算机的某个特定端口上“待机”,并进入 监听(Listen) 状态,等待客户端的到来

image\.png

2. 客户端发起连接
接着,运行 client.exe ,它会主动向 server.exe 所在的计算机 IP 地址 和指定的端口号发起连接请求

3. 建立连接
server.exe 收到连接请求后,如果一切正常,就会接受这个请求,与 client.exe 之间建立起一条专属的通信“通道”

image\.png

4. 数据交换
连接建立后,双方就可以通过这条通道进行数据交换。

客户端发送请求: client.exe 通过输出流向服务器发送数据或指令(例如,发送一个查询请求或一个游戏操作)

image\.png

服务器处理并响应: server.exe 通过输入流接收到数据,根据预设的逻辑进行处理(比如查询数据库、执行计算),然后将处理结果通过输出流返回给客户端

image\.png

客户端接收响应: client.exe 通过输入流收到服务器的响应,并将其展示在交互界面

5. 关闭连接
当通信任务完成后,客户端或服务器会主动关闭连接,释放系统资源

两个程序通常由同一代码库编译而来,仅通过条件编译或配置区分角色,所以在ida中结构很相似。

动调会触发反调试程序

image\.png

server.exe/client.exe 的导入表分析:server 有 bind/listen/accept,两边都只有 send/recv 没有 sendto/recvfrom, 所以是 TCP,端口 5566,回环通信。

密文这里是直接运行查看

Text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Server listening on 127.0.0.1:5566
[SERVER] Client connected.
[SERVER] Received request header (4 bytes): 00 00 00 08
[SERVER] DES request length: 8
[SERVER] DES request ciphertext (8 bytes): FA 35 9A E4 FF 94 79 E4
[SERVER] DES request plaintext: 11111
[SERVER] Client serial plaintext: 11111
[SERVER] Client serial AES ciphertext (16 bytes): 7E 3F F6 68 C2 81 10 E5 5D B1 14 39 7A 20 4A 77
[SERVER] Expected AES ciphertext (48 bytes): FC 8F 2B 91 3A 35 B5 E8 70 EB 18 63 79 F4 CB A0 C4 B0 CC 19 8D 3F A6 39 C5 4E E2 0D 1A 8E 3E 6C 79 16 BD 4C A3 BE 71 4B 95 FC A7 CD 77 73 A2 56
[SERVER] Ciphertext comparison result: MISMATCH
[SERVER] Response plaintext: FAIL: wrong flag
[SERVER] AES response ciphertext (32 bytes): 8B 5E F8 CC 97 AC 6D 61 B4 3B 3C A5 2A C1 FE 03 2E 35 28 42 15 C6 48 EF 8C 7C BA B0 55 0B FC 30
[SERVER] Response header (4 bytes): 00 00 00 20
[SERVER] Encrypted response sent.

=============================================

Enter serial: 11111
[CLIENT] Preparing connection to 127.0.0.1:5566
[CLIENT] Connected to server.
[CLIENT] Plain serial: 11111
[CLIENT] Plain serial length: 5
[CLIENT] DES ciphertext (8 bytes): FA 35 9A E4 FF 94 79 E4
[CLIENT] Packet header (4 bytes): 00 00 00 08
[CLIENT] Sent DES-encrypted payload to server.
[CLIENT] Received response header (4 bytes): 00 00 00 20
[CLIENT] AES response length: 32
[CLIENT] AES response ciphertext (32 bytes): 8B 5E F8 CC 97 AC 6D 61 B4 3B 3C A5 2A C1 FE 03 2E 35 28 42 15 C6 48 EF 8C 7C BA B0 55 0B FC 30
[CLIENT] AES response plaintext: FAIL: wrong flag
Server: FAIL: wrong flag

直接运行程序可以得到的服务端预期密文 FC 8F 2B 91 3A 35 B5 E8 70 EB 18 63 79 F4 CB A0 C4 B0 CC 19 8D 3F A6 39 C5 4E E2 0D 1A 8E 3E 6C 79 16 BD 4C A3 BE 71 4B 95 FC A7 CD 77 73 A2 56

image\.png

整体请求-校验-响应流程大概如下(基于 DES + AES 的自定义 TCP 协议):

** 建立连接**

客户端连接 127.0.0.1:5566

** 客户端构造并发送请求**

读取用户输入的 serial 。

对 serial 做 DES 加密(块大小 8 字节,不足则 PKCS#7 填充),得到 8 字节密文 FA 35 9A E4 FF 94 79 E4 。

组装数据包:4 字节大端长度头 00 00 00 08 + 8 字节 DES 密文,发送给服务端。

** 服务端接收并解密 **

先读 4 字节头,得知 body 长度 = 8。

读 8 字节 DES 密文,DES 解密得到 serial 明文 11111 成功还原出,也就是说两边持有的 DES 密钥相同**。**

** 服务端校验 serial(核心逻辑)**

把该 serial 再用 AES 加密,得到 16 字节 7E 3F...4A 77。

与内置的预期 AES 密文(48 字节) 做比对(48 字节可能代表 3 个合法 serial 的 AES 块,或拼接校验值)。

11111 不匹配 ,判定 wrong flag。

** 服务端构造并发送响应**

生成响应明文 FAIL: wrong flag(16 字节)。

对其做 AES 加密(PKCS#7 补 16 字节 0x10 填充 → 共 32 字节密文)。

组装数据包,4 字节长度头 00 00 00 20(=32) + 32 字节 AES 密文,发回客户端。

** 客户端接收并解密响应 **

读 4 字节头得长度 32。

读 32 字节 AES 密文,AES 解密得到明文 FAIL: wrong flag,打印。

这边直接先分析server.exe

1
2
3
4
5
6
NTSTATUS BCryptOpenAlgorithmProvider(
[out] BCRYPT_ALG_HANDLE *phAlgorithm,
[in] LPCWSTR pszAlgId, //要使用的算法标识符,这是一个宽字符串指针
[in] LPCWSTR pszImplementation,
[in] ULONG dwFlags
);

在这个函数下断点,动调的时候为了查看到有关加密的过程

image\.png

image\.png

image\.png

发现了BCryptOpenAlgorithmProvider是被调用了两次,一次是 DES ,第二次是 AES 的;往下翻可以看到 AES 加密的模式

屏幕截图 2026\-04\-28 232446\.png

AES-CBC

屏幕截图 2026\-05\-05 124802\.png

在寄存器窗口跳转到 AES 变量名称的地址,然后往上翻

这里有两块连续紧靠数据区域,RDI寄存器和R15寄存器,RDI寄存器指向的刚好是16字节,是密钥?还是AES初始化向量(?)

image\.png

追踪寄存器查看,发现BCryptGenerateSymmetricKey 函数 (bcrypt.h)调用了寄存器r15的数据,也就是下面的 91ADF387C9B48AEED2A19FC7B3D985E4

屏幕截图 2026\-05\-05 134645\.png

BCryptGenerateSymmetricKey 函数 (bcrypt.h)

BCryptGenerateSymmetricKey 函数创建一个密钥对象,用于提供的密钥中的对称密钥加密算法。

1
2
3
4
5
6
7
8
9
NTSTATUS BCryptGenerateSymmetricKey(
[in, out] BCRYPT_ALG_HANDLE hAlgorithm, //指定对称加密算法的句柄
[out] BCRYPT_KEY_HANDLE *phKey, //接收生成的密钥句柄,后续加密/解密操作需使用
[out, optional] PUCHAR pbKeyObject, //密钥内存缓冲区
[in] ULONG cbKeyObject,
[in] PUCHAR pbSecret,
[in] ULONG cbSecret,
[in] ULONG dwFlags
);

接下来的BCryptEncrypt 函数 (bcrypt.h)

BCryptEncrypt 函数加密数据块,这里推入R15寄存器的数据

image\.png

可以确认密钥 91ADF387C9B48AEED2A19FC7B3D985E4

屏幕截图 2026\-05\-05 120346\.png

初始向量IV 6EC1A237589F03D4B5E70C92FA418B66

image\.png

解密

68b35500b4c69fca8f3b2eb2d966664a\.png

Flag: dart{A1B2C3D4E5F60718293A45C6D7E8F90}

IDA Linux 远程控制

IDA (Windows客户端) <--TCP自定义协议--> linux_server (Linux目标机)

默认端口 23946

  • 传输层:TCP

  • 应用层:IDA 私有二进制调试协议(非公开标准)

  • 通信模式:请求-响应式 — IDA发命令(设断点、读内存、单步),server返回结果

  • 本质:远程过程调用(RPC)的变体

无论是IDA远程调试、自编C/S程序还是Web建站,底层都是 Socket 通信(TCP/UDP),差异在于应用层协议的选择(私有二进制 / HTTP / 数据库协议)。逆向分析的核心是通过 API 调用链识别通信类型,再结合抓包还原数据格式。

系统调用与库函数

系统调用

应用程序可以通过系统调用,间接地调用OS中的I/O过程,对I/O设备进行操作。

由OS向用户提供的所有功能,用户进程都必须通过系统调用用来获取,这就涉及到接下来要说的C语言库函数