На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
! Друзья, соблюдайте, пожалуйста, правила форума и данного раздела:
Данный раздел не предназначен для вопросов и обсуждений, он содержит FAQ-заготовки для разных языков программирования. Любой желающий может разместить здесь свою статью. Вопросы же задавайте в тематических разделах!
• Если ваша статья может быть перенесена в FAQ соответствующего раздела, при условии, что она будет оформлена в соответствии с Требованиями к оформлению статей.
• Чтобы остальным было проще понять, указывайте в описании темы (подзаголовке) название языка в [квадратных скобках]!
Модераторы: Модераторы
  
> Отправка e-mail'а с вложением, [Assembler] Windows, Работа с сетью
     
    Отправка e-mail'а с вложением

    ExpandedWrap disabled
      ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      ; Sending mail with attach in FASM
      ;         Created by Ct757
      ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
      ;
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      ; Здесь я хочу показать, как можно отправить письмо с вложением
      ; напрямую через SMTP-сервер (в данном случае smtp.mail.ru)
      ; В принципе, команды те же, что и при посылке обычного письма,
      ; разница только в том, что аттач нужно закодировать по алгоритму
      ; base64, а так же указать некоторые дополнительные пункты в заголовке письма
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
      format PE GUI 4.0
      entry start
       
        include '%fasminc%\win32a.inc'
       
      section '.code' code readable writeable executable
       
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      ; Я не буду в подробностях объяснять SMTP-команды, если вы их не знаете смотрите RFC
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
        smtp_server  db '194.67.23.111',0                 ; IP-адрес smtp.mail.ru
       
        helo_0       db 'HELO 0',13,10                    ; Команда helo
        helo_0_sz    = $ - helo_0                     ;
       
        mail_fr      db 'MAIL FROM: 111@mail.ru',13,10            ; От кого письмо
        mail_fr_sz   = $ - mail_fr                        ;
       
        rcpt_to      db 'RCPT TO: test3456@mail.ru',13,10         ; Кому отправлять
        rcpt_to_sz   = $ - rcpt_to                        ;
       
        data_        db 'DATA',13,10                      ; Команда data
        data_sz      = $ - data_                      ;
       
       
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      ; Заголовок и текст письма
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
        message      db 'From: Bill Gates <111@mail.ru>',13,10,\              ; От кого
                'Subject: Test MESSAGE',13,10,\                   ; Тема
                'To: TEST <test3456@mail.ru>',13,10,\                 ; Кому
                'MIME-Version: 1.0',13,10,\                       ; Версия MIME
                'Content-Type: multipart/mixed;',13,10,\              ; Тип содержимого
                ' boundary="--ct757"',13,10,13,10,\                   ; Разделитель
                '----ct757',13,10,\
                'Content-Type: text/plain; charset=Windows-1251',13,10,\      ; Содержимое: текст,
                'Content-Transfer-Encoding: 8bit',13,10,13,10,\           ; кодировка Win-1251
                'Hello, this is the test message with attachment.',13,10,13,10,\  ; Текст письма
                '----ct757',13,10,\
                'Content-Type: application/octet-stream; name="test.rar"',13,10,\ ; Содержимое: вложение
                'Content-Disposition: attachment; filename="test.rar"',13,10,\    ; имя файла - test.rar
                'Content-Transfer-Encoding: base64',13,10,13,10           ; Поясняем, что закодировано
                                                  ; с помощью base64
       
        message_sz   = $ - message                                ; Размер письма вместе с
                                                  ; заголовком (без вложения!)
       
       
        file_name    db 'D:\test.rar',0                           ; Файл, который нужно отправить
       
        sock         dd 0                                 ; Дескриптор сокета
        file_h       dd 0                                 ; Дескриптор файла
        map_h        dd 0                                 ; Дескриптор мэппинга
        map_addr     dd 0                                     ; Адрес мэппинга
        al_mem       dd 0                                 ; Адрес памяти в куче
       
        buf_sz       = 100h                                   ; Размер буффера
        buf          rb buf_sz                                ; Буффер для recv
       
        WSA          WSADATA                                  ; Необходимые
        sin          sockaddr_in                              ; структуры
       
       
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      ; base64 encoder without dictionary by RT Fishel
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      ;
      ; ebp = length, esi -> src buffer, edi -> dst buffer
       
        b64:
          .newline:
            call     b64.store_crlf
       
          .encode:
            push     (76 shr 2)+1
            pop      edx
       
          .outer:
            dec      edx
            je       b64.newline
            lodsd
            dec      esi
            inc      ebp
            bswap    eax
            mov      ecx,4
       
          .inner:
            rol      eax,6
            and      al,3Fh
            cmp      al,3Eh
            jb       b64.testchar
            shl      al,2
            sub      al,((3Eh shl 2)+'A'-'+') and 0FFh
       
          .testchar:
            sub      al,4
            cmp      al,'0'
            jnl      b64.store
            add      al,'A'+4
            cmp      al,'Z'
            jbe      b64.store
            add      al,'a'-'Z'-1
       
          .store:
            stosb
            dec      ebp
            loopne   b64.inner
            jne      b64.outer
            mov      al,'='
            rep      stosb
            ret
       
          .store_crlf:
            mov      ax,0A0Dh
            stosw
            ret
       
       
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      ; Процедура чтения в буффер из сокета
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
        read_buf:
            invoke   recv,[sock],buf,buf_sz,esi
            ret
       
       
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      ; Начало основной программы
      ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
        start:
            xor      esi,esi
       
            invoke   CreateFile,file_name,GENERIC_WRITE or GENERIC_READ,\     ; Откроем нужный
               esi,esi,OPEN_EXISTING,esi,esi                  ; нам файл
            inc      eax                              ; Выходим в
            je       exit                             ; случае ошибки
            dec      eax                              ; Если всё ок,
            mov      [file_h],eax                         ; сохраним его хэндл
       
            invoke   GetFileSize,eax,esi                      ; Узнаем размер файла
            mov      ebx,eax                              ; Сохраним его в ebx
            rol      eax,1                                ; Умножим размер на два
                                              ; (на всякий случай, т.к.
                                              ; размер закодированного
                                              ; в base64 файла всегда больше)
            add      eax,message_sz                           ; Прибавим к получившемуся
                                              ; результату размер уже
                                              ; имеющегося письма
       
            invoke   LocalAlloc,LMEM_FIXED,eax                    ; Выделим место в куче
            test     eax,eax                              ; Если ошибка -
            je       exit                             ; выходим, иначе
            mov      [al_mem],eax                         ; сохраним адрес
       
            mov      edi,eax                              ; Переместим в кучу
            mov      esi,message                          ; подготовленный
            mov      ecx,message_sz                           ; заголовок и текст
            rep      movsb                                ; письма
       
            xor      esi,esi
       
            invoke   CreateFileMapping,[file_h],esi,PAGE_READWRITE,esi,ebx,esi    ; Создадим file mapping
            test     eax,eax                              ; Выходим в
            je       clean_exit3                          ; случае ошибки
            mov      [map_h],eax                          ; Если всё ok, сохраним хэндл
       
            invoke   MapViewOfFile,eax,2,esi,esi,esi                  ; Спроецируем файл в память
            test     eax,eax                              ; Выходим в
            je       clean_exit2                          ; случае ошибки
            mov      [map_addr],eax                           ; Если всё ok,
                                              ; сохраним адрес мэппинга
       
            mov      esi,eax                              ; Укажем, откуда
                                              ; брать данные
            mov      ebp,ebx                              ; Укажем размер данных
            call     b64.encode                           ; Кодируем в base64
       
            mov      ax,0A0Dh                             ; Добавим к
            stosw                                 ; получившемуся
            mov      ax,0A0Dh                             ; письму
            stosw                                 ; CRLF
            mov      al,'.'                               ; .
            stosb                                 ; CRLF
            mov      ax,0A0Dh                             ;
            stosw                                 ;
       
            mov      eax,edi                              ; Вычислим размер
            sub      eax,[al_mem]                         ; получившегося письма,
            mov      ebx,eax                              ; и сохраним его в ebx
       
            xor      esi,esi
       
            invoke   WSAStartup,101h,WSA                      ; Инициализируем winsock
            test     eax,eax                              ; Выходим в
            jne      clean_exit1                          ; случае ошибки
       
            invoke   socket,AF_INET,SOCK_STREAM,0                 ; Создаем сокет
            inc      eax                              ; Выходим
            je       clean_exit                           ; если
            dec      eax                              ; ошибка
            mov      [sock],eax                           ; Если ok - сохраним
                                              ; его дескриптор
       
            push     smtp_server                          ; Преобразуем адрес
            call     [inet_addr]                          ; сервера
       
            mov      [sin.sin_family],AF_INET                     ; Заполним структуру
            mov      [sin.sin_port],1900h                     ; sockaddr_in
            mov      [sin.sin_addr],eax                       ;
       
            invoke   connect,[sock],sin,10h                       ; Коннектимся к серверу
            inc      eax                              ; Если ошибка
            je       shtdown                              ; выходим
       
            call     read_buf                             ; Получим и
            inc      eax                              ; проверим
            je       shtdown                              ; ответ сервера
            cmp      dword [buf],'220 '                       ;
            jne      shtdown                              ;
       
            invoke   send,[sock],helo_0,helo_0_sz,esi                 ; Пошлем приветствие
            inc      eax                              ; Выход,
            je       shtdown                              ; если ошибка
       
            call     read_buf                             ; Проверим ответ сервера
            inc      eax
            je       shtdown
            cmp      dword [buf],'250 '
            jne      shtdown
       
            invoke   send,[sock],mail_fr,mail_fr_sz,esi               ; MAIL FROM
            inc      eax
            je       shtdown
       
            call     read_buf
            inc      eax
            je       shtdown
            cmp      dword [buf],'250 '
            jne      shtdown
       
            invoke   send,[sock],rcpt_to,rcpt_to_sz,esi               ; RCPT TO
            inc      eax
            je       shtdown
       
            call     read_buf
            inc      eax
            je       shtdown
            cmp      dword [buf],'250 '
            jne      shtdown
       
            invoke   send,[sock],data_,data_sz,esi                    ; DATA
            inc      eax
            je       shtdown
       
            call     read_buf
            inc      eax
            je       shtdown
            cmp      dword [buf],'354 '
            jne      shtdown
       
            invoke   send,[sock],[al_mem],ebx,esi                 ; Посылаем письмо
            inc      eax
            je       shtdown
       
            call     read_buf
       
        shtdown:
            invoke   shutdown,[sock],esi                      ; Разрываем соединение
            invoke   closesocket,[sock]                       ; и закрываем сокет
       
        clean_exit:
            invoke   WSACleanup
       
        clean_exit1:
            invoke   UnmapViewOfFile,[map_addr]                   ; Выгрузим файл из памяти
       
        clean_exit2:
            invoke   CloseHandle,[map_h]                      ; Закроем хэндл мэппинга
       
        clean_exit3:
            invoke   LocalFree,[al_mem]                       ; Освободим память в куче
            invoke   CloseHandle,[file_h]                     ; Закроем файл
       
        exit:
            invoke   ExitProcess,esi                          ; Выходим из программы
       
       
      data import                                 ; Import table
       
        library kernel32,'KERNEL32.DLL',\
            wsock32,'WSOCK32.DLL'
       
        include '%fasminc%\APIA\kernel32.inc'
        include '%fasminc%\APIA\wsock32.inc'
       
      end data
      Скомпилировал код, запустил. Программа закончилась не успев начаться, стал идти по проверкам Errorов, получилось что закругляется после попытки законектиться.
      ExpandedWrap disabled
        invoke   connect,[sock],sin,10h           ; Коннектимся к серверу
      SOCKET_ERROR полез по интернетам, ничего не понял, тема для меня новая, наткнулся сегодня случайно. Поскольку со дня создания оного кода минуло без малого девять лет не знаю что и предполагать. Вариантов (по незнанию) в голове куча, начиная от того что айпи на сервере уже не тот и заканчивая тем что и протокол быть может поменяль. Сомнения подогрели тёрки на одном из форумов о борьбе майловцев со спамерами и т.п. Вобщем за что хвататься не знаю. Если не затруднит дать пару дельных советов буду благодарен.
      Подпись выключена.
        Да уж, много времени прошло :D Пример не очень актуален, да и кривовато написан. Протокол конечно никто не менял, но во-первых IP нужно получать динамически через gethostbyname (видимо автору лень было этим заниматься), плюс на всех серверах сейчас требуется авторизация (SMTP AUTH). Вот более свежий пример, хотя ему тоже уже много лет http://nepanda.net/wasm/article.php-article=simplesmtp.htm. А вообще по данной теме лучше искать инфу тут - wasm.ru/forum/
          Спасибо за ответ, в теме не в зуб ногой, постараюсь нарыть инфу по вновь открывшимся обстоятельствам через поисковики.
          Подпись выключена.
            Пример нерабочий, ссылка битая... Если кто исправит, верну обратно в Assembler FAQ...
            Tell me would you kill to save a life?
            Tell me would you kill to prove you're right?
            Crash, crash, burn, let it all burn
            This hurricane's chasing us all underground...
            1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
            0 пользователей:


            Рейтинг@Mail.ru
            [ Script Execution time: 0,1275 ]   [ 14 queries used ]   [ Generated: 22.10.17, 15:36 GMT ]