首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >sendto发送垃圾(VBA)

sendto发送垃圾(VBA)
EN

Stack Overflow用户
提问于 2018-02-21 23:06:20
回答 2查看 340关注 0票数 1

我使用来自这里的代码进行了一些更改--在某些定义中添加了私有关键字,因为Excel报告了错误,并将类型更改为IPRAW/ICMP。

最后,我在数据包的数据部分的wireshark中看到垃圾,但是数据大小是正确的(3个字节)。当执行sendBuf时,我检查了sendTo实际上包含了作为三个'a‘的第一个字节。怎么啦?

数据是使用清单底部的CommandButton1_Click()子发送的。

这是密码

代码语言:javascript
复制
'reference
'http://msdn.microsoft.com/en-us/library/windows/desktop/ms740673(v=vs.85).aspx
Const INVALID_SOCKET = -1
Const WSADESCRIPTION_LEN = 256

Enum AF
  AF_UNSPEC = 0
  AF_INET = 2
  AF_IPX = 6
  AF_APPLETALK = 16
  AF_NETBIOS = 17
  AF_INET6 = 23
  AF_IRDA = 26
  AF_BTH = 32
End Enum

Enum sock_type
   SOCK_STREAM = 1
   SOCK_DGRAM = 2
   SOCK_RAW = 3
   SOCK_RDM = 4
   SOCK_SEQPACKET = 5
End Enum

Enum Protocol
   IPPROTO_ICMP = 1
   IPPROTO_IGMP = 2
   BTHPROTO_RFCOMM = 3
   IPPROTO_TCP = 6
   IPPROTO_UDP = 17
   IPPROTO_ICMPV6 = 58
   IPPROTO_RM = 113
End Enum

'Type sockaddr
'   sa_family As Integer
'   sa_data(0 To 13) As Byte
'End Type

Private Type sockaddr_in
  sin_family As Integer
  sin_port As Integer
  sin_addr(0 To 3) As Byte
  sin_zero(0 To 7) As Byte
End Type

Private Type socket
   pointer As Long
End Type

Private Type LPWSADATA_Type
   wVersion As Integer
   wHighVersion As Integer
   szDescription(0 To WSADESCRIPTION_LEN) As Byte
   szSystemStatus(0 To WSADESCRIPTION_LEN) As Byte
   iMaxSockets As Integer
   iMaxUdpDg As Integer
   lpVendorInfo As Long
End Type

Private Declare Function WSAGetLastError Lib "Ws2_32.dll" () As Integer
Private Declare Function WSAStartup Lib "Ws2_32.dll" (ByVal wVersionRequested As Integer, ByRef lpWSAData As LPWSADATA_Type) As Long
Private Declare Function sendto Lib "Ws2_32.dll" (ByVal socket As Long, ByRef buf() As Byte, ByVal length As Long, ByVal flags As Long, ByRef toaddr As sockaddr_in, tolen As Long) As Long
Private Declare Function f_socket Lib "Ws2_32.dll" Alias "socket" (ByVal AF As Long, ByVal stype As Long, ByVal Protocol As Long) As Long
Private Declare Function closesocket Lib "Ws2_32.dll" (ByVal socket As Long) As Long
Private Declare Sub WSACleanup Lib "Ws2_32.dll" ()

Sub SendPacket(Message As String, IP As String, Port As Integer)
   Dim ConnectSocket As socket
   Dim wsaData As LPWSADATA_Type
   Dim iResult As Integer: iResult = 0
   Dim send_sock As sock_type: send_sock = INVALID_SOCKET
   Dim iFamily As AF: iFamily = AF_INET
   Dim iType As Integer: iType = SOCK_RAW 'SOCK_UDP
   Dim iProtocol As Integer: iProtocol = IPPROTO_ICMP 'IPPROTO_UDP
   Dim SendBuf(0 To 1023) As Byte
   Dim BufLen As Integer: BufLen = 1024
   Dim RecvAddr As sockaddr_in: RecvAddr.sin_family = AF_INET: RecvAddr.sin_port = Port
   Dim SplitArray As Variant: SplitArray = Split(IP, ".")

   RecvAddr.sin_addr(0) = SplitArray(0)
   RecvAddr.sin_addr(1) = SplitArray(1)
   RecvAddr.sin_addr(2) = SplitArray(2)
   RecvAddr.sin_addr(3) = SplitArray(3)


   For buf = 1 To Len(Message)
      SendBuf(buf - 1) = Asc(Mid(Message, buf, 1))
   Next buf
   SendBuf(buf + 1) = 0

   iResult = WSAStartup(&H202, wsaData)
   If iResult <> 0 Then
      MsgBox ("WSAStartup failed: " & iResult)
      Exit Sub
   End If

   send_sock = f_socket(iFamily, iType, iProtocol)
   If send_sock = INVALID_SOCKET Then
      Errno = WSAGetLastError()
      Exit Sub
   End If

   iResult = sendto(send_sock, SendBuf, Len(Message), 0, RecvAddr, Len(RecvAddr)) ' BufLen, 0, RecvAddr, Len(RecvAddr))
   If iResult = -1 Then
      MsgBox ("sendto failed with error: " & WSAGetLastError())
      closesocket (send_sock)
      Call WSACleanup
      Exit Sub
   End If

   iResult = closesocket(send_sock)
   If iResult <> 0 Then
      MsgBox ("closesocket failed with error : " & WSAGetLastError())
      Call WSACleanup
   End If
End Sub


