将字符串正确转换为流

时间:2019-01-29 03:59:08

标签: vb.net vbscript

Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports System.IO.Compression
Imports System.Text

Namespace WindowScriptingObject
    <Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
        Public Interface _WindowScriptingObject
        <DispId(1)> Function Decompress(ByVal value as String) As String
    End Interface

    <Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
        ClassInterface(ClassInterfaceType.None), _
        ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
    Implements _WindowScriptingObject

    Public WindowScriptingObject()
        Public Function Decompress(ByVal value as string) As String Implements _WindowScriptingObject.Decompress
            Dim x As String
            '     on error resume next
            Dim xstream As New MemoryStream(Encoding.Unicode.GetBytes(value))
            Dim mem2 As New IO.MemoryStream()
            'Dim streamMe As New StreamWriter(mem2,Encoding.UTF8)
            'streamMe.Write(value)
            'StreamMe.Close()
            'mem2.Position=0

            Dim gz As New System.IO.Compression.GZipStream(xstream, IO.Compression.CompressionMode.Decompress)

            Dim sr As New IO.StreamReader(gz)
            x = sr.ReadLine

            sr.Close()
            'End Using

            Decompress = x
        End Function
    End Class
End Namespace

我验证了发送过来的字符串包含来自VBScript的正确值。但是,它说标题是错误的。

上面的代码必须经过编译才能进行测试

"C:\Windows\Microsoft.NET\Framework\v4.0.30319\vbc.exe" /target:library /out:"%userprofile%\desktop\t.dll" "%userprofile%\desktop\t.txt" /verbose

然后注册

"C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm" /codebase "%userprofile%\desktop\t.dll" /tlb:"%userprofile%\desktop\t.tlb" /v

然后调用

c:\windows\SysWOW64\cscript.exe old.vbs

即使不是最终目标,我也将代码放入文件中以读取内容。当我这样做时,文件将正确解压缩。

Dim xstream As New MemoryStream(Encoding.Unicode.GetBytes(value))

此行听到的声音似乎错误地将我的字符串转换为流。

目标是发送压缩的字符串并返回未压缩的字符串。

上面的代码与此代码一起调用

Const adTypeBinary = 1
Set wso = CreateObject("WindowScriptingObject")
Dim objStream
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
objStream.Open
objStream.LoadFromFile "e:\download\result.gz"
'objStream.Charset = "Windows-1252" 
x = objStream.Read(900)
objStream.Close

For i=1 To Len(x) 
    t = t & Chr(AscW(Mid(x, i, 1)) And 255)
    t = t & Chr((AscW(Mid(x, i, 1)) And 65280)/256)
Next
MsgBox wso.Decompress(t), , "vbs"

我尝试了这个,甚至将字符串转换为base64以使其正常工作。

Dim gzBuffer As Byte() = Convert.FromBase64String(value)
    Using ms As New MemoryStream()
        Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
        ms.Write(gzBuffer, 4, gzBuffer.Length - 4)

        Dim buffer As Byte() = New Byte(msgLength - 1) {}
        ms.Position = 0
        Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
              zipStream.Read(buffer, 0, buffer.Length)
        End Using
    Decompress=System.Text.Encoding.Unicode.GetString(buffer, 0, buffer.Length)
    End Using

数据没有正确转换,因为我在GZip标头中仍然有幻数不正确。

将base64编码值转储到在线解码器中,而我传入的字符串与解码值匹配。

版本2 迫使我对它进行base64编码,但随后它起作用了。 如何消除这种烦恼。

Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports System.IO.Compression
Imports System.Text

Namespace WindowScriptingObject
    <Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
        Public Interface _WindowScriptingObject
        <DispId(1)> Function Decompress(ByVal value as String) As String
    End Interface

    <Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
        ClassInterface(ClassInterfaceType.None), _
        ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
    Implements _WindowScriptingObject

    Public WindowScriptingObject()
        Public Function Decompress(ByVal value as string) As String Implements _WindowScriptingObject.Decompress
            Dim x As String
            '     on error resume next
    Dim gzBuffer As Byte() = Convert.FromBase64String(value)
    Using ms As New MemoryStream()
        Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
        ms.Write(gzBuffer, 0, gzBuffer.Length)

        Dim buffer As Byte() = New Byte(msgLength - 1) {}
        ms.Position = 0
        Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
              zipStream.Read(buffer, 0, buffer.Length)
        End Using
    Decompress=System.Text.Encoding.ASCII.GetString(buffer, 0, buffer.Length)
    End Using
