文本版|topic 高级搜索
   名人堂 帮助 论坛制度 意见反馈 | 首页 博客 周新贴 招聘 专题 新闻
RSS 底部
 
社区导航: 专家门诊   网络技术   操作系统   数据库   程序设计   系统应用   考试认证   CIO及信息化   站长交流   综合交流   下载基地  51CTO产品服务 设为首页 | 收藏本站
51CTO技术论坛» .Net » VB6中使用Winsock穿越各种代理       [ 打印]  [ 订阅]  [ 收藏]  [ 推荐给朋友]   [ 本帖文本页]

论坛跳转:
     
标题: [转载] VB6中使用Winsock穿越各种代理  ( 查看:159  回复:1 )   
 
Easy
助理工程师  点击可查看详细



帖子 365
精华 2
无忧币 1770
积分 1609
阅读权限 40
注册日期 2007-11-6
最后登录 2008-5-5 离线

[查看资料]  [发短消息]  [Blog
       
发表于:2007-11-8 17:53   标题:VB6中使用Winsock穿越各种代理
上一帖 |
关于用vb的winsock穿透代理的讨论归讨论,一直没有什么源代码放出,现在我就放源出来,省的某些人拿这所谓的"技术"去骗钱.
  由于缺乏测试环境,本程序只在我自己编写的代理模拟器上测试过,其结果和腾讯QQ,MSN,网易泡泡穿越该模拟器时得出的结果基本一致.因此,代码可能有错误的地方,请各位有条件的用户自行改正,请见谅!
  首先,是基础知识,也就是RFC文档.这个是必看内容.我的程序就是基于这些文档写出.下面是各RFC的连接,为了准确,我先提供英文版的连接,在下面的介绍中再把关键部分翻译成中文.另外,要纠正一个错误.国内很多文章说socks5代理的用户名/密码校验标准在 RFC 1928里有说明,其实这是一个完全错误的说法(我很怀疑写那文章的人有没有看过RFC),socks5用户名/密码校验标准其实是在 RFC 1929 里面说明的.
  RFC 1928 - socks5 代理标准
  RFC 1929 - socks5 代理用户名/密码校验标准
  RFC ???? - socks4 代理标准
  RFC 2616 - HTTP1.1 标准
  我们现在直入正题:先说socks5的TCP穿透(有了这个例子大家自己照这可以写UDP穿透)
  首先和代理服务器连接-直接用winsock去connect指定的地址端口(通常是1080)即可.然后进入细节商议阶段.
  细节商议--无用户名/密码校验
  RFC 1928 中对于细节商议的第一步是这样描述的:
  The client connects to the server, and sends a version
  identifier/method selection message:
  +----+----------+----------+
  |VER | NMETHODS | METHODS |
  +----+----------+----------+
  | 1 | 1 | 1 to 255 |
  +----+----------+----------+
  The VER field is set to X'05' for this version of the protocol. The
  NMETHODS field contains the number of method identifier octets that
  appear in the METHODS field.
  The server selects from one of the methods given in METHODS, and
  sends a METHOD selection message:
  +----+--------+
  |VER | METHOD |
  +----+--------+
  | 1 | 1 |
  +----+--------+
  If the selected METHOD is X'FF', none of the methods listed by the
  client are acceptable, and the client MUST close the connection.
  The values currently defined for METHOD are:
  o X'00' NO AUTHENTICATION REQUIRED ---------无用户密码 00
  o X'01' GSSAPI ---------??? GSSAPI ?
  o X'02' USERNAME/PASSWORD ---------有用户密码 02
  o X'03' to X'7F' IANA ASSIGNED
  o X'80' to X'FE' RESERVED FOR ** METHODS
  o X'FF' NO ACCEPTABLE METHODS ---------失败 255
  The client and server then enter a method-specific sub-negotiation.
 换言之,就是向服务器发送三个字节的Byte数组,由于是无须用户/密码校验,展开来写是 05 01 00
  然后服务器返回两个字节的信息,第一个字节固定,第而个字节是说明,如果是16进制的FF(即十进制255)表示连接失败(o X'FF' NO ACCEPTABLE METHODS)根据上面的列表,我们连接成功应该第二字节为 00.
  然后我们进入第二步,请看以下RFC说明:
  Once the method-dependent subnegotiation has completed, the client
  sends the request details. If the negotiated method includes
  encapsulation for purposes of integrity checking and/or
  confidentiality, these requests MUST be encapsulated in the method-
  dependent encapsulation.
  The SOCKS request is formed as follows:+----+-----+-------+------+----------+----------+
  |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
  +----+-----+-------+------+----------+----------+
  | 1 | 1 | X'00' | 1 | Variable | 2 |
  +----+-----+-------+------+----------+----------+
  Where:
  o VER protocol version: X'05' ------------- 固定 05
  o CMD
  o CONNECT X'01' ------------- TCP方式 01
  o BIND X'02'
  o UDP ASSOCIATE X'03' ------------- UDP方式 03
  o RSV RESERVED ------------- 固定 00
  o ATYP address type of following address
  o IP V4 address: X'01' ------------- IPv4 01
  o DOMAINNAME: X'03'
  o IP V6 address: X'04'
  o DST.ADDR desired destination address
  o DST.PORT desired destination port in network octet
  order
  The SOCKS server will typically evaluate the request based on source
  and destination addresses, and return one or more reply messages, as
  appropriate for the request type.
  发送 05 01 00 01 + 目的地址(4字节) + 目的端口(2字节),目的地址和端口都是16进制码(不是字符串)。
  例202.103.190.27 - 7201
  则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21
  (CA=202 67=103 BE=190 1B=27 1C21=7201)
关于我是怎么把16进制码换成10进制的,请自己看程序
  最后,接受服务器返回数据,看RFC:
  +----+-----+-------+------+----------+----------+
  |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
  +----+-----+-------+------+----------+----------+
  | 1 | 1 | X'00' | 1 | Variable | 2 |
  +----+-----+-------+------+----------+----------+
  Where:
  o VER protocol version: X'05' ------------ 固定 05
  o REP Reply field:
  o X'00' succeeded ------------ 若为 00 成功 其余可以都看成失败
  o X'01' general SOCKS server failure
  o X'02' connection not allowed by ruleset
  o X'03' Network unreachable
  o X'04' Host unreachable
  o X'05' Connection refused
  o X'06' TTL expired
  o X'07' Command not supported
  o X'08' Address type not supported
  o X'09' to X'FF' unassigned
  o RSV RESERVED
  o ATYP address type of following address
  o IP V4 address: X'01'
  o DOMAINNAME: X'03'
  o IP V6 address: X'04'
  o BND.ADDR server bound address
  o BND.PORT server bound port in network octet order
  Fields marked RESERVED (RSV) must be set to X'00'.
  可见,对于返回信息,只须判断第二字节是否为00.若为 00 连接成功,剩下的操作和直连一样,Winsock可直接用SendData 和 GetData 发送\接受数据.
  下面介绍需要验证用户名/密码的socks5穿透
  第一步还是发送三个字节,只是内容有变,展开来写为: 05 01 02
  服务器返回信息也有所不同,正确的返回为 05 02
  成功后发送用户/密码信息,请看RFC 说明:
  Once the SOCKS V5 server has started, and the client has selected the
  Username/Password Authentication protocol, the Username/Password
  subnegotiation begins. This begins with the client producing a
  Username/Password request:
  +----+------+----------+------+----------+
  |VER | ULEN | UNAME | PLEN | PASSWD |
  +----+------+----------+------+----------+| 1 | 1 | 1 to 255 | 1 | 1 to 255 |
  +----+------+----------+------+----------+
  The VER field contains the current version of the subnegotiation,
  which is X'01'. The ULEN field contains the length of the UNAME field
  that follows. The UNAME field contains the username as known to the
  source operating system. The PLEN field contains the length of the
  PASSWD field that follows. The PASSWD field contains the password
  association with the given UNAME.
  The server verifies the supplied UNAME and PASSWD, and sends the
  following response:
  +----+--------+
  |VER | STATUS |
  +----+--------+
  | 1 | 1 |
  +----+--------+
  A STATUS field of X'00' indicates success. If the server returns a
  `failure' (STATUS value other than X'00') status, it MUST close the
  connection.
即 发送 01 + 用户名长度(一字节) + 转换成16进制码的用户名 + 密码长度(一字节) + 转换成16进制码的密码,关于如何把用户名和密码转换为10进制Byte数组,请自己看程序.
  然后服务器返回两个字节的信息,只须判断第二字节,00 为成功,其余为失败.
  剩下的步骤和无用户名密码校验是一样的,即
  发送 05 01 00 01 + 目的地址(4字节) + 目的端口(2字节),目的地址和端口都是16进制码(不是字符串)。
  例202.103.190.27 - 7201
  则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21
  (CA=202 67=103 BE=190 1B=27 1C21=7201)
  关于我是怎么把16进制码换成10进制的,请自己看程序
  最后接受服务器返回信息.对于返回信息,只须判断第二字节是否为00.若为 00 连接成功,剩下的操作和直连一样,Winsock可直接用SendData 和 GetData 发送\接受数据.
  socks4的TCP穿透(事实上,socks4只支持TCP穿透)
  无用户名/密码验证
  请看 RFC 说明
  1) CONNECT
  The client connects to the SOCKS server and sends a CONNECT request when
  it wants to establish a connection to an application server. The client
  includes in the request packet the IP address and the port number of the
  destination host, and userid, in the following format.
  +----+----+----+----+----+----+----+----+----+----+....+----+
  | VN | CD | DSTPORT | DSTIP | USERID |NULL|
  +----+----+----+----+----+----+----+----+----+----+....+----+
  1 1 2 4 variable 1
  VN is the SOCKS protocol version number and should be 4. CD is the
  SOCKS command code and should be 1 for CONNECT request. NULL is a byte
  of all zero bits.
  我们首先还是连接服务器,然后根据RFC的格式发送数据给服务器.由于是无用户密码验证,我们需要发送9个字节的数据,展开写为 04 01 + 目标端口(2字节) + 目标IP(4字节) + 00,奇怪的是,表中的USERID部分似乎是没有用的,我参照过大量的C++代码,代码中都没有体现该部分.
  至于如何转换目标端口和IP为相应的Byte数组,请自己看示例程序.消息发出后,服务器会返回信息,格式如下:
  +----+----+----+----+----+----+----+----+
  | VN | CD | DSTPORT | DSTIP |
  +----+----+----+----+----+----+----+----+
  1 1 2 4
  VN is the version of the reply code and should be 0. CD is the result
  code with one of the following values:
  90: request granted -------------- 成功
  91: request rejected or failed -------------- 失败



网络工程师到底该不该去考CCIE认证?
2007-11-8 17:531楼
[ 顶部 ]
 
Easy
助理工程师  点击可查看详细



帖子 365
精华 2
无忧币 1770
积分 1609
阅读权限 40
注册日期 2007-11-6
最后登录 2008-5-5 离线

[查看资料]  [发短消息]  [Blog
       
发表于:2007-11-8 17:54 
92: request rejected becasue SOCKS server cannot connect to

  identd on the client

  93: request rejected because the client program and identd

  report different user-ids

  The remaining fields are ignored.

  根据RFC的说法,代理服务器返回8字节的数据,我们只要判断第二字节是否为90即可,若是90连接成功,否则失败.剩下的操作和直连一样,Winsock可直接用SendData 和 GetData 发送\接受数据.

  HTTP1.1 代理的穿透

  由于RFC 2616过于冗长,加上HTTP代理穿透的步骤比socks简单,这里就不详细说明了,我只给出连接的步骤和发送数据格式.

  第一步仍然是用Winsock去连接代理服务器.第二步为发送请求字符,其格式为:

  无用户名/密码校验 格式:

  "CONNECT" + 空格 + 目标连接地址 + ":" + 目标连接端口 + 空格 + "HTTP/1.1" + Chr(13) + Chr(10) + "Host:" + 空格 + 目标连接地址 + ":" + 目标连接端口 + Chr(13) + Chr(10) + Chr(13) + Chr(10)

  用户名/密码验证格式:

  "CONNECT" + 空格 + 目标连接地址 + ":" + 目标连接端口 + 空格 + "HTTP/1.1" + Chr(13) + Chr(10) + "Host:" + 空格 + 目标连接地址 + ":" + 目标连接端口 + Chr(13) + Chr(10) + "Authorization: Basic" + 空格 + 经Base64加密过后的[用户名:密码] + Chr(13) + Chr(10) + Chr(13) + Chr(10) + "Proxy-Authorization: Basic" + 空格 + 经Base64加密过后的[用户名:密码] + Chr(13) + Chr(10) + Chr(13) + Chr(10)

 发送请求完毕后,将收到代理的回应,根据RFC说明(注意 Status-Line 和 Status-Code):

  6 Response

  After receiving and interpreting a request message, a server responds

  with an HTTP response message.

  Response = Status-Line ; Section 6.1

  *(( general-header ; Section 4.5

  | response-header ; Section 6.2

  | entity-header ) CRLF) ; Section 7.1

  CRLF

  [ message-body ] ; Section 7.2

  6.1 Status-Line

  The first line of a Response message is the Status-Line, consisting

  of the protocol version followed by a numeric status code and its

  associated textual phrase, with each element separated by SP

  characters. No CR or LF is allowed except in the final CRLF sequence.

  Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

  6.1.1 Status Code and Reason Phrase

  The Status-Code element is a 3-digit integer result code of the

  attempt to understand and satisfy the request. These codes are fully

  defined in section 10. The Reason-Phrase is intended to give a short

  textual description of the Status-Code. The Status-Code is intended

  for use by automata and the Reason-Phrase is intended for the human

  user. The client is not required to examine or display the Reason-

  Phrase.

  The first digit of the Status-Code defines the class of response. The

  last two digits do not have any categorization role. There are 5

  values for the first digit:

  - 1xx: Informational - Request received, continuing process

  - 2xx: Success - The action was successfully received,

  understood, and accepted

  - 3xx: Redirection - Further action must be taken in order to

  complete the request

  - 4xx: Client Error - The request contains bad syntax or cannot

SendByte(7) = GetIPByte(4, DestIP)

  SendByte(8) = 0 '最后要以 0 结束

  Form1.Winsock1.SendData SendByte()

  ConnStep = PStep + 1

  Exit Function

  End If

  If PStep = 2 Then '代理回复,第二字节为 90 为成功,其余值为失败

  If Asc(Mid(RevBuffer, 2, 1)) <> 90 Then

  Debug.Print Asc(Mid(RevBuffer, 2, 1))

  MsgBox "连接sock4代理失败!", 48, "错误"

  Form1.Winsock1.Close

  ConnStep = 0

  Exit Function

  Else

  Form1.Label8.Caption = "连接目标服务器成功!"

  ConnStep = -1

  Form2.Show

  Exit Function

  End If

  End If

  End If

 '*******************下面的例子有大量重复代码,是为了让大家更清楚地了解sock5穿透过程,大家可以拿回去自己优化 **********************************

  If ProxyType = 1 Then '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ sock5代理

  Select Case PStep

  Case 1

  ReDim SendByte(0 To 2) As Byte '第一步 无验证发送 05 01 00, 有验证发送 05 02 02

  SendByte(0) = 5 ' 05

  SendByte(1) = 1 '01 '在有用户密码验证时此字节是 1 还是 2 有诸多争论,现以腾讯QQ穿越代理模拟器时发送的数据为准,如有错误,请自己修改!

  SendByte(2) = IIf(Form1.Check1.Value = 0, 0, 2) '00 或 02

  Form1.Winsock1.SendData SendByte()

  ConnStep = PStep + 1

  Exit Function

  Case 2 '代理回复

  If Asc(Mid(RevBuffer, 2, 1)) = 255 Then 'FF (255) 为失败

  MsgBox "连接代理失败!", 64

  Form1.Winsock1.Close

  ConnStep = 0

  Exit Function

  End If

  If Asc(Mid(RevBuffer, 2, 1)) = 0 And Asc(Mid(RevBuffer, 1, 1)) = 5 Then '若代理回复 05 00 为无验证连接成功

  Form1.Label8.Caption = "连接成功!无验证"

  ReDim SendByte(0 To 9) As Byte '第二步 无验证 发送连接请求

  SendByte(0) = 5

  SendByte(1) = 1

  SendByte(2) = 0

  SendByte(3) = 1

  SendByte(4) = GetIPByte(1, DestIP)

  SendByte(5) = GetIPByte(2, DestIP)

  SendByte(6) = GetIPByte(3, DestIP)

  SendByte(7) = GetIPByte(4, DestIP)

  SendByte(8) = Int(DestPort / 256) '把10进制端口分成两个字节

  SendByte(9) = DestPort Mod 256 '把10进制端口分成两个字节

  Form1.Winsock1.SendData SendByte()

  ConnStep = ConnStep + 1

  Exit Function

  End If

  If Asc(Mid(RevBuffer, 2, 1)) = 2 And Asc(Mid(RevBuffer, 1, 1)) = 5 Then '第二步 有用户名密码验证 成功为 05 02

  Form1.Label8.Caption = "连接成功!有验证"

  ReDim SendByte(0 To 2 + Len(UserName) + Len(UserPassword)) As Byte

  SendByte(0) = 1

  SendByte(1) = Len(UserName)

  MemCopy SendByte(2), ByVal UserName, Len(UserName) '将用户名转换

  SendByte(2 + Len(UserName)) = Len(UserPassword)

  MemCopy SendByte(3 + Len(UserName)), ByVal UserPassword, Len(UserPassword) '将密码转换

  Form1.Winsock1.SendData SendByte()

  ConnStep = ConnStep + 1

  Exit Function

  End If

  Case 3

  If Asc(Mid(RevBuffer, 2, 1)) <> 0 And Form1.Check1.Value = 1 Then '有验证,验证失败 代理回复第二字节为 00 验证成功,其余值为失败

  MsgBox "sock5代理校验用户名、密码失败!", 48, "错误"

  Form1.Winsock1.Close

  ConnStep = 0

  Exit Function

End If

  If Asc(Mid(RevBuffer, 2, 1)) = 0 And Form1.Check1.Value = 1 Then '有验证,验证成功,回复值第二字节为 00 ,其余值为失败

  Form1.Label8.Caption = "连接成功!有验证!"

  ReDim SendByte(0 To 9) As Byte '发送连接请求

  SendByte(0) = 5

  SendByte(1) = 1

  SendByte(2) = 0

  SendByte(3) = 1

  SendByte(4) = GetIPByte(1, DestIP)

  SendByte(5) = GetIPByte(2, DestIP)

  SendByte(6) = GetIPByte(3, DestIP)

  SendByte(7) = GetIPByte(4, DestIP)

  SendByte(8) = Int(DestPort / 256) '把10进制端口分成两个字节

  SendByte(9) = DestPort Mod 256 '把10进制端口分成两个字节

  Form1.Winsock1.SendData SendByte()

  ConnStep = ConnStep + 1

  Exit Function

  End If

  If Asc(Mid(RevBuffer, 2, 1)) = 0 And Form1.Check1.Value = 0 Then

  Form1.Label8.Caption = "连接目标服务器成功!" '无验证的最后一步,代理回复第二字节为 00 成功,其余值为失败

  ConnStep = -1

  Form2.Show

  Exit Function

  End If

  If Asc(Mid(RevBuffer, 2, 1)) <> 0 And Form1.Check1.Value = 0 Then

  MsgBox "连接目标服务器失败!", 48, "错误" '无验证的最后一步,代理回复第二字节为 00 成功,其余值为失败

  ConnStep = 0

  Form1.Winsock1.Close

  Exit Function

  End If

  Case 4 '只有有验证才会用到这一步

  If Asc(Mid(RevBuffer, 2, 1)) <> 0 Then

  MsgBox "sock5代理连接目标服务器失败!", 48, "错误"

  ConnStep = 0

  Form1.Winsock1.Close

  Exit Function

  Else

  Form1.Label8.Caption = "连接目标服务器成功!"

  ConnStep = -1

  Form2.Show

  Exit Function

  End If

  End Select

  End If

  If ProxyType = 2 Then '@@@@@@@@@@@@@@@@@@@@@@@@HTTP1.1代理

  If PStep = 1 Then '无用户名密码验证

  If Form1.Check1.Value = 0 Then

  HTTPHeader = "CONNECT " & Form1.Text5.Text & ":" & Form1.Text6.Text & _

  " HTTP/1.1" & Chr(13) & Chr(10) & "Host: " & Form1.Text5.Text & ":" & Form1.Text6.Text & Chr(13) & Chr(10) & Chr(13) & Chr(10)

  ConnStep = PStep + 1

  Form1.Winsock1.SendData HTTPHeader

  Exit Function

  End If

  If Form1.Check1.Value = 1 Then ' 有用户名密码验证

  HTTPHeader = "CONNECT " & Form1.Text5.Text & ":" & Form1.Text6.Text & _

  " HTTP/1.1" & Chr(13) & Chr(10) & "Host: " & Form1.Text5.Text & ":" & _

  Form1.Text6.Text & Chr(13) & Chr(10) & "Authorization: Basic " & StrtoBase64(Form1.Text3.Text & _

  ":" & Form1.Text4.Text) & Chr(13) & Chr(10) & Chr(13) & Chr(10) & "Proxy-Authorization: Basic " & _

  StrtoBase64(Form1.Text3.Text & ":" & Form1.Text4.Text) & Chr(13) & Chr(10) & Chr(13) & Chr(10)

  ' Chr(13) & Chr(10) 能否直接用vbCrLf ? 我不知道

  Debug.Print HTTPHeader

  ConnStep = PStep + 1

  Form1.Winsock1.SendData HTTPHeader

  Exit Function

  End If

  End If

  If PStep = 2 Then '代理服务器回复,格式:HTTP/[代理版本] [状态代码] [状态说明]

  If LCase(Left(RevBuffer, 4)) = "http" And Mid(" 200 ", 1) <> 0 Then '状态代码为 200 为成功

Form1.Label8.Caption = "连接目标服务器成功!"

  Form2.Show

  ConnStep = -1

  Else

  MsgBox "HTTP1.1代理连接目标服务器失败!", 48, "错误"

  ConnStep = 0

  Form1.Winsock1.Close

  Exit Function

  End If

  End If

  End If

  End Function



网络工程师到底该不该去考CCIE认证?
2007-11-8 17:542楼
[ 顶部 ]
     
论坛跳转:  

| | |

| | |

标记已读 · 删除论坛Cookies · 文本版 · WAP
 
| 诚征版主 | 版主堂 | 意见建议 | 大史记 | 论坛地图
Copyright©2005-2008 51CTO.COM  Powered by Discuz!
本论坛言论纯属发布者个人意见,不代表51CTO网站立场!如有疑义,请与管理员联系。
京ICP备05051492号