Die Community zu .NET und Classic VB.
Menü

Tipp-Upload: VB.NET 0171: Dynamische Entschlüsselung des eigenen Quellcodes

 von 

Hinweis zum Tippvorschlag  

Dieser Vorschlag wurde noch nicht auf Sinn und Inhalt überprüft und die Zip-Datei wurde noch nicht auf schädlichen Inhalt hin untersucht.
Bitte haben Sie ein wenig Geduld, bis die Freigabe erfolgt.

Über den Tipp  

Dieser Tippvorschlag ist noch unbewertet.

Der Vorschlag ist in den folgenden Kategorien zu finden:

  • Sonstiges

Dem Tippvorschlag wurden folgende Schlüsselwörter zugeordnet:
Compiler, Crypto, Entschlüsseln, Schutz, Attribute, Reflection

Der Vorschlag wurde erstellt am: 03.01.2008 14:23.
Die letzte Aktualisierung erfolgte am 03.01.2008 14:32.

Zurück zur Übersicht

Beschreibung  

.NET-Programme kann man leicht wieder disassemblen und sich den Quellcode ansehen oder verändern.
Ist das aus guten Gründen nicht erwünscht, kann man Mechanismen wie den vorgestellten verwenden, um den eigenen Quellcode z.B. von einem Passwort abhängig zu verschlüsseln, zur Laufzeit zu kompilieren und laufen zu lassen.

Vorteil auch: Die Passwortabfrage kann nicht umgangen werden.

Das Passwort für diesen Upload lautet: ProgrammAccess

Schwierigkeitsgrad

Schwierigkeitsgrad 3

Verwendete API-Aufrufe:

Download:

Download des Beispielprojektes [21,67 KB]

' Dieser Source stammt von http://www.activevb.de
' und kann frei verwendet werden. Für eventuelle Schäden
' wird nicht gehaftet.

' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
' Ansonsten viel Spaß und Erfolg mit diesem Source!
'
' Beachten Sie, das vom Designer generierter Code hier ausgeblendet wird.
' In den Zip-Dateien ist er jedoch zu finden.

' -------- Anfang Projektgruppe DynamicDecryption.sln --------
' ------- Anfang Projektdatei DynamicDecryption.vbproj -------
' ---------------- Anfang Datei Attribute.vb  ----------------
Imports System

