一、代理抓包

1. 代理服务器转发TCP数据包并打印

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>

#pragma comment(lib, "ws2_32.lib")

#define SOCKS5_PORT 1080 // 代理服务器监听端口
#define BUFFER_SIZE 4096
#define HEX_LINE_WIDTH 16 // 每行显示16字节的十六进制

// 记录流量到文件(新增地址参数和十六进制打印)
void log_packet(
const char* client_ip, int client_port,
const char* server_ip, int server_port,
const char* data, int len
) {
FILE* log_file = fopen("traffic.log", "ab");
if (!log_file) return;

// 1. 打印地址信息
fprintf(log_file, "[%s:%d -> %s:%d] Length: %d\n",
client_ip, client_port, server_ip, server_port, len);

// 2. 打印十六进制数据(自动换行)
for (int i = 0; i < len; i++) {
fprintf(log_file, "%02X ", (unsigned char)data[i]);

// 每行显示HEX_LINE_WIDTH字节后换行
if ((i + 1) % HEX_LINE_WIDTH == 0 || i == len - 1) {
fprintf(log_file, "\n");
}
}

fclose(log_file);
}

// 处理客户端连接
DWORD WINAPI handle_client(LPVOID lpParam) {
SOCKET client_sock = (SOCKET)lpParam;
char buffer[BUFFER_SIZE];
int bytes_read;

// 1. SOCKS5握手阶段
bytes_read = recv(client_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read < 3 || buffer[0] != 0x05) {
closesocket(client_sock);
return 1;
}

// 返回无需认证
char handshake_response[] = { 0x05, 0x00 };
send(client_sock, handshake_response, 2, 0);

// 2. 获取客户端请求(目标地址和端口)
bytes_read = recv(client_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read < 7 || buffer[1] != 0x01) { // 只处理CONNECT请求
closesocket(client_sock);
return 1;
}

// 解析目标地址
char dest_ip[INET_ADDRSTRLEN];
unsigned short dest_port;
struct sockaddr_in dest_addr;

if (buffer[3] == 0x01) { // IPv4
memcpy(&dest_addr.sin_addr, buffer + 4, 4);
memcpy(&dest_port, buffer + 8, 2);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = dest_port;
}
else {
closesocket(client_sock);
return 1;
}

// 3. 连接目标服务器
SOCKET dest_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connect(dest_sock, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) == SOCKET_ERROR) {
closesocket(client_sock);
closesocket(dest_sock);
return 1;
}

// 返回连接成功响应
char connect_response[] = { 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
send(client_sock, connect_response, 10, 0);

// 4. 双向转发数据(抓包核心逻辑)
fd_set readfds;
while (1) {
FD_ZERO(&readfds);
FD_SET(client_sock, &readfds);
FD_SET(dest_sock, &readfds);

if (select(0, &readfds, NULL, NULL, NULL) == SOCKET_ERROR) break;

// 从客户端读取并转发到目标服务器
if (FD_ISSET(client_sock, &readfds)) {
bytes_read = recv(client_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read <= 0) break;

log_packet(buffer, bytes_read, "Client -> Server");
send(dest_sock, buffer, bytes_read, 0);
}

// 从目标服务器读取并转发到客户端
if (FD_ISSET(dest_sock, &readfds)) {
bytes_read = recv(dest_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read <= 0) break;

log_packet(buffer, bytes_read, "Server -> Client");
send(client_sock, buffer, bytes_read, 0);
}
}

closesocket(client_sock);
closesocket(dest_sock);
return 0;
}

