Правильно конвертировать строку в поток - PullRequest
0 голосов
/ 29 января 2019
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))

Эта строка слышит, как представляется, неправильно преобразовывает мою строку в поток.

Цель состоит в том, чтобы отправить сжатую строку и вернуть несжатыйstring.

Приведенный выше код вызывается с этим кодом

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

Обновление этого кода работает, за исключением того, что выходной размер составляет 500 КБ, и есть только 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 Iпреобразовать 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, это кажется ужасной идеей.Если выходное значение больше 559 КБ, то это похоже на переполнение буфера, которое только и ждет.

Я думаю, что это решает ужасную проблему размера буфера.

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 голосов
/ 30 января 2019

Мне удалось заставить ваш код работать, изменив функцию и интерфейс 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 в два набора скобок, но я думаю, что это как-то связано с принудительной передачей параметра по значению, а не по ссылке, и помогает емупреобразовать в байтовый массив.Я получал сообщение об ошибке, прежде чем добавил лишнюю пару скобок.

Редактировать: Чтобы ответить на некоторые другие ваши вопросы:

  • Я не думаю,вам нужно создать новый GUID для новой функции, только для нового интерфейса или класса.
  • Чтобы создать новый GUID, вы можете просто скопировать существующий и изменить его часть (до цифр от 0 до F).включительно), чтобы быть уникальным, или вы можете перейти к https://www.guidgenerator.com/ или вы можете выбрать «Создать GUID» в меню «Инструменты» Visual Studio.
  • Если вы можете прояснить проблему с длиной данных на основе нового кода(если проблема все еще существует), я мог бы ответить.
0 голосов
/ 30 января 2019

Прошло слишком много времени с тех пор, как я написал vbscript, поэтому я больше не знаю достаточно, чтобы давать исправления.Тем не менее, я могу указать на некоторые серьезные недостатки в части vbscript этого кода.

Он начинается с чтения до 900 байтов из файла .gz, независимо от фактической длиныфайл.Все, что длиннее, чем просто 900 байтов, не будет прочитано.

Он выполняет это чтение в двоичном режиме.Двоичный режим игнорирует любой набор символов или информацию о кодировке и просто читает необработанные байты, что подходит для файла .gz.Однако следующее, что происходит с этими данными, это использование функции Len(), которая предназначена для строк , а не двоичных данных;Len() - это , а не соответствующая функция здесь.Кроме того, данные затем используются в цикле For через функцию Mid().Mid() также предназначен только для строк , а вариант x - , а не строка .Строковые объекты vbscript - это не просто необработанные символы;они включают в себя метаданные для таких вещей, как кодирование, длина и символьные буферы, и эти строковые функции основаны на объектах, которые правильно создаются со всеми метаданными.,Пока это не решено, нет смысла даже смотреть на код vb.net.Опять же, я слишком далеко зашел, чтобы предложить реальное решение, но я рекомендую попытаться передать неизмененный байтовый массив стороне .Net, а не строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...