Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11855
Последний выпуск: 19.06.2015

Работа с протоколом Socks5 на MASM

Автор: c4m310t
Дата: 20 мая 2009 года
Источник: www.wasm.ru

Недавно столкнулся с реализацией работы через прокси сервер по протоколу Socks5 на языке ассемблера. К моему удивлению, на эту тему я не нашел какого либо завершенного материала (даже на wasm'овском форуме !). Это и послужило поводом для написательства данной статьи.

На первый взгляд, все кажется сложным, но на самом деле все просто =) Полное описание протокола можно найти в rfc 1928 и rfc 1929, а я на простом примере покажу как реализуется коннект, отправка и прием данных, через не требующий авторизации Socks5 прокси сервер.

Печатая эти строки, я предполагаю, что у читателя есть навыки работы с WinSock, а так же начальные знания языка Ассемблера (MASM). И так, приступаем:

1. Инициализируем структуру WSAStartup (используя версию сокетов 1.1):

 
invoke WSAStartup, 101h, addr lpWSAData

2. Создаем сокет и зполняем структуру sockaddr_in:

invoke socket, AF_INET, SOCK_STREAM, 0
cmp eax, INVALID_SOCKET			; Если ошибка...
jz ERRSOCK				; .. выходим
mov hSocket, eax			; сохраняем хендл нашего сокета
 
mov SinStructSocks.sin_family,	AF_INET
invoke htons, 1080d			; Порт прокси сервера преобразуем в сетевой порядок бит
mov SinStructSocks.sin_port, ax		; Теперь кидаем в структуру
 
invoke inet_addr, addr SocksHost	; IP адрес Прокси сервера, берем из переменной...
 
mov SinStructSocks.sin_addr.S_un.S_addr, eax ; .. Преобразуем, и кидаем в структуру

3. Пробуем приконектиться к заданному серверу:

invoke connect, hSocket, offset SinStructSocks, sizeof SinStructSocks
 
cmp eax, 0
jne ERRCON				; Если облом - выход...
 

4. И так, коннект прошел успешно. Теперь начинается самое интересное =):

Что бы начать работу через Прокси, мы должны послать запрос авторизации.

Выдержка из RFC 1928:

 
   Клиент соединяется с сервером и посылает сообщение с номером версии
   и выбором соответствующего метода аутентификации:
 
                   +----+----------+----------+
                   |VER | NMETHODS | METHODS  |
                   +----+----------+----------+
                   | 1  |    1     | 1 to 255 |
                   +----+----------+----------+
 
   Значения для поля METHOD:
 
          o  X'00' аутентификация не требуется
          o  X'01' GSSAPI
          o  X'02' USERNAME/PASSWORD (см. RFC1929)
          o  X'03' до X'7F' зарезервировано IANA 
          o  X'80' до X'FE' преднозначено для частных методов
          o  X'FF' нет применимых методов
 
   Поле NMETHODS содержит число октетов в идентификаторах методов авторизации
   в поле METHODS.

В нашем случае, авторизация не нужна, по этому, запрос будет выглядеть так:

0x05 0x01 0x00

в памяти:

....
.DATA
 
szNOAUTH	db	05h, 01h, 00h
....

В ответ, Прокся пошлет нам всего 2 байта:

  • 1 байт - версия протокола (0х05)
  • 2 байт - выбранный метод авторизации (в нашем случае 0х00)
invoke send, hSocket, offset szNOAUTH, 3, 0		;шлем данные
 
invoke recv, hSocket, addr szSocksRecvBuff, sizeof szSocksRecvBuff, 0	;тут ответ

5. Далее мы должны послать запрос на соединение с "целевым хостом".

Под "целевым хостом" я подразумеваю конечный узел\ресурс, с которым мы собственно и будем работать через упомянутый выше Прокси %) Для примера я взял SMTP сервер Yandex'a, с которым будет происходить обмен данными.

Снова выдержка из RFC 1928:

 
SOCKS-запрос формируется следующим образом:
 
        +----+-----+-------+------+----------+----------+
        |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+
 
     Где:
 
          o  VER    версия протокола: X'05'
          o  CMD
             o  CONNECT X'01'
             o  BIND X'02'
             o  UDP ASSOCIATE X'03'
          o  RSV    зарезервировано
          o  ATYP   тип адреса, следующего вида:
             o  IP v4 адрес: X'01'
             o  имя домена:  X'03'
             o  IP v6 адрес: X'04'
          o  DST.ADDR требуемый адрес
          o  DST.PORT требуемый порт (в сетевом порядке октетов)
 
Адресация
 
   Тип адреса содержащегося в адресном поле (DST.ADDR, BND.ADDR), 
   определяется содержимым поля ATYP:
 
          o  X'01'
 
   адрес является адресом IP v4, длинна адреса 4 октета
 
          o  X'03'
 
   поле адреса содержит имя домена. Первый октет адресного поля содержит
   число октетов в последующем за ним имени.
 
          o  X'04'
 
   адрес является адресом IP v6, длинна адреса 16 октет   