int main() {
WSADATA wsa;
SOCKET listen_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
int client_addr_len = sizeof(client_addr);

WSAStartup(MAKEWORD(2, 2), &wsa);

// 创建监听Socket
listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(SOCKS5_PORT);

bind(listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen(listen_sock, SOMAXCONN);

printf("SOCKS5 Proxy Server listening on port %d...\n", SOCKS5_PORT);

// 接受客户端连接
while ((client_sock = accept(listen_sock, (struct sockaddr*)&client_addr, &client_addr_len)) != INVALID_SOCKET) {
char client_ip[INET_ADDRSTRLEN];
// 使用 inet_ntop 替换 inet_ntoa
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
printf("New client connected: %s:%d\n",
client_ip, ntohs(client_addr.sin_port));

// 为每个客户端创建线程
CreateThread(NULL, 0, handle_client, (LPVOID)client_sock, 0, NULL);
}

closesocket(listen_sock);
WSACleanup();
return 0;
}

2. 以16进制打印TCP数据包并且标明地址与端口

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>

#pragma comment(lib, "ws2_32.lib")

#define SOCKS5_PORT 1080
#define BUFFER_SIZE 4096
#define HEX_LINE_WIDTH 16 // 每行显示16字节的十六进制

// 记录流量到文件(新增地址参数和十六进制打印)
void log_packet(
const char* client_ip, int client_port,
const char* server_ip, int server_port,
const char* data, int len
) {
FILE* log_file = fopen("traffic.log", "ab");
if (!log_file) return;

// 1. 打印地址信息
fprintf(log_file, "[%s:%d -> %s:%d] Length: %d\n",
client_ip, client_port, server_ip, server_port, len);

// 2. 打印十六进制数据(自动换行)
for (int i = 0; i < len; i++) {
fprintf(log_file, "%02X ", (unsigned char)data[i]);

// 每行显示HEX_LINE_WIDTH字节后换行
if ((i + 1) % HEX_LINE_WIDTH == 0 || i == len - 1) {
fprintf(log_file, "\n");
}
}

fclose(log_file);
}

DWORD WINAPI handle_client(LPVOID lpParam) {
SOCKET client_sock = (SOCKET)lpParam;
SOCKET dest_sock = INVALID_SOCKET; // 统一在此处声明并初始化
char buffer[BUFFER_SIZE];
int bytes_read;

// 获取客户端地址信息
struct sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
getpeername(client_sock, (struct sockaddr*)&client_addr, &client_addr_len);
char client_ip[INET_ADDRSTRLEN];
int client_port = ntohs(client_addr.sin_port);
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);

// 1. SOCKS5握手阶段
bytes_read = recv(client_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read < 3 || buffer[0] != 0x05) {
closesocket(client_sock);
return 1;
}
send(client_sock, "\x05\x00", 2, 0);

// 2. 解析客户端请求
bytes_read = recv(client_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read < 7 || buffer[1] != 0x01) { // 仅处理 CONNECT 请求
closesocket(client_sock);
return 1;
}

// 解析目标地址和端口
struct sockaddr_in dest_addr;
char dest_ip[INET_ADDRSTRLEN];
unsigned short dest_port_network;
int dest_port;

if (buffer[3] == 0x01) { // IPv4
memcpy(&dest_addr.sin_addr, buffer + 4, 4);
inet_ntop(AF_INET, &dest_addr.sin_addr, dest_ip, INET_ADDRSTRLEN);
memcpy(&dest_port_network, buffer + 8, 2);
dest_port = ntohs(dest_port_network);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(dest_port);
}
else {
closesocket(client_sock);
return 1;
}

// 3. 连接目标服务器(使用已声明的 dest_sock)
dest_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connect(dest_sock, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) == SOCKET_ERROR) {
printf("[Proxy] Failed to connect to target server. Error Code: %d\n", WSAGetLastError());
closesocket(client_sock);
closesocket(dest_sock);
return 1;
}

send(client_sock, "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00", 10, 0);

// 4. 双向转发数据(修改日志调用)
fd_set readfds;
while (1) {
FD_ZERO(&readfds);
FD_SET(client_sock, &readfds);
FD_SET(dest_sock, &readfds);

if (select(0, &readfds, NULL, NULL, NULL) == SOCKET_ERROR) break;

// 从客户端读取并转发到目标服务器
if (FD_ISSET(client_sock, &readfds)) {
bytes_read = recv(client_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read <= 0) break;

log_packet(client_ip, client_port, dest_ip, dest_port, buffer, bytes_read);
send(dest_sock, buffer, bytes_read, 0);
}

// 从目标服务器读取并转发到客户端
if (FD_ISSET(dest_sock, &readfds)) {
bytes_read = recv(dest_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read <= 0) break;

log_packet(dest_ip, dest_port, client_ip, client_port, buffer, bytes_read);
send(client_sock, buffer, bytes_read, 0);
}
}

// 5. 清理资源(确保在此处关闭socket)
closesocket(client_sock);
closesocket(dest_sock);
return 0;
}

