有一些方法可以保护脚本代码吗?

时间:2012-05-28 17:53:58

标签: powershell vbscript readonly protection

假设所有基于脚本的语言(例如VBscript和Powershell)每次都在客户机器上“嵌入”整个代码,我应该假设这段代码是“开放的”吗?我的意思是,有一些方法可以保护基于脚本的代码以便阅读(并因此写入)?

4 个答案:

答案 0 :(得分:5)

有些工具可以将VBScript转换为可执行文件,例如vbs2exevbseditscriptcryptordoing it yourself in .netusing PowerGUI Props2exe也可以通过PowerShell创建可执行文件。

使用这些工具,您可以使脚本“关闭”。与(几乎)所有客户端站点代码一样,它仍然可能被黑客入侵,但这需要更多的工具和知识,而不仅仅是在记事本中打开vbs文件并窥视脚本。

答案 1 :(得分:3)

我不相信有任何完整的证据方式,混淆和最小化是试图保护代码的方法(并且在最小化的情况下减少存储/传输大小)但最终有足够时间的人可以逆转通过调试/反汇编工具设计或观察程序的执行。我认为你最安全的假设客户端机器上的任何东西都可以被玩弄,并且保护代码或信息的最佳选择是将它存储/执行在具有适当安全性的服务器上,并且不断更新安全漏洞补丁。 / p>

答案 2 :(得分:0)