'            Dim xstream As New MemoryStream(value.ToArray())
            Dim mem2 As New IO.MemoryStream()
            'Dim streamMe As New StreamWriter(mem2,Encoding.UTF8)
            'streamMe.Write(value)
            'StreamMe.Close()
            'mem2.Position=0

            'Dim gz As New System.IO.Compression.GZipStream(xstream, IO.Compression.CompressionMode.Decompress)

            'Dim sr As New IO.StreamReader(gz)
           ' x = sr.ReadLine

            'sr.Close()
            'End Using

            'Decompress = x
        End Function
    End Class
End Namespace

更新此代码有效,但输出大小为500K,并且只有3100字节的文本。

Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports System.IO.Compression
Imports System.Text

Namespace WindowScriptingObject
    <Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
        Public Interface _WindowScriptingObject
        <DispId(1)> Function Decompress(ByVal value as string) As String
    End Interface

    <Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
        ClassInterface(ClassInterfaceType.None), _
        ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
    Implements _WindowScriptingObject

    Public WindowScriptingObject()
        Public Function Decompress(ByVal value as string) As String Implements _WindowScriptingObject.Decompress
            '     on error resume next
    Dim gzBuffer() As Byte = System.Text.Encoding.Default.Getbytes(value)

    Using ms As New MemoryStream()
        Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)
        ms.Write(gzBuffer, 0, gzBuffer.Length)
 msgbox(msgLength)
        Dim buffer As Byte() = New Byte(msgLength - 1) {}
        ms.Position = 0

        Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
              zipStream.Read(buffer, 0, buffer.Length)
        End Using
    Decompress=System.Text.Encoding.Default.GetString(buffer, 0, buffer.Length)
    End Using

        End Function
    End Class
End Namespace

由于某些原因,msgLength的大小为559,903,解压缩后的文本大约为3100字节。这意味着BitConverter.toint32出现故障,因为gzBuffer为865字节。最终输出大小仅对于GZIPStream函数是已知的,因为文本被压缩,而输入大小与输出大小无关。

其他问题

  1. 这可以更有效地编码吗?
  2. 如何防止恶意代码注入?
  3. 是否将输出限制为正确的大小?
  4. 如果添加新功能,是否需要更多Guid?
  5. 如何生成新的Guid?
  6. 在代码块3中,我将X转换为字符串t,并在不进行转换的情况下传递了值。

输出大小似乎基于错误的信息。

intOutputLength=zipStream.Read(buffer, 0, buffer.Length)
End Using
Decompress=System.Text.Encoding.Default.GetString(buffer, 0, intOutputLength)

至少这减少了返回主程序的数据量。

Dim msgLength As Integer = BitConverter.ToInt32(gzBuffer, 0)

如果我没看错,msgLength是否由输入流的前4个字符确定?由于GZip标头始终为1f 8b 08 00,这似乎是一个可怕的主意。如果输出中的每一个大于559k,则似乎只是缓冲区溢出而已。

我认为这解决了可怕的缓冲区大小问题。

Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.Win32
Imports System.IO
Imports System.IO.Compression
Imports System.Text