int main() {
WSADATA wsa;
SOCKET listen_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
int client_addr_len = sizeof(client_addr);

WSAStartup(MAKEWORD(2, 2), &wsa);

// 创建监听Socket
listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(SOCKS5_PORT);

bind(listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen(listen_sock, SOMAXCONN);

printf("SOCKS5 Proxy Server listening on port %d...\n", SOCKS5_PORT);

// 接受客户端连接
while ((client_sock = accept(listen_sock, (struct sockaddr*)&client_addr, &client_addr_len)) != INVALID_SOCKET) {
char client_ip[INET_ADDRSTRLEN];
// 使用 inet_ntop 替换 inet_ntoa
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
printf("New client connected: %s:%d\n",
client_ip, ntohs(client_addr.sin_port));

// 为每个客户端创建线程
CreateThread(NULL, 0, handle_client, (LPVOID)client_sock, 0, NULL);
}

closesocket(listen_sock);
WSACleanup();
return 0;
}

3. 支持域名解析

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdint.h>

#pragma comment(lib, "ws2_32.lib")

#define SOCKS5_PORT 1080
#define BUFFER_SIZE 4096
#define HEX_LINE_WIDTH 16
#define LOG_QUEUE_SIZE 1000

volatile BOOL g_shutdown = FALSE;

typedef struct {
char client_ip[INET_ADDRSTRLEN];
int client_port;
char server_ip[INET_ADDRSTRLEN];
int server_port;
char data[BUFFER_SIZE];
int data_len;
} LogEntry;

CRITICAL_SECTION log_lock;
HANDLE log_semaphore;
LogEntry log_queue[LOG_QUEUE_SIZE];
int log_head = 0, log_tail = 0;

// 改进的日志函数
void LogPacketAsync(const char* client_ip, int client_port,
const char* server_ip, int server_port,
const char* data, int len) {
if (len <= 0 || len > BUFFER_SIZE) return;

EnterCriticalSection(&log_lock);

strncpy(log_queue[log_head].client_ip, client_ip, INET_ADDRSTRLEN);
strncpy(log_queue[log_head].server_ip, server_ip, INET_ADDRSTRLEN);
log_queue[log_head].client_port = client_port;
log_queue[log_head].server_port = server_port;
memcpy(log_queue[log_head].data, data, len);
log_queue[log_head].data_len = len;

log_head = (log_head + 1) % LOG_QUEUE_SIZE;
ReleaseSemaphore(log_semaphore, 1, NULL);

LeaveCriticalSection(&log_lock);
}

DWORD WINAPI LogThread(LPVOID lpParam) {
while (!g_shutdown) {
WaitForSingleObject(log_semaphore, 100);

EnterCriticalSection(&log_lock);
if (log_head == log_tail) {
LeaveCriticalSection(&log_lock);
continue;
}

LogEntry entry = log_queue[log_tail];
log_tail = (log_tail + 1) % LOG_QUEUE_SIZE;
LeaveCriticalSection(&log_lock);

FILE* log = fopen("traffic.log", "ab");
if (log) {
fprintf(log, "[%s:%d -> %s:%d] %d bytes\n",
entry.client_ip, entry.client_port,
entry.server_ip, entry.server_port,
entry.data_len);

for (int i = 0; i < entry.data_len; i++) {
fprintf(log, "%02X%c",
(unsigned char)entry.data[i],
(i + 1) % HEX_LINE_WIDTH ? ' ' : '\n');
}
fclose(log);
}
}
return 0;
}

DWORD WINAPI handle_client(LPVOID lpParam) {
SOCKET client_sock = (SOCKET)lpParam;
SOCKET remote_sock = INVALID_SOCKET;
char buffer[BUFFER_SIZE];
int bytes_read;

// 获取客户端信息
struct sockaddr_in client_addr;
int addr_len = sizeof(client_addr);
getpeername(client_sock, (struct sockaddr*)&client_addr, &addr_len);
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
int client_port = ntohs(client_addr.sin_port);

// SOCKS5 握手:只支持 CONNECT(TCP)方式,不支持 UDP 关联
bytes_read = recv(client_sock, buffer, 2, 0);
if (bytes_read != 2 || buffer[0] != 0x05) {
closesocket(client_sock);
return 0;
}

// 读取认证方法
int nmethods = buffer[1];
recv(client_sock, buffer, nmethods, 0);

// 发送认证响应
char auth_response[2] = { 0x05, 0x00 };
send(client_sock, auth_response, 2, 0);

// 读取请求头(仅处理 CONNECT 命令)
bytes_read = recv(client_sock, buffer, 4, 0);
if (bytes_read != 4 || buffer[1] != 0x01) {
closesocket(client_sock);
return 0;
}

// 解析目标地址
char remote_ip[INET_ADDRSTRLEN] = { 0 };
unsigned short remote_port = 0;
struct sockaddr_in remote_addr = { 0 };

switch (buffer[3]) {
case 0x01: { // IPv4 地址
bytes_read = recv(client_sock, buffer + 4, 6, 0);
if (bytes_read != 6) {
closesocket(client_sock);
return 0;
}
memcpy(&remote_addr.sin_addr, buffer + 4, 4);
remote_port = ntohs(*(unsigned short*)(buffer + 8));
break;
}
case 0x03: { // 域名地址
uint8_t domain_len;
recv(client_sock, &domain_len, 1, 0);
bytes_read = recv(client_sock, buffer + 5, domain_len + 2, 0);
if (bytes_read != domain_len + 2) {
closesocket(client_sock);
return 0;
}
char domain[256];
memcpy(domain, buffer + 5, domain_len);
domain[domain_len] = '\0';
remote_port = ntohs(*(unsigned short*)(buffer + 5 + domain_len));

// DNS 解析
struct addrinfo hints = { 0 }, * result = NULL;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(domain, NULL, &hints, &result) != 0) {
char reply[10] = { 0x05, 0x04, 0x00, 0x01 };
send(client_sock, reply, 10, 0);
closesocket(client_sock);
return 0;
}
struct sockaddr_in* dns_res = (struct sockaddr_in*)result->ai_addr;
remote_addr.sin_addr = dns_res->sin_addr;
freeaddrinfo(result);
break;
}
default:
closesocket(client_sock);
return 0;
}

// 设置远程地址参数
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(remote_port);
inet_ntop(AF_INET, &remote_addr.sin_addr, remote_ip, INET_ADDRSTRLEN);

// 连接目标服务器(TCP)
remote_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connect(remote_sock, (SOCKADDR*)&remote_addr, sizeof(remote_addr)) == SOCKET_ERROR) {
char reply[10] = { 0x05, 0x05, 0x00, 0x01 };
send(client_sock, reply, 10, 0);
closesocket(client_sock);
closesocket(remote_sock);
return 0;
}