''' <summary>
''' Eine verschlüsselte Methode - Ach nein, ein Property, dass sie enthält
''' </summary>
''' <remarks></remarks>
<AttributeUsage(AttributeTargets.Property)> Class UDEncryptedAttribute

    Inherits Attribute

    Private mHashSequence As String
    Private mImports As New Generic.List(Of String)

    ''' <summary>
    ''' Initialisieren
    ''' </summary>
    ''' <param name="SHAHashSequence">Hashsequenz des Orginalcodes (SHA256)</param>
    ''' <param name="Imports">Additional imports</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal SHAHashSequence As String, ByVal ParamArray [Imports]() As String)

        mHashSequence = SHAHashSequence
        mImports.AddRange([Imports])

    End Sub

#Region "Properties"
    ''' <summary>
    ''' Die hash sequence
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property HashSequence() As String
        Get
            Return mHashSequence

        End Get

    End Property

    ''' <summary>
    ''' Imports, die die Funktion braucht
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property [Imports]() As IEnumerable(Of String)
        Get
            Return mImports

        End Get

    End Property

#End Region

End Class

' ----------------- Ende Datei Attribute.vb  -----------------
' ----------------- Anfang Datei Compiler.vb -----------------
Imports System.Reflection
Imports System.ComponentModel
Imports System.CodeDom.Compiler
Imports System.Environment

''' <summary>
''' Unser Compiler
''' </summary>
''' <remarks></remarks>
Public Class Compiler

    Implements IDisposable

    Private mProv As New Microsoft.VisualBasic.VBCodeProvider
    Private mAssembly As [Assembly]

    ''' <summary>
    ''' Kompilieren
    ''' </summary>
    ''' <param name="Source">Quellcode</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Compile(ByVal Source As String) As Boolean

        With mProv.CompileAssemblyFromSource(New CompilerParameters With {.GenerateInMemory = _
            True}, Source)

            If .Errors.Count > 0 Then Return False
            mAssembly = .CompiledAssembly()
            Return True
        End With

    End Function

    ''' <summary>
    ''' Die Assembly abfragen
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property [Assembly]() As [Assembly]
        Get
            Return mAssembly

        End Get

    End Property

    ''' <summary>
    ''' Und ab in den Mülleimer
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Dispose() Implements IDisposable.Dispose

        If mProv Is Nothing Then Return
        mProv.Dispose()
        mProv = Nothing
        GC.SuppressFinalize(Me)

    End Sub

End Class

' ------------------ Ende Datei Compiler.vb ------------------
' --------------- Anfang Datei CreateSource.vb ---------------
Imports System
Imports System.Reflection

''' <summary>
''' Quellcode zusammenstellen
''' </summary>
''' <remarks></remarks>
Public Class SourceCreator

    Private mSource As New Text.StringBuilder
    Private mImports As New List(Of String)

    ''' <summary>
    ''' Methoden eines Typen auslesen
    ''' </summary>
    ''' <param name="Password">Passwort</param>
    ''' <param name="tType">Typ</param>
    ''' <remarks></remarks>
    Public Sub Reflect(ByVal Password As String, ByVal tType As Type)

        Dim Container As Type = tType

        For Each [Property] In Container.GetProperties

            Dim Attribute As UDEncryptedAttribute = System.Attribute.GetCustomAttributes( _
                [Property]).OfType(Of UDEncryptedAttribute).FirstOrDefault

            If Attribute Is Nothing Then Continue For

            Dim TempSource As String = CryptoService.Decrypt(Password, [Property].GetValue( _
                Nothing, Nothing))

            ' Autsch
            If CryptoService.GetHash(TempSource) <> Attribute.HashSequence Then

                Throw New Exception("Hashes do not equal. You are stronly adviced to stop " & _
                    "code execution")

                Continue For
            End If

            mImports.AddRange(Attribute.Imports)

            mSource.AppendLine(TempSource)

        Next

    End Sub

    ''' <summary>
    ''' Quellcode zusammenstellen
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public ReadOnly Property Source() As String
        Get

            Dim ImportSequence As String = "Imports " & String.Join(Environment.NewLine & _
                "Imports ", mImports.Distinct.OrderBy(Function(a As String) _
                a.Length).ToArray)

            Return String.Join(Environment.NewLine, New String() { ImportSequence, "", "", _
                "' Programme sequence", "", "", "Public Class DecryptionSource", "", "", _
                mSource.ToString, "End Class"})

        End Get

    End Property

End Class

' ---------------- Ende Datei CreateSource.vb ----------------
' -------------- Anfang Datei CryptoService.vb  --------------
Imports System.Security.Cryptography

''' <summary>
''' Kryptographiedienste zur Verfügung stellen
''' </summary>
''' <remarks></remarks>
Public Class CryptoService

    ''' <summary>
    ''' Wir verwenden AES
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared mAlgo As New AesCryptoServiceProvider

    ''' <summary>
    ''' Stringdaten verschlüsseln
    ''' </summary>
    ''' <param name="Password">Key</param>
    ''' <param name="Data">Daten</param>
    ''' <returns>Ergebnis</returns>
    ''' <remarks></remarks>
    Public Shared Function Encrypt(ByVal Password As String, ByVal Data As String) As String

        Return Process(Password, Data, AddressOf mAlgo.CreateEncryptor, AddressOf _
            System.Text.Encoding.UTF8.GetBytes, AddressOf Convert.ToBase64String)

    End Function

    ''' <summary>
    ''' Stringdaten entschlüsseln
    ''' </summary>
    ''' <param name="Password">Key</param>
    ''' <param name="Data">Daten</param>
    ''' <returns>Ergebnis</returns>
    ''' <remarks></remarks>
    Public Shared Function Decrypt(ByVal Password As String, ByVal Data As String) As String

        Return Process(Password, Data, AddressOf mAlgo.CreateDecryptor, AddressOf _
            Convert.FromBase64String, AddressOf System.Text.Encoding.UTF8.GetString)

    End Function

    ''' <summary>
    ''' Abstrakte Verschlüsselungsprozedur
    ''' </summary>
    ''' <param name="Password">Passwort</param>
    ''' <param name="Data">Daten</param>
    ''' <param name="Operation">ICryptoTransform-Operation</param>
    ''' <returns>Ergebnis</returns>
    ''' <remarks></remarks>
    Private Shared Function Process(ByVal Password As String, ByVal Data As String, ByVal _
        Operation As Func(Of ICryptoTransform), ByVal Transformer1 As Converter(Of String, _
        Byte()), ByVal Transformer2 As Converter(Of Byte(), String)) As String

        Dim btClear() As Byte

        InitAlgo(Password)

        Dim ms As New IO.MemoryStream
        Dim cs As New CryptoStream(ms, Operation(), CryptoStreamMode.Write)

        Try

            btClear = Transformer1(Data)
            cs.Write(btClear, 0, btClear.Length)
            cs.Close()

        Catch ex As Exception

            Return Nothing

        End Try

        Return Transformer2(ms.ToArray)

    End Function

    ''' <summary>
    ''' Algorithmus initialisieren
    ''' </summary>
    ''' <param name="Password">Password</param>
    ''' <remarks></remarks>
    Private Shared Sub InitAlgo(ByVal Password As String)

        Dim btSalt(7) As Byte
        Dim KeyGenerator As New Rfc2898DeriveBytes(Password, btSalt)

        mAlgo.Key = KeyGenerator.GetBytes(mAlgo.Key.Length)
        mAlgo.IV = KeyGenerator.GetBytes(mAlgo.IV.Length)

    End Sub

    ''' <summary>
    ''' SHA256-Hash berechnen
    ''' </summary>
    ''' <param name="Source">Source data</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetHash(ByVal Source As String)

        Return GetHash(Source, AddressOf SHA256.Create)

    End Function

    ''' <summary>
    ''' Hash berechnen
    ''' </summary>
    ''' <param name="Source">Daten</param>
    ''' <param name="CreateAlgo">Algorithmus</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetHash(ByVal Source As String, ByVal CreateAlgo As Func(Of _
        HashAlgorithm))

        Dim HashAlgo As HashAlgorithm = CreateAlgo()
        Dim Dest As Byte() = HashAlgo.ComputeHash(System.Text.Encoding.UTF8.GetBytes(Source))

        Dim str As String = "0x"

        For i As Integer = 0 To Dest.Length - 1
            str = str & Hex(Dest(i))
        Next

        Return str

    End Function

End Class

' --------------- Ende Datei CryptoService.vb  ---------------
' ----------------- Anfang Datei Encoder.vb  -----------------

''' <summary>
''' Methoden verschlüsseln
''' </summary>
''' <remarks></remarks>
Public Class Encoder

    ''' <summary>
    ''' Quellcode verschlüsseln
    ''' </summary>
    ''' <param name="Source">Sourcecode</param>
    ''' <param name="Password">Passwort</param>
    ''' <param name="FuncName">Funktionsname</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function EncodeSource(ByVal Source As String, ByVal Password As String, _
        ByVal FuncName As String) As String

        Dim Result As String = ""

        Result &= String.Format("<UDEncrypted(""{0}"")> _", CryptoService.GetHash(Source)) & _
            Environment.NewLine

        Result &= String.Concat("Public Shared ReadOnly Property ", FuncName, "() As " & _
            "String", Environment.NewLine, "Get", Environment.NewLine, "Return """, _
            CryptoService.Encrypt(Password, Source), """", Environment.NewLine, "End Get", _
            Environment.NewLine, "End Property")

        Return Result

    End Function

End Class

' ------------------ Ende Datei Encoder.vb  ------------------
' ---------------- Anfang Datei Functions.vb  ----------------
''' <summary>
''' Unsere Funktionen gesammelt
''' </summary>
''' <remarks>Alles, was hier mit [UDEncrypted()] drin steh, wird vom Provider entschlüsselt und kompiliert</remarks>
Public Class Functions

    ''' <summary>
    ''' Ich bin *die* Methode, aber keiner kann mich lesen xD
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    <UDEncrypted("0x834CD2AE80AA64D2AA3475A5E4E63AAC10EA9AD262A8F9FE3D59EADB46ECDF2E", _
        "System", "System.Diagnostics", "System.Text")> Public Shared ReadOnly Property _
        SecretMethod() As String

        Get

            Return "Lbz2qLORZ4SI6RC37+FiFipXwn/FphKzR6ET1LW//te5MFKk/M2752saqKsAdKOWuAp2f" & _
                "XuvSxOhvJERYv7etEiKeHt3C4zNIKjCGPGbP8u0Nm9bUm/aVf9Vntw6bDVjrv3UCz6xbxDsKpW/oR5CTGhDQI" & _
                "kmrMwNWu6pYh+ik2sqNIbbP9ZvTqUU5XcPtc8+5DWU8lXfXVp/zG76Zf66vA21CamkRKzRQ8J/jWRFOWxCPa6" & _
                "+VXOL3EkYzsDR53Fuh6oTNCGbqFfeWxwRzKF0NXsHMvVTauRr/ddUUAJHoXAH2PO8FRWOSgViAVr4RPzU9dvJ" & _
                "g0wwcNeZH/3BsWxkiLxwEw7xkPnIsTImwymgwsHABfhSXbpPIJGIQAMA0jeYkbJ/J8CYNrPEjbxJCe7YjW/Q/" & _
                "KtCqd93caefYArrpCUUIY9uQhm03rF94PKWlsJx"

        End Get

    End Property

    ' Für all die, die keinen Code ausführen, den sie nicht sehen ...
    ' Public Shared Function SecretMethod(ByVal Path As String, ByVal Text As String) As String
    ' My.Computer.FileSystem.WriteAllText(Path, String.Format("Der Benutzer hat den Text
    ' ""{0}"" eingegeben.", Text), False)
    '    Process.Start(Path)
    '    Return "Juhu, ich habe in eine Datei geschrieben ;-)"
    ' End Function

End Class

' ----------------- Ende Datei Functions.vb  -----------------
' -------------- Anfang Datei MethodProvider.vb --------------
''' <summary>
''' Unsere Methoden zur Verfügung stellen
''' </summary>
''' <remarks></remarks>
Public Class MethodProvider

    Implements IDisposable

    Private mSource As New SourceCreator
    Private mTypes As New List(Of Type)
    Private mComp As New Compiler

    Public Sub Add(Of Container)()

        mTypes.Add(GetType(Container))

    End Sub

    Public Sub Add(ByVal Type As Type)

        mTypes.Add(Type)

    End Sub

    ''' <summary>
    ''' Kompilieren und Entschlüsseln
    ''' </summary>
    ''' <param name="Password"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Compile(ByVal Password As String) As Boolean

        For Each tType In mTypes
            mSource.Reflect(Password, tType)
        Next

        Return mComp.Compile(mSource.Source)

    End Function

    ''' <summary>
    ''' Methodendelegaten abrufen
    ''' </summary>
    ''' <param name="Name">Name der Methode</param>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Default Public ReadOnly Property Method(ByVal Name As String) As Func(Of Object(), Object)
        Get

            Static ExecType As Type = mComp.Assembly.GetType("DecryptionSource")

            Return Function(Params As Object()) ExecType.GetMethod(Name).Invoke(Nothing, Params)

        End Get

    End Property

    Public Sub Dispose() Implements IDisposable.Dispose

        mComp.Dispose()
        GC.SuppressFinalize(Me)

    End Sub

End Class

' --------------- Ende Datei MethodProvider.vb ---------------
' ------------------ Anfang Datei Form1.vb  ------------------
Public Class frmPassword

    Private Sub txtPassword_TextChanged(ByVal sender As System.Object, ByVal e As _
        System.EventArgs) Handles txtPassword.TextChanged

        cmdOK.Enabled = Not (txtPassword.Text = "")

    End Sub

    Private Sub cmdQuit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles cmdQuit.Click

        Application.Exit()

    End Sub

    Private Sub cmdOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles cmdOK.Click

        ' Hashsequenzenvergleich - kann man austricksen ;-)
        If CryptoService.GetHash(txtPassword.Text) <> _
            "0x27C1E848CF348C3E6552D16E213ECBCAB6474A426EA52BF8A5C3A3698C94" Then

            MessageBox.Show("Das Passwort ist nicht korrekt", "Falsches Passwort", _
                MessageBoxButtons.OK, MessageBoxIcon.Error)

            Exit Sub

        End If

        Call (New frmMain With {.Password = txtPassword.Text}).Show()

    End Sub

End Class

' ------------------- Ende Datei Form1.vb  -------------------
' ------------------- Anfang Datei Main.vb -------------------
Imports System.Windows.Forms

Public Class frmMain

    Public Password As String

    Private mProvider As New MethodProvider

    Private Sub frmMain_FormClosing(ByVal sender As Object, ByVal e As _
        System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

        Me.Dispose()
        Application.Exit()

    End Sub

    Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles MyBase.Load

        frmPassword.Dispose()

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles Button1.Click

        txtRes.Text = Encoder.EncodeSource(txtMethod.Text, txtPassword.Text, txtMethodName.Text)

    End Sub

    Private Sub TextChange(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles txtPassword.TextChanged, txtMethodName.TextChanged, txtMethod.TextChanged

        Button1.Enabled = txtMethodName.Text <> "" And txtPassword.Text <> "" And _
            txtMethod.Text <> ""

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles Button2.Click

        txtMethodName.Text = "" : txtPassword.Text = "" : txtMethod.Text = "" : txtRes.Text = ""

    End Sub

    Private Sub cmdDecodeMethod_Click(ByVal sender As System.Object, ByVal e As _
        System.EventArgs) Handles cmdDecodeMethod.Click

        mProvider.Add(GetType(Functions))

        If Not mProvider.Compile(Password) Then

            MessageBox.Show("Was für ein Mist", "Autsch", MessageBoxButtons.OK, _
                MessageBoxIcon.Error)

            Application.Exit()

        Else

            MessageBox.Show("Juhu", "Juhu", MessageBoxButtons.OK, MessageBoxIcon.Information)
        End If

        cmdDecodeMethod.Enabled = False
        cmdExecuteMethod.Enabled = True

    End Sub

    Private Sub cmdDecodeMethod_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles cmdDecodeMethod.Disposed

        Me.Dispose()
        mProvider.Dispose()

    End Sub

    Private Sub cmdExecuteMethod_Click(ByVal sender As System.Object, ByVal e As _
        System.EventArgs) Handles cmdExecuteMethod.Click

        ' Methode abfragen - Das ist alles
        Dim Method As Func(Of Object(), Object) = mProvider("SecretMethod")

        Dim Path As String = Application.StartupPath & "\Foo.txt"

        Dim Text As String = InputBox("Geben sie einen Text, z.B. einen Satz, ein", _
            "Texteingabe", "Hallo, Welt")

        If Method IsNot Nothing Then

            Dim Res As String = CStr(Method.Invoke(New Object() {Path, Text}))

            MessageBox.Show("Die Methode gibt folgendes zurück: """ & Res & """", _
                "Ergebnis", MessageBoxButtons.OK, MessageBoxIcon.Information)

        End If

    End Sub

End Class

' -------------------- Ende Datei Main.vb --------------------
' -------- Ende Projektdatei DynamicDecryption.vbproj --------
' --------- Ende Projektgruppe DynamicDecryption.sln ---------

	

Diskussion  

Diese Funktion ermöglicht es, Fragen, die die Veröffentlichung des Tipps betreffen, zu klären, oder Anregungen und Verbesserungsvorschläge einzubringen. Nach der Veröffentlichung des Tipps werden diese Beiträge nicht weiter verlinkt. Allgemeine Fragen zum Inhalt sollten daher hier nicht geklärt werden.
Folgende Diskussionen existieren bereits

Um eine Diskussion eröffnen zu können, müssen sie angemeldet sein.