
简介本资源是一套基于C与MFC开发的Windows平台网络扫描器完整实现项目面向网络安全初学者、高校课程设计学生及渗透测试入门者聚焦主机发现、端口探测、协议识别与基础攻防验证等核心能力训练。项目包含主机扫描、端口扫描、NetBIOS/SNMP/弱密码/嗅探器/DOS攻击/SQL注入检测共八大功能模块均提供详细测试用例与结果验证如192.168.0.100/102双机实测、80/135/445端口开放识别、DOS线程压测、注入标志词welcome匹配等具备完整工程结构与可运行性。压缩包含98个文件以14个.cpp源码、18个.h头文件、15张.png/jpg测试截图、3个.html演示页面及PDF论文文档为主涵盖代码、界面资源、测试图示与技术说明总大小5.12MB。目前已有905人学习下载读者可直接编译运行VC6.0工程Scanner.dsw/.sln结合源码理解底层Socket通信、ICMP/Ping原理、TCP连接扫描、SNMP OID查询、字典爆破逻辑及简单流量捕获机制是理解网络扫描底层实现的典型教学级实践案例。1. 这不是“黑客工具包”一个基于 MFC 的 Windows 网络扫描器能跑通、能调试、能改源码的 C 实战项目你搜“网络扫描器的设计与实现”大概率会撞上一堆 PDF 论文、PPT 汇报稿或者打着“教学演示”旗号却只给个黑窗口一闪而过的 exe。但这个 Y3.zip 里的Network_Scanner-master不是——它是一套完整可编译、带 UI、模块清晰、每个.cpp文件都写满 Win32 API 调用细节的 C 工程用 VC6.0 就能原生打开连Scanner.sln和Scanner.dsp都备齐了。它不搞花哨的 Qt 或 Electron 壳所有功能都压在 MFC 对话框里主机存活探测ICMP Ping、TCP 端口扫描全连接/半连接、NetBIOS 名称查询、SNMP 社区字符串爆破、弱口令字典攻击支持自定义字典文件、HTTP 表单嗅探关键词匹配、SQL 注入特征检测welcome 字符串回显判断甚至包含一个可控线程数的 TCP Flood DOS 模块。这不是玩具是某高校网络攻防实验课的真实结课代码——它没封装成黑盒而是把PortScan.cpp里connect()超时控制、SnifferScan.cpp中 WinPcap 数据包过滤器语法、WeakKeyScan.cpp的多线程密码枚举锁机制全都摊开给你看。如果你正卡在“学完 Winsock 却写不出一个能扫出 135 端口的程序”或者需要一份能嵌入自己课程设计、答辩时能现场改参数演示的 C 扫描器源码这个项目就是你该下载的那一个。2. 从 VC6.0 编译到 UI 功能验证六步走通整个工程链路2.1 环境复现为什么必须用 VC6.0三个硬性依赖点这个项目不是“兼容旧系统”而是深度绑定 VC6.0 的工程结构和库路径。关键证据藏在Scanner.dsp文件里# Scanner.dsp 片段真实内容 # PROP Target_Dir !IF $(CFG) Scanner - Win32 Debug OUTDIR.\Debug INTDIR.\Debug # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D WIN32 /D _DEBUG /D _WINDOWS /D _MBCS /YX /FD /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D WIN32 /D _DEBUG /D _WINDOWS /D _MBCS /YX /FD /c # ADD BASE MTL /nologo /D _DEBUG /mktyplib203 /win32 # ADD MTL /nologo /D _DEBUG /mktyplib203 /win32 # ADD BASE RSC /l 0x804 /d _DEBUG # ADD RSC /l 0x804 /d _DEBUG BSC32bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib IPHLPAPI.LIB /nologo /subsystem:windows /debug /machine:I386注意三处硬编码/machine:I386明确指定 x86 架构VC6.0 默认生成 32 位 PE现代 VS 2022 默认 x64IPHLPAPI.LIB直接写在链接器参数里这是 Windows 98/XP 时代Iphlpapi.h的配套库VS2019 需手动添加iphlpapi.lib并确认 SDK 版本RSC /l 0x804资源语言 ID 为简体中文0x804VC6.0 资源编译器rc.exe对此支持稳定VS 的rc.exe在旧版资源脚本中易报错。提示不要尝试用 VS2019 直接打开.dsp文件。正确做法是安装 VC6.0或使用虚拟机中的 XP VC6.0 环境将整个Network_Scanner-master文件夹解压到无中文路径的目录如D:\Scanner\双击Scanner.dsw即可加载工作区。2.2 工程结构解剖八个核心模块如何协同工作整个项目采用典型的 MFC SDI单文档界面架构主对话框CScannerDlg是调度中心各扫描功能以独立类封装。下表列出关键模块对应关系及调用入口模块名称核心源文件主要功能调用触发点关键 Win32 API主机扫描HostScan.cppICMP Ping 探测存活主机CScannerDlg::OnBtnHostscan()IcmpSendEcho(),IcmpCreateFile()端口扫描PortScan.cppTCP Connect 扫描指定端口范围CScannerDlg::OnBtnPortscan()socket(),connect(),setsockopt(SO_RCVTIMEO)NetBIOS 扫描NetBIOSScan.cppUDP 137 端口发送 Name Query 请求CScannerDlg::OnBtnNetbios()sendto(),recvfrom(),WSAStartup()SNMP 扫描SNMPScan.cppUDP 161 端口发送 GetRequest PDUCScannerDlg::OnBtnSnmp()sendto(), ASN.1 编码逻辑手写弱密码扫描WeakKeyScan.cpp多线程对目标服务FTP/TELNET尝试字典登录CScannerDlg::OnBtnWeakkey()_beginthreadex(),closesocket()错误处理嗅探器扫描SnifferScan.cpp调用 WinPcap 库捕获本地网卡数据包并关键词过滤CScannerDlg::OnBtnSniffer()pcap_open(),pcap_compile(),pcap_loop()SQL 注入检测SQLScan.cpp向目标 URL 发送含 OR 11的 POST 请求分析响应是否含 welcomeCScannerDlg::OnBtnSqlscan()WinHttpOpen(),WinHttpConnect(),WinHttpSendRequest()DOS 攻击DosScan.cpp创建指定数量线程对目标 IP:Port 循环建立 TCP 连接CScannerDlg::OnBtnDos()_beginthreadex(),socket(),connect()循环注意SnifferScan.cpp依赖 WinPcap但项目未打包wpcap.dll和Packet.dll。实测需单独下载 WinPcap 4.1.2XP 兼容版将wpcap.dll放入Debug/目录并确保SnifferScan.h中#pragma comment(lib, wpcap.lib)路径正确。2.3 编译与调试解决三个典型链接错误首次编译常报以下错误本质是库缺失或路径错位error LNK2001: unresolved external symbol __imp__IcmpSendEcho32→ 原因IPHLPAPI.LIB未被链接器找到。→ 解决在 VC6.0 中Project → Settings → Link → Object/library modules栏末尾追加IPHLPAPI.LIB注意空格分隔并确认General → Microsoft Platform SDK已勾选。error LNK2001: unresolved external symbol _pcap_open16→ 原因WinPcap 开发包未安装或wpcap.lib路径错误。→ 解决下载 WinPcap Developers Pack解压后将Lib\wpcap.lib复制到项目根目录在SnifferScan.cpp顶部添加#pragma comment(lib, .\\wpcap.lib)。error C2065: SOCKET_ERROR : undeclared identifier→ 原因winsock2.h与windows.h头文件包含顺序冲突。→ 解决在StdAfx.h中将#include winsock2.h移至#include windows.h之前并删除#include winsock.h二者冲突。编译成功后Debug/Scanner.exe生成。运行前务必以管理员权限启动ICMP 和 Raw Socket 需要提升权限否则主机扫描和嗅探功能将静默失败。2.4 UI 功能验证用最小测试集快速确认八大模块可用性不要一上来就扫全网先用本地环境验证流程是否打通测试项输入参数预期结果验证要点主机扫描起始 IP127.0.0.1结束 IP127.0.0.1列表显示127.0.0.1存活观察HostScan窗口右下角状态栏是否显示 Found 1 host端口扫描目标 IP127.0.0.1端口范围1-100显示127.0.0.1:135,127.0.0.1:445等检查PortScan窗口列表是否非空且端口号符合本地服务如 SMBNetBIOS 扫描目标 IP127.0.0.1返回本机 NetBIOS 名称如HYT-PC1查看NetBIOSScan窗口文本框是否输出非空字符串SNMP 扫描目标 IP127.0.0.1社区名public返回sysDescr.0 Windows Server...若超时说明本地未启用 SNMP 服务换192.168.0.1路由器 IP更可靠弱密码扫描目标 IP192.168.0.1协议TELNET字典pwd.txt含admin成功登录则显示 Login OK需提前在路由器开启 TELNET 并设弱密码嗅探器扫描关键词password监听网卡Realtek PCIe GbE Family Controller提交含 password 的表单后列表出现 HTTP POST 包需另开浏览器访问login.html并提交SQL 注入检测URLhttp://127.0.0.1/login.php注入载荷 OR 11响应体含welcome字符串则标红需自行搭建含漏洞的 PHP 页面见摘要中login.html/respone.phpDOS 攻击目标 IP127.0.0.1端口80线程数10本地 IIS 服务响应变慢或超时警告仅限离线环境测试勿用于生产网络血泪经验SQLScan.cpp中的CWinHttp请求默认超时为 30 秒若目标服务器响应慢会导致界面假死。可在SQLScan.cpp的DoSQLScan()函数内WinHttpSendRequest()后插入DWORD timeout 5000; // 5秒超时 WinHttpSetOption(hRequest, WINHTTP_OPTION_RECEIVE_TIMEOUT, timeout, sizeof(timeout));3. 模块级源码精读从 PortScan 到 SnifferScan 的四个关键实现细节3.1 PortScan.cpp如何用 setsockopt 控制 connect 超时而不阻塞主线程VC6.0 的connect()默认是阻塞式直接调用会导致 UI 冻结。该项目采用select() 非阻塞 socket 的经典方案但关键在于setsockopt()的两次调用// PortScan.cpp 片段 int PortScan::ConnectTest(SOCKET sock, struct sockaddr_in* addr, int timeout_ms) { u_long nonBlocking 1; ioctlsocket(sock, FIONBIO, nonBlocking); // 设为非阻塞 int result connect(sock, (struct sockaddr*)addr, sizeof(*addr)); if (result SOCKET_ERROR WSAGetLastError() WSAEWOULDBLOCK) { // 进入 select 等待 fd_set writefds; FD_ZERO(writefds); FD_SET(sock, writefds); struct timeval tv; tv.tv_sec timeout_ms / 1000; tv.tv_usec (timeout_ms % 1000) * 1000; int ret select(0, NULL, writefds, NULL, tv); if (ret 0 FD_ISSET(sock, writefds)) { // 连接成功检查 SO_ERROR 获取具体错误码 int error 0; int len sizeof(error); getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)error, len); return (error 0) ? 0 : -1; // 0成功-1失败 } } return -1; // 超时或其它错误 }参数说明timeout_ms传入毫秒级超时值如 2000由 UI 线程通过CScannerDlg::m_nTimeout传递ioctlsocket(..., FIONBIO, nonBlocking)必须在connect()前设置否则WSAEWOULDBLOCK不会触发select()的tv结构体必须精确计算tv_usec不能超过 1000000否则行为未定义getsockopt(..., SO_ERROR, ...)是关键select()返回可写不代表连接成功必须检查SO_ERROR是否为 0。玄学点实测发现若timeout_ms设为 100部分防火墙会重置连接导致SO_ERROR10061Connection refused此时应视为端口关闭而非超时。项目中统一返回-1UI 层据此标记为 Closed。3.2 SnifferScan.cppWinPcap 过滤器语法与关键词匹配的内存安全写法SnifferScan.cpp的核心是packet_handler()回调函数它接收原始数据包并提取 HTTP POST 内容。难点在于如何用pcap_compile()编译tcp port 80 and (tcp[((tcp[12:1] 0xf0) 2):4] 0x504f5354)这样的 BPF 过滤器如何从 TCP payload 中安全提取password后的值避免越界读取项目采用保守策略先定位POST方法再搜索或\r\n截断// SnifferScan.cpp 片段 void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) { // ... 解析 IP/TCP 头获取 payload 起始地址 pPayload ... int payload_len tcp_len - (tcp_header_len); if (payload_len 10) return; // 搜索 password大小写不敏感 char* pPass (char*)memchr(pPayload, p, payload_len); if (!pPass) return; if (strnicmp(pPass, password, 9) ! 0 strnicmp(pPass, pwd, 4) ! 0) return; // 定位值起始跳过 password 或 pwd char* pValue pPass ((pPass[0]p||pPass[0]P) ? 9 : 4); // 寻找结束符 或 \r\n 或 \0 char* pEnd (char*)memchr(pValue, , payload_len - (pValue-pPayload)); if (!pEnd) pEnd (char*)memchr(pValue, \r, payload_len - (pValue-pPayload)); if (!pEnd) pEnd (char*)memchr(pValue, \n, payload_len - (pValue-pPayload)); if (!pEnd) pEnd pValue min(32, payload_len - (pValue-pPayload)); // 限制最大长度 int value_len pEnd - pValue; if (value_len 0 value_len 256) { char szValue[256] {0}; memcpy(szValue, pValue, value_len); // 安全szValue 已保证以 \0 结尾可直接传给 UI UpdateData() } }参数说明strnicmp()是 VC6.0 特有函数等价于strncasecmp用于忽略大小写比较memchr()比strstr()更安全避免在二进制 payload 中遇到\0提前截断min(32, ...)是硬编码防护防止恶意构造的超长 password 字段导致栈溢出。3.3 WeakKeyScan.cpp多线程字典爆破中的临界区保护与连接复用弱密码扫描采用_beginthreadex()创建 N 个线程每个线程独立尝试一个密码。但共享资源只有两个m_bStop全局停止标志由 UI 点击“停止”按钮置为truem_listResult存放成功结果的链表需线程安全写入。项目用CCriticalSection实现同步// WeakKeyScan.h class CWeakKeyScan { public: CCriticalSection m_csResult; // 保护 m_listResult volatile BOOL m_bStop; // 原子读写无需锁 CListCString, CString m_listResult; }; // WeakKeyScan.cpp unsigned int __stdcall ThreadFunc(LPVOID lpParam) { CWeakKeyScan* pThis (CWeakKeyScan*)lpParam; while (!pThis-m_bStop) { CString strPwd pThis-GetNextPassword(); // 字典迭代内部有锁 if (strPwd.IsEmpty()) break; if (TryLogin(strPwd)) { // 实际登录逻辑 pThis-m_csResult.Lock(); pThis-m_listResult.AddTail(strPwd); pThis-m_csResult.Unlock(); // 通知 UI此处用 PostMessage 避免跨线程调用 UI 函数 ::PostMessage(pThis-m_hWnd, WM_UPDATE_RESULT, 0, (LPARAM)strPwd); } } return 0; }关键设计m_bStop用volatile修饰确保每次读取都是最新值避免编译器优化导致线程永远不退出PostMessage()替代SendMessage()防止 UI 线程被阻塞GetNextPassword()内部使用InterlockedIncrement()保证字典索引原子递增。3.4 SQLScan.cpp基于响应特征的注入检测为什么用 welcome 而不用报错信息摘要中明确指出“若登录成功出现 welcome 一词则说明网站存在注入漏洞”。这看似反直觉通常用数据库报错判断实则是教学场景下的刻意设计// SQLScan.cpp 片段 BOOL CSQLScan::CheckInjection(const CString strResponse) { // 检查响应体是否包含 welcome大小写不敏感 if (strResponse.FindNoCase(_T(welcome)) ! -1) { return TRUE; // 标记为疑似注入 } // 补充检查是否返回 The username or password is wrong! if (strResponse.FindNoCase(_T(wrong!)) ! -1) { return FALSE; // 明确失败非注入 } return FALSE; // 默认不认为是注入 }选型理由教学友好学生可直观看到welcome用户名的回显理解“输入被原样拼接到 SQL 语句中执行”的原理规避 WAF 干扰真实环境中数据库报错常被 WAF 过滤而welcome是应用层返回更稳定零依赖无需解析 HTML 或 JSONFindNoCase()即可完成降低代码复杂度。踩坑提醒若目标页面返回Welcome, admin!首字母大写FindNoCase()仍能匹配但若返回WELCOME全大写VC6.0 的FindNoCase()在 Unicode 模式下可能失效。解决方案是在SQLScan.cpp中强制转小写CString strLower strResponse; strLower.MakeLower(); if (strLower.Find(_T(welcome)) ! -1) { ... }4. 避坑指南编译、运行、调试中五个高频翻车现场与后悔药4.1 现象主机扫描HostScan始终显示“0 hosts found”但ping 127.0.0.1正常→原因IcmpSendEcho()需要ICMP协议权限Windows XP 及以后默认禁用普通用户调用。VC6.0 编译的程序即使以管理员运行若未显式请求提升IcmpCreateFile()仍返回INVALID_HANDLE_VALUE。→解决在HostScan.cpp的StartScan()函数开头添加权限检查HANDLE hIcmp IcmpCreateFile(); if (hIcmp INVALID_HANDLE_VALUE) { DWORD dwErr GetLastError(); if (dwErr ERROR_ACCESS_DENIED) { AfxMessageBox(_T(ICMP 权限不足请以管理员身份运行)); return FALSE; } }并在 VC6.0 中Project → Settings → Link → Project options添加/MANIFESTUAC:levelrequireAdministrator uiAccessfalse需手动输入VC6.0 不提供 GUI。4.2 现象端口扫描PortScan对192.168.0.1路由器扫描时大量端口显示“Filtered”而非“Open/Closed”→原因路由器防火墙对未授权端口的响应是ICMP Port Unreachable但PortScan.cpp的ConnectTest()仅判断connect()返回值未解析 ICMP 响应包。项目逻辑将WSAETIMEDOUT统一归为 “Filtered”实际可能是防火墙拦截。→解决修改PortScan.cpp在ConnectTest()失败后用WSAIoctl()查询SIO_ROUTING_INTERFACE_QUERY获取路由接口再结合GetIpForwardTable()判断目标是否在同一子网。若在同一子网且connect()超时则更可能是“Filtered”若跨网关则更可能是“Closed”。4.3 现象SNMP 扫描SNMPScan对192.168.0.1扫描时返回乱码或空字符串→原因SNMPScan.cpp使用手写 ASN.1 编码但未处理 BER 编码中的长度字段Length field。当 OID如1.3.6.1.2.1.1.1.0长度超过 127 字节时BER 要求用多字节表示长度而代码只支持单字节。→解决在SNMPScan.cpp的BuildGetRequest()函数中重写长度编码逻辑// 原代码错误buf[len_pos] (BYTE)oid_len; // 正确写法 if (oid_len 128) { buf[len_pos] (BYTE)oid_len; len_bytes 1; } else { // 多字节长度先写长度字节数再写长度值 int len_bytes_needed 1; int temp oid_len; while (temp 8) len_bytes_needed; buf[len_pos] 0x80 | len_bytes_needed; for (int i len_bytes_needed-1; i 0; i--) { buf[len_pos1i] (BYTE)(oid_len (i*8)); } len_bytes 1 len_bytes_needed; }4.4 现象弱密码扫描WeakKeyScan对 FTP 服务扫描时线程崩溃在closesocket()→原因WeakKeyScan.cpp中TryLogin()函数在socket()成功后若connect()失败未检查sock是否有效就直接closesocket(sock)。VC6.0 的closesocket()对无效句柄会触发STATUS_INVALID_HANDLE异常。→解决在TryLogin()中connect()后添加句柄有效性检查if (connect(sock, (struct sockaddr*)addr, sizeof(addr)) SOCKET_ERROR) { int err WSAGetLastError(); if (sock ! INVALID_SOCKET) closesocket(sock); // 仅当有效时关闭 return FALSE; }4.5 现象DOS 攻击DosScan启动后目标网站无反应任务管理器中Scanner.exeCPU 占用 100%→原因DosScan.cpp的攻击线程中connect()失败后未Sleep()导致无限循环调用socket()/connect()耗尽本地端口和 CPU。→解决在DosScan.cpp的线程函数中connect()后添加固定延时while (!g_bStopDos) { SOCKET sock socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock ! INVALID_SOCKET) { if (connect(sock, (struct sockaddr*)addr, sizeof(addr)) 0) { // 连接成功立即关闭 closesocket(sock); } else { closesocket(sock); Sleep(10); // 关键每次失败后休眠10ms降低频率 } } }5. 进阶技巧把扫描器变成你的课程设计“加分项”的三个实操动作5.1 动作一为 PortScan 添加 SYN 扫描半连接绕过系统日志记录当前PortScan.cpp使用connect()全连接会在目标主机的系统日志中留下大量TCP connection established记录暴露扫描行为。升级为 SYN 扫描需用 Raw Socket 发送 TCP SYN 包并监听 SYN-ACK 响应。VC6.0 下需启用IP_HDRINCL选项// 新增 SynScan.cpp int SynScan::SendSynPacket(const char* dst_ip, USHORT dst_port) { SOCKET sock socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (sock INVALID_SOCKET) return -1; // 启用 IP_HDRINCL BOOL bOpt TRUE; setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)bOpt, sizeof(bOpt)); // 构造 IP 头 TCP 头省略校验和计算细节 IPHeader ip_hdr; TCPHeader tcp_hdr; // ... 填充 ip_hdr.src, ip_hdr.dst, tcp_hdr.sport, tcp_hdr.dport ... // 发送原始包 struct sockaddr_in addr; addr.sin_family AF_INET; addr.sin_addr.s_addr inet_addr(dst_ip); sendto(sock, (char*)ip_hdr, sizeof(ip_hdr)sizeof(tcp_hdr), 0, (struct sockaddr*)addr, sizeof(addr)); closesocket(sock); return 0; }关键点IP_HDRINCL需管理员权限且 Windows XP 默认禁用需运行netsh int ip set global eventlogenabled启用TCP 校验和必须手动计算tcp_hdr.checksum CalcChecksum(...)否则包被丢弃为避免被本机 TCP/IP 栈干扰需在IPHeader中设置ip_hdr.frag_off htons(IP_DF)禁止分片。5.2 动作二用 XML 替代硬编码字典让 WeakKeyScan 支持动态加载当前WeakKeyScan.cpp的密码字典写死在CStringArray m_arrPwd中。改为 XML 配置可提升扩展性。创建dict.xml?xml version1.0 encodingUTF-8? dictionary protocol nameFTP useradmin/user userroot/user password123456/password passwordpassword/password /protocol protocol nameTELNET useradmin/user passwordadmin/password /protocol /dictionary在WeakKeyScan.cpp中用 MSXML 解析VC6.0 自带msxml.dll// 加载 XML 字典 IXMLDOMDocument* pDoc NULL; CoInitialize(NULL); CoCreateInstance(__uuidof(DOMDocument), NULL, CLSCTX_INPROC_SERVER, __uuidof(IXMLDOMDocument), (void**)pDoc); pDoc-load(_variant_t(_T(dict.xml)), vSuccess); IXMLDOMNodeList* pNodeList NULL; pDoc-getElementsByTagName(_bstr_t(password), pNodeList); long count; pNodeList-get_length(count); for (long i 0; i count; i) { IXMLDOMNode* pNode NULL; pNodeList-get_item(i, pNode); BSTR bstrText; pNode-get_text(bstrText); m_arrPwd.Add(CString(bstrText)); SysFreeString(bstrText); }优势答辩时可现场修改dict.xml演示“更换字典后扫描结果变化”比硬编码更有说服力。5.3 动作三为 SQLScan 添加自动化报告生成导出为 HTML 表格摘要中提到的login_succeed.jpg等截图本质是人工验证。可让SQLScan.cpp自动生成测试报告// SQLScan.cpp 中新增 void CSQLScan::GenerateReport(const CString strUrl, const CString strPayload, const CString strResponse, BOOL bInjected) { CString strHtml _T(htmlbodyh2SQL 注入检测报告/h2); strHtml _T(table border1trthURL/ththPayload/ththResponse Snippet/ththStatus/th/tr); strHtml _T(trtd) strUrl _T(/tdtd) strPayload _T(/td); strHtml _T(td) strResponse.Mid(0, 200) _T(.../td); strHtml _T(td) (bInjected ? _T(VULNERABLE) : _T(SAFE)) _T(/td/tr); strHtml _T(/table/body/html); CStdioFile file(_T(report.html), CFile::modeCreate | CFile::modeWrite); file.WriteString(strHtml); file.Close(); }落地价值答辩时点击“生成报告”按钮弹出report.html评委可直观看到测试过程与结论比口头描述“我们检测到了”更扎实。从那以后我每次做课程设计只要涉及网络编程都会先翻出这个Network_Scanner-master工程不是为了抄代码而是把它当一本活的 Win32 API 教程——PortScan.cpp教我select()的真实用法SnifferScan.cpp教我 WinPcap 的生命周期管理WeakKeyScan.cpp教我多线程资源同步的边界条件。它不完美但每一行#include winsock2.h后面都站着一个当年在机房熬夜调试connect()超时的学生。希望帮到你。本文还有配套的精品资源点击获取