是的!您可以为此使用我的模板。并且不要忘记将密码从“ qweasd”更改为其他密码!

    function global:Decrypt-String {
        param($Encrypted,$Passphrase,$salt,$init)

        if ($Encrypted -is [string]) {
            $Encrypted = [Convert]::FromBase64String($Encrypted)
        }

        $r = New-Object System.Security.Cryptography.RijndaelManaged
        $pass = [System.Text.Encoding]::UTF8.GetBytes($Passphrase)
        $salt = [System.Text.Encoding]::UTF8.GetBytes($salt)

        $r.Key = (New-Object Security.Cryptography.PasswordDeriveBytes $pass,$salt,"SHA256",5).GetBytes(256/8)
        $r.IV = (New-Object Security.Cryptography.SHA1Managed).ComputeHash([Text.Encoding]::UTF8.GetBytes($init))[0..15]

        $d = $r.CreateDecryptor()
        $ms = New-Object IO.MemoryStream @(,$Encrypted)
        $cs = New-Object Security.Cryptography.CryptoStream $ms,$d,"Read"
        $sr = New-Object IO.StreamReader $cs
        Write-Output $sr.ReadToEnd()
        $sr.Close()
        $cs.Close()
        $ms.Close()
        $r.Clear()
    }

    function global:Run-Decrypt ([string]$encrypted) {
        $private:pass = Read-Host "Enter password to decode script code" -AsSecureString
        $private:BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($private:pass)
        $private:UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($private:BSTR)
        $block = (global:Decrypt-String -Encrypted $encrypted -Passphrase $private:UnsecurePassword -salt "d35104f3-dcd0-4cd7-80bb-5e66388e6ede" -init "3982c1d2-04da-4883-9a46-4b860794084e")
        return $block
    }

    function global:Save-Decrypt ([string]$encrypted) {
        try {
            $answer = Read-Host "Save decoded script version? (y/n)"
            switch ($answer) { 
                Y {} 
                N {return} 
                Default {return} 
            }
            $decrypted = Run-Decrypt $encrypted
            $p = (Read-Host "Enter path for new file")
            if (-Not (Is-ValidPath $p)) { return }
            if ($host.version -ne "2.0") {
                $offset = $global:secure.StartPosition.Start + 1
            } else {
                $offset = $global:secure.StartPosition.Start
            }
            (Get-Content $global:secure.File | Out-String).Remove($offset,$global:secure.ToString().Length).Insert($offset, $decrypted) | Out-File -FilePath $p -NoClobber
            Write-Host 'Decoded file successfully saved.'
        } catch {
            Write-Host 'Error while saving file.'
            Write-Host $error[0]  
        }
    }

    function global:Is-ValidPath([string]$path) {
        if ($path -eq '') {
            Write-Host 'No path. Failed to create a file.'; return $false
        } elseif (-not (Test-Path (Split-Path $path -Parent))) {
            Write-Host 'Path does not exists. Failed to create a file.'; return $false
        } elseif (Test-Path $path) {
            Write-Host 'File already exists. Failed to create a file.'; return $false
        }
        return $true;
    }

    $global:secure = {
        function global:Encrypt-String {
            param($String,$Passphrase,$salt,$init,[switch]$arrayOutput)

            $r = New-Object System.Security.Cryptography.RijndaelManaged
            $pass = [Text.Encoding]::UTF8.GetBytes($Passphrase)
            $salt = [Text.Encoding]::UTF8.GetBytes($salt)

            $r.Key = (New-Object Security.Cryptography.PasswordDeriveBytes $pass,$salt,"SHA256",5).GetBytes(256/8)
            $r.IV = (New-Object Security.Cryptography.SHA1Managed).ComputeHash([Text.Encoding]::UTF8.GetBytes($init))[0..15]

            $c = $r.CreateEncryptor()
            $ms = New-Object IO.MemoryStream
            $cs = New-Object Security.Cryptography.CryptoStream $ms,$c,"Write"
            $sw = New-Object IO.StreamWriter $cs
            $sw.Write($String)
            $sw.Close()
            $cs.Close()
            $ms.Close()
            $r.Clear()
            [byte[]]$result = $ms.ToArray()
            if ($arrayOutput) {
                return $result
            } else {
                return [Convert]::ToBase64String($result)
            }
        }

        function global:Save-Encrypt () {
            $answer = Read-Host "`nSave encoded version of this script? (y/n)"
            switch ($answer) { 
                Y {} 
                N {return} 
               Default {return} 
            }
            try {
                $path = (Read-Host "Enter path for encoded file").Trim("`"'")
                if (-Not (Is-ValidPath $path)) {return}
                Run-Encrypt | Out-File -FilePath $path -NoClobber
                Write-Host 'Encoded file successfully saved.'
            } catch {
                Write-Host 'Error while saving file.'
                Write-Host $error[0]
            }
        }

        function global:Run-Encrypt () {
            param(
            $pass = "qweasd",
            $salt = "d35104f3-dcd0-4cd7-80bb-5e66388e6ede",
            $init = "3982c1d2-04da-4883-9a46-4b860794084e"
            )

            $encrypted = global:Encrypt-String -String $global:secure -Passphrase $pass -salt $salt -init $init
            if ($host.version -ne "2.0") {
                $offset = $global:secure.StartPosition.Start + 1
            } else {
                $offset = $global:secure.StartPosition.Start
            }
            $block = (Get-Content $global:secure.File | Out-String).Remove($offset, $global:secure.ToString().Length).Insert($offset, "New-Object -TypeName System.String '$encrypted'")
            return $block
        }

        #program starts here

        Write-Host "Hello World!"

        #program ends here
    }

    try {
        $null = $global:secure.GetSteppablePipeline() #dirty hack
        Write-Warning "Script encoded!"
        try {
            Invoke-Command -ScriptBlock ([Scriptblock]::Create((Run-Decrypt $global:secure.Invoke())))
        } finally {
            Save-Decrypt  $global:secure.Invoke()
        }
    } catch {
        try {
            Invoke-Command -ScriptBlock $global:secure
        } finally {
            Get-Job | Remove-Job -Force
            Save-Encrypt
        }
    }

答案 3 :(得分:-1)

我对可执行方法并不满意,因为我发现复杂的脚本不容易编译(通常根本不编译),最后也很难处理。正如许多人所指出的那样,对于坚定的人来说,可执行文件不是障碍。我决定一个更好的方法只是让人类可读的脚本更难以改变,然后只是要求原始开发人员进行更改。

我编写obfuscate-powershell来更改变量和函数名称,删除注释并更改空格只是为了使代码更易于阅读和理解。它仍然没有任何安全保障,但它总比什么都不做更好。