// 发送成功响应
char reply[10] = { 0x05, 0x00, 0x00, 0x01 };
memcpy(reply + 4, &remote_addr.sin_addr, 4);
memcpy(reply + 8, &remote_port, 2);
send(client_sock, reply, 10, 0);

// 数据转发
fd_set readfds;
while (!g_shutdown) {
FD_ZERO(&readfds);
FD_SET(client_sock, &readfds);
FD_SET(remote_sock, &readfds);

struct timeval timeout = { 1, 0 };
int ret = select(0, &readfds, NULL, NULL, &timeout);
if (ret == SOCKET_ERROR) break;

if (FD_ISSET(client_sock, &readfds)) {
bytes_read = recv(client_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read <= 0) break;

LogPacketAsync(client_ip, client_port, remote_ip, remote_port,
buffer, bytes_read);
send(remote_sock, buffer, bytes_read, 0);
}

if (FD_ISSET(remote_sock, &readfds)) {
bytes_read = recv(remote_sock, buffer, BUFFER_SIZE, 0);
if (bytes_read <= 0) break;

LogPacketAsync(remote_ip, remote_port, client_ip, client_port,
buffer, bytes_read);
send(client_sock, buffer, bytes_read, 0);
}
}

closesocket(client_sock);
closesocket(remote_sock);
return 0;
}

int main() {
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);

InitializeCriticalSection(&log_lock);
log_semaphore = CreateSemaphore(NULL, 0, LOG_QUEUE_SIZE, NULL);
HANDLE hLogThread = CreateThread(NULL, 0, LogThread, NULL, 0, NULL);

SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(SOCKS5_PORT),
.sin_addr.s_addr = INADDR_ANY
};

bind(listen_sock, (SOCKADDR*)&addr, sizeof(addr));
listen(listen_sock, SOMAXCONN);

printf("[Server] SOCKS5 Proxy listening on port %d\n", SOCKS5_PORT);

while (!g_shutdown) {
SOCKET client = accept(listen_sock, NULL, NULL);
if (client == INVALID_SOCKET) {
if (WSAGetLastError() == WSAEINTR) break;
continue;
}

// 显示新连接信息
struct sockaddr_in client_addr;
int addr_len = sizeof(client_addr);
getpeername(client, (SOCKADDR*)&client_addr, &addr_len);
char ip_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, ip_str, INET_ADDRSTRLEN);
printf("[Client] New connection from %s:%d\n",
ip_str, ntohs(client_addr.sin_port));

QueueUserWorkItem(handle_client, (LPVOID)client, WT_EXECUTEDEFAULT);
}

g_shutdown = TRUE;
closesocket(listen_sock);
WaitForSingleObject(hLogThread, 5000);
DeleteCriticalSection(&log_lock);
CloseHandle(log_semaphore);
WSACleanup();
return 0;
}

二、测试代理TCP流量并以16进制打印

  1. C语言TCP协议写一个Linux服务端程序LinServer并运行,功能为接收来自客户端的消息并打印。
  2. C语言TCP协议写一个Windows客户端程序WinClient.exe并运行,功能为给服务器发送消息。
  3. C语言Socket5协议在Windows中写一个代理服务器ProxyServer.exe并运行。
  4. 使用代理转发工具Proxifier或者SocksCap64ProxyServer.exe代理WinClient.exeTCP流量。