Namespace WindowScriptingObject
    <Guid("7448E08D-ED0F-4E23-B528-91937BB41756"), _
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
        Public Interface _WindowScriptingObject
        <DispId(1)> Function Decompress(ByVal value as string) As String
    End Interface


    <Guid("B146BF9E-78FC-4DB0-ABFE-9FF026B43E4D"), _
        ClassInterface(ClassInterfaceType.None), _
        ProgId("WindowScriptingObject")> Public Class WindowScriptingObject
    Implements _WindowScriptingObject


    Public WindowScriptingObject()
        Public Function Decompress(ByVal value as string) As String Implements _WindowScriptingObject.Decompress
            '     on error resume next
    Dim gzBuffer() As Byte = System.Text.Encoding.Default.Getbytes(value)
    dim intOutputLength as integer
    Dim intBlock as integer
    Decompress=""
    Using ms As New MemoryStream()
        Dim msgLength As Integer = 4096
        ms.Write(gzBuffer, 0, gzBuffer.Length)

        Dim buffer As Byte() = New Byte(4096) {}
        ms.Position = 0

        Using zipStream As New System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress)
        intOutputLength=0
        intBlock=4096
        while intBlock=4096
              intBlock=zipStream.Read(buffer, 0, buffer.Length)
            Decompress+=System.Text.Encoding.Default.GetString(buffer, 0, intBlock)
            intOutputLength+=intBlock
        end while 
        End Using

    End Using

        End Function
    End Class
End Namespace

2 个答案:

答案 0 :(得分:3)

通过更改VB.NET函数和界面使其看起来像这样(主要是更改参数类型),我可以使您的代码正常工作:

<Guid("7448E08E-ED0F-4E23-B528-91937BB41756"),
        InterfaceType(ComInterfaceType.InterfaceIsIDispatch)>
Public Interface _WindowScriptingObject
   <DispId(1)> Function Decompress(ByVal value As Byte()) As String
End Interface

Public Function Decompress(ByVal value As Byte()) As String Implements _WindowScriptingObject.Decompress
   Using xstream As New MemoryStream(value)
      Using gz As New System.IO.Compression.GZipStream(xstream, IO.Compression.CompressionMode.Decompress)
         Using sr As New IO.StreamReader(gz)
            Return sr.ReadLine()
         End Using
      End Using
   End Using
End Function

我的测试VBS看起来像这样

Const adTypeBinary = 1
Dim wso
Set wso = CreateObject("WindowScriptingObject")
Dim objStream, x
Set objStream = CreateObject("ADODB.Stream")
objStream.Type = adTypeBinary
objStream.Open
objStream.LoadFromFile "c:\users\bluem\desktop\Notes.txt.gz"
x = objStream.Read(342737)
objStream.Close
WScript.StdOut.WriteLine wso.Decompress((x))

我不完全确定为什么需要将x参数放在两组括号中,但是我认为这与强制将参数通过值而不是通过引用传递有关,并有助于将其转换为a字节数组。在添加额外的一对括号之前,我遇到了错误。

编辑: 要回答您的其他一些问题:

  • 我认为您不需要为新功能而仅为新接口或类创建新的GUID。
  • 要创建新的GUID,您只需复制现有的GUID并将其一部分(更改为0到F之间的数字)更改为唯一,或者可以转到https://www.guidgenerator.com/或选择“创建GUID “从Visual Studio的“工具”菜单中。”
  • 如果您可以根据新代码来澄清数据长度问题(如果问题仍然存在),我也许可以回答。

答案 1 :(得分:0)

自从我写了vbscript以来已经很久了,所以我已经不知道要提供修复了。但是,我可以在此代码的vbscript部分指出一些严重缺陷

首先从.gz文件中读取900个字节,而不管文件的实际长度如何。长度超过900字节的任何内容都不会被读取。

它以二进制模式执行此读取。二进制模式将忽略任何字符集或编码信息,仅读取原始字节,这适用于.gz文件。但是,此数据发生的下一件事是使用Len()函数,该函数用于字符串,而不是二进制数据; Len()在此不是适当的功能。此外,接下来将通过For函数在Mid()循环中使用数据。 Mid()同样旨在仅用于字符串,而x变体不是字符串。 vbscript字符串对象不仅仅是原始字符。它们包括诸如编码,长度和字符缓冲区之类的元数据,而这些字符串函数依赖于使用所有元数据正确构造的对象。

该vbscript不可能 产生正确的结果。在解决该问题之前,即使查看vb.net代码也没有任何意义。再次,我太过分地建议一个真正的解决方案,但是我建议尝试将一个未更改的字节数组而不是字符串传递给.Net端。