Private Sub CommandButton1_Click()
    Call SendPacket("aaa", "192.168.1.55", 1000)
End Sub

更新:根据雷米·莱博的建议,我做了以下修改:

代码语言:javascript
复制
Private Declare Function sendto Lib "Ws2_32.dll" (ByVal socket As Long, ByVal buf As LongPtr, ByVal length As Long, ByVal flags As Long, ByRef toaddr As sockaddr_in, tolen As Long) As Long

ByRef buf() As Byte改变ByVal buf As LongPtr

代码语言:javascript
复制
Private Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias "VarPtr" (Var() As Any) As LongPtr
...
iResult = sendto(send_sock, VarPtrArray(SendBuf) + 12, Len(Message), 0, RecvAddr, Len(RecvAddr))

SendBuf改为VarPtrArray(SendBuf) + 12

但我还是能拿到垃圾。

更新2:成功:

已添加

代码语言:javascript
复制
Private Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias "VarPtr" (Var() As Any) As LongPtr

已修改

代码语言:javascript
复制
iResult = sendto(send_sock, VarPtr(SendBuf(0)), Len(Message), 0, RecvAddr, Len(RecvAddr))
EN

回答 2

Stack Overflow用户

发布于 2018-02-21 23:41:40

您在buf参数sendto()中传递了错误的内存地址,因此它从错误的内存中检索字节。这就是为什么在数据包有效负载中看到“垃圾”的原因。

ByRef buf() as Byte用于sendto()buf参数是错误的。sendto()期望一个指针直接指向要发送的实际字节。但是您的SendBuf变量是一个动态数组(它是包含指向实际字节的指针的COM SAFEARRAY的包装器)。通过传递SendBuf as-is使用ByRef,您实际上是在传递sendto() -- SendBuf变量本身的内存地址,而不是SendBuf引用的字节数据的内存地址(位于内存的其他地方)。

来自VBA内部:变量中的内容

VBA中的数组至少由3个指针构建。首先,对数组变量调用VarPtrArray()将获得变量内容的地址。如果直接读取变量内容,就会得到另一个指针--指向SAFEARRAY结构的开始。最后,如果直接从SAFEARRAY的字节偏移量12 (SAFEARRAY字段)读取数据,您将得到一个指向数组元素数据开始的指针。

最后一个值(“指向数组元素数据开始的指针”)是您需要传递给buf参数sendto()的内存地址。因此,将buf参数更改为LongPtr,然后使用VarPtrArray()CopyMemory()的组合从SendBuf的内部SAFEARRAY中提取指向字节数据的指针。

请参阅VBA内部:获取指针 (它根据您的Office版本为VarPtrArray()提供了适当的声明)和VBA内部:数组变量和深度指针 (它向您展示了如何使用VarPtrArray()从数组变量中获取内部数据指针)。

例如:

代码语言:javascript
复制
Public Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias "VarPtr" (Var() As Any) As LongPtr
' Public Declare Function VarPtrArray Lib "VBE6" Alias "VarPtr" (Var() As Any) As Long
...
Private Declare Function sendto Lib "Ws2_32.dll" (ByVal socket As Long, ByVal buf As LongPtr, ByVal length As Long, ByVal flags As Long, ByRef toaddr As sockaddr_in, tolen As Long) As Long
...

Dim SendBuf(0 To 1023) As Byte
Dim ptrToArrayVar As LongPtr
Dim ptrToSafeArray As LongPtr
Dim ptrToArrayData As LongPtr
Dim uSAFEARRAY As SAFEARRAY_VECTOR

...

' Get pointer to array *variable*
ptrToArrayVar = VarPtrArray(SendBuf)

' Get the pointer to the *SAFEARRAY* by directly
' reading the variable's address
CopyMemory ptrToSafeArray, ByVal ptrToArrayVar, PTR_LENGTH

' Read the SAFEARRAY struct
CopyMemory uSAFEARRAY, ByVal ptrToSafeArray, LenB(uSAFEARRAY)

' Get the pointer to the actual vector of bytes
ptrToArrayData = uSAFEARRAY.pvData

iResult = sendto(send_sock, ptrToArrayData, buf + 1, 0, RecvAddr, Len(RecvAddr))

Update:显然,您根本不需要直接访问SAFEARRAYVarPtr()能够获取数组变量的特定元素的内存地址。因此,您可以使用以下方法获取SendBuf中第一个字节的内存地址(这实际上与内部SAFEARRAY所指向的内存地址相同):

代码语言:javascript
复制
iResult = sendto(send_sock, VarPtr(SendBuf(0)), buf + 1, 0, RecvAddr, Len(RecvAddr))
票数 0
EN

Stack Overflow用户

发布于 2018-02-22 06:48:21

sendto方法获取缓冲区中数据开头的地址。

使用ByRef buffer As Any声明参数

代码语言:javascript
复制
Private Declare PtrSafe Function sendto Lib "Ws2_32.dll" ( _
    ByVal socket As Long, _
    ByRef buffer As Any, _
    ByVal length As Long, _
    ByVal flags As Long, _
    ByRef toaddr As Any, _
    ByVal tolen As Long) As Long

并通过参考提供第一个要素:

代码语言:javascript
复制
Dim buffer() As Byte, size As Long

buffer = StrConv(Message, vbFromUnicode)  ' UTF-16 2 bytes to ANSI 1 byte
size = UBound(buffer) + 1

iResult = sendto(send_sock, buffer(0), size, 0, RecvAddr, Len(RecvAddr))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48917030

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档