☰
VC6 SMTP源码拆解:从MFC工程到邮件伪造实验台
2026/10/1 10:50:53 网站建设 项目流程

简介:这份资源围绕SMTP协议与邮件伪造机制展开,面向网络安全初学者、邮件系统运维人员及对钓鱼攻击防护感兴趣的开发者。包内以C++实现的SMTP客户端工程为主体,包含6个h头文件、4个cpp源文件,以及res资源、manifest清单、vcproj与sln工程配置等,另有编译产物exe、pdb、ilk等,共36个文件,压缩包约11.97MB,可直接在Visual Studio中打开编译运行,便于对照代码理解MAIL FROM、RCPT TO、DATA等命令的交互流程。资源同时涉及SPF、DKIM、DMARC等邮件验证技术的原理说明,帮助读者认识发件人伪造的成因与防护思路。目前已有1314人学习下载,适合作为邮件协议分析与安全防护的入门实践素材,也可用于教学演示或二次开发参考。

1. 从一份 VC6 工程拆起:SMTP.rar 里到底装了什么

翻到这份SMTP.rar的时候,我第一反应不是「又一个邮件伪造工具」,而是「这居然是个带完整 VC 工程文件的源码包」。压缩包里躺着SMTP.sln、SMTP.vcproj、SMTPDlg.cpp、base64.cpp、ReadMe.txt,还有编译产物Debug/SMTP.exe、SMTP.pdb、SMTP.ilk。它本质上是一个基于 MFC 对话框的 Windows 桌面程序,用 C++ 实现了 SMTP 会话交互,把「伪造发件人」这件事拆成了可点击、可填参数、可看日志的图形界面。适合谁?做邮件安全测试、想理解 SMTP 命令握手细节、或者需要一份能直接跑起来的 C++ 协议实现参考的从业者。它解决的不是「怎么发垃圾邮件」,而是「怎么在一个可控环境里观察MAIL FROM与RCPT TO到底发生了什么」。下面我按拆包、编译、跑通、排错的顺序,把这份资源讲透。

2. 拆包与工程结构:VC6 到 VS 的迁移路径

2.1 文件清单与模块职责

先把压缩包解开,目录结构大致是这样:

文件/目录类型作用
SMTP.slnVS 解决方案入口,双击可拉起 IDE
SMTP.vcprojVC 工程文件定义编译选项、依赖、输出路径
SMTPDlg.cpp/.hMFC 对话框主界面逻辑,按钮事件、参数读取
SMTP.cpp/.h核心实现SMTP 命令拼装与 socket 收发
base64.cpp/.h编码模块处理邮件正文与认证信息的 Base64
stdafx.cpp/.h预编译头MFC 工程标配
SMTP.rc/resource.h资源脚本对话框布局、控件 ID
Debug/编译产物SMTP.exe、SMTP.pdb、SMTP.ilk
ReadMe.txt说明作者留下的使用备注

SMTP.suo、SMTP.ncb、SMTP.aps是 IDE 的缓存文件,换机器后可以删掉,不影响编译。ClassDiagram1.cd是类图缓存,同样可弃。真正要关注的是SMTPDlg.cpp和SMTP.cpp这两个文件,所有协议交互逻辑都在里面。

2.2 用 VS 打开旧工程的正确姿势

这份工程是 VC6/VS2008 时代的产物,直接双击SMTP.sln在现代 VS 上大概率会提示「项目需要迁移」。我一般这么做:

# 先备份原始工程,迁移失败还能回退 cp -r SMTP SMTP_backup # 用 VS 2019/2022 打开 sln,走迁移向导 # 迁移完成后检查两个地方: # 1. 字符集:项目属性 -> 高级 -> 字符集,改成「使用多字节字符集」 # 2. MFC 使用:项目属性 -> MFC -> 在共享 DLL 中使用 MFC

逻辑说明:旧工程默认可能是 Unicode 字符集,而源码里的字符串处理是按多字节写的,不改会出现C2664无法转换参数的血泪经验。MFC 改成共享 DLL 是为了避免静态链接时缺mfc140u.lib之类的报错。参数上,如果你机器上没装 MFC 组件,需要在 VS Installer 里勾选「适用于最新 v143 生成工具的 C++ MFC」。

2.3 编译产物与调试符号

Debug/里已经有编译好的SMTP.exe,理论上可以直接跑。但我不建议直接双击——你无法确认它编译时的源码是否和当前一致。SMTP.pdb是程序数据库文件,保留了符号信息,配合SMTP.ilk增量链接文件,说明作者是在 Debug 模式下编译的。自己重新编译一遍,把断点打在SMTP.cpp的send调用前后,才能看清每个 SMTP 命令实际发出去的字节。常见做法是:在CSMTP::SendMail这类函数入口下断点,观察MAIL FROM:后面的地址是怎么从对话框控件读出来的。

3. 跑通一次 SMTP 会话:从填参数到看日志

3.1 界面参数与 SMTP 命令的映射

程序跑起来后,对话框上通常有这几类输入:SMTP 服务器地址、端口、发件人、收件人、主题、正文。这些控件值最终会映射成标准 SMTP 命令序列:

EHLO client.example.com MAIL FROM:<sender@example.com> RCPT TO:<receiver@example.com> DATA Subject: test (空行) 邮件正文 . QUIT

关键点在于MAIL FROM:这一行。SMTP 协议本身不校验这个地址是否真的属于发送者,服务器只负责把它放进信封。程序做的就是让你自由填写这个字段,从而观察不同服务器对伪造发件人的处理差异。端口一般填 25,但很多服务器现在只开 587(提交端口)并要求 STARTTLS,这份老工程默认走的是明文 25 端口。

3.2 用 Wireshark 抓一次明文会话

想真正理解发生了什么,抓包是最直接的。启动程序前先开 Wireshark,过滤tcp.port == 25,然后点发送。你会看到类似这样的交互:

S: 220 mail.example.com ESMTP C: EHLO test S: 250-mail.example.com S: 250-AUTH LOGIN PLAIN S: 250 OK C: MAIL FROM:<fake@example.com> S: 250 OK C: RCPT TO:<target@example.com> S: 250 OK C: DATA S: 354 Start mail input C: ...邮件内容... C: . S: 250 Message accepted C: QUIT

逻辑说明:250 OK只代表服务器接受了信封,不代表邮件最终会进收件箱。很多服务器在DATA结束后才做 SPF 检查,检查失败可能返回550或在投递阶段静默丢弃。参数上,EHLO后面的域名随便填,但有些服务器会做正向解析校验,填一个不存在的域名可能直接被拒。

3.3 认证环节:Base64 模块在做什么

base64.cpp的存在说明程序支持 SMTP 认证。当服务器返回250-AUTH LOGIN时,客户端需要把用户名和密码做 Base64 编码后发送:

// base64.cpp 典型调用方式 CString encodedUser = Base64Encode("your_username"); CString encodedPass = Base64Encode("your_password"); // 发送序列: // AUTH LOGIN // (服务器返回 334) // encodedUser // (服务器返回 334) // encodedPass

逻辑说明:AUTH LOGIN是挑战-应答模式,服务器先要用户名再要密码,两次都是 Base64 编码的明文。这也是为什么现在推荐用AUTH PLAIN配合 TLS,否则密码在网络上等同于裸奔。参数上注意 Base64 编码后不要带换行符,有些服务器对多余空白敏感。如果你只是想测试伪造发件人,很多内网测试服务器允许匿名中继,可以跳过认证直接发。

4. 避坑与排查:五个真实翻车现场

4.1 编译报错fatal error C1083: 无法打开包括文件: "afxwin.h"

现象:迁移工程后一编译就提示找不到 MFC 头文件。原因:VS 安装时没勾选 MFC 组件,或者项目属性里「使用 MFC」被设成了「不使用」。解决:打开 VS Installer,修改当前版本,勾选「C++ MFC 最新 v143 生成工具」,然后在项目属性 -> 常规 -> 使用 MFC 里选「在共享 DLL 中使用 MFC」。

4.2 程序发不出邮件,socket 连接超时

现象:点发送后卡住,最后提示连接失败。原因:目标服务器 25 端口被防火墙拦截,或者你本地网络禁止出站 25 端口。解决:先telnet mail.example.com 25确认端口通不通;如果 25 被封,换 587 端口并在代码里加STARTTLS逻辑——这份老工程没有 TLS 支持,需要自己补 OpenSSL 或换用测试服务器。

4.3 服务器返回550 5.7.1 Relaying denied

现象:RCPT TO阶段被拒。原因:你连接的服务器不负责目标收件人的域,且不允许匿名中继。解决:要么用目标域自己的 SMTP 服务器,要么在测试环境里配置一台允许中继的 Postfix,把mynetworks设成你的测试网段。注意这只在隔离的实验环境里做。

4.4 邮件进了垃圾箱,收件人看不到

现象:服务器返回250 accepted,但收件箱里没有。原因:SPF/DKIM/DMARC 校验失败,邮件被标记或丢弃。解决:这是协议层面的限制,不是程序 bug。想验证投递结果,去看目标服务器的日志,或者用一个自己控制的域名配置好 SPF 记录再做测试。常见做法是在测试域名的 DNS 里加一条v=spf1 ip4:你的出口IP -all。

4.5 中文正文乱码

现象:收到的邮件主题和正文是乱码。原因:base64.cpp编码的是原始字节,但邮件头没有声明字符集。解决:在DATA阶段加入Content-Type: text/plain; charset=UTF-8和Content-Transfer-Encoding: base64,并确保传入 Base64 函数的是 UTF-8 字节串而不是 GBK。参数上,MFC 的CString在多字节模式下是 GBK,需要先转成 UTF-8 再编码。

5. 进阶:把这份工程当成 SMTP 协议实验台

跑通之后,我建议别把它只当「发信工具」用,而是改造成一个协议观察台。具体做法:在SMTP.cpp的 socket 收发函数里加一层日志,把每个send和recv的原始字节同时写到文件和界面。这样你能看到服务器返回的完整能力列表,比如它支持SIZE、PIPELINING、8BITMIME中的哪些。然后可以做一个对照实验:同一封邮件,分别用真实发件人和伪造发件人发,观察目标服务器返回码的差异。我一般会建一张表记录:

测试项真实发件人伪造发件人服务器返回差异
MAIL FROM 阶段250 OK250 OK无差异
DATA 结束后250 accepted250 accepted无差异
实际投递进收件箱进垃圾箱/丢弃有差异

这张表能直观告诉你:SMTP 握手阶段的「成功」和最终投递是两回事。另一个进阶玩法是改SMTPDlg.cpp,加一个「批量测试」按钮,对同一目标服务器循环发送不同MAIL FROM地址,统计哪些域名被直接拒绝、哪些被放行。这比手工一个个填效率高得多。最后提醒一句:所有测试都在你自己控制的服务器和域名上做,别拿别人的邮箱当靶子。从那以后我每次碰这类协议工具,都强制先在隔离环境里抓一遍包再动生产配置。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询