SMTP协议学习笔记


这几天敝人并没有及时更新博客,一是由于白天工作中的锁事比较繁杂,二来连续看了两个晚上的SMTP协议。

我比较喜欢用实践来证明一切,这样才会加深自己的理解!

一、准备工作:

1、本机环境:Windows XP SP3、ADSL 10M光纤

2、开发工具:WildPackets OmniPeek V5.1.4

Visual C++ 6.0

Outlook Express6.0

FlexEdit V2.3.1871

二、SMTP命令:

1、HELO 向服务器标识用户身份
2、MAIL 初始化邮件传输mail from: <xxx>
3、RCPT 标识单个的邮件接收人;常在MAIL命令后面可有多个rcpt to: <xxx>
4、DATA 在单个或多个RCPT命令后,表示所有的邮件接收人已标识,初始化数据传输,以.结束
5、NOOP 无操作,服务器应响应OK
6、RSET 重置会话,当前传输被取消
7、QUIT 结束会话

三、分析数据包:

1、打开Outlook Express6.0,创建新邮件,内容如下:

2、打开OmniPeek,选择SMTP:

3、先开始抓包,再发送上面的测试邮件,得到的数据包如下图:

(要注意Source与Destination,即源地址与目标地址)

4、只需要看第20条数据包,其他可以比较容易理解:

5、其他小技巧

<CR> <LF>即对应C/C++中的"/r /n"

比如 Line 8: charset="gb2312"<CR><LF>,因为需要用到转义字符

所以对应的字符串应该为char * sData = "charset=/"gb2312/"/r/n";

四、相关代码:

1、以下代码通过socket与SMTP服务器建立连接并验证身份。打开Visual C++,新建一个控制台工程、并添加一个CPP文件:

[cpp] view plaincopyprint?
  1. /************************************************************************/
  2. /*main.cppSMTP协议学习笔记-登录验证
  3. /*byKoma2009.9.1011:35
  4. /*http://blog.csdn.net/wangningyu
  5. /************************************************************************/
  6. #include"stdio.h"
  7. #include"ZBase64.h"
  8. #include"winsock2.h"
  9. #pragmacomment(lib,"ws2_32.lib")
  10. intmain(intargc,char*argv[])
  11. {
  12. SOCKADDR_INsaServer;
  13. LPHOSTENTlphostent;
  14. WSADATAwsadata;
  15. SOCKEThsocket;
  16. intnRet;
  17. char*host_name="smtp.tom.com";
  18. char*req=
  19. //每发送一行数据服务器都会作出响应
  20. "EHLOKOMAWANG/r/n"
  21. "AUTHLOGIN/r/n"
  22. //两行是登录用户与密码(采用Base64加密)
  23. "bm**********20=/r/n"
  24. "d2******W4=/r/n"
  25. "QUIT/r/n";
  26. //初始化套接字
  27. if(WSAStartup(MAKEWORD(2,2),&wsadata))
  28. printf("初始化SOCKET出错!");
  29. //SMTP端口默认是25
  30. lphostent=gethostbyname(host_name);
  31. if(lphostent==NULL)
  32. printf("lphostent为空!");
  33. hsocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
  34. saServer.sin_family=AF_INET;
  35. saServer.sin_port=htons(25);
  36. saServer.sin_addr=*((LPIN_ADDR)*lphostent->h_addr_list);
  37. //利用SOCKET连接
  38. nRet=connect(hsocket,(LPSOCKADDR)&saServer,sizeof(SOCKADDR_IN));
  39. if(nRet==SOCKET_ERROR)
  40. {
  41. printf("建立连接时出错!/n");
  42. closesocket(hsocket);
  43. return0;
  44. }
  45. //利用SOCKET发送
  46. nRet=send(hsocket,req,strlen(req),0);
  47. if(nRet==SOCKET_ERROR)
  48. {
  49. printf("发送数据包时出错!");
  50. closesocket(hsocket);
  51. }
  52. charDest[3000];
  53. memset(Dest,0,3000);
  54. nRet=1;
  55. while(nRet>0)
  56. {
  57. //接收返回数据包
  58. nRet=recv(hsocket,(LPSTR)Dest,sizeof(Dest),0);
  59. if(nRet>0)
  60. Dest[nRet]=0;
  61. else
  62. Dest[0]=0;
  63. //显示返回数据包的大小、内容
  64. printf("/n返回数据包大小:%d/n",nRet);
  65. printf("返回数据包内容:/n%s",Dest);
  66. }
  67. return0;
  68. }

2、下面是Base64加解密头与CPP文件:

[cpp] view plaincopyprint?
  1. /************************************************************************/
  2. /*ZBase64.h
  3. /************************************************************************/
  4. #ifndef_ZBASE64
  5. #define_ZBASE64
  6. #pragmawarning(disable:4786)
  7. #include<string>
  8. usingnamespacestd;
  9. classZBase64
  10. {
  11. public:
  12. /*编码
  13. DataByte
  14. [in]输入的数据长度,以字节为单位
  15. */
  16. stringEncode(constunsignedchar*Data,intDataByte);
  17. /*解码
  18. DataByte
  19. [in]输入的数据长度,以字节为单位
  20. OutByte
  21. [out]输出的数据长度,以字节为单位,请不要通过返回值计算
  22. 输出数据的长度
  23. */
  24. stringDecode(constchar*Data,intDataByte,int&OutByte);
  25. };
  26. #endif

[cpp] view plaincopyprint?
  1. /************************************************************************/
  2. /*ZBase64.cpp
  3. /************************************************************************/
  4. #include"ZBase64.h"
  5. stringZBase64::Encode(constunsignedchar*Data,intDataByte)
  6. {
  7. //编码表
  8. constcharEncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  9. //返回值
  10. stringstrEncode;
  11. unsignedcharTmp[3]={0};
  12. intLineLength=0;
  13. for(inti=0;i<(int)(DataByte/3);i++)
  14. {
  15. Tmp[1]=*Data++;
  16. Tmp[2]=*Data++;
  17. Tmp[3]=*Data++;
  18. strEncode+=EncodeTable[Tmp[1]>>2];
  19. strEncode+=EncodeTable[((Tmp[1]<<4)|(Tmp[2]>>4))&0x3F];
  20. strEncode+=EncodeTable[((Tmp[2]<<2)|(Tmp[3]>>6))&0x3F];
  21. strEncode+=EncodeTable[Tmp[3]&0x3F];
  22. if(LineLength+=4,LineLength==76){strEncode+="/r/n";LineLength=0;}
  23. }
  24. //对剩余数据进行编码
  25. intMod=DataByte%3;
  26. if(Mod==1)
  27. {
  28. Tmp[1]=*Data++;
  29. strEncode+=EncodeTable[(Tmp[1]&0xFC)>>2];
  30. strEncode+=EncodeTable[((Tmp[1]&0x03)<<4)];
  31. strEncode+="==";
  32. }
  33. elseif(Mod==2)
  34. {
  35. Tmp[1]=*Data++;
  36. Tmp[2]=*Data++;
  37. strEncode+=EncodeTable[(Tmp[1]&0xFC)>>2];
  38. strEncode+=EncodeTable[((Tmp[1]&0x03)<<4)|((Tmp[2]&0xF0)>>4)];
  39. strEncode+=EncodeTable[((Tmp[2]&0x0F)<<2)];
  40. strEncode+="=";
  41. }
  42. returnstrEncode;
  43. }
  44. stringZBase64::Decode(constchar*Data,intDataByte,int&OutByte)
  45. {
  46. //解码表
  47. constcharDecodeTable[]=
  48. {
  49. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  50. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  51. 62,//'+'
  52. 0,0,0,
  53. 63,//'/'
  54. 52,53,54,55,56,57,58,59,60,61,//'0'-'9'
  55. 0,0,0,0,0,0,0,
  56. 0,1,2,3,4,5,6,7,8,9,10,11,12,
  57. 13,14,15,16,17,18,19,20,21,22,23,24,25,//'A'-'Z'
  58. 0,0,0,0,0,0,
  59. 26,27,28,29,30,31,32,33,34,35,36,37,38,
  60. 39,40,41,42,43,44,45,46,47,48,49,50,51,//'a'-'z'
  61. };
  62. //返回值
  63. stringstrDecode;
  64. intnValue;
  65. inti=0;
  66. while(i<DataByte)
  67. {
  68. if(*Data!='/r'&&*Data!='/n')
  69. {
  70. nValue=DecodeTable[*Data++]<<18;
  71. nValue+=DecodeTable[*Data++]<<12;
  72. strDecode+=(nValue&0x00FF0000)>>16;
  73. OutByte++;
  74. if(*Data!='=')
  75. {
  76. nValue+=DecodeTable[*Data++]<<6;
  77. strDecode+=(nValue&0x0000FF00)>>8;
  78. OutByte++;
  79. if(*Data!='=')
  80. {
  81. nValue+=DecodeTable[*Data++];
  82. strDecode+=nValue&0x000000FF;
  83. OutByte++;
  84. }
  85. }
  86. i+=4;
  87. }
  88. else//回车换行,跳过
  89. {
  90. Data++;
  91. i++;
  92. }
  93. }
  94. returnstrDecode;
  95. }

3、程序运行效果:

优质内容筛选与推荐>>
1、【sqli-labs】 less26a GET- Blind based -All you SPACES and COMMENTS belong to us -String-single quotes-Parenthesis(GET型基于盲注的去除了空格和注释的单引号括号注入)
2、JavaScript-滑动效果
3、 好用的Google Analytics分析服務
4、html和css入门 (四)
5、JavaScript跨域总结与解决办法(转)


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn