为汇编通讯做点宣传 顺便转载一个自己写的Email发送程序
对第五期电子邮件发送程序的完善 作者:zklhp 于2008-9-19上传
--------------------------------------------------------------------------------
我是汇编通讯的忠实读者,看汇编通讯一年了,也写个程序,也算是为杂志做点贡献吧。写的不好,还望各位高手指点。
看第五期时,我就对《用汇编语言写ESMTP电子邮件发送程序》很感兴趣。可程序提示发送成功后,并没有收到邮件,当时也没再深究,
后来再试,又能成功发送了,真是@#%。现在放假了,又想起那个程序,就研究了一下ESMTP发邮件的过程,顺便完善了一下谢平的程序。
帖一下我的写的发送线程函数吧。排版可能不太好,建议用masmplus直接看工程。
程序代码:
.code _SendProc proc uses ebx edi esi _Param:DWORD local @hSocket:DWORD local @stWsadata:WSADATA local @stSin:sockaddr_in local @szRcvBuffer[1024]:BYTE local @szSend[4096]:BYTE local @szBuffer[2048]:BYTE invoke WSAStartup, 202h, addr @stWsadata invoke socket, AF_INET, SOCK_STREAM, 0 .if eax == INVALID_SOCKET invoke WSAGetLastError invoke wsprintf,addr @szBuffer,CTXT('创建套接字出错 错误码 %x',0dh,0ah),eax invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szBuffer invoke MessageBox,hWinMain,CTXT('发送失败!'),CTXT('错误'),0 jmp @exit .endif mov @hSocket, eax invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('创建套接字成功!',0dh,0ah) invoke RtlZeroMemory,addr @stSin,sizeof @stSin mov @stSin.sin_family, AF_INET invoke htons, 25 ;默认端口是25 mov @stSin.sin_port, ax invoke gethostbyname,offset szSmtpAddr .if eax mov eax, [eax + hostent.h_list] mov eax, [eax] mov eax, [eax] mov @stSin.sin_addr, eax .endif ;建立连接 invoke connect,@hSocket, addr @stSin, sizeof @stSin .if eax == SOCKET_ERROR invoke WSAGetLastError invoke wsprintf,@szBuffer,CTXT('连接服务器出错 错误码 %x',0dh,0ah),eax invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szBuffer invoke MessageBox,hWinMain,CTXT('发送失败!'),CTXT('错误'),0 jmp @exit .endif invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('连接到服务器成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer ;发送“ehlo local” invoke lstrlen,offset szEhlo invoke send, @hSocket, addr szEhlo, eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 ehlo local 成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer ;发送“auth login” ;好象大多数免费邮箱都支持login验证方式 支持cram-md5的却没找到~~~ 这里只用login吧 invoke lstrlen,addr szAuth invoke send, @hSocket, addr szAuth, eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 auth login 成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 lea esi,@szRcvBuffer add esi,4 invoke lstrlen,esi mov edi,eax ;要把最后的\r\t除去 dec edi dec edi ;貌似这样比 sub edi,2 省个字节 呵呵 invoke RtlZeroMemory,addr @szBuffer,sizeof @szBuffer invoke _Base64Decode,esi,addr @szBuffer,edi invoke wsprintf,addr @szRcvBuffer,CTXT('334 %s',0dh,0ah),addr @szBuffer ;我们自己把他解码还原 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer ;发送用户名 invoke lstrlen,offset szUserName invoke _Base64Encode,offset szUserName,addr @szBuffer,eax invoke wsprintf,addr @szSend,CTXT('%s',0dh,0ah),addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend, eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送用户名成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 lea esi,@szRcvBuffer add esi,4 invoke lstrlen,esi mov edi,eax dec edi dec edi ;貌似这样比 sub edi,2 省个字节 呵呵 invoke RtlZeroMemory,addr @szBuffer,sizeof @szBuffer invoke _Base64Decode,esi,addr @szBuffer,edi invoke wsprintf,addr @szRcvBuffer,CTXT('334 %s',0dh,0ah),addr @szBuffer ;我们自己把他解码还原 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer ;发送密码 invoke lstrlen,offset szPassWord invoke _Base64Encode,offset szPassWord,addr @szBuffer,eax invoke wsprintf,addr @szSend,CTXT('%s',0dh,0ah),addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend, eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送密码成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer invoke StrStr,addr @szRcvBuffer,CTXT('235') .if eax == 0 ;没有就是验证不通过 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('验证失败!',0dh,0ah) invoke WSACleanup invoke GetDlgItem,hWinMain,IDC_BTN_SEND invoke EnableWindow,eax,TRUE xor eax,eax dec eax ret .endif invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('验证成功!',0dh,0ah) ;发送“mail from” invoke GetDlgItemText,hWinMain,IDC_EDT_SENDADDR,addr @szBuffer,sizeof @szBuffer invoke wsprintf,addr @szSend,addr szMailFrom,addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend,eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 mail from 成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer ;发送“rcpt to” invoke GetDlgItemText,hWinMain,IDC_EDT_RCPTADDR,addr @szBuffer,sizeof @szBuffer invoke wsprintf,addr @szSend,addr szRcptTo,addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend,eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 rcpt to 成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer ;发送“data” invoke lstrlen,addr szData invoke send, @hSocket, addr szData, eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 data 成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer ;发送“from” invoke GetDlgItemText,hWinMain,IDC_EDT_SENDADDR,addr @szBuffer,sizeof @szBuffer invoke wsprintf,addr @szSend,addr szFrom,addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend,eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 from 成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke Sleep,1000 ;发送“to” invoke GetDlgItemText,hWinMain,IDC_EDT_RCPTADDR,addr @szBuffer,sizeof @szBuffer invoke wsprintf,addr @szSend,addr szTo,addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend,eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 to 成功!',0dh,0ah) ;发送主题 invoke GetDlgItemText,hWinMain,IDC_EDT_SUB,addr @szBuffer,sizeof @szBuffer invoke wsprintf,addr @szSend,addr szSubject,addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend,eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送主题成功!',0dh,0ah) ;发送"Reply-TO" invoke RtlZeroMemory,addr @szSend,sizeof @szSend invoke RtlZeroMemory,addr @szBuffer,sizeof @szBuffer invoke GetDlgItemText,hWinMain,IDC_EDT_SENDADDR,addr @szBuffer,sizeof @szBuffer invoke wsprintf,addr @szSend,addr szReplyTo,addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend,eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 Reply-TO 成功!',0dh,0ah) ;发送空行 invoke lstrlen,addr szCrLf invoke send, @hSocket, addr szCrLf,eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送空行成功!',0dh,0ah) ;发送邮件正文 invoke RtlZeroMemory,addr @szSend,sizeof @szSend invoke RtlZeroMemory,addr @szBuffer,sizeof @szBuffer invoke GetDlgItemText,hWinMain,IDC_EDT_CONTENT,addr @szBuffer,sizeof @szBuffer invoke wsprintf,addr @szSend,addr szContent,addr @szBuffer invoke lstrlen,addr @szSend invoke send, @hSocket, addr @szSend,eax, 0 ;发送“.” invoke lstrlen,addr szDot invoke send, @hSocket, addr szDot, eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 . 成功!',0dh,0ah) invoke RtlZeroMemory,addr @szRcvBuffer,sizeof @szRcvBuffer invoke recv, @hSocket, addr @szRcvBuffer,sizeof @szRcvBuffer,0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,addr @szRcvBuffer ;发送“quit” invoke lstrlen,addr szQuit invoke send, @hSocket, addr szQuit, eax, 0 invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('发送 quit 成功!',0dh,0ah) ;断开连接 invoke closesocket, @hSocket invoke SendDlgItemMessage,hWinMain,IDC_EDT_DEBUG,EM_REPLACESEL,0,CTXT('与服务器连接断开!',0dh,0ah) invoke MessageBox,hWinMain,CTXT('发送成功!'),CTXT('提示'),0 @exit: invoke WSACleanup invoke GetDlgItem,hWinMain,IDC_BTN_SEND invoke EnableWindow,eax,TRUE xor eax,eax ret _SendProc endp
开始,我以为验证时要用到CRAM-MD5 等算法,可用telnet一试才知道,免费邮箱大多支持login验证方式,就简化了这个函数,
用一种简单的方式判断验证成功,省了不少时间,呵呵。
其他的都不用说了,很简单,看代码都能看懂。
总结一下,这个程序的存在的缺点有:
1. 界面处理写的太烂,不怎么规矩。
2. 发送函数过于简陋,支持的验证方法少。
3. 对线程的处理不太好,对发送错误的情况考虑不太好。
4. 不支持发送附件。
我的汇编还很菜,程序中的错误还请各位高手指出。在程序的写作过程中得到了很多高手的无私帮助,在此一并表示感谢。也感谢
老罗和谢平为我的程序提供范例,为本程序的写作铺平道路。
最后,感谢Aogosoft为我们这些汇编爱好者提供这样一个交流的平台,希望高手们多多支持汇编通讯,让汇编通讯越办越好!
参考:
1. 罗云彬的《Windows环境下32位汇编语言程序设计》
2. 老罗的《用汇编语言编写ESMTP邮件发送程序》
3. 汇编通讯第五期《用汇编语言写ESMTP电子邮件发送程序》
4.https://hi.bccn.net/space-64405-do-blog-id-2002.html 在命令行下发送Email。
5.http://dev. ESMTP身份验证机制探索手记。
6.自己写的几个函数:
https://bbs.bccn.net/thread-227380-1-1.html BASE64编码函数。
https://bbs.bccn.net/thread-228639-1-1.html BASE64解码函数。
https://bbs.bccn.net/thread-227039-1-1.html CRAM-MD5算法实现函数,并没用上。
https://bbs.bccn.net/thread-226811-1-1.html MD5 算法实现函数,并没用上。
[[it] 本帖最后由 zklhp 于 2008-9-20 11:49 编辑 [/it]]