В нашем случае, нам нужно соединиться с узлом smtp.yandex.ru через порт 25. Отсюда следует, что:

  • тип соединения CONNECT (0х01)
  • тип адреса - имя домена (0х03)

получаем запрос вида:

0х05 0х01 0х00 0х03 0х0E 'smtp.yandex.ru' 0х00 0х19 0х00

где:

  • первые 4 байта Вам должны быть уже понтяны ;)
  • пятый - 0х0Е это количество символов в имени "целевого хоста"
  • далее само имя "целевого хоста"
  • завершающий NUL - 0 (об этом скажу подробнее, в конце стати.)
  • и последние 2 байта есть не что иное как порт 25, но только в сетевом порядке бит (как он получается догадайтесь сами ;) )

в памяти наш запрос выглядит так:

....
.DATA
 
szCONNECT	db	05h,01h,00h,03h, sizeof nmSMTP-1, SMTPNAME,0,19h,00h
....

Теперь отсылаем все это серверу:

invoke send, hSocket, offset szCONNECT, sizeof szCONNECT, 0
invoke recv, hSocket, addr szSocksRecvBuff, 30, 0	 ; тут ответ сервера

6. Получение ответа. В области памяти по имени szSocksRecvBuff, будет находится ответ сервера.

Выглядит он примерно так:

0х05 0х00 0х00 0х01 0х0A 0х0A 0х0A 0х64 0х20 0х04

Внимательно смотрим на 2-ой байт ! Если он НЕ РАВЕН нулю, значит произошла ошибка.. =(

За получением всех возможных вариантов.. ..Обратимся к RFC 1928:

 
Сервер обрабатывает запрос и посылает ответ в следующей форме:
 
        +----+-----+-------+------+----------+----------+
        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+
 
     Где:
 
          o  VER    версия протокола: X'05'
          o  REP    код ответа:
             o  X'00' успешный
             o  X'01' ошибка SOCKS-сервера
             o  X'02' соединение запрещено набором правил
             o  X'03' сеть недоступна
             o  X'04' хост недоступен
             o  X'05' отказ в соединении
             o  X'06' истечение TTL
             o  X'07' команда не поддерживается
             o  X'08' тип адреса не поддерживается
             o  X'09' до X'FF' не определены
          o  RSV    зарезервирован
          o  ATYP   тип последующего адреса
             o  IP v4 адрес: X'01'
             o  имя домена:  X'03'
             o  IP v6 адрес: X'04'
          o  BND.ADDR       выданный сервером адрес
          o  BND.PORT       выданный сервером порт (в сетевом порядке октетов)
 
   Значения зарезервированных (RSV) полей должны быть установлены в X'00'.

7. Ошибки нет ? Тогда нас можно поздравить, ведь теперь мы наконец можем работать черз Прокси =)

Что бы доказать это, мы пошлем SMTP серверу Yandex'a приветственное сообщение, и примем от него ответ.

....
.DATA
szEHLO	       db 	'HELO localhost', 13, 10
 
....
 
invoke recv, hSocket, addr szRecvTrashBuff, sizeof szRecvTrashBuff, 0  ;получаем приветствие яндекса
 
invoke send, hSocket, addr szEHLO, sizeof szEHLO, 0		; посылаем наше приветствие..
 
invoke recv, hSocket, addr szRecvBuff, sizeof szRecvBuff, 0	;..и получаем ответ.

Буфер szRecvBuff содержит такой ответ:

250 smtp16.yandex.ru Hello localhost

То же самое Вы можете проделать используя утилиту telnet:

telnet smtp.yandex.ru 25
 
HELO localhost

8. По завершении работ вызываем WinApi функции closesocket и WSACleanup:

invoke closesocket, hSocket
invoke WSACleanup

Хочу обратить Ваше внимание на добавление нулевого октета в запросе, после имени "целевого хоста".. В оригинальном рфц написанно: "The first octet of the address field contains the number of octets of name that follow, there is no terminating NUL octet."

В русскоязычном переводе: "Первый октет адресного поля содержит число октетов в последующем за ним имени, завершающий NUL-октет в конце строки не применяется."

И тем не мение без него, лично у меня сервер возвращал ошибку...

Так же к данной статье прилагается работающий пример.

Успехов ! ;)

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
83K
05 мая 2012 года
Aids
0 / / 05.05.2012
+1 / -0
Мне нравитсяМне не нравится
5 мая 2012, 12:22:54
>И тем не мение без него, лично у меня сервер возвращал ошибку...
>00h,19h,00h
порт записывается в обратном порядке. А не так 19h,00h, правильная запись будет
szCONNECT db 05h,01h,00h,03h, sizeof nmSMTP-1, SMTPNAME,0,